diff --git a/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx b/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx
index bddb4e3..a9466ff 100644
--- a/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx
+++ b/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx
@@ -2,6 +2,7 @@ import React from 'react';
import { Link, useNavigate, useParams } from 'react-router-dom';
import AdminHeader from '@/components/admin/AdminHeader';
import { getSubmissionById } from '@/services/admin/submission';
+import apiClient from '@/services/api/apiClient';
const caretUpSrc = '/assets/images/caret-up.svg';
const establishmentIconSrc = '/assets/images/Establishment.svg';
@@ -25,10 +26,10 @@ const employmentIcons = {
const ValidationReview = () => {
const navigate = useNavigate();
const { id } = useParams();
- const [toast, setToast] = React.useState(null);
const [isRejectOpen, setIsRejectOpen] = React.useState(false);
const [rejectReason, setRejectReason] = React.useState('');
const [loading, setLoading] = React.useState(true);
+ const [actionLoading, setActionLoading] = React.useState(false);
const [error, setError] = React.useState(null);
const [submissionData, setSubmissionData] = React.useState(null);
@@ -71,22 +72,69 @@ const ValidationReview = () => {
fetchSubmission();
}, [id]);
- const showApproveToast = () => {
- const establishmentName = submissionData?.establishment?.factory_name || 'Establishment';
- setToast({ type: 'success', text: `${establishmentName} has been approved successfully.` });
- window.clearTimeout(showApproveToast._t);
- showApproveToast._t = window.setTimeout(() => setToast(null), 4000);
+ const handleApprove = async () => {
+ if (actionLoading) return;
+
+ setActionLoading(true);
+ try {
+ const response = await apiClient.put(`/approveOrRejectSubmission/${id}`, {
+ status: 'Approved',
+ remarks: ''
+ });
+
+ if (response?.data || response?.status === 'success') {
+ const establishmentName = submissionData?.establishment?.factory_name || 'Establishment';
+ navigate('/admin/validations', {
+ state: {
+ showSuccessToast: true,
+ successMessage: `${establishmentName} has been approved successfully.`
+ }
+ });
+ } else {
+ throw new Error('Failed to approve submission');
+ }
+ } catch (err) {
+ console.error('Approval failed:', err);
+ alert(err.response?.data?.message || err.message || 'Failed to approve submission. Please try again.');
+ } finally {
+ setActionLoading(false);
+ }
};
- const handleRejectSubmit = () => {
- setToast({
- type: 'info',
- text: rejectReason ? `Submission rejected. Reason: ${rejectReason}` : 'Submission rejected.'
- });
- window.clearTimeout(showApproveToast._t);
- showApproveToast._t = window.setTimeout(() => setToast(null), 4000);
- setIsRejectOpen(false);
- setRejectReason('');
+ const handleRejectSubmit = async () => {
+ if (actionLoading) return;
+
+ if (!rejectReason.trim()) {
+ alert('Please provide a reason for rejection.');
+ return;
+ }
+
+ setActionLoading(true);
+ try {
+ const response = await apiClient.put(`/approveOrRejectSubmission/${id}`, {
+ status: 'Rejected',
+ remarks: rejectReason.trim()
+ });
+
+ if (response?.data || response?.status === 'success') {
+ const establishmentName = submissionData?.establishment?.factory_name || 'Establishment';
+ navigate('/admin/validations', {
+ state: {
+ showSuccessToast: true,
+ successMessage: `${establishmentName} has been rejected successfully.`
+ }
+ });
+ } else {
+ throw new Error('Failed to reject submission');
+ }
+ } catch (err) {
+ console.error('Rejection failed:', err);
+ alert(err.response?.data?.message || err.message || 'Failed to reject submission. Please try again.');
+ } finally {
+ setActionLoading(false);
+ setIsRejectOpen(false);
+ setRejectReason('');
+ }
};
if (loading) {
@@ -253,22 +301,6 @@ const ValidationReview = () => {
- {toast && (
-
-
-
-
- )}
-
@@ -454,8 +488,12 @@ const ValidationReview = () => {
@@ -469,26 +507,29 @@ const ValidationReview = () => {
placeholder="Enter the reason for rejection..."
value={rejectReason}
onChange={(event) => setRejectReason(event.target.value)}
+ disabled={actionLoading}
/>
diff --git a/ipi-survey-platform/src/pages/Admin/Validations.jsx b/ipi-survey-platform/src/pages/Admin/Validations.jsx
index de0fcb6..e0a4da1 100644
--- a/ipi-survey-platform/src/pages/Admin/Validations.jsx
+++ b/ipi-survey-platform/src/pages/Admin/Validations.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Link, useNavigate } from 'react-router-dom';
+import { Link, useNavigate, useLocation } from 'react-router-dom';
import AdminHeader from '@/components/admin/AdminHeader';
import Table from '@/components/common/Table';
import { SelectField } from '@/components/common/FormControls';
@@ -51,6 +51,7 @@ const Badge = ({ children, status }) => {
const ManageSubmissions = () => {
const navigate = useNavigate();
+ const location = useLocation();
const [submissions, setSubmissions] = React.useState([]);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState(null);
@@ -60,8 +61,47 @@ const ManageSubmissions = () => {
const [emirate, setEmirate] = React.useState('');
const [status, setStatus] = React.useState('');
const [currentPage, setCurrentPage] = React.useState(1);
+ const [toast, setToast] = React.useState(null);
const pageSize = 10;
+ const toastTimeoutRef = React.useRef(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 closeToast = React.useCallback(() => {
+ if (toastTimeoutRef.current) {
+ window.clearTimeout(toastTimeoutRef.current);
+ toastTimeoutRef.current = null;
+ }
+ setToast(null);
+ }, []);
+
+ React.useEffect(() => {
+ return () => {
+ if (toastTimeoutRef.current) {
+ window.clearTimeout(toastTimeoutRef.current);
+ }
+ };
+ }, []);
+
+ React.useEffect(() => {
+ if (location.state?.showSuccessToast && location.state?.successMessage) {
+ showToast('success', location.state.successMessage);
+ window.history.replaceState({}, document.title);
+ }
+ }, [location.state, showToast]);
+
React.useEffect(() => {
const fetchSubmissions = async () => {
try {
@@ -194,6 +234,30 @@ const ManageSubmissions = () => {
<>
+
+ {toast && (
+
+
+
+ {toast.message}
+
+
+
+
+ )}
+