diff --git a/src/components/layout/Navbar.jsx b/src/components/layout/Navbar.jsx index a06fc4a..6d47ae8 100644 --- a/src/components/layout/Navbar.jsx +++ b/src/components/layout/Navbar.jsx @@ -1,13 +1,9 @@ import { useState, useRef, useEffect } from 'react'; import { Link, NavLink, useNavigate } from 'react-router-dom'; - -// ─── Replace with your real auth hook / context ─────────────────────────────── -// e.g. import { useAuth } from '../../contexts/AuthContext'; -const useAuth = () => ({ - user: null, // set to a user object when logged in, e.g. { name: 'Alice', avatarUrl: null } - logout: () => {}, -}); -// ───────────────────────────────────────────────────────────────────────────── +import { useAppDispatch, useAppSelector } from '../../store/hooks'; +import { selectCurrentUser } from '../../features/auth/authSelectors'; +import { logoutUser } from '../../features/auth/authThunks'; +import { toastSuccess } from '../../utils/toast'; const NAV_LINKS = [ { label: 'How it works', to: '/how-it-works' }, @@ -25,11 +21,13 @@ function initials(name = '') { } export default function Navbar() { - const { user, logout } = useAuth(); + const dispatch = useAppDispatch(); const navigate = useNavigate(); + const user = useAppSelector(selectCurrentUser); const [menuOpen, setMenuOpen] = useState(false); const [avatarOpen, setAvatarOpen] = useState(false); + const [isLoggingOut, setIsLoggingOut] = useState(false); const avatarRef = useRef(null); /* close avatar dropdown on outside click */ @@ -46,10 +44,24 @@ export default function Navbar() { /* close mobile menu on route change */ const handleNavClick = () => setMenuOpen(false); - const handleLogout = () => { + const handleLogout = async () => { setAvatarOpen(false); - logout(); - navigate('/'); + setIsLoggingOut(true); + try { + // Dispatch logoutUser thunk which calls POST /api/auth/logout + await dispatch(logoutUser()).unwrap(); + // Show success toast + toastSuccess('You have been logged out.'); + // Redirect to login + navigate('/login'); + } catch { + // Even if logout fails on the backend, clear local state and redirect + // This ensures user can't access protected routes if disconnected + toastSuccess('You have been logged out.'); + navigate('/login'); + } finally { + setIsLoggingOut(false); + } }; return ( @@ -356,8 +368,14 @@ export default function Navbar() { setAvatarOpen(false)}>Profile setAvatarOpen(false)}>Settings
-
)} @@ -402,8 +420,13 @@ export default function Navbar() { Profile Settings
- ) : ( diff --git a/src/features/auth/authSlice.js b/src/features/auth/authSlice.js index 340a623..e8b3c4a 100644 --- a/src/features/auth/authSlice.js +++ b/src/features/auth/authSlice.js @@ -65,6 +65,7 @@ const authSlice = createSlice({ }) .addCase(logoutUser.pending, (state) => { state.isLoading = true; + state.error = null; }) .addCase(logoutUser.fulfilled, (state) => { state.user = null; @@ -75,7 +76,11 @@ const authSlice = createSlice({ }) .addCase(logoutUser.rejected, (state, action) => { state.isLoading = false; - state.error = action.payload; + state.error = action.payload?.message || 'Logout failed'; + // Still clear credentials on error to ensure user is logged out locally + state.user = null; + state.token = null; + state.isAuthenticated = false; }) .addCase(verifyEmail.pending, (state) => { state.isLoading = true;