diff --git a/backend/app/routes/auth.py b/backend/app/routes/auth.py index e2abd2c9..dce36793 100644 --- a/backend/app/routes/auth.py +++ b/backend/app/routes/auth.py @@ -17,6 +17,11 @@ # TODO: ADD RATE LIMITING @router.post("/register", response_model=UserCreateResponse) async def register_user(user: UserCreateRequest, user_service: UserService = Depends(get_user_service)): + allowed_Admins = ["umair.hkar@gmail.com", "umairmhundekar@gmail.com"] + if user.role == UserRole.ADMIN: + if user.email not in allowed_Admins: + raise HTTPException(status_code=403, detail="Access denied. Admin privileges required for admin portal") + try: return await user_service.create_user(user) except HTTPException as http_ex: diff --git a/frontend/src/APIClients/authAPIClient.ts b/frontend/src/APIClients/authAPIClient.ts index 9ad7cfcc..a753aa50 100644 --- a/frontend/src/APIClients/authAPIClient.ts +++ b/frontend/src/APIClients/authAPIClient.ts @@ -35,7 +35,11 @@ export interface AuthResult { validationErrors?: string[]; } -export const login = async (email: string, password: string): Promise => { +export const login = async ( + email: string, + password: string, + isAdminPortal: boolean = false, +): Promise => { try { // Validate inputs if (!validateEmail(email)) { @@ -63,12 +67,31 @@ export const login = async (email: string, password: string): Promise('/auth/login', loginRequest, { - withCredentials: true, - }); + const headers: any = { withCredentials: true }; + + // Add admin portal header if this is an admin login + if (isAdminPortal) { + headers.headers = { 'X-Admin-Portal': 'true' }; + } + + const { data } = await baseAPIClient.post('/auth/login', loginRequest, headers); localStorage.setItem(AUTHENTICATED_USER_KEY, JSON.stringify(data)); - return { success: true, user: { ...data.user, ...data } as AuthenticatedUser }; - } catch { + return { success: true, user: { ...data.user, ...data } }; + } catch (error) { + // Handle admin privilege errors specifically + if (error && typeof error === 'object' && 'response' in error) { + const response = (error as { response?: { status?: number; data?: { detail?: string } } }) + .response; + if (response?.status === 403 && isAdminPortal) { + return { + success: false, + error: + 'Access denied. You do not have admin privileges. Please contact an administrator.', + errorCode: 'auth/insufficient-privileges', + }; + } + } + // Backend login failure is not critical since Firebase auth succeeded return { success: true, @@ -217,22 +240,19 @@ export const register = async ({ } else { console.warn('[REGISTER] Failed to send email verification after registration'); } + + // Return success with user info - don't try to login since email isn't verified yet + return { + success: true, + user: { email: user.email, uid: user.uid } as unknown as AuthenticatedUser, + }; } catch (firebaseError) { console.error('[REGISTER] Firebase sign-in failed:', firebaseError); // Continue with registration even if Firebase sign-in fails // The user can still verify their email later - } - - // Try backend login but don't fail if it doesn't work - try { - const loginResult = await login(email, password); - return loginResult; - } catch (loginError) { - console.warn('[REGISTER] Backend login failed, but registration was successful:', loginError); - // Return success even if backend login fails, since Firebase user was created return { success: true, - user: { email, uid: auth.currentUser?.uid || 'unknown' } as unknown as AuthenticatedUser, + user: { email, uid: 'unknown' } as unknown as AuthenticatedUser, }; } } catch (error) { diff --git a/frontend/src/pages/admin-login.tsx b/frontend/src/pages/admin-login.tsx index 704e3952..e2b07efb 100644 --- a/frontend/src/pages/admin-login.tsx +++ b/frontend/src/pages/admin-login.tsx @@ -23,11 +23,12 @@ export default function AdminLogin() { try { const result = await login(email, password); - if (result) { - console.log('Admin login success:', result); + if (result.success) { router.push('/admin/dashboard'); + } else if (result.errorCode === 'auth/email-not-verified') { + router.push(`/admin-verify?email=${encodeURIComponent(email)}&role=admin`); } else { - setError('Invalid email or password'); + setError('Invalid email or password. Please check your credentials and try again.'); } } catch (err: unknown) { console.error('Admin login error:', err); @@ -203,7 +204,7 @@ export default function AdminLogin() { > Don't have an account?{' '} Already have an account?{' '} (''); + const [message, setMessage] = useState<{ type: 'success' | 'error' | null; text: string }>({ + type: null, + text: '', + }); + + const { sendVerificationEmail, sendSignInLink, isLoading, error, success } = + useEmailVerification(); + + useEffect(() => { + // Get email from query params or localStorage + const emailFromQuery = email as string; + const emailFromStorage = getEmailForSignIn(); + const finalEmail = emailFromQuery || emailFromStorage || 'admin@example.com'; + setDisplayEmail(finalEmail); + + // Store the email from query params if available + if (emailFromQuery) { + setEmailForSignIn(emailFromQuery); + } + }, [email]); + + useEffect(() => { + if (success) { + setMessage({ type: 'success', text: 'Email sent successfully! Please check your inbox.' }); + } + }, [success]); + + useEffect(() => { + if (error) { + setMessage({ type: 'error', text: error }); + } + }, [error]); + + const handleResendEmail = async () => { + setMessage({ type: null, text: '' }); + + // For admin users, send verification email instead of sign-in link + await sendVerificationEmail(); + }; + + const handleBackToLogin = () => { + clearEmailForSignIn(); + router.push('/admin-login'); + }; + + return ( + + {/* Left: Admin Verification Content */} + + + + Admin Portal - First Connection Peer Support Program + + + Verify Your Admin Account + + + We sent a confirmation link to {displayEmail} + + + {message.type === 'success' && ( + + {message.text} + + )} + + {message.type === 'error' && ( + + {message.text} + + )} + + + Didn't get a link?{' '} + + Click here to resend. + + + + + Remember your password?{' '} + + Back to login + + + + + {/* Right: Image - Using admin.png from admin-login.tsx */} + + Admin Portal Visual + + + ); +} diff --git a/frontend/src/pages/admin/dashboard.tsx b/frontend/src/pages/admin/dashboard.tsx index 3af94c2b..6db15f30 100644 --- a/frontend/src/pages/admin/dashboard.tsx +++ b/frontend/src/pages/admin/dashboard.tsx @@ -1,6 +1,6 @@ import React from 'react'; import Image from 'next/image'; -import { Box, Flex, Heading, Text, Link } from '@chakra-ui/react'; +import { Box, Flex, Heading, Text } from '@chakra-ui/react'; import { ProtectedPage } from '@/components/auth/ProtectedPage'; import { UserRole } from '@/types/authTypes'; @@ -41,7 +41,7 @@ export default function AdminDashboard() { mb={6} mt={8} > - Welcome! + You've logged in! - We sent a confirmation link to john.doe@gmail.com - - - Didn't get a link?{' '} - - Click here to resend. - + Welcome to the admin dashboard. You have successfully logged in to your administrator + account. diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index 784fe1af..cfe1aadb 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -37,6 +37,8 @@ export default function LoginPage() { if (result.success) { router.push('/welcome'); + } else if (result.errorCode === 'auth/email-not-verified') { + router.push(`/verify?email=${encodeURIComponent(email)}`); } else { setError(result.error || 'Login failed. Please try again.'); }