+ {/* Header */}
+
+
+ {modalMode === 'add' ? 'Add New HS Code' : modalMode === 'edit' ? 'Edit HS Code' : 'View HS Code'}
-
-
-
-
-
-
+ {/* Form */}
+
+ {/* HS Code */}
+
-
+ {/* Row 2: Unit + Status */}
+
+
+
+ {isLoading ? (
+
+ Loading units...
+
+ ) : error ? (
+
+ {error}
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+ {/* Footer */}
+ {modalMode !== 'view' && (
+
-
+ )}
)}
+ {/* Delete Confirmation Modal */}
{showDeleteConfirm && (
@@ -336,47 +755,41 @@ const IsicHsCodes = () => {
className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white border"
style={{
width: '480px',
- maxWidth: '92vw',
borderColor: '#CBD5E1',
boxShadow: '0 20px 45px rgba(0,0,0,0.12)',
}}
>
-
-
-
+
-
Delete HS Codes
-
+
+ Delete HS Codes
+
+
Are you sure you want to delete{' '}
- {deletingCode && (
-
- {`${deletingCode.code} - ${deletingCode.product}`}
-
- )}
+
+ {deletingCode && `${deletingCode.code} - ${deletingCode.product}`}
+
?
-
+
This action will permanently delete the data and cannot be undone.
-
+
)}
+
);
};
diff --git a/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx b/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx
index fd159a9..ff05c1e 100644
--- a/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx
+++ b/ipi-survey-platform/src/pages/Admin/configuration/QuarterlyWindows.jsx
@@ -6,7 +6,7 @@ import StatusBadge from '@/components/common/StatusBadge';
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
const pencilActiveSrc = '/assets/images/PencilSimple.svg';
-const pencilInactiveSrc = '/assets/images/PencilSimple-inactive.svg';
+const pencilInactiveSrc = '/assets/images/pencilsimple-inactive.svg';
const trashActiveSrc = '/assets/images/Trash - active.svg';
const trashInactiveSrc = '/assets/images/Trash - Inactive.svg';
const deleteIconSrc = '/assets/images/delete.svg';
diff --git a/ipi-survey-platform/src/pages/Login/Login.jsx b/ipi-survey-platform/src/pages/Login/Login.jsx
index d97f1d3..a5381eb 100644
--- a/ipi-survey-platform/src/pages/Login/Login.jsx
+++ b/ipi-survey-platform/src/pages/Login/Login.jsx
@@ -2,19 +2,23 @@ import React from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { login } from '@/services/auth/authService.js';
import { RefreshCw } from "lucide-react";
+
const logoSrc = '/assets/images/FCSCLogo.svg';
const Login = () => {
const navigate = useNavigate();
const location = useLocation();
+
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
const [showPassword, setShowPassword] = React.useState(false);
- const [rememberMe, setRememberMe] = React.useState(false);
+ const [rememberMe, setRememberMe] = React.useState(true);
const [loading, setLoading] = React.useState(false);
- const [error, setError] = React.useState('');
const [toast, setToast] = React.useState(null);
+ const [emailError, setEmailError] = React.useState('');
+ const [passwordError, setPasswordError] = React.useState('');
+
const [captcha, setCaptcha] = React.useState('');
const [userCaptcha, setUserCaptcha] = React.useState('');
const [captchaError, setCaptchaError] = React.useState('');
@@ -22,6 +26,7 @@ const Login = () => {
const toastTimeoutRef = React.useRef(null);
const navigateTimeoutRef = React.useRef(null);
+ // Generate CAPTCHA
const generateCaptcha = React.useCallback(() => {
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
let code = '';
@@ -31,9 +36,11 @@ const Login = () => {
setCaptcha(code);
}, []);
+
+ // Toast helpers
const closeToast = React.useCallback(() => {
if (toastTimeoutRef.current) {
- window.clearTimeout(toastTimeoutRef.current);
+ clearTimeout(toastTimeoutRef.current);
toastTimeoutRef.current = null;
}
setToast(null);
@@ -42,24 +49,25 @@ const Login = () => {
const showToast = React.useCallback((type, message) => {
if (!message) return;
if (toastTimeoutRef.current) {
- window.clearTimeout(toastTimeoutRef.current);
+ clearTimeout(toastTimeoutRef.current);
toastTimeoutRef.current = null;
}
setToast({ type, message });
- toastTimeoutRef.current = window.setTimeout(() => {
+ toastTimeoutRef.current = setTimeout(() => {
setToast(null);
toastTimeoutRef.current = null;
}, 4000);
}, []);
+ // Navigate delay
const scheduleNavigate = React.useCallback(
(path) => {
if (!path) return;
if (navigateTimeoutRef.current) {
- window.clearTimeout(navigateTimeoutRef.current);
+ clearTimeout(navigateTimeoutRef.current);
navigateTimeoutRef.current = null;
}
- navigateTimeoutRef.current = window.setTimeout(() => {
+ navigateTimeoutRef.current = setTimeout(() => {
navigate(path);
navigateTimeoutRef.current = null;
}, 500);
@@ -74,45 +82,74 @@ const Login = () => {
React.useEffect(() => {
if (location.state?.showSuccessToast && location.state?.successMessage) {
showToast('success', location.state.successMessage);
-
window.history.replaceState({}, document.title);
}
}, [location.state, showToast]);
React.useEffect(
() => () => {
- if (toastTimeoutRef.current) {
- window.clearTimeout(toastTimeoutRef.current);
- }
- if (navigateTimeoutRef.current) {
- window.clearTimeout(navigateTimeoutRef.current);
- }
+ if (toastTimeoutRef.current) clearTimeout(toastTimeoutRef.current);
+ if (navigateTimeoutRef.current) clearTimeout(navigateTimeoutRef.current);
},
[]
);
const handleCaptchaChange = (e) => {
setUserCaptcha(e.target.value.toUpperCase());
+ if (captchaError) setCaptchaError('');
+ };
+
+ const refreshCaptcha = () => {
+ generateCaptcha();
+ setUserCaptcha('');
setCaptchaError('');
};
+ // Email format check
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+
+ const validateForm = () => {
+ let valid = true;
+ setEmailError('');
+ setPasswordError('');
+ setCaptchaError('');
+
+ if (!email.trim()) {
+ setEmailError('Enter your email address.');
+ valid = false;
+ } else if (!emailRegex.test(email)) {
+ setEmailError('Enter a valid email address.');
+ valid = false;
+ }
+
+ if (!password.trim()) {
+ setPasswordError('Enter your password.');
+ valid = false;
+ }
+
+ if (!userCaptcha.trim()) {
+ setCaptchaError('Please enter the CAPTCHA.');
+ valid = false;
+ } else if (userCaptcha !== captcha) {
+ setCaptchaError('Invalid. Try again or refresh for a new code.');
+ valid = false;
+ }
+
+ return valid;
+ };
+
const submit = async (e) => {
e.preventDefault();
- setError('');
- setCaptchaError('');
- setLoading(true);
- if (userCaptcha !== captcha) {
- setCaptchaError('Incorrect CAPTCHA. Please try again.');
- generateCaptcha();
- setLoading(false);
- return;
- }
+ if (!validateForm()) return;
+
+ setLoading(true);
try {
const response = await login({ email, password });
+
if (response?.status !== 'success' || !response?.data) {
- throw new Error(response?.message || 'Invalid response');
+ throw new Error('Email or password is incorrect.');
}
const token = response.data;
@@ -131,6 +168,7 @@ const Login = () => {
if (role) sessionStorage.setItem('user_role', role);
const profile = {
+ id: payload?.id || payload?.user_id || '',
name: payload?.name || payload?.username || '',
email: payload?.email || '',
};
@@ -163,13 +201,11 @@ const Login = () => {
showToast('success', successMessage);
scheduleNavigate('/dashboard');
} else {
- setError('No establishment associated with this account.');
+ showToast('error', 'Email or password is incorrect.');
}
} catch (err) {
console.error('Login failed', err);
- const apiMessage = err.response?.data?.message || err.response?.data?.error;
- const fallbackMessage = err.message || 'Unable to sign in. Please try again.';
- setError(apiMessage || fallbackMessage);
+ showToast('error', 'Email or password is incorrect.');
} finally {
setLoading(false);
}
@@ -208,30 +244,41 @@ const Login = () => {
-
-

-
IPI Survey Platform
-
-
-