diff --git a/ipi-survey-platform/src/App.jsx b/ipi-survey-platform/src/App.jsx index edaec63..508fd59 100644 --- a/ipi-survey-platform/src/App.jsx +++ b/ipi-survey-platform/src/App.jsx @@ -279,11 +279,11 @@ function App() { } /> */} - -} /> +} /> */} {/* } /> */} + + + + } + /> } /> } /> } /> diff --git a/ipi-survey-platform/src/components/layout/HeaderBar.jsx b/ipi-survey-platform/src/components/layout/HeaderBar.jsx index 9585a93..0fb5a3a 100644 --- a/ipi-survey-platform/src/components/layout/HeaderBar.jsx +++ b/ipi-survey-platform/src/components/layout/HeaderBar.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { NavLink, useNavigate } from 'react-router-dom'; - + const logoSrc = '/assets/images/FCSCLogo.svg'; const surveyIconActiveSrc = '/assets/images/Vector.svg'; const surveyIconInactiveSrc = '/assets/images/Vectorblack.svg'; @@ -10,7 +10,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'); @@ -18,7 +18,8 @@ const HeaderBar = () => { const [userOpen, setUserOpen] = React.useState(false); const profileRef = React.useRef(null); const navigate = useNavigate(); - + const establishmentId = sessionStorage.getItem("establishment_id") || ""; + // Close dropdown when clicking outside React.useEffect(() => { const handleClickOutside = (event) => { @@ -26,13 +27,13 @@ const HeaderBar = () => { setUserOpen(false); } }; - + document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, []); - + React.useEffect(() => { let parsed; try { @@ -52,7 +53,7 @@ const HeaderBar = () => { setUserEmail(email); } }, []); - + const onLogout = () => { try { sessionStorage.removeItem('auth_token'); @@ -63,12 +64,12 @@ const HeaderBar = () => { setUserOpen(false); navigate('/index'); }; - + const onChangePassword = () => { setUserOpen(false); navigate('/reset-password'); }; - + const initials = React.useMemo(() => { const source = userName || userEmail; if (!source) return 'U'; @@ -97,10 +98,10 @@ const HeaderBar = () => { `inline-flex items-center gap-2 pb-1 border-b-2 ${ - isActive - ? 'text-[#92722A] font-medium border-[#92722A]' + isActive + ? 'text-[#92722A] font-medium border-[#92722A]' : (window.location.pathname === '/dashboard' || window.location.pathname === '/overview') - ? 'text-gray-400 cursor-not-allowed' + ? 'text-gray-400 cursor-not-allowed' : 'text-[#232528] hover:text-gray-900 border-transparent' }`} onClick={(e) => { @@ -111,10 +112,10 @@ const HeaderBar = () => { > {({ isActive }) => ( <> - Survey Survey @@ -131,6 +132,37 @@ const HeaderBar = () => { )} + + `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 }) => ( + <> + + + + Profile + + )} + {/* `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'}`} @@ -199,27 +231,27 @@ const HeaderBar = () => { Dashboard Dashboard - { 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]' + isActive + ? 'text-[#92722A] bg-[#F2ECCF] border-[#92722A]' : window.location.pathname === '/dashboard' - ? 'text-gray-400 cursor-not-allowed bg-gray-100' + ? 'text-gray-400 cursor-not-allowed bg-gray-100' : 'text-[#232528] hover:bg-gray-100 border-transparent' }`} > - Survey Survey @@ -265,5 +297,5 @@ const HeaderBar = () => { ); }; - -export default HeaderBar; + +export default HeaderBar; \ No newline at end of file diff --git a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx index f1c9fbc..4c7d173 100644 --- a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx +++ b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx @@ -236,19 +236,33 @@ const EstablishmentInfo = ({ }); }; +// const handleEditProfile = (e) => { +// e.preventDefault(); + +// const establishmentId = sessionStorage.getItem('establishment_id'); +// if (!establishmentId) { +// alert('No establishment ID found in session'); +// return; +// } + +// localStorage.setItem('returnTo', window.location.pathname); +// sessionStorage.setItem('edit_profile_from', 'EstablishmentUser'); +// // navigate(`/profile/edit/${establishmentId}`); +// }; const handleEditProfile = (e) => { - e.preventDefault(); - - const establishmentId = sessionStorage.getItem('establishment_id'); - if (!establishmentId) { - alert('No establishment ID found in session'); - return; - } - - localStorage.setItem('returnTo', window.location.pathname); - sessionStorage.setItem('edit_profile_from', 'EstablishmentUser'); - navigate(`/profile/edit/${establishmentId}`); + e.preventDefault(); + + const establishmentId = sessionStorage.getItem('establishment_id'); + if (!establishmentId) { + alert('No establishment ID found in session'); + return; + } + + localStorage.setItem('returnTo', window.location.pathname); + sessionStorage.setItem('edit_profile_from', 'EstablishmentUser'); + navigate(`/edit-profile/${establishmentId}`); }; + const handleEmployeeChange = (field) => (event) => { onChange({ ...info, @@ -375,7 +389,7 @@ const EstablishmentInfo = ({ here .

*/} -

+ {/*

Need to update details? Go to Profile →{' '} . Changes saved there will appear here. -

+

*/} +

+ Need to update details? Go to Profile →{' '} + + Edit Profile + +

Step 1: Review Establishment Information

diff --git a/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/AddAdminUsers.jsx b/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/AddAdminUsers.jsx index 8a09366..7291ce9 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/AddAdminUsers.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/AddAdminUsers.jsx @@ -15,6 +15,8 @@ const AddAdminUsers = ({ isOpen, onClose, onSave }) => { }); const [errors, setErrors] = useState({}); + const [passwordError, setPasswordError] = useState(''); + const [passwordTouched, setPasswordTouched] = useState(false); const [loading, setLoading] = useState(false); const [toastData, setToastData] = useState(null); // 👈 for custom toast @@ -41,16 +43,14 @@ const AddAdminUsers = ({ isOpen, onClose, onSave }) => { if (!formData.status) newErrors.status = 'Status is required'; - if (!formData.password) { - newErrors.password = 'Password is required'; - } else if (formData.password.length < 8) { - newErrors.password = 'Password must be at least 8 characters'; - } else if (formData.password.length > 12) { - newErrors.password = 'Password cannot exceed 12 characters'; + const passwordValidation = validatePassword(formData.password); + if (passwordValidation) { + newErrors.password = passwordValidation; } - if (formData.password !== formData.confirmPassword) + if (formData.password !== formData.confirmPassword) { newErrors.confirmPassword = 'Passwords do not match'; + } return newErrors; }; @@ -70,10 +70,38 @@ const AddAdminUsers = ({ isOpen, onClose, onSave }) => { } }, [isOpen]); + const validatePassword = (password) => { + if (!password) return 'Password is required'; + if (password.length < 8) return 'Password must be at least 8 characters'; + if (!/[A-Z]/.test(password)) return 'Must contain at least one uppercase letter'; + if (!/[a-z]/.test(password)) return 'Must contain at least one lowercase letter'; + if (!/\d/.test(password)) return 'Must contain at least one number'; + if (!/[!@#$%^&*]/.test(password)) return 'Must contain at least one special character (!@#$%^&*)'; + return ''; + }; + const handleChange = (e) => { const { name, value } = e.target; setFormData((prev) => ({ ...prev, [name]: value })); + + // Clear any existing error for this field if (errors[name]) setErrors((prev) => ({ ...prev, [name]: '' })); + + // Real-time password validation + if (name === 'password') { + setPasswordTouched(true); + const error = validatePassword(value); + setPasswordError(error); + } + + // Clear confirm password error when either password changes + if ((name === 'password' || name === 'confirmPassword') && formData.password && formData.confirmPassword) { + if (formData.password !== formData.confirmPassword) { + setErrors(prev => ({ ...prev, confirmPassword: 'Passwords do not match' })); + } else { + setErrors(prev => ({ ...prev, confirmPassword: '' })); + } + } }; const handleSubmit = async (e) => { @@ -156,29 +184,37 @@ const AddAdminUsers = ({ isOpen, onClose, onSave }) => { placeholder="Enter email" /> - +
+ setPasswordTouched(true)} + error={passwordTouched && passwordError ? passwordError : ''} + required + placeholder="Enter password" + showToggle + /> +
- +
+ + {formData.confirmPassword && !errors.confirmPassword && ( +

Passwords match

+ )} +