Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions app/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,25 @@ export default defineConfig([
ecmaVersion: 2020,
globals: globals.browser,
},
rules: {
'react-hooks/set-state-in-effect': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'react-refresh/only-export-components': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_|err|e',
varsIgnorePattern: '^_|err|e',
caughtErrorsIgnorePattern: '^_|err|e',
Comment on lines +29 to +31

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

no-unused-vars ignore regex is overly broad.

'^_|err|e' matches almost any identifier containing e, so many real unused variables are silently ignored. Anchor this to exact ignore names instead.

Suggested fix
-          argsIgnorePattern: '^_|err|e',
-          varsIgnorePattern: '^_|err|e',
-          caughtErrorsIgnorePattern: '^_|err|e',
+          argsIgnorePattern: '^(_|err|e)$',
+          varsIgnorePattern: '^(_|err|e)$',
+          caughtErrorsIgnorePattern: '^(_|err|e)$',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
argsIgnorePattern: '^_|err|e',
varsIgnorePattern: '^_|err|e',
caughtErrorsIgnorePattern: '^_|err|e',
argsIgnorePattern: '^(_|err|e)$',
varsIgnorePattern: '^(_|err|e)$',
caughtErrorsIgnorePattern: '^(_|err|e)$',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/eslint.config.js` around lines 29 - 31, The no-unused-vars ignore
patterns are too broad because `argsIgnorePattern`, `varsIgnorePattern`, and
`caughtErrorsIgnorePattern` in `eslint.config.js` currently match almost any
identifier containing `e` or `err`. Narrow these regexes in the ESLint config so
they only ignore the intended exact placeholder names (for example,
underscore-prefixed names or specific catch variable names) and do not silently
exempt real unused variables.

},
],
}
},
{
files: ['src/components/ui/**/*.{ts,tsx}'],
rules: {
'react-refresh/only-export-components': 'off',
'react-hooks/purity': 'off',
},
},
])
8 changes: 4 additions & 4 deletions app/src/api/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const getUsers = async (page = 1, limit = 20, search = '') => {
return response.data;
};

export const editUser = async (userId: string, updates: any) => {
export const editUser = async (userId: string, updates: Record<string, unknown>) => {
const response = await axios.put(`${API_BASE_URL}/api/admin/users/${userId}`, updates, getAuthHeader());
return response.data;
};
Expand All @@ -38,12 +38,12 @@ export const deleteUser = async (userId: string) => {
};

// ========== CONTENT MANAGEMENT ==========
export const addProblem = async (problemData: any) => {
export const addProblem = async (problemData: Record<string, unknown>) => {
const response = await axios.post(`${API_BASE_URL}/api/admin/problems`, problemData, getAuthHeader());
return response.data;
};

export const editProblem = async (problemId: string, updates: any) => {
export const editProblem = async (problemId: string, updates: Record<string, unknown>) => {
const response = await axios.put(`${API_BASE_URL}/api/admin/problems/${problemId}`, updates, getAuthHeader());
return response.data;
};
Expand All @@ -59,7 +59,7 @@ export const deleteForumPost = async (postId: string) => {
return response.data;
};

export const editForumPost = async (postId: string, updates: any) => {
export const editForumPost = async (postId: string, updates: Record<string, unknown>) => {
const response = await axios.put(`${API_BASE_URL}/api/admin/forum/posts/${postId}`, updates, getAuthHeader());
return response.data;
};
Expand Down
5 changes: 3 additions & 2 deletions app/src/components/custom/AlgoBot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,9 @@ export function AlgoBot({ onAuthClick }: { onAuthClick: (mode: 'login' | 'signup
setLatestAiIndex(newMsgs.length - 1);
return newMsgs;
});
} catch (error: any) {
const errorData = error?.response?.data;
} catch (error: unknown) {
const axiosError = error as { response?: { data?: { error?: string; details?: string } } };
const errorData = axiosError?.response?.data;
const mainError = errorData?.error || 'Sorry, something went wrong.';
const details = errorData?.details ? `\n\n🔍 Debug: ${errorData.details}` : '';
setMessages(prev => [...prev, { role: 'assistant', content: `⚠️ **${mainError}**${details}` }]);
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/custom/AuthModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function AuthModal({ isOpen, onClose, defaultMode = 'login' }: AuthModalP
onClose();
}
}
} catch (err) {
} catch (_err) {
toast.error('An unexpected error occurred');
} finally {
setIsLoading(false);
Expand Down
4 changes: 2 additions & 2 deletions app/src/components/custom/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {

interface NavigationProps {
currentView: string;
onNavigate: (view: 'home' | 'dashboard' | 'topic' | 'problems' | 'notes' | 'leaderboard') => void;
onNavigate: (view: 'home' | 'dashboard' | 'topic' | 'problems' | 'notes' | 'leaderboard' | 'admin') => void;
onAuthClick: (mode: 'login' | 'signup') => void;
}

Expand Down Expand Up @@ -71,7 +71,7 @@ export function Navigation({ currentView, onNavigate, onAuthClick }: NavigationP
{ id: 'roadmaps', label: 'Roadmaps', icon: Map, view: 'home' as const, isAnchor: true },
{ id: 'problems', label: 'Problems', icon: List, view: 'problems' as const, isAnchor: false },
{ id: 'leaderboard', label: 'Leaderboard', icon: Trophy, view: 'leaderboard' as const, isAnchor: false },
...(user?.role === 'admin' ? [{ id: 'admin', label: 'Admin', icon: Shield, view: 'admin' as any, isAnchor: false }] : []),
...(user?.role === 'admin' ? [{ id: 'admin', label: 'Admin', icon: Shield, view: 'admin' as const, isAnchor: false }] : []),
];

const handleNavClick = (link: typeof navLinks[0]) => {
Expand Down
26 changes: 13 additions & 13 deletions app/src/contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ interface User {
role?: string;
xp_points?: number;
streak_days?: number;
solvedProblems?: any[];
activityLog?: any[];
solvedProblems?: unknown[];
activityLog?: unknown[];
}

interface AuthContextType {
user: User | null;
profile: any | null;
profile: User | null;
isLoading: boolean;
isAuthReady: boolean;
signIn: (email: string, password: string) => Promise<{ error: any }>;
signUp: (email: string, password: string, name: string) => Promise<{ error: any }>;
signInWithGoogle: (credential?: string) => Promise<{ error: any; isNewUser?: boolean }>;
signIn: (email: string, password: string) => Promise<{ error: string | null }>;
signUp: (email: string, password: string, name: string) => Promise<{ error: string | null }>;
signInWithGoogle: (credential?: string) => Promise<{ error: string | null; isNewUser?: boolean }>;
signOut: () => Promise<void>;
updateProfile: (updates: Record<string, unknown>) => Promise<{ error: any }>;
updateProfile: (updates: Record<string, unknown>) => Promise<{ error: string | null }>;
refreshProfile: () => Promise<void>;
}

Expand All @@ -31,7 +31,7 @@ const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:5000

export function AuthProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [profile, setProfile] = useState<any | null>(null);
const [profile, setProfile] = useState<User | null>(null);
const isLoading = false;
const [isAuthReady, setIsAuthReady] = useState(false);

Expand Down Expand Up @@ -121,7 +121,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setProfile({ ...data, id: data.id });

return { error: null };
} catch (err) {
} catch (_err) {
return { error: 'Network error. Ensure backend is running.' };
}
};
Expand Down Expand Up @@ -158,7 +158,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setProfile({ ...data, id: data.id });

return { error: null };
} catch (err) {
} catch (_err) {
return { error: 'Network error. Ensure backend is running.' };
}
};
Expand Down Expand Up @@ -197,7 +197,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setProfile({ ...data, id: data.id });

return { error: null, isNewUser: data.isNewUser };
} catch (err) {
} catch (_err) {
return { error: 'Network error during Google Auth' };
}
};
Expand Down Expand Up @@ -231,7 +231,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
return { error: data.message || 'Failed to update profile' };
}

setProfile((prev: any) => ({ ...prev, ...data }));
setProfile((prev) => prev ? { ...prev, ...data } : data);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Prevent stale profile resurrection after logout.

If updateProfile resolves after a logout, prev may be null; the current fallback (: data) can rehydrate profile unexpectedly. Keep it null when prev is null.

Suggested fix
-      setProfile((prev) => prev ? { ...prev, ...data } : data);
+      setProfile((prev) => (prev ? { ...prev, ...data } : null));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
setProfile((prev) => prev ? { ...prev, ...data } : data);
setProfile((prev) => (prev ? { ...prev, ...data } : null));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/contexts/AuthContext.tsx` at line 234, The updateProfile state merge
in AuthContext.tsx can resurrect a logged-out profile because setProfile falls
back to data when prev is null. Update the updateProfile flow so that when the
previous profile is null, it remains null instead of assigning data, and only
merge data into an existing profile using the existing setProfile callback
logic.


if (user) {
setUser((prevUser) => {
Expand All @@ -245,7 +245,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}

return { error: null };
} catch (err) {
} catch (_err) {
return { error: 'Network error. Ensure backend is running.' };
}
};
Expand Down
Loading
Loading