From 396567cada175728843b5f9cc9118a0ca9dd1dd2 Mon Sep 17 00:00:00 2001 From: Malini Date: Fri, 5 Dec 2025 13:09:46 +0530 Subject: [PATCH] fixed --- .../src/components/admin/AdminHeader.jsx | 179 +++++++---- .../src/components/layout/HeaderBar.jsx | 304 +++++++----------- .../src/services/auth/authService.js | 27 +- 3 files changed, 255 insertions(+), 255 deletions(-) diff --git a/ipi-survey-platform/src/components/admin/AdminHeader.jsx b/ipi-survey-platform/src/components/admin/AdminHeader.jsx index 97248ce..bac1a82 100644 --- a/ipi-survey-platform/src/components/admin/AdminHeader.jsx +++ b/ipi-survey-platform/src/components/admin/AdminHeader.jsx @@ -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 ? ( - {label} + {label} ) : ( - + )} {label} @@ -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 = () => {
FCSC + +
- {/* */}
+ {profileOpen && (
-

- {userName?.replace(/([a-z])([A-Z])/g, '$1 $2')} -

-

{userEmail}

+

+ {userName?.replace(/([a-z])([A-Z])/g, '$1 $2')} +

+

+ {userEmail} +

- {/* */} + +
+
+ {open && (
)} diff --git a/ipi-survey-platform/src/components/layout/HeaderBar.jsx b/ipi-survey-platform/src/components/layout/HeaderBar.jsx index b912c4c..1d9adfa 100644 --- a/ipi-survey-platform/src/components/layout/HeaderBar.jsx +++ b/ipi-survey-platform/src/components/layout/HeaderBar.jsx @@ -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 (
- FCSC -
+ + {/* MOBILE NAV */} {open && (
-
@@ -303,5 +229,5 @@ const HeaderBar = () => {
); }; - -export default HeaderBar; \ No newline at end of file + +export default HeaderBar; diff --git a/ipi-survey-platform/src/services/auth/authService.js b/ipi-survey-platform/src/services/auth/authService.js index 7b39491..0950c60 100644 --- a/ipi-survey-platform/src/services/auth/authService.js +++ b/ipi-survey-platform/src/services/auth/authService.js @@ -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, };