From dcc05fc76298be2021ece03f23864b4348463a41 Mon Sep 17 00:00:00 2001 From: Malini Date: Tue, 28 Oct 2025 10:29:12 +0530 Subject: [PATCH] Changes in dashboard --- ipi-survey-platform/src/App.jsx | 91 +++++++++++- .../src/components/admin/AdminHeader.jsx | 8 +- .../src/components/layout/HeaderBar.jsx | 8 +- .../pages/ChangePassword/ChangePassword.jsx | 7 +- ipi-survey-platform/src/pages/Login/Login.jsx | 137 +++++++++++++++--- .../src/services/api/apiClient.js | 2 +- .../src/services/utils/establishment.js | 2 +- 7 files changed, 218 insertions(+), 37 deletions(-) diff --git a/ipi-survey-platform/src/App.jsx b/ipi-survey-platform/src/App.jsx index 6cda3c5..befd636 100644 --- a/ipi-survey-platform/src/App.jsx +++ b/ipi-survey-platform/src/App.jsx @@ -12,19 +12,94 @@ import History from './pages/History/History' import ChangePassword from './pages/ChangePassword/ChangePassword' import ForgotPassword from './pages/ForgotPassword/ForgotPassword' +const RequireRole = ({ allowedRoles = [], children }) => { + let role + let token + try { + role = sessionStorage.getItem('user_role') + token = sessionStorage.getItem('auth_token') + } catch (error) { + role = null + token = null + } + + const normalizedRole = String(role || '').toLowerCase() + const isAllowed = Boolean(token) && allowedRoles.some((allowed) => String(allowed || '').toLowerCase() === normalizedRole) + + if (isAllowed) { + return children + } + + return +} + function App() { return ( } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + + + + )} + /> + + + + )} + /> + + + + )} + /> + + + + )} + /> + + + + )} + /> + + + + )} + /> + + + + )} + /> } /> - } /> + + + + )} + /> } /> } /> } /> diff --git a/ipi-survey-platform/src/components/admin/AdminHeader.jsx b/ipi-survey-platform/src/components/admin/AdminHeader.jsx index 8b2b0a6..33ffd05 100644 --- a/ipi-survey-platform/src/components/admin/AdminHeader.jsx +++ b/ipi-survey-platform/src/components/admin/AdminHeader.jsx @@ -42,7 +42,7 @@ const AdminHeader = () => { React.useEffect(() => { try { - const stored = localStorage.getItem('user_profile'); + const stored = sessionStorage.getItem('user_profile'); if (stored) { const parsed = JSON.parse(stored); if (parsed?.name || parsed?.username) { @@ -59,8 +59,10 @@ const AdminHeader = () => { const handleLogout = () => { try { - localStorage.removeItem('auth_token'); - localStorage.removeItem('user_profile'); + sessionStorage.removeItem('auth_token'); + sessionStorage.removeItem('user_profile'); + sessionStorage.removeItem('user_role'); + sessionStorage.removeItem('establishment_id'); } catch { // ignore storage errors } diff --git a/ipi-survey-platform/src/components/layout/HeaderBar.jsx b/ipi-survey-platform/src/components/layout/HeaderBar.jsx index a8b9a58..ed2f021 100644 --- a/ipi-survey-platform/src/components/layout/HeaderBar.jsx +++ b/ipi-survey-platform/src/components/layout/HeaderBar.jsx @@ -18,7 +18,7 @@ const HeaderBar = () => { React.useEffect(() => { let parsed; try { - const stored = localStorage.getItem('user_profile'); + const stored = sessionStorage.getItem('user_profile'); if (stored) { parsed = JSON.parse(stored); } @@ -37,8 +37,10 @@ const HeaderBar = () => { const onLogout = () => { try { - localStorage.removeItem('auth_token'); - localStorage.removeItem('user_profile'); + sessionStorage.removeItem('auth_token'); + sessionStorage.removeItem('user_profile'); + sessionStorage.removeItem('user_role'); + sessionStorage.removeItem('establishment_id'); } catch {} setUserOpen(false); navigate('/login'); diff --git a/ipi-survey-platform/src/pages/ChangePassword/ChangePassword.jsx b/ipi-survey-platform/src/pages/ChangePassword/ChangePassword.jsx index 6a0188d..0224608 100644 --- a/ipi-survey-platform/src/pages/ChangePassword/ChangePassword.jsx +++ b/ipi-survey-platform/src/pages/ChangePassword/ChangePassword.jsx @@ -39,9 +39,10 @@ const ChangePassword = () => { throw new Error(message); } try { - localStorage.removeItem('auth_token'); - localStorage.removeItem('user_profile'); - localStorage.removeItem('user_role'); + sessionStorage.removeItem('auth_token'); + sessionStorage.removeItem('user_profile'); + sessionStorage.removeItem('user_role'); + sessionStorage.removeItem('establishment_id'); } catch (storageError) { console.warn('Unable to clear stored session', storageError); } diff --git a/ipi-survey-platform/src/pages/Login/Login.jsx b/ipi-survey-platform/src/pages/Login/Login.jsx index a122beb..821590d 100644 --- a/ipi-survey-platform/src/pages/Login/Login.jsx +++ b/ipi-survey-platform/src/pages/Login/Login.jsx @@ -11,14 +11,17 @@ const Login = () => { const [rememberMe, setRememberMe] = React.useState(false); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(''); + const [toast, setToast] = React.useState(null); + const toastTimeoutRef = React.useRef(null); + const navigateTimeoutRef = React.useRef(null); React.useEffect(() => { try { - const remembered = localStorage.getItem('remember_me'); + const remembered = sessionStorage.getItem('remember_me'); if (remembered === 'true') { setRememberMe(true); - const storedEmail = localStorage.getItem('remembered_email'); - const storedPassword = localStorage.getItem('remembered_password'); + const storedEmail = sessionStorage.getItem('remembered_email'); + const storedPassword = sessionStorage.getItem('remembered_password'); if (storedEmail) { setEmail(storedEmail); } @@ -31,6 +34,48 @@ const Login = () => { } }, []); + const closeToast = React.useCallback(() => { + if (toastTimeoutRef.current) { + window.clearTimeout(toastTimeoutRef.current); + toastTimeoutRef.current = null; + } + setToast(null); + }, []); + + const showToast = React.useCallback((type, message) => { + if (!message) return; + if (toastTimeoutRef.current) { + window.clearTimeout(toastTimeoutRef.current); + toastTimeoutRef.current = null; + } + setToast({ type, message }); + toastTimeoutRef.current = window.setTimeout(() => { + setToast(null); + toastTimeoutRef.current = null; + }, 4000); + }, []); + + const scheduleNavigate = React.useCallback((path) => { + if (!path) return; + if (navigateTimeoutRef.current) { + window.clearTimeout(navigateTimeoutRef.current); + navigateTimeoutRef.current = null; + } + navigateTimeoutRef.current = window.setTimeout(() => { + navigate(path); + navigateTimeoutRef.current = null; + }, 500); + }, [navigate]); + + React.useEffect(() => () => { + if (toastTimeoutRef.current) { + window.clearTimeout(toastTimeoutRef.current); + } + if (navigateTimeoutRef.current) { + window.clearTimeout(navigateTimeoutRef.current); + } + }, []); + const submit = async (e) => { e.preventDefault(); setError(''); @@ -43,7 +88,7 @@ const Login = () => { const token = response.data; try { - localStorage.setItem('auth_token', token); + sessionStorage.setItem('auth_token', token); } catch (storageError) { console.error('Failed to persist auth token', storageError); } @@ -61,7 +106,7 @@ const Login = () => { const role = payload?.role ?? (payload?.is_admin ? 'Admin' : undefined); if (role) { try { - localStorage.setItem('user_role', role); + sessionStorage.setItem('user_role', role); } catch (storageError) { console.warn('Unable to persist user role', storageError); } @@ -72,37 +117,39 @@ const Login = () => { name: payload?.name || payload?.username || '', email: payload?.email || '', }; - localStorage.setItem('user_profile', JSON.stringify(profile)); + sessionStorage.setItem('user_profile', JSON.stringify(profile)); } catch (storageError) { console.warn('Unable to persist user profile', storageError); } const establishmentId = payload?.establishment_id ?? payload?.establishmentId; const isAdmin = String(role || '').toLowerCase() === 'admin' || payload?.is_admin === true; + const successMessage = response?.message || 'Login successful.'; if (isAdmin) { try { - localStorage.removeItem('establishment_id'); + sessionStorage.removeItem('establishment_id'); } catch (storageError) { console.warn('Unable to clear establishment ID', storageError); } - navigate('/admin/dashboard'); + showToast('success', successMessage); + scheduleNavigate('/admin/dashboard'); return; } if (rememberMe) { try { - localStorage.setItem('remember_me', 'true'); - localStorage.setItem('remembered_email', email); - localStorage.setItem('remembered_password', password); + sessionStorage.setItem('remember_me', 'true'); + sessionStorage.setItem('remembered_email', email); + sessionStorage.setItem('remembered_password', password); } catch (storageError) { console.warn('Unable to persist remember-me preference', storageError); } } else { try { - localStorage.removeItem('remember_me'); - localStorage.removeItem('remembered_email'); - localStorage.removeItem('remembered_password'); + sessionStorage.removeItem('remember_me'); + sessionStorage.removeItem('remembered_email'); + sessionStorage.removeItem('remembered_password'); } catch (storageError) { console.warn('Unable to clear remembered credentials', storageError); } @@ -110,17 +157,20 @@ const Login = () => { if (establishmentId) { try { - localStorage.setItem('establishment_id', String(establishmentId)); + sessionStorage.setItem('establishment_id', String(establishmentId)); } catch (storageError) { console.warn('Unable to persist establishment ID', storageError); } - navigate('/dashboard'); + showToast('success', successMessage); + scheduleNavigate('/dashboard'); } else { setError('No establishment associated with this account.'); } } catch (err) { console.error('Login failed', err); - setError(err.message || 'Unable to sign in. Please try again.'); + const apiMessage = err.response?.data?.message || err.response?.data?.error; + const fallbackMessage = err.message || 'Unable to sign in. Please try again.'; + setError(apiMessage || fallbackMessage); } finally { setLoading(false); } @@ -128,6 +178,57 @@ const Login = () => { return (
+ {loading && ( +
+
+
+ )} + {toast && ( +
+
+
+ {toast.type === 'success' ? ( + + + + ) : ( + + + + )} + {toast.message} +
+ +
+
+ )}
@@ -147,7 +248,7 @@ const Login = () => { type="email" value={email} onChange={(e) => setEmail(e.target.value)} - placeholder="you@example.com" + placeholder="Enter Email" className="block w-full h-10 rounded-md border-2 border-[#92722A] focus:border-[#92722A] focus:ring-0 px-4 text-sm bg-white" required /> diff --git a/ipi-survey-platform/src/services/api/apiClient.js b/ipi-survey-platform/src/services/api/apiClient.js index c6a83fc..891ba3c 100644 --- a/ipi-survey-platform/src/services/api/apiClient.js +++ b/ipi-survey-platform/src/services/api/apiClient.js @@ -22,7 +22,7 @@ apiClient.interceptors.request.use((config) => { if (!config.headers.Authorization) { let token; try { - token = localStorage.getItem('auth_token'); + token = sessionStorage.getItem('auth_token'); } catch (error) { token = undefined; } diff --git a/ipi-survey-platform/src/services/utils/establishment.js b/ipi-survey-platform/src/services/utils/establishment.js index 0456d84..1409189 100644 --- a/ipi-survey-platform/src/services/utils/establishment.js +++ b/ipi-survey-platform/src/services/utils/establishment.js @@ -10,7 +10,7 @@ export const resolveEstablishmentId = (inputId) => { } let storedId; try { - storedId = localStorage.getItem('establishment_id'); + storedId = sessionStorage.getItem('establishment_id'); } catch (error) { storedId = undefined; }