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 && ( -
-
- - - - {toast.text} -
- -
- )} -
@@ -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} +
+ +
+
+ )} +