diff --git a/frontend/src/components/Dialog/LogoutDialog.tsx b/frontend/src/components/Dialog/LogoutDialog.tsx new file mode 100644 index 000000000..c53600796 --- /dev/null +++ b/frontend/src/components/Dialog/LogoutDialog.tsx @@ -0,0 +1,42 @@ +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogDescription, +} from '@/components/ui/alert-dialog'; + +interface LogoutDialogProps { + open: boolean; + onCancel: () => void; + onConfirm: () => void; +} + +export function LogoutDialog({ open, onCancel, onConfirm }: LogoutDialogProps) { + return ( + + + + Log out + + Are you sure you want to log out? You’ll need to sign in again to + access your account. + + + + + Cancel + + Logout + + + + + ); +} diff --git a/frontend/src/components/Navigation/Navbar/Navbar.tsx b/frontend/src/components/Navigation/Navbar/Navbar.tsx index c565b7f6d..fd21a436d 100644 --- a/frontend/src/components/Navigation/Navbar/Navbar.tsx +++ b/frontend/src/components/Navigation/Navbar/Navbar.tsx @@ -8,6 +8,8 @@ import { convertFileSrc } from '@tauri-apps/api/core'; import { FaceSearchDialog } from '@/components/Dialog/FaceSearchDialog'; export function Navbar() { + const dispatch = useDispatch(); + const userName = useSelector(selectName); const userAvatar = useSelector(selectAvatar); @@ -15,9 +17,11 @@ export function Navbar() { const isSearchActive = searchState.active; const queryImage = searchState.queryImage; - const dispatch = useDispatch(); + /* ---------------- Avatar Normalization (Tauri + Logout Safe) ---------------- */ + const displayName = userName || 'Guest'; + return ( -
+
{/* Logo */}
@@ -28,13 +32,13 @@ export function Navbar() { {/* Search Bar */}
-
+
{/* Query Image */} {queryImage && (
dispatch(clearSearch())} - className="absolute -top-1 -right-1 flex h-3 w-3 items-center justify-center rounded-full bg-red-600 text-[10px] leading-none text-white" - title="Close" - aria-label="Close" + className="absolute -top-1 -right-1 flex h-3 w-3 items-center justify-center rounded-full bg-red-600 text-[10px] text-white" + aria-label="Clear search" > ✕ @@ -54,20 +57,18 @@ export function Navbar() {
)} - {/* Input */} + {/* Search Input */} - {/* FaceSearch Dialog */} - + {/* Face Search */}
+
+ + {/* Name */} +
+ + setLocalName(e.target.value)} + /> +
+ + {/* Actions */} +
+ + + + + +
+
+
+
+ ); +}; + +export default EditProfilePage; diff --git a/frontend/src/pages/ProfilePage/ProfilePage.tsx b/frontend/src/pages/ProfilePage/ProfilePage.tsx new file mode 100644 index 000000000..765231b3a --- /dev/null +++ b/frontend/src/pages/ProfilePage/ProfilePage.tsx @@ -0,0 +1,119 @@ +import { useDispatch, useSelector } from 'react-redux'; +import { useState } from 'react'; +import { selectAvatar, selectName } from '@/features/onboardingSelectors'; +import { resetOnboarding } from '@/features/onboardingSlice'; +import { LogoutDialog } from '@/components/Dialog/LogoutDialog'; +import { useTheme } from '@/contexts/ThemeContext'; + +const ProfilePage = () => { + const dispatch = useDispatch(); + const { theme } = useTheme(); + + const userName = useSelector(selectName); + const userAvatar = useSelector(selectAvatar); + + const [showLogout, setShowLogout] = useState(false); + + const completion = (userAvatar ? 50 : 0) + (userName ? 50 : 0); + + const handleLogout = () => { + dispatch(resetOnboarding()); + window.location.href = '/'; + }; + + return ( +
+
+ {/* Header */} +
+
+

+ Your Account +

+

Profile

+
+ + + Logged in + +
+ + {/* Card */} +
+
+ {/* Avatar */} +
+
+ User avatar +
+
+ + {/* Info */} +
+

+ {userName || 'Guest User'} +

+

+ Manage your personal info, security, and preferences. +

+ + {/* Meta */} +
+ + Profile completion: {completion}% + + + + Theme: {theme} + +
+
+
+ + {/* Divider */} +
+ + {/* Actions */} +
+ + Edit Profile + ⌘E + + + + Account Settings + + + + +
+
+
+ + {/* Logout Dialog */} + setShowLogout(false)} + onConfirm={handleLogout} + /> +
+ ); +}; + +export default ProfilePage; diff --git a/frontend/src/routes/AppRoutes.tsx b/frontend/src/routes/AppRoutes.tsx index 22153edbb..596140846 100644 --- a/frontend/src/routes/AppRoutes.tsx +++ b/frontend/src/routes/AppRoutes.tsx @@ -9,6 +9,8 @@ import { MyFav } from '@/pages/Home/MyFav'; import { AITagging } from '@/pages/AITagging/AITagging'; import { PersonImages } from '@/pages/PersonImages/PersonImages'; import { ComingSoon } from '@/pages/ComingSoon/ComingSoon'; +import ProfilePage from '@/pages/ProfilePage/ProfilePage'; +import EditProfilePage from '@/pages/ProfilePage/EditProfilePage'; export const AppRoutes: React.FC = () => { return ( @@ -23,6 +25,8 @@ export const AppRoutes: React.FC = () => { } /> } /> } /> + } /> + } /> );