diff --git a/ipi-survey-platform/src/components/overview/DetailedOverview.jsx b/ipi-survey-platform/src/components/overview/DetailedOverview.jsx
index 811a48c..f0fc60c 100644
--- a/ipi-survey-platform/src/components/overview/DetailedOverview.jsx
+++ b/ipi-survey-platform/src/components/overview/DetailedOverview.jsx
@@ -260,7 +260,14 @@ export const DetailedOverview = ({ submission, onBack }) => {
return [
productData.hs_code || '—',
- productData.product_name || '—',
+
+
+ {productData.product_name || '—'}
+
+
,
unit.uom || 'N/A',
product.current_quantity || '0',
`AED ${product.current_cost || '0'}`,
diff --git a/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx b/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx
index f9318bb..a50cec7 100644
--- a/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx
+++ b/ipi-survey-platform/src/pages/Admin/configuration/AdminUsers/ResetPasswordModal.jsx
@@ -18,8 +18,21 @@ const ResetPasswordModal = ({
const [showOldPassword, setShowOldPassword] = useState(false);
const [showNewPassword, setShowNewPassword] = useState(false);
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
+ const [passwordTouched, setPasswordTouched] = useState(false);
+ const [confirmPasswordTouched, setConfirmPasswordTouched] = useState(false);
+
+ 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 passwordError = validatePassword(newPassword);
- // ✅ Validation: minimum 8 characters (no 12 limit)
const validateForm = () => {
const newErrors = {};
@@ -27,10 +40,8 @@ const ResetPasswordModal = ({
newErrors.oldPassword = 'Old password is required';
}
- if (!newPassword.trim()) {
- newErrors.newPassword = 'New password is required';
- } else if (newPassword.length < 8) {
- newErrors.newPassword = 'Password must be at least 8 characters long';
+ if (passwordTouched && passwordError) {
+ newErrors.newPassword = passwordError;
}
if (!confirmPassword.trim()) {
@@ -56,8 +67,17 @@ const ResetPasswordModal = ({
const handleInputChange = (field, value) => {
if (field === 'oldPassword') setOldPassword(value);
- if (field === 'newPassword') setNewPassword(value);
- if (field === 'confirmPassword') setConfirmPassword(value);
+ if (field === 'newPassword') {
+ setNewPassword(value);
+ // If confirm password has value, re-validate it when new password changes
+ if (confirmPassword) {
+ setConfirmPasswordTouched(true);
+ }
+ }
+ if (field === 'confirmPassword') {
+ setConfirmPassword(value);
+ setConfirmPasswordTouched(true);
+ }
// Clear error when user starts typing
if (errors[field]) {
@@ -137,12 +157,17 @@ const ResetPasswordModal = ({
type={showNewPassword ? "text" : "password"}
placeholder="Enter new password"
className={`w-full border rounded-lg px-4 py-3 text-sm focus:outline-none focus:ring-2 transition-all pr-10 ${
- errors.newPassword
+ (passwordTouched && passwordError) || errors.newPassword
? 'border-red-300 focus:ring-red-500 bg-red-50'
: 'border-gray-300 focus:border-[#B68A35] focus:ring-2 focus:ring-[#B68A35] focus:ring-opacity-20'
}`}
value={newPassword}
- onChange={(e) => handleInputChange('newPassword', e.target.value)}
+ onChange={(e) => {
+ setNewPassword(e.target.value);
+ if (errors.newPassword) setErrors(prev => ({ ...prev, newPassword: '' }));
+ }}
+ onFocus={() => setPasswordTouched(true)}
+ onBlur={() => setPasswordTouched(true)}
onKeyPress={handleKeyPress}
disabled={loading}
/>
@@ -156,7 +181,10 @@ const ResetPasswordModal = ({
- {errors.newPassword && (
+ {passwordTouched && passwordError && (
+ {passwordError}
+ )}
+ {!passwordTouched && errors.newPassword && (
{errors.newPassword}
)}
@@ -171,12 +199,16 @@ const ResetPasswordModal = ({
type={showConfirmPassword ? "text" : "password"}
placeholder="Confirm new password"
className={`w-full border rounded-lg px-4 py-3 text-sm focus:outline-none focus:ring-2 transition-all pr-10 ${
- errors.confirmPassword
+ (confirmPasswordTouched && confirmPassword && newPassword !== confirmPassword) || errors.confirmPassword
? 'border-red-300 focus:ring-red-500 bg-red-50'
+ : confirmPassword && newPassword === confirmPassword
+ ? 'border-green-300 focus:ring-green-500 bg-green-50'
: 'border-gray-300 focus:border-[#B68A35] focus:ring-2 focus:ring-[#B68A35] focus:ring-opacity-20'
}`}
value={confirmPassword}
onChange={(e) => handleInputChange('confirmPassword', e.target.value)}
+ onFocus={() => setConfirmPasswordTouched(true)}
+ onBlur={() => setConfirmPasswordTouched(true)}
onKeyPress={handleKeyPress}
disabled={loading}
/>
@@ -190,7 +222,13 @@ const ResetPasswordModal = ({
- {errors.confirmPassword && (
+ {confirmPasswordTouched && confirmPassword && newPassword !== confirmPassword && (
+ Passwords do not match
+ )}
+ {confirmPasswordTouched && confirmPassword && newPassword === confirmPassword && (
+ Passwords match
+ )}
+ {!confirmPassword && errors.confirmPassword && (
{errors.confirmPassword}
)}