This commit is contained in:
Malini 2025-12-05 13:09:46 +05:30
parent 30057d56c0
commit 396567cada
3 changed files with 255 additions and 255 deletions

View File

@ -1,5 +1,6 @@
import React, { useRef, useEffect } from 'react';
import { NavLink, useNavigate } from 'react-router-dom';
import { logout as logoutApi } from '@/services/auth/authService';
const logoSrc = '/assets/images/FCSCLogo.svg';
const dashboardIconActiveSrc = '/assets/images/cuida_dashboard-outline.svg';
@ -18,15 +19,25 @@ const NavItem = ({ label, to, iconActive, iconInactive, end = false }) => (
end={end}
className={({ isActive }) =>
`inline-flex items-center gap-2 pb-1 border-b-2 text-[14px] leading-5 ` +
(isActive ? 'text-[#92722A] font-medium border-[#92722A]' : 'text-[#232528] border-transparent hover:text-gray-900')
(isActive
? 'text-[#92722A] font-medium border-[#92722A]'
: 'text-[#232528] border-transparent hover:text-gray-900')
}
>
{({ isActive }) => (
<>
{iconActive && iconInactive ? (
<img src={isActive ? iconActive : iconInactive} alt={label} className="h-[18px] w-[18px]" />
<img
src={isActive ? iconActive : iconInactive}
alt={label}
className="h-[18px] w-[18px]"
/>
) : (
<span className={`inline-block h-[18px] w-[18px] rounded ${isActive ? 'bg-[#92722A]' : 'bg-[#C9CDD1]'}`} />
<span
className={`inline-block h-[18px] w-[18px] rounded ${
isActive ? 'bg-[#92722A]' : 'bg-[#C9CDD1]'
}`}
/>
)}
<span>{label}</span>
</>
@ -45,26 +56,31 @@ const AdminHeader = () => {
const profileButtonRef = useRef(null);
const mobileMenuButtonRef = useRef(null);
// Handle click outside for profile dropdown and mobile menu
useEffect(() => {
const handleClickOutside = (event) => {
// Close profile dropdown if clicked outside
if (profileOpen && profileRef.current && !profileRef.current.contains(event.target) &&
profileButtonRef.current && !profileButtonRef.current.contains(event.target)) {
if (
profileOpen &&
profileRef.current &&
!profileRef.current.contains(event.target) &&
profileButtonRef.current &&
!profileButtonRef.current.contains(event.target)
) {
setProfileOpen(false);
}
// Close mobile menu if clicked outside
if (open && mobileMenuRef.current && !mobileMenuRef.current.contains(event.target) &&
mobileMenuButtonRef.current && !mobileMenuButtonRef.current.contains(event.target)) {
if (
open &&
mobileMenuRef.current &&
!mobileMenuRef.current.contains(event.target) &&
mobileMenuButtonRef.current &&
!mobileMenuButtonRef.current.contains(event.target)
) {
setOpen(false);
}
};
// Add event listener when the component mounts
document.addEventListener('mousedown', handleClickOutside);
// Clean up the event listener when the component unmounts
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
@ -82,22 +98,26 @@ const AdminHeader = () => {
setUserEmail(parsed.email);
}
}
} catch {
// ignore corrupt storage
}
} catch {}
}, []);
const handleLogout = () => {
// 🚀 UPDATED: LOGOUT VIA API
const handleLogout = async () => {
try {
sessionStorage.removeItem('auth_token');
sessionStorage.removeItem('user_profile');
sessionStorage.removeItem('user_role');
sessionStorage.removeItem('establishment_id');
} catch {
// ignore storage errors
await logoutApi(); // <-- API CALL
sessionStorage.clear();
localStorage.removeItem('auth_token');
localStorage.removeItem('user_profile');
localStorage.removeItem('user_role');
localStorage.removeItem('establishment_id');
setProfileOpen(false);
navigate('/index');
} catch (error) {
console.error('Logout failed:', error);
navigate('/index');
}
setProfileOpen(false);
navigate('/index');
};
return (
@ -105,52 +125,51 @@ const AdminHeader = () => {
<div className="max-w-[1280px] mx-auto px-4">
<div className="flex items-center h-20 gap-6 ">
<img src={logoSrc} alt="FCSC" className="w-[140px] h-[44px] " />
<nav className="flex-1 flex justify-end items-center gap-6 xl:gap-8 text-[14px] leading-5 ml-auto ">
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={dashboardIconActiveSrc} iconInactive={dashboardIconInactiveSrc} />
<NavItem to="/admin/validations" label="Submissions" iconActive={checkCircleActiveSrc} iconInactive={manageSubmissionInactiveSrc} />
<NavItem to="/admin/configuration" label="Configuration" iconActive={configActiveSrc} iconInactive={configInactiveSrc} />
{/* <NavItem to="admin/configuration/admin-users"label="Users" iconActive={userActiveSrc} iconInactive={userInactiveSrc} /> */}
<NavItem
to="/admin/dashboard"
end
label="Dashboard"
iconActive={dashboardIconActiveSrc}
iconInactive={dashboardIconInactiveSrc}
/>
<NavItem
to="/admin/validations"
label="Submissions"
iconActive={checkCircleActiveSrc}
iconInactive={manageSubmissionInactiveSrc}
/>
<NavItem
to="/admin/configuration"
label="Configuration"
iconActive={configActiveSrc}
iconInactive={configInactiveSrc}
/>
</nav>
<div className="hidden lg:flex items-center gap-3 ml-auto">
{/* <button
type="button"
aria-label="Notifications"
className="inline-flex h-9 w-9 items-center justify-center rounded-full border border-transparent hover:border-[#E5E7EB]"
>
<img src={bellIconSrc} alt="Notifications" className="h-[18px] w-[18px]" />
</button> */}
<div className="relative" ref={profileRef}>
<button
ref={profileButtonRef}
type="button"
onClick={() => setProfileOpen((value) => !value)}
className="h-9 w-9 rounded-full bg-[#F2F2F2] grid place-items-center text-[13px] font-medium text-[#232528]"
aria-haspopup="menu"
aria-expanded={profileOpen}
>
{userName?.slice(0, 1)?.toUpperCase() || 'U'}
</button>
{profileOpen && (
<div className="absolute right-0 mt-3 w-64 rounded-[12px] border border-[#E5E7EB] bg-white shadow-[0_20px_30px_rgba(15,23,42,0.12)] z-50">
<div className="px-4 py-3 border-b border-[#F1F5F9] text-left space-y-1">
<p
className="text-sm font-semibold text-[#232528] truncate"
title={userName}
>
{userName?.replace(/([a-z])([A-Z])/g, '$1 $2')}
</p>
<p className="text-xs text-[#6B7280] truncate" title={userEmail}>{userEmail}</p>
<p className="text-sm font-semibold text-[#232528] truncate">
{userName?.replace(/([a-z])([A-Z])/g, '$1 $2')}
</p>
<p className="text-xs text-[#6B7280] truncate">
{userEmail}
</p>
</div>
{/* <button
type="button"
className="w-full px-4 py-2.5 text-center text-sm text-[#232528] hover:bg-[#F2ECCF]"
onClick={() => {
setProfileOpen(false);
navigate('/admin/profile');
}}
>
Profile
</button> */}
<button
type="button"
className="w-full px-4 py-2.5 text-left text-sm text-[#232528] hover:bg-[#F2ECCF]"
@ -161,6 +180,7 @@ const AdminHeader = () => {
>
Change Password
</button>
<button
type="button"
className="w-full px-4 py-2.5 text-left text-sm text-[#B52520] hover:bg-[#FEE2E2]"
@ -172,27 +192,60 @@ const AdminHeader = () => {
)}
</div>
</div>
<div className="ml-auto lg:hidden" ref={mobileMenuRef}>
<button
ref={mobileMenuButtonRef}
type="button"
aria-label="Open Menu"
className="inline-flex items-center justify-center h-10 w-10 rounded-full border border-[#E5E7EB]"
onClick={() => setOpen((v) => !v)}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 6h16M4 12h16M4 18h16"
/>
</svg>
</button>
</div>
</div>
{open && (
<div className="lg:hidden pb-6 border-t border-[#E5E7EB]">
<nav className="flex flex-col gap-3 pt-4 text-[14px] leading-5">
<NavItem to="/admin/dashboard" end label="Dashboard" iconActive={dashboardIconActiveSrc} iconInactive={dashboardIconInactiveSrc} />
<NavItem to="/admin/validations" label="Manage Submissions" iconActive={checkCircleActiveSrc} iconInactive={manageSubmissionInactiveSrc} />
<NavItem to="/admin/configuration" label="Configuration" iconActive={configActiveSrc} iconInactive={configInactiveSrc} />
<NavItem to="/admin/users" label="Users" iconActive={userActiveSrc} iconInactive={userInactiveSrc} />
<NavItem
to="/admin/dashboard"
end
label="Dashboard"
iconActive={dashboardIconActiveSrc}
iconInactive={dashboardIconInactiveSrc}
/>
<NavItem
to="/admin/validations"
label="Manage Submissions"
iconActive={checkCircleActiveSrc}
iconInactive={manageSubmissionInactiveSrc}
/>
<NavItem
to="/admin/configuration"
label="Configuration"
iconActive={configActiveSrc}
iconInactive={configInactiveSrc}
/>
<NavItem
to="/admin/users"
label="Users"
iconActive={userActiveSrc}
iconInactive={userInactiveSrc}
/>
</nav>
</div>
)}

View File

@ -1,6 +1,7 @@
import React from 'react';
import { NavLink, useNavigate } from 'react-router-dom';
import authService from "@/services/auth/authService";
const logoSrc = '/assets/images/FCSCLogo.svg';
const surveyIconActiveSrc = '/assets/images/Vector.svg';
const surveyIconInactiveSrc = '/assets/images/Vectorblack.svg';
@ -10,7 +11,7 @@ const historyIconActiveSrc = '/assets/images/mdi_history.svg';
const historyIconInactiveSrc = '/assets/images/history.svg';
const overviewIconActiveSrc = '/assets/images/mdi_file-find-outline.svg';
const overviewIconInactiveSrc = '/assets/images/mdi_file-find-outline-active.svg';
const HeaderBar = () => {
const [open, setOpen] = React.useState(false);
const [userName, setUserName] = React.useState('User');
@ -19,199 +20,174 @@ const HeaderBar = () => {
const profileRef = React.useRef(null);
const navigate = useNavigate();
const establishmentId = localStorage.getItem("establishment_id") || "";
// Close dropdown when clicking outside
// Close dropdown on outside click
React.useEffect(() => {
const handleClickOutside = (event) => {
if (profileRef.current && !profileRef.current.contains(event.target)) {
setUserOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
React.useEffect(() => {
let parsed;
try {
const stored = localStorage.getItem('user_profile');
if (stored) {
parsed = JSON.parse(stored);
}
} catch (error) {
parsed = undefined;
}
const name = parsed?.name || parsed?.username || parsed?.email || '';
const email = parsed?.email || '';
if (name) {
setUserName(name);
}
if (email) {
setUserEmail(email);
}
}, []);
const onLogout = () => {
try {
sessionStorage.removeItem('auth_token');
sessionStorage.removeItem('user_profile');
sessionStorage.removeItem('user_role');
sessionStorage.removeItem('establishment_id');
const parsed = stored ? JSON.parse(stored) : {};
setUserName(parsed?.name || parsed?.username || parsed?.email || 'User');
setUserEmail(parsed?.email || '');
} catch {}
}, []);
// ================================
// BACKEND LOGOUT API CONNECTED
// ================================
const onLogout = async () => {
try {
await authService.logout(); // <-- LOGOUT API CALL
} catch (error) {
console.error("Logout API failed:", error);
}
// Clear storage after API
sessionStorage.removeItem('auth_token');
sessionStorage.removeItem('user_profile');
sessionStorage.removeItem('user_role');
sessionStorage.removeItem('establishment_id');
localStorage.removeItem('auth_token');
localStorage.removeItem('user_profile');
localStorage.removeItem('user_role');
localStorage.removeItem('establishment_id');
setUserOpen(false);
navigate('/index');
};
const onChangePassword = () => {
setUserOpen(false);
navigate('/reset-password');
};
const initials = React.useMemo(() => {
const source = userName || userEmail;
if (!source) return 'U';
const parts = source.trim().split(' ');
const letters = parts.slice(0, 2).map((part) => part.charAt(0)).join('');
return letters ? letters.toUpperCase() : 'U';
const letters = parts.slice(0, 2).map((p) => p[0]).join('');
return letters.toUpperCase() || 'U';
}, [userEmail, userName]);
return (
<header className="bg-white border-b border-b-[#E2E8F0]">
<div className="max-w-[1280px] mx-auto px-4">
<div className="flex items-center justify-between h-16">
<img src={logoSrc} alt="FCSC" className="w-[131px] h-[40px] opacity-100 rotate-0" />
<nav className="hidden md:flex items-center gap-8 text-[14px] leading-5">
<img src={logoSrc} alt="FCSC" className="w-[131px] h-[40px]" />
{/* DESKTOP NAV */}
<nav className="hidden md:flex items-center gap-8 text-[14px]">
<NavLink
to="/dashboard"
className={({ isActive }) => `inline-flex items-center gap-2 pb-1 border-b-2 ${isActive ? 'text-[#92722A] font-medium border-[#92722A]' : 'text-[#232528] hover:text-gray-900 border-transparent'}`}
aria-current="page"
className={({ isActive }) =>
`inline-flex items-center gap-2 pb-1 border-b-2 ${
isActive
? 'text-[#92722A] font-medium border-[#92722A]'
: 'text-[#232528] hover:text-gray-900 border-transparent'
}`
}
>
{({ isActive }) => (
<>
<img src={isActive ? dashboardIconActiveSrc : dashboardIconInactiveSrc} alt="Dashboard" className="h-[18px] w-[18px]" />
<img src={isActive ? dashboardIconActiveSrc : dashboardIconInactiveSrc} className="h-[18px] w-[18px]" />
<span>Dashboard</span>
</>
)}
</NavLink>
<NavLink
to="/survey"
className={({ isActive, isPending }) => `inline-flex items-center gap-2 pb-1 border-b-2 ${
isActive
? 'text-[#92722A] font-medium border-[#92722A]'
: (window.location.pathname === '/dashboard' ||
window.location.pathname === '/overview' ||
window.location.pathname.startsWith('/edit-profile'))
? 'text-gray-400 cursor-not-allowed'
className={({ isActive }) =>
`inline-flex items-center gap-2 pb-1 border-b-2 ${
isActive
? 'text-[#92722A] font-medium border-[#92722A]'
: 'text-[#232528] hover:text-gray-900 border-transparent'
}`}
onClick={(e) => {
if (window.location.pathname === '/dashboard' ||
window.location.pathname === '/overview' ||
window.location.pathname.startsWith('/edit-profile')) {
e.preventDefault();
}
}}
}`
}
>
{({ isActive }) => (
<>
<img
src={isActive ? surveyIconActiveSrc : surveyIconInactiveSrc}
alt="Survey"
className={`h-[18px] w-[18px] ${(window.location.pathname === '/dashboard' ||
window.location.pathname === '/overview' ||
window.location.pathname.startsWith('/edit-profile')) ? 'opacity-50' : ''}`}
/>
<img src={isActive ? surveyIconActiveSrc : surveyIconInactiveSrc} className="h-[18px] w-[18px]" />
<span>Survey</span>
</>
)}
</NavLink>
<NavLink
to="/overview"
className={({ isActive }) => `inline-flex items-center gap-2 pb-1 border-b-2 ${isActive ? 'text-[#92722A] font-medium border-[#92722A]' : 'text-[#232528] hover:text-gray-900 border-transparent'}`}
className={({ isActive }) =>
`inline-flex items-center gap-2 pb-1 border-b-2 ${
isActive
? 'text-[#92722A] font-medium border-[#92722A]'
: 'text-[#232528] hover:text-gray-900 border-transparent'
}`
}
>
{({ isActive }) => (
<>
<img src={isActive ? overviewIconActiveSrc : overviewIconInactiveSrc} alt="Overview" className="h-[18px] w-[18px]" />
<img src={isActive ? overviewIconActiveSrc : overviewIconInactiveSrc} className="h-[18px] w-[18px]" />
<span>Overview</span>
</>
)}
</NavLink>
<NavLink
to={`/edit-profile/${establishmentId}`}
className={({ isActive }) =>
`inline-flex items-center gap-2 pb-1 border-b-2 ${
isActive
? "text-[#92722A] font-medium border-[#92722A]"
: "text-[#232528] hover:text-gray-900 border-transparent"
}`
}
>
{({ isActive }) => (
<>
<svg
className={`h-[16px] w-[18px] ${
isActive ? "text-[#92722A]" : "text-[#232528]"
}`}
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
/>
</svg>
<span>Profile</span>
</>
)}
</NavLink>
{/* <NavLink
to="/history"
className={({ isActive }) => `inline-flex items-center gap-2 pb-1 border-b-2 ${isActive ? 'text-[#92722A] font-medium border-[#92722A]' : 'text-[#232528] hover:text-gray-900 border-transparent'}`}
<NavLink
to={`/edit-profile/${establishmentId}`}
className={({ isActive }) =>
`inline-flex items-center gap-2 pb-1 border-b-2 ${
isActive
? "text-[#92722A] font-medium border-[#92722A]"
: "text-[#232528] hover:text-gray-900 border-transparent"
}`
}
>
{({ isActive }) => (
<>
<img src={isActive ? historyIconActiveSrc : historyIconInactiveSrc} alt="History" className="h-[18px] w-[18px]" />
<span>History</span>
</>
)}
</NavLink> */}
<svg className="h-[16px] w-[18px]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<span>Profile</span>
</NavLink>
{/* PROFILE DROPDOWN */}
<div className="relative" ref={profileRef}>
<button
type="button"
onClick={(e) => {
e.stopPropagation();
setUserOpen((v) => !v);
}}
className="h-8 w-8 rounded-full bg-gray-200 grid place-items-center text-[12px] text-gray-700 cursor-pointer"
aria-label="Profile"
aria-expanded={userOpen}
className="h-8 w-8 rounded-full bg-gray-200 grid place-items-center text-[12px]"
>
{initials}
</button>
{userOpen && (
<div className="absolute right-0 mt-3 w-64 rounded-[12px] border border-[#E2E8F0] bg-white shadow-[0_20px_30px_rgba(15,23,42,0.12)] z-50">
<div className="px-4 py-3 border-b border-[#F1F5F9] text-left space-y-1">
<p className="text-sm font-semibold text-[#232528] truncate" title={userName}>
{userName?.replace(/([a-z])([A-Z])/g, '$1 $2')}
</p>
{userEmail && <p className="text-xs text-[#6B7280] truncate" title={userEmail}>{userEmail}</p>}
<div className="absolute right-0 mt-3 w-64 rounded-[12px] bg-white shadow z-50">
<div className="px-4 py-3 ">
<p className="text-sm font-semibold">{userName}</p>
{userEmail && <p className="text-xs text-gray-600">{userEmail}</p>}
</div>
<button
type="button"
onClick={onChangePassword}
className="w-full px-4 py-2.5 text-left text-sm text-[#232528] hover:bg-[#F2ECCF]"
className="w-full px-4 py-2.5 text-left text-sm hover:bg-gray-100"
>
Change Password
</button>
<button
type="button"
onClick={onLogout}
className="w-full px-4 py-2.5 text-left text-sm text-[#B91C1C] hover:bg-[#FEE2E2] transition-colors"
className="w-full px-4 py-2.5 text-left text-sm text-red-600 hover:bg-red-100"
>
Logout
</button>
@ -219,82 +195,32 @@ const HeaderBar = () => {
)}
</div>
</nav>
{/* MOBILE MENU BUTTON */}
<button
type="button"
aria-label="Open Menu"
className="md:hidden inline-flex items-center justify-center h-9 w-9 rounded hover:bg-gray-100"
onClick={() => setOpen((v) => !v)}
className="md:hidden h-9 w-9 rounded hover:bg-gray-100"
onClick={() => setOpen(v => !v)}
>
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
{/* MOBILE NAV */}
{open && (
<div className="md:hidden pb-3">
<nav className="flex flex-col gap-2 text-[14px] leading-5">
<NavLink to="/dashboard" onClick={() => setOpen(false)} className={({ isActive }) => `inline-flex items-center gap-2 px-2 py-2 rounded border-b-2 ${isActive ? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]' : 'text-[#232528] hover:bg-gray-100 border-transparent'}`}>
<img src={dashboardIconInactiveSrc} alt="Dashboard" className="h-[18px] w-[18px]" />
<span>Dashboard</span>
</NavLink>
<NavLink
to="/survey"
onClick={(e) => {
if (window.location.pathname === '/dashboard') {
e.preventDefault();
} else {
setOpen(false);
}
}}
className={({ isActive }) => `inline-flex items-center gap-2 px-2 py-2 rounded border-b-2 ${
isActive
? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]'
: window.location.pathname === '/dashboard'
? 'text-gray-400 cursor-not-allowed bg-gray-100'
: 'text-[#232528] hover:bg-gray-100 border-transparent'
}`}
>
<img
src={surveyIconInactiveSrc}
alt="Survey"
className={`h-[18px] w-[18px] ${window.location.pathname === '/dashboard' ? 'opacity-50' : ''}`}
/>
<span>Survey</span>
</NavLink>
<NavLink to="/overview" onClick={() => setOpen(false)} className={({ isActive }) => `inline-flex items-center gap-2 px-2 py-2 rounded border-b-2 ${isActive ? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]' : 'text-[#232528] hover:bg-gray-100 border-transparent'}`}>
<img src={overviewIconInactiveSrc} alt="Overview" className="h-[18px] w-[18px]" />
<span>Overview</span>
</NavLink>
<NavLink to="/history" onClick={() => setOpen(false)} className={({ isActive }) => `inline-flex items-center gap-2 px-2 py-2 rounded border-b-2 ${isActive ? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]' : 'text-[#232528] hover:bg-gray-100 border-transparent'}`}>
<img src={historyIconInactiveSrc} alt="History" className="h-[18px] w-[18px]" />
<span>History</span>
</NavLink>
<button
type="button"
onClick={() => {
setOpen(false);
navigate('/reset-password');
}}
className="inline-flex items-center gap-2 px-2 py-2 rounded text-[#232528] hover:bg-gray-100 text-left"
>
<span>Change Password</span>
<nav className="flex flex-col gap-2 text-[14px]">
<NavLink to="/dashboard" className="px-2 py-2">Dashboard</NavLink>
<NavLink to="/survey" className="px-2 py-2">Survey</NavLink>
<NavLink to="/overview" className="px-2 py-2">Overview</NavLink>
<button className="px-2 py-2" onClick={() => navigate('/reset-password')}>
Change Password
</button>
<button
type="button"
onClick={() => {
setOpen(false);
navigate('/profile');
}}
className="inline-flex items-center gap-2 px-2 py-2 rounded text-[#232528] hover:bg-gray-100 text-left"
>
<span>Edit Profile</span>
</button>
<button
type="button"
onClick={onLogout}
className="inline-flex items-center gap-2 px-2 py-2 rounded text-[#B91C1C] hover:bg-[#FEE2E2] text-left"
>
<span>Logout</span>
<button className="px-2 py-2 text-red-600" onClick={onLogout}>
Logout
</button>
</nav>
</div>
@ -303,5 +229,5 @@ const HeaderBar = () => {
</header>
);
};
export default HeaderBar;
export default HeaderBar;

View File

@ -1,22 +1,43 @@
import apiClient from '@/services/api/apiClient';
export const login = async ({ email, password }) => {
const response = await apiClient.post('/auth/login', { email, password }, { skipAuth: true , withCredentials: true});
const response = await apiClient.post(
'/auth/login',
{ email, password },
{ skipAuth: true, withCredentials: true }
);
return response.data;
};
export const changePassword = async ({ currentPassword, newPassword }) => {
const response = await apiClient.post('/auth/change-password', { currentPassword, newPassword });
const response = await apiClient.post('/auth/change-password', {
currentPassword,
newPassword,
});
return response.data;
};
export const requestPasswordReset = async ({ email }) => {
const response = await apiClient.post('/auth/forgot-password', { email }, { skipAuth: true });
const response = await apiClient.post(
'/auth/forgot-password',
{ email },
{ skipAuth: true }
);
return response.data;
};
export const logout = async () => {
const response = await apiClient.get('/auth/logout', {
withCredentials: true, // Important for session cookie
skipAuth: false, // This API requires user to be logged in
});
return response.data;
};
export default {
login,
changePassword,
requestPasswordReset,
logout,
};