bug fixed in admin dashboard

This commit is contained in:
Malini 2025-11-07 19:02:38 +05:30
parent d0d8bd13f3
commit 9986f7c16b
13 changed files with 458 additions and 174 deletions

View File

@ -84,10 +84,16 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
Rejected Rejected
</span> </span>
); );
} else if (normalized === 'pending') { } else if (normalized === 'submitted') {
return ( return (
<span className="px-3 py-1 rounded-md text-blue-600 bg-blue-50 font-medium text-sm whitespace-nowrap"> <span className="px-3 py-1 rounded-md text-blue-600 bg-blue-50 font-medium text-sm whitespace-nowrap">
Pending Submitted
</span>
);
} else if (normalized === 'resubmitted') {
return (
<span className="px-3 py-1 rounded-md text-[#7C5E24] bg-[#F9F7ED] font-medium text-sm whitespace-nowrap">
Resubmitted
</span> </span>
); );
} else { } else {
@ -133,12 +139,14 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
return ( return (
<div <div
className="border border-[#E5E7EB] bg-white shadow-[0_16px_32px_rgba(15,23,42,0.06)] rounded-[8px]" className="border border-[#E5E7EB] bg-white shadow-[0_8px_16px_rgba(15,23,42,0.05)] rounded-[6px] w-full overflow-hidden py-2"
style={{ style={{
width: '1250px', minHeight: filtered.length === 0 || loading ? 'auto' : '200px',
minHeight: filtered.length === 0 || loading ? 'auto' : '780px', }}
}} >
> <h2 className="px-4 pr-100 py-2 mt-3 text-[18px] leading-[28px] font-medium text-[#232528]">
{titleText}
</h2>
<div className="space-y-[1px] overflow-x-auto"> <div className="space-y-[1px] overflow-x-auto">
{/* <div className="px-6 pt-6 pb-4"> {/* <div className="px-6 pt-6 pb-4">
<h2 className="text-[18px] leading-[28px] font-medium text-[#232528]"> <h2 className="text-[18px] leading-[28px] font-medium text-[#232528]">
@ -155,7 +163,7 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
No Submission Found No Submission Found
</div> </div>
) : ( ) : (
<div className="min-w-[1200px]"> <div className="w-full overflow-x-auto pt-5 h-[550px]">
<Table <Table
headers={headers} headers={headers}
rows={tableRows} rows={tableRows}
@ -235,7 +243,7 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
<button <button
type="button" type="button"
onClick={() => navigate('/admin/validations')} onClick={() => navigate('/admin/validations')}
className="inline-flex h-[44px] w-[190px] items-center justify-center gap-2 rounded-md bg-[#9E792B] text-sm font-medium text-white shadow-[0_8px_18px_rgba(146,114,42,0.35)] hover:bg-[#846522]" className="inline-flex h-[44px] w-[190px] items-center justify-center gap-2 rounded-md bg-[#9E792B] text-sm font-medium text-white shadow-[0_8px_18px_rgba(146,114,42,0.35)] hover:bg-[#846522] py-6"
> >
View All Submissions View All Submissions
</button> </button>

View File

@ -3,12 +3,14 @@ import React from 'react';
const toneClasses = { const toneClasses = {
green: 'bg-[#F3FAF4] text-[#2F663C] ring-1 ring-[#C4E5CC]', green: 'bg-[#F3FAF4] text-[#2F663C] ring-1 ring-[#C4E5CC]',
gray: 'bg-[#E9EDF3] text-[#232528] ring-1 ring-[#D6DBE4]', gray: 'bg-[#E9EDF3] text-[#232528] ring-1 ring-[#D6DBE4]',
resubmitted: 'bg-[#F9F7ED] text-[#8B8000] ring-1 ring-[#E5DFC5]',
}; };
const normalizeTone = (tone, status) => { const normalizeTone = (tone, status) => {
if (tone) return tone; if (tone) return tone;
const normalizedStatus = String(status || '').toLowerCase(); const normalizedStatus = String(status || '').toLowerCase();
if (normalizedStatus === 'active' || normalizedStatus === 'open') return 'green'; if (normalizedStatus === 'active' || normalizedStatus === 'open') return 'green';
if (normalizedStatus === 'resubmitted') return 'resubmitted';
return 'gray'; return 'gray';
}; };

View File

@ -30,16 +30,28 @@ const getStatusBadge = (status) => {
Approved Approved
</span> </span>
); );
} else if (normalized === 'submitted') {
return (
<span className="px-3 py-1 rounded-md text-green-700 bg-green-50 font-medium text-sm whitespace-nowrap">
Submitted
</span>
);
} else if (normalized === 'resubmitted') {
return (
<span className="px-3 py-1 rounded-md text-[#7C5E24] bg-[#F9F7ED] font-medium text-sm whitespace-nowrap">
Resubmitted
</span>
);
} else if (['pending', 'under review', 'in-progress'].includes(normalized)) { } else if (['pending', 'under review', 'in-progress'].includes(normalized)) {
return ( return (
<span className="px-3 py-1 rounded-md text-blue-600 bg-blue-50 font-medium text-sm whitespace-nowrap"> <span className="px-3 py-1 rounded-md text-blue-600 bg-blue-50 font-medium text-sm whitespace-nowrap">
Under Review Under Review
</span> </span>
); );
} else if (['rejected', 'returned'].includes(normalized)) { } else if (normalized === 'rejected') {
return ( return (
<span className="px-3 py-1 rounded-md text-red-600 bg-red-50 font-medium text-sm whitespace-nowrap"> <span className="px-3 py-1 rounded-md text-red-600 bg-red-50 font-medium text-sm whitespace-nowrap">
Returned Rejected
</span> </span>
); );
} else { } else {
@ -63,7 +75,7 @@ const downloadCsv = (data) => {
const normalized = String(item.status || '').toLowerCase(); const normalized = String(item.status || '').toLowerCase();
if (normalized === 'approved') return 'Approved'; if (normalized === 'approved') return 'Approved';
if (['pending', 'under review', 'in-progress'].includes(normalized)) return 'Under Review'; if (['pending', 'under review', 'in-progress'].includes(normalized)) return 'Under Review';
if (['rejected', 'returned'].includes(normalized)) return 'Returned'; if (['rejected', 'rejected'].includes(normalized)) return 'Returned';
return item.status || '—'; return item.status || '—';
})(); })();

View File

@ -30,7 +30,7 @@ const SurveyCarousel = ({
setCurrentIndex((prev) => (prev === surveys.length - 1 ? 0 : prev + 1)); setCurrentIndex((prev) => (prev === surveys.length - 1 ? 0 : prev + 1));
return ( return (
<div className="bg-black rounded-lg shadow-sm ring-1 ring-gray-200 mb-8 ml-2 "> <div className="bg-black rounded-lg shadow-sm ring-1 w-[1275px] ring-gray-200 h-[148px] mb-8 ml-2 ">
<div className="rounded-none bg-[#F2ECCF] px-8 py-8 min-h-[148px] flex items-center justify-between transition-all duration-500"> <div className="rounded-none bg-[#F2ECCF] px-8 py-8 min-h-[148px] flex items-center justify-between transition-all duration-500">
<div className="flex-1"> <div className="flex-1">
<h3 className="text-[18px] leading-[28px] font-medium text-[#232528]"> <h3 className="text-[18px] leading-[28px] font-medium text-[#232528]">

View File

@ -44,7 +44,8 @@ export const DetailedOverview = ({ submission, onBack }) => {
'Approved': 'bg-[#F3FAF4] text-[#2F663C]', 'Approved': 'bg-[#F3FAF4] text-[#2F663C]',
'Submitted': 'bg-[#E7F5FF] text-[#003CFF]', 'Submitted': 'bg-[#E7F5FF] text-[#003CFF]',
'Pending': 'bg-[#F9F7ED] text-[#7C5E24]', 'Pending': 'bg-[#F9F7ED] text-[#7C5E24]',
'Rejected': 'bg-[#FEF2F2] text-[#B52520]' 'Rejected': 'bg-[#FEF2F2] text-[#B52520]',
'Resubmitted': 'bg-[#F9F7ED] text-[#7C5E24]'
}; };
const statusClass = statusMap[status] || 'bg-gray-100 text-gray-800'; const statusClass = statusMap[status] || 'bg-gray-100 text-gray-800';
@ -172,7 +173,7 @@ export const DetailedOverview = ({ submission, onBack }) => {
product.current_cost || '0', product.current_cost || '0',
product.forecast_quantity || '0', product.forecast_quantity || '0',
product.forecast_cost || '0', product.forecast_cost || '0',
product.status || 'Pending' product.status || 'Submitted'
].map((value) => `"${String(value).replace(/"/g, '""')}"`).join(',')); ].map((value) => `"${String(value).replace(/"/g, '""')}"`).join(','));
}); });
@ -231,8 +232,8 @@ export const DetailedOverview = ({ submission, onBack }) => {
productData.hs_code || '—', productData.hs_code || '—',
productData.product_name || '—', productData.product_name || '—',
unit.uom || 'N/A', unit.uom || 'N/A',
product.previous_quantity || '0', product.current_quantity || '0',
`AED ${product.previous_cost || '0'}`, `AED ${product.current_cost || '0'}`,
// <span // <span
// key={`status-${index}`} // key={`status-${index}`}
// className={`inline-flex items-center justify-center rounded-md px-3 py-1 text-xs font-medium ${ // className={`inline-flex items-center justify-center rounded-md px-3 py-1 text-xs font-medium ${

View File

@ -50,6 +50,13 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
textColor: 'text-[#043DFF]', textColor: 'text-[#043DFF]',
iconColor: 'text-[#286CFF]', iconColor: 'text-[#286CFF]',
message: 'Your survey was successfully submitted and is waiting for approval.' message: 'Your survey was successfully submitted and is waiting for approval.'
},
resubmitted: {
type: 'resubmitted',
bgColor: 'bg-[#E7F5FF]',
textColor: 'text-[#043DFF]',
iconColor: 'text-[#286CFF]',
message: 'Your survey was successfully Resubmitted and is waiting for approval.'
} }
}; };
@ -182,9 +189,11 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
industry_code: product.industry_code, industry_code: product.industry_code,
license_number: product.license_number, license_number: product.license_number,
isic_code: product.isic_code, isic_code: product.isic_code,
emirate: product.emirate emirate: product.emirate,
status: product.status // Include status for reference
}, },
isResubmit: true isResubmit: true,
submissionId: product.submission_id // Add submissionId for resubmission
} }
}); });
}} }}

View File

@ -252,6 +252,7 @@ const ReviewSubmit = ({
onToastClose = () => {}, onToastClose = () => {},
isSubmitting = false, isSubmitting = false,
hasSubmitted = false, hasSubmitted = false,
submitButtonText = 'Submit',
}) => { }) => {
const [confirm, setConfirm] = React.useState(false); const [confirm, setConfirm] = React.useState(false);
const [remarks, setRemarks] = React.useState(() => { const [remarks, setRemarks] = React.useState(() => {
@ -734,11 +735,10 @@ const ReviewSubmit = ({
<h3 className="text-base font-semibold text-gray-900 mb-4">Remarks</h3> <h3 className="text-base font-semibold text-gray-900 mb-4">Remarks</h3>
<div className="space-y-2"> <div className="space-y-2">
<textarea <textarea
placeholder="Enter your remarks here..."
readOnly readOnly
value={remarks} value={remarks || ''}
onChange={(e) => setRemarks(e.target.value)} placeholder="No remarks provided"
className="w-full min-h-[100px] p-3 border border-#CBA344 rounded-md focus:ring-2 focus:ring-[#CBA344] focus:border-transparent" className="w-full min-h-[100px] p-3 border border-gray-200 rounded-md bg-gray-50 text-gray-700 resize-none focus:outline-none focus:ring-0 focus:border-gray-200"
/> />
</div> </div>
</div> </div>
@ -792,7 +792,7 @@ const ReviewSubmit = ({
: 'bg-[#92722A] text-white hover:bg-[#7b5c1f]' : 'bg-[#92722A] text-white hover:bg-[#7b5c1f]'
}`} }`}
> >
<span>{submitLabel}</span> <span>{submitButtonText}</span>
</button> </button>
</div> </div>
</div> </div>

View File

@ -33,6 +33,7 @@ const ValidationReview = () => {
const [actionLoading, setActionLoading] = React.useState(false); const [actionLoading, setActionLoading] = React.useState(false);
const [error, setError] = React.useState(null); const [error, setError] = React.useState(null);
const [submissionData, setSubmissionData] = React.useState(null); const [submissionData, setSubmissionData] = React.useState(null);
const [quarterPeriods, setQuarterPeriods] = React.useState(null);
React.useEffect(() => { React.useEffect(() => {
const fetchSubmission = async () => { const fetchSubmission = async () => {
@ -49,10 +50,16 @@ const ValidationReview = () => {
const result = await getSubmissionById(id); const result = await getSubmissionById(id);
let data = null; let data = null;
if (result?.status === 'success' && result?.data) { if (result?.status === 'success') {
data = result.data; data = result.data;
if (result.quarter_periods) {
setQuarterPeriods(result.quarter_periods);
}
} else if (result?.data) { } else if (result?.data) {
data = result.data; data = result.data;
if (result.quarter_periods) {
setQuarterPeriods(result.quarter_periods);
}
} else { } else {
data = result; data = result;
} }
@ -239,10 +246,9 @@ const ValidationReview = () => {
}, },
]; ];
const quarterPeriods = submissionData?.quarter_periods || {}; const previousQuarter = quarterPeriods?.previous_quarter;
const previousQuarter = quarterPeriods.previous_quarter || 'Q1'; const currentQuarter = quarterPeriods?.current_quarter;
const currentQuarter = quarterPeriods.current_quarter || 'Q2'; const forecastQuarter = quarterPeriods?.forecast_quarter;
const forecastQuarter = quarterPeriods.forecast_quarter || 'Q3';
const year = submissionData?.year || new Date().getFullYear(); const year = submissionData?.year || new Date().getFullYear();
const products = submissionData?.products || []; const products = submissionData?.products || [];
@ -380,13 +386,7 @@ const ValidationReview = () => {
</section> </section>
{productDetails.length > 0 ? ( {productDetails.length > 0 ? (
<div <div className={`grid gap-4 ${productDetails.length === 1 ? 'grid-cols-1' : 'grid-cols-1 lg:grid-cols-2'}`}>
className={`grid gap-4 ${
productDetails.length === 1
? 'grid-cols-1'
: 'grid-cols-1 lg:grid-cols-2'
}`}
>
{productDetails.map((product, idx) => ( {productDetails.map((product, idx) => (
<section <section
key={product.code + idx} key={product.code + idx}
@ -420,113 +420,180 @@ const ValidationReview = () => {
Metric Metric
</th> </th>
<th colSpan="3" className="bg-[#F2ECCF] text-[#92722A] px-4 py-2 text-xs font-semibold uppercase text-center"> <th colSpan="3" className="bg-[#F2ECCF] text-[#92722A] px-4 py-2 text-xs font-semibold uppercase text-center">
Q4-2024 (Previous Quarter) {quarterPeriods?.previous_quarter}-{quarterPeriods?.previous_year} (Previous Quarter)
</th> </th>
<th colSpan="3" className="bg-[#F2ECCF] text-[#92722A] px-4 py-2 text-xs font-semibold uppercase text-center"> <th colSpan="3" className="bg-[#F2ECCF] text-[#92722A] px-4 py-2 text-xs font-semibold uppercase text-center">
Q1-2025 (Current Quarter) {quarterPeriods?.current_quarter}-{quarterPeriods?.current_year} (Current Quarter)
</th> </th>
<th colSpan="3" className="bg-[#F2ECCF] text-[#92722A] px-4 py-2 text-xs font-semibold uppercase text-center"> <th colSpan="3" className="bg-[#F2ECCF] text-[#92722A] px-4 py-2 text-xs font-semibold uppercase text-center">
Q2-2025 (Next Quarter) {quarterPeriods?.forecast_quarter}-{quarterPeriods?.forecast_year} (Next Quarter)
</th> </th>
</tr> </tr>
<tr> <tr>
<th className="bg-[#F4F8FF] px-4 py-2 font-medium text-[#286CFF]">Oct</th> <th className="bg-[#F4F8FF] px-4 py-2 font-medium text-[#286CFF]">{quarterPeriods?.current_month?.current_period_one}</th>
<th className="bg-[#F4F8FF] px-4 py-2 font-medium text-[#286CFF]">Nov</th> <th className="bg-[#F4F8FF] px-4 py-2 font-medium text-[#286CFF]">{quarterPeriods?.current_month?.current_period_two}</th>
<th className="bg-[#F4F8FF] px-4 py-2 font-medium text-[#286CFF]">Dec</th> <th className="bg-[#F4F8FF] px-4 py-2 font-medium text-[#286CFF]">{quarterPeriods?.current_month?.current_period_three}</th>
<th className="bg-[#F3FAF4] px-4 py-2 font-medium text-[#2F663C]">Jan</th> <th className="bg-[#F3FAF4] px-4 py-2 font-medium text-[#2F663C]">{quarterPeriods?.forecast_month?.forecast_period_one}</th>
<th className="bg-[#F3FAF4] px-4 py-2 font-medium text-[#2F663C]">Feb</th> <th className="bg-[#F3FAF4] px-4 py-2 font-medium text-[#2F663C]">{quarterPeriods?.forecast_month?.forecast_period_two}</th>
<th className="bg-[#F3FAF4] px-4 py-2 font-medium text-[#2F663C]">Mar</th> <th className="bg-[#F3FAF4] px-4 py-2 font-medium text-[#2F663C]">{quarterPeriods?.forecast_month?.forecast_period_three}</th>
<th className="bg-[#FFF6EC] px-4 py-2 font-medium text-[#F29F0E]">Apr</th> <th className="bg-[#FFF6EC] px-4 py-2 font-medium text-[#F29F0E]">{quarterPeriods?.previous_month?.previous_period_one}</th>
<th className="bg-[#FFF6EC] px-4 py-2 font-medium text-[#F29F0E]">May</th> <th className="bg-[#FFF6EC] px-4 py-2 font-medium text-[#F29F0E]">{quarterPeriods?.previous_month?.previous_period_two}</th>
<th className="bg-[#FFF6EC] px-4 py-2 font-medium text-[#F29F0E]">Jun</th> <th className="bg-[#FFF6EC] px-4 py-2 font-medium text-[#F29F0E]">{quarterPeriods?.previous_month?.previous_period_three}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr className="border-t border-[#E5E7EB]"> {submissionData?.products?.map((product, idx) => (
<td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]"> <React.Fragment key={idx}>
Quantity (liters) {/* Quantity Row */}
</td> <tr className="border-t border-[#E5E7EB]">
<td className="px-4 py-3 text-[#232528]">1200</td> <td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]">
<td className="px-4 py-3 text-red-600">1180 </td> Quantity ({product.unit?.uom || 'units'})
<td className="px-4 py-3 text-green-600">1250 </td> </td>
{/* Previous Quarter Quantities */}
<td className="px-4 py-3 text-[#232528]">
{product.previous_quantity_period_one || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.previous_quantity_period_two || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.previous_quantity_period_three || '0'}
</td>
{/* Current Quarter Quantities */}
<td className="px-4 py-3 text-[#232528]">
{product.current_quantity_period_one || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.current_quantity_period_two || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.current_quantity_period_three || '0'}
</td>
{/* Forecast Quarter Quantities */}
<td className="px-4 py-3 text-[#232528]">
{product.forecast_quantity_period_one || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.forecast_quantity_period_two || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.forecast_quantity_period_three || '0'}
</td>
</tr>
<td className="px-4 py-3 text-[#232528]">1280</td> {/* Cost Row */}
<td className="px-4 py-3 text-[#232528]">1340</td> <tr className="border-t border-[#E5E7EB]">
<td className="px-4 py-3 text-[#232528]">1375</td> <td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]">
Cost (AED)
</td>
{/* Previous Quarter Costs */}
<td className="px-4 py-3 text-[#232528]">
{product.previous_cost_period_one || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.previous_cost_period_two || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.previous_cost_period_three || '0'}
</td>
{/* Current Quarter Costs */}
<td className="px-4 py-3 text-[#232528]">
{product.current_cost_period_one || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.current_cost_period_two || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.current_cost_period_three || '0'}
</td>
{/* Forecast Quarter Costs */}
<td className="px-4 py-3 text-[#232528]">
{product.forecast_cost_period_one || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.forecast_cost_period_two || '0'}
</td>
<td className="px-4 py-3 text-[#232528]">
{product.forecast_cost_period_three || '0'}
</td>
</tr>
{/* Remarks Row (if exists) */}
{product.remarks && (
<tr className="border-t border-[#E5E7EB] bg-gray-100">
<td className="px-4 py-3 font-medium text-[#232528]">
Remarks
</td>
<td colSpan="9" className="px-4 py-3 text-[#232528]">
{product.remarks}
</td>
</tr>
)}
{/* Current Quarter Reason Row */}
<tr className="border-t border-[#E5E7EB]">
<td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]">
Reason (Current)
</td>
<td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
<td colSpan="3" className="px-4 py-3 text-center bg-[#E9F6EC] text-[#1E7C34] font-medium rounded-md">
{product.variation_reason?.reason || 'No reason provided'}
{product.other_variation_reason && (
<div className="text-xs mt-1">Note: {product.other_variation_reason}</div>
)}
</td>
<td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
</tr>
<td className="px-4 py-3 text-[#232528]">1400</td> {/* Forecast Quarter Reason Row */}
<td className="px-4 py-3 text-[#232528]">1450</td> <tr className="border-t border-[#E5E7EB]">
<td className="px-4 py-3 text-[#232528]">1500</td> <td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]">
</tr> Reason (Forecast)
</td>
<tr className="border-t border-[#E5E7EB]"> <td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
<td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]"> <td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
Cost (AED) <td colSpan="3" className="px-4 py-3 text-center bg-[#FFF2E0] text-[#D97706] font-medium rounded-md">
</td> {product.zero_target_reason?.reason || 'No reason provided'}
<td className="px-4 py-3 text-[#232528]">39,000</td> {product.other_zero_target_reason && (
<td className="px-4 py-3 text-red-600">37,500 </td> <div className="text-xs mt-1">Note: {product.other_zero_target_reason}</div>
<td className="px-4 py-3 text-green-600">41,000 </td> )}
</td>
<td className="px-4 py-3 text-[#232528]">40,000</td> </tr>
<td className="px-4 py-3 text-[#232528]">42,000</td> </React.Fragment>
<td className="px-4 py-3 text-[#232528]">43,500</td> ))}
<td className="px-4 py-3 text-[#232528]">44,000</td>
<td className="px-4 py-3 text-[#232528]">45,000</td>
<td className="px-4 py-3 text-[#232528]">46,000</td>
</tr>
<tr className="border-t border-[#E5E7EB]">
<td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]">
Reason (Current)
</td>
<td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
<td colSpan="3" className="px-4 py-3 text-center bg-[#E9F6EC] text-[#1E7C34] font-medium rounded-md">
Seasonal Increase
</td>
<td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
</tr>
<tr className="border-t border-[#E5E7EB]">
<td className="bg-[#FFFCF2] px-4 py-3 font-medium text-[#232528]">
Reason (Forecast)
</td>
<td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
<td colSpan="3" className="px-4 py-3 text-center text-[#6B7280]">--</td>
<td colSpan="3" className="px-4 py-3 text-center bg-[#FFF2E0] text-[#D97706] font-medium rounded-md">
Projected demand
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div>
<div className="mt-4">
{/* <p>
<div className="text-xs text-[#4B5563] mt-2"> <span className="text-[#16A34A] font-semibold">Green </span> indicates upward trend;{' '}
<p> <span className="text-[#DC2626] font-semibold">Red </span> indicates downward trend compared to previous month or quarter
<span className="text-[#16A34A] font-semibold">Green </span> indicates upward trend;{' '} </p> */}
<span className="text-[#DC2626] font-semibold">Red </span> indicates downward trend compared to previous month or quarter <p className="mt-3 text-sm text-[#4B5563]">
</p> <strong className="font-semibold text-[#232528]">Remarks:</strong> NA
<p className="mt-3 text-sm text-[#4B5563]"> </p>
<strong className="font-semibold text-[#232528]">Remarks:</strong> NA
</p>
</div>
<div className="mt-3">
<label className="block text-sm font-semibold mb-1 text-[#232528]">Admin Remarks</label>
<textarea
rows="2"
className="w-full rounded-[10px] border border-[#D1D5DB] bg-[#FFFCF2] px-4 py-2 text-sm text-[#232528] focus:ring-2 focus:ring-[#92722A] focus:outline-none"
placeholder="Add short note..."
></textarea>
</div>
</section>
))}
</div> </div>
<div className="mt-3">
<label className="block text-sm font-semibold mb-1 text-[#232528]">Admin Remarks</label>
<textarea
rows="2"
className="w-full rounded-[10px] border border-[#D1D5DB] bg-[#FFFCF2] px-4 py-2 text-sm text-[#232528] focus:ring-2 focus:ring-[#92722A] focus:outline-none"
placeholder="Add short note..."
></textarea>
</div>
</div>
</section>
))}
</div>
) : ( ) : (
<div className="rounded-lg bg-amber-50 border border-amber-200 p-6 text-center"> <div className="rounded-lg bg-amber-50 border border-amber-200 p-6 text-center">
<p className="text-amber-800">No products found for this submission.</p> <p className="text-amber-800">No products found for this submission.</p>

View File

@ -13,6 +13,8 @@ const STATUS_VARIANTS = {
Approved: { background: '#F3FAF4', text: '#2F663C', border: '#F3FAF4' }, Approved: { background: '#F3FAF4', text: '#2F663C', border: '#F3FAF4' },
Pending: { background: '#E7F5FF', text: '#286CFF', border: '#E7F5FF' }, Pending: { background: '#E7F5FF', text: '#286CFF', border: '#E7F5FF' },
Rejected: { background: '#FEF2F2', text: '#B52520', border: '#FEF2F2' }, Rejected: { background: '#FEF2F2', text: '#B52520', border: '#FEF2F2' },
Resubmitted: { background: '#F9F7ED', text: '#7C5E24', border: '#FEF2F2' },
Submitted: { background: '#E7F5FF', text: '#003CFF', border: '#FEF2F2' },
}; };
const SUMMARY_VARIANTS = { const SUMMARY_VARIANTS = {
@ -20,8 +22,12 @@ const SUMMARY_VARIANTS = {
approved: { background: '#F3FAF4', label: '#2F663C', value: '#232528' }, approved: { background: '#F3FAF4', label: '#2F663C', value: '#232528' },
pending: { background: '#E7F5FF', label: '#003CFF', value: '#232528' }, pending: { background: '#E7F5FF', label: '#003CFF', value: '#232528' },
rejected: { background: '#FEF2F2', label: '#B52520', value: '#232528' }, rejected: { background: '#FEF2F2', label: '#B52520', value: '#232528' },
resubmitted: { background: '#F9F7ED', text: '#7C5E24', border: '#FEF2F2' },
submitted: { background: '#E7F5FF', text: '#003CFF', border: '#FEF2F2' },
}; };
const formatDateTime = (value) => { const formatDateTime = (value) => {
if (!value) return '—'; if (!value) return '—';
const date = new Date(value); const date = new Date(value);

View File

@ -1947,6 +1947,7 @@ const requiredFields = [
factory_name: form.establishmentName || form.contactName || '', factory_name: form.establishmentName || form.contactName || '',
permanent_factory_code: form.permanentFactoryCode || '', permanent_factory_code: form.permanentFactoryCode || '',
industry_code: form.industryCodeBusiness || form.industryCodeCurrent || '', industry_code: form.industryCodeBusiness || form.industryCodeCurrent || '',
industry_code_production: form.industryCodeBusiness || form.industryCodeCurrent || '',
license_number: form.uniqueLicenseNumber || '', license_number: form.uniqueLicenseNumber || '',
isic_code: form.isicCode || form.industryCodeBusiness || '', isic_code: form.isicCode || form.industryCodeBusiness || '',
description: form.industryDescription || '', description: form.industryDescription || '',
@ -2025,6 +2026,7 @@ const requiredFields = [
factory_name: form.establishmentName || form.contactName || '', factory_name: form.establishmentName || form.contactName || '',
permanent_factory_code: form.permanentFactoryCode || '', permanent_factory_code: form.permanentFactoryCode || '',
industry_code: form.industryCodeBusiness || form.industryCodeCurrent || '', industry_code: form.industryCodeBusiness || form.industryCodeCurrent || '',
industry_code_production: form.industryCodeBusiness || form.industryCodeCurrent || '',
license_number: form.uniqueLicenseNumber || '', license_number: form.uniqueLicenseNumber || '',
isic_code: form.isicCode || form.industryCodeBusiness || '', isic_code: form.isicCode || form.industryCodeBusiness || '',
description: form.industryDescription || '', description: form.industryDescription || '',

View File

@ -11,15 +11,40 @@ const BreadcrumbVector = '/assets/images/Breadcrumb-vector.svg';
const caretDownSrc = '/assets/images/CaretDown.svg'; const caretDownSrc = '/assets/images/CaretDown.svg';
const Badge = ({ variant = 'default', children }) => { const Badge = ({ variant = 'default', children }) => {
// Define all possible status variants and their styles
const styles = { const styles = {
approved: 'bg-[#F3FAF4] text-[#2F663C]', // Approved status
submitted: 'bg-[#E7F5FF] text-[#003CFF]', approved: 'text-green-700 bg-green-50',
pending: 'bg-[#F9F7ED] text-[#7C5E24]',
rejected: 'bg-[#FEF2F2] text-[#B52520]', // Submitted status
default: 'bg-gray-50 text-gray-700', submitted: 'text-green-700 bg-green-50',
// Under Review status (includes pending and in-progress)
'under review': 'text-blue-600 bg-blue-50',
pending: 'text-blue-600 bg-blue-50',
'in-progress': 'text-blue-600 bg-blue-50',
// Rejected status (includes returned)
rejected: 'text-red-600 bg-red-50',
returned: 'text-red-600 bg-red-50',
// Resubmitted status
resubmitted: 'text-[#7C5E24] bg-[#F9F7ED]',
// Default fallback
default: 'text-gray-600 bg-gray-50',
}; };
// Normalize the variant key
const normalizedVariant = String(variant || '').toLowerCase().trim();
// Get the appropriate style, fallback to default if not found
const style = styles[normalizedVariant] || styles.default;
return ( return (
<span className={`inline-flex items-center justify-center rounded-full text-xs font-medium px-3 py-1 ${styles[variant.toLowerCase()] || styles.default}`}> <span
className={`inline-flex items-center justify-center rounded-md px-3 py-1 text-sm font-medium whitespace-nowrap ${style}`}
>
{children} {children}
</span> </span>
); );
@ -180,8 +205,9 @@ const formatExportDateTime = (value) => {
const text = String(status || '').toLowerCase(); const text = String(status || '').toLowerCase();
if (text === 'approved') return 'approved'; if (text === 'approved') return 'approved';
if (text === 'submitted') return 'submitted'; if (text === 'submitted') return 'submitted';
if (text === 'rejected') return 'rejected'; if (text === 'resubmitted') return 'resubmitted';
if (text === 'pending' || text === 'in-progress' || text === 'under review') return 'pending'; if (text === 'rejected' || text === 'returned') return 'rejected';
if (text === 'pending' || text === 'in-progress' || text === 'under review') return 'under review';
return 'default'; return 'default';
}, []); }, []);
@ -375,7 +401,7 @@ const filteredRows = useMemo(() => {
'Quarter', 'Quarter',
'HS Code', 'HS Code',
'Product', 'Product',
'Status', { name: 'Status', className: 'text-center' },
'Actors', 'Actors',
'Details' 'Details'
]; ];
@ -850,14 +876,24 @@ const tableRows = auditHistory.map((entry, index) => {
loading={loading} loading={loading}
error={error} error={error}
className="mt-4" className="mt-4"
pagination={{ columnWidths={[
currentPage: pagination.currentPage, { width: 180, style: { whiteSpace: 'normal', wordWrap: 'break-word' } }, // Submission Date
onPageChange: handlePageChange, { width: 80, style: { whiteSpace: 'normal', wordWrap: 'break-word' } }, // Year
pageSize: pagination.pageSize, { width: 80, style: { whiteSpace: 'normal', wordWrap: 'break-word' } }, // Quarter
totalItems: pagination.totalItems, { width: 120, style: { whiteSpace: 'normal', wordWrap: 'break-word' } }, // HS Code
pageSizeOptions: [10, 25, 50, 100], { width: 200, style: { whiteSpace: 'normal', wordWrap: 'break-word' } }, // Product
onPageSizeChange: handlePageSizeChange, { width: 130, align: 'center', style: { whiteSpace: 'normal', wordWrap: 'break-word' } }, // Status
}} { width: 140, style: { whiteSpace: 'normal', wordWrap: 'break-word' } }, // Actors
{ width: 270, style: { whiteSpace: 'normal', wordWrap: 'break-word' } } // Details
]}
pagination={{
currentPage: pagination.currentPage,
onPageChange: handlePageChange,
pageSize: pagination.pageSize,
totalItems: pagination.totalItems,
pageSizeOptions: [10, 25, 50, 100],
onPageSizeChange: handlePageSizeChange,
}}
renderCell={(value, ri, ci) => { renderCell={(value, ri, ci) => {
if (ci === 5) { // Status column if (ci === 5) { // Status column
return <Badge variant={toVariant(filteredRows[ri]?.status)}>{formatStatus(filteredRows[ri]?.status)}</Badge>; return <Badge variant={toVariant(filteredRows[ri]?.status)}>{formatStatus(filteredRows[ri]?.status)}</Badge>;

View File

@ -14,6 +14,7 @@ const statusStyles = {
submitted: 'text-[#003CFF] bg-[#E7F5FF]', submitted: 'text-[#003CFF] bg-[#E7F5FF]',
pending: 'text-[#7C5E24] bg-[#F9F7ED]', pending: 'text-[#7C5E24] bg-[#F9F7ED]',
rejected: 'text-[#B52520] bg-[#FEF2F2]', rejected: 'text-[#B52520] bg-[#FEF2F2]',
resubmitted: 'text-[#7C5E24] bg-[#F9F7ED]',
}; };
const formatDate = (dateString) => { const formatDate = (dateString) => {

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import { submitSurvey, fetchSubmissionDetail } from '@/services/submissions/submissionService'; import { submitSurvey, fetchSubmissionDetail, resubmitSurvey } from '@/services/submissions/submissionService';
import { fetchEstablishmentDetail, fetchEstablishmentDashboard } from '@/services/establishments/establishmentService'; import { fetchEstablishmentDetail, fetchEstablishmentDashboard } from '@/services/establishments/establishmentService';
import EstablishmentInfo from '@/components/survey/EstablishmentInfo/EstablishmentInfo'; import EstablishmentInfo from '@/components/survey/EstablishmentInfo/EstablishmentInfo';
import HeaderBar from '@/components/layout/HeaderBar'; import HeaderBar from '@/components/layout/HeaderBar';
@ -71,6 +71,8 @@ const Survey = () => {
const [establishmentLoading, setEstablishmentLoading] = React.useState(false); const [establishmentLoading, setEstablishmentLoading] = React.useState(false);
const [establishmentError, setEstablishmentError] = React.useState(''); const [establishmentError, setEstablishmentError] = React.useState('');
const isViewMode = React.useMemo(() => Boolean(locationState.submission), [locationState.submission]); const isViewMode = React.useMemo(() => Boolean(locationState.submission), [locationState.submission]);
const isResubmit = React.useMemo(() => locationState?.isResubmit === true, [locationState?.isResubmit]);
const submissionId = React.useMemo(() => locationState?.submissionId || locationState?.submission?.id, [locationState]);
const toastTimeoutRef = React.useRef(null); const toastTimeoutRef = React.useRef(null);
React.useEffect(() => { React.useEffect(() => {
@ -98,8 +100,18 @@ const Survey = () => {
const initializeSurveyData = async () => { const initializeSurveyData = async () => {
try { try {
// If this is a resubmission, use the quarter and year from the submission
if (isResubmit && locationState?.submission) {
if (!cancelled) {
setEstablishmentData(prev => ({
...prev,
quarter: locationState.submission.quarter || '',
year: locationState.submission.year?.toString() || ''
}));
}
}
// If quarter and year are not provided in location state, fetch them // If quarter and year are not provided in location state, fetch them
if (!locationState?.currentQuarter || !locationState?.currentYear) { else if (!locationState?.currentQuarter || !locationState?.currentYear) {
const { quarter, year } = await fetchCurrentQuarterAndYear(); const { quarter, year } = await fetchCurrentQuarterAndYear();
if (!cancelled) { if (!cancelled) {
setEstablishmentData(prev => ({ setEstablishmentData(prev => ({
@ -128,7 +140,7 @@ const Survey = () => {
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [locationState?.currentQuarter, locationState?.currentYear]); // Only depend on these values }, [locationState?.currentQuarter, locationState?.currentYear]);
React.useEffect(() => { React.useEffect(() => {
let cancelled = false; let cancelled = false;
@ -204,19 +216,39 @@ const Survey = () => {
const mergeEstablishmentData = (detail) => { const mergeEstablishmentData = (detail) => {
const summary = locationState.submission || {}; const summary = locationState.submission || {};
const establishment = detail?.establishment || {};
return { return {
quarter: ensureString(detail?.quarter) || ensureString(summary.quarter) || '', quarter: ensureString(detail?.quarter) || ensureString(summary.quarter) || '',
year: ensureString(detail?.year) || ensureString(summary.year) || '', year: ensureString(detail?.year) || ensureString(summary.year) || '',
establishmentName: ensureString(summary.establishment_name) || establishmentData.establishmentName || '', establishmentName: ensureString(establishment.factory_name) ||
permanentFactoryCode: ensureString(summary.establishment_name) ||
ensureString(summary.permanent_factory_code) || establishmentData.establishmentName || '',
ensureString(detail?.establishment_id) || permanentFactoryCode: ensureString(establishment.permanent_factory_code) ||
establishmentData.permanentFactoryCode || '', ensureString(summary.permanent_factory_code) ||
industryCode: ensureString(summary.industry_code) || establishmentData.industryCode || '', ensureString(detail?.establishment_id) ||
licenseNumber: ensureString(summary.license_number) || establishmentData.licenseNumber || '', establishmentData.permanentFactoryCode || '',
isicCode: ensureString(summary.isic_code) || establishmentData.isicCode || '', industryCode: ensureString(establishment.industry_code) ||
emirate: ensureString(summary.emirate) || establishmentData.emirate || '', ensureString(summary.industry_code) ||
employeeInfo: { ...establishmentData.employeeInfo }, establishmentData.industryCode || '',
licenseNumber: ensureString(establishment.license_number) ||
ensureString(summary.license_number) ||
establishmentData.licenseNumber || '',
isicCode: ensureString(establishment.isic_code) ||
ensureString(summary.isic_code) ||
establishmentData.isicCode || '',
emirate: ensureString(establishment.establishment_emirate_id) ||
ensureString(establishment.emirate) ||
ensureString(summary.emirate) ||
establishmentData.emirate || '',
employeeInfo: {
emiratiMale: ensureString(establishment.emirati_male) || establishmentData.employeeInfo.emiratiMale || '',
emiratiFemale: ensureString(establishment.emirati_female) || establishmentData.employeeInfo.emiratiFemale || '',
nonEmiratiMale: ensureString(establishment.non_emirati_male) || establishmentData.employeeInfo.nonEmiratiMale || '',
nonEmiratiFemale: ensureString(establishment.non_emirati_female) || establishmentData.employeeInfo.nonEmiratiFemale || '',
totalEmirati: ensureString(establishment.total_emirati) || establishmentData.employeeInfo.totalEmirati || '',
totalEmployees: ensureString(establishment.total_employees) || establishmentData.employeeInfo.totalEmployees || '',
},
}; };
}; };
@ -224,20 +256,50 @@ const Survey = () => {
if (!Array.isArray(detailProducts)) return []; if (!Array.isArray(detailProducts)) return [];
return detailProducts.map((product, index) => ({ return detailProducts.map((product, index) => ({
id: product?.id ?? index + 1, id: product?.id ?? index + 1,
productId: product?.product_id || product?.product?.id || '',
product: ensureString(product?.product?.product_name) || ensureString(product?.product_id) || '', product: ensureString(product?.product?.product_name) || ensureString(product?.product_id) || '',
unit: ensureString(product?.unit?.name) || ensureString(product?.unit_id) || '', unit: ensureString(product?.unit?.uom) || ensureString(product?.unit?.name) || ensureString(product?.unit_id) || '',
unitId: product?.unit_id || product?.unit?.id || '',
capacity: ensureString(product?.annual_installed_capacity), capacity: ensureString(product?.annual_installed_capacity),
previousQuantity: ensureString(product?.previous_quantity),
previousCost: ensureString(product?.previous_cost), // Previous Quarter (Q4) - October, November, December
currentQuantity: ensureString(product?.current_quantity), octQuantity: ensureString(product?.previous_quantity_period_one || ''),
currentCost: ensureString(product?.current_cost), novQuantity: ensureString(product?.previous_quantity_period_two || ''),
forecastQuantity: ensureString(product?.forecast_quantity), decQuantity: ensureString(product?.previous_quantity_period_three || ''),
forecastCost: ensureString(product?.forecast_cost), octCost: ensureString(product?.previous_cost_period_one || ''),
variationReason: ensureString(product?.variation_reason_master_id), novCost: ensureString(product?.previous_cost_period_two || ''),
otherVariationReason: ensureString(product?.other_variation_reason), decCost: ensureString(product?.previous_cost_period_three || ''),
zeroTargetReason: ensureString(product?.zero_target_reason_master_id),
otherZeroTargetReason: ensureString(product?.other_zero_target_reason), // Current Quarter (Q1) - January, February, March
remarks: ensureString(product?.remarks), janQuantity: ensureString(product?.current_quantity_period_one || ''),
febQuantity: ensureString(product?.current_quantity_period_two || ''),
marQuantity: ensureString(product?.current_quantity_period_three || ''),
janCost: ensureString(product?.current_cost_period_one || ''),
febCost: ensureString(product?.current_cost_period_two || ''),
marCost: ensureString(product?.current_cost_period_three || ''),
// Forecast Quarter (Q2) - April, May, June
aprQuantity: ensureString(product?.forecast_quantity_period_one || ''),
mayQuantity: ensureString(product?.forecast_quantity_period_two || ''),
junQuantity: ensureString(product?.forecast_quantity_period_three || ''),
aprCost: ensureString(product?.forecast_cost_period_one || ''),
mayCost: ensureString(product?.forecast_cost_period_two || ''),
junCost: ensureString(product?.forecast_cost_period_three || ''),
// Totals (for backward compatibility)
previousQuantity: ensureString(product?.previous_quantity || ''),
previousCost: ensureString(product?.previous_cost || ''),
currentQuantity: ensureString(product?.current_quantity || ''),
currentCost: ensureString(product?.current_cost || ''),
forecastQuantity: ensureString(product?.forecast_quantity || ''),
forecastCost: ensureString(product?.forecast_cost || ''),
// Reasons and remarks
variationReason: ensureString(product?.variation_reason_master_id || ''),
otherVariationReason: ensureString(product?.other_variation_reason || ''),
zeroTargetReason: ensureString(product?.zero_target_reason_master_id || ''),
otherZeroTargetReason: ensureString(product?.other_zero_target_reason || ''),
remarks: ensureString(product?.remarks || '')
})); }));
}; };
@ -309,7 +371,7 @@ const Survey = () => {
return String(value); return String(value);
}, []); }, []);
const buildSubmissionPayload = React.useCallback(() => { const buildSubmissionPayload = React.useCallback((isResubmitFlow = false) => {
const info = establishmentData?.employeeInfo ?? {}; const info = establishmentData?.employeeInfo ?? {};
return { return {
quarter: establishmentData?.quarter ?? '', quarter: establishmentData?.quarter ?? '',
@ -324,11 +386,13 @@ const Survey = () => {
products: productsData.map((product) => { products: productsData.map((product) => {
const variationId = parseNumber(product.variationReason, null); const variationId = parseNumber(product.variationReason, null);
const zeroTargetId = parseNumber(product.zeroTargetReason, null); const zeroTargetId = parseNumber(product.zeroTargetReason, null);
const productId = parseNumber(product.id);
// Map monthly data to period-specific fields // Map monthly data to period-specific fields
return { return {
...(isResubmitFlow && productId ? { id: productId } : {}), // Only include ID during resubmit
product_id: parseNumber(product.productId) || parseNumber(product.product), product_id: parseNumber(product.productId) || parseNumber(product.product),
unit_id: parseNumber(product.unit), unit_id: parseNumber(product.unitId) || parseNumber(product.unit),
annual_installed_capacity: stringify(product.capacity), annual_installed_capacity: stringify(product.capacity),
// Previous Quarter (Q4) - October, November, December // Previous Quarter (Q4) - October, November, December
@ -412,7 +476,31 @@ const Survey = () => {
} }
}; };
const handleSubmit = React.useCallback(async () => { const handleSubmit = React.useCallback(async (e) => {
if (e) e.preventDefault();
if (isSubmitting) return;
// Validate current step before proceeding
if (step === 1) {
const establishmentError = validateEstablishmentInfo();
if (establishmentError) {
setError(establishmentError);
return;
}
} else if (step === 2) {
const productError = validateProductData();
if (productError) {
setError(productError);
return;
}
}
// If this is the final step (step 3) and it's a resubmission, include the submission ID
if (step === 3 && isResubmit && submissionId) {
await handleResubmit();
return;
}
setIsSubmitting(true); setIsSubmitting(true);
try { try {
const payload = buildSubmissionPayload(); const payload = buildSubmissionPayload();
@ -432,6 +520,57 @@ const Survey = () => {
} }
}, [buildSubmissionPayload, showToast]); }, [buildSubmissionPayload, showToast]);
const handleResubmit = async () => {
setIsSubmitting(true);
setError('');
try {
const payload = {
...buildSubmissionPayload(true), // Pass true to indicate resubmission flow
status: 'Resubmitted', // Set status to Resubmitted for resubmissions
id: submissionId // Include submission ID in the payload
};
// Use the resubmitSurvey API with the submission ID and payload
await resubmitSurvey(submissionId, payload);
setShowSuccessPopup(true);
setHasSubmitted(true);
showToast('success', 'Survey resubmitted successfully!');
} catch (error) {
console.error('Resubmission failed:', error);
const message = error?.response?.data?.message || error?.message || 'Failed to resubmit survey. Please try again.';
setError(message);
showToast('error', message);
} finally {
setIsSubmitting(false);
}
};
const handleFinalSubmit = async () => {
if (isResubmit && submissionId) {
await handleResubmit();
return;
}
setIsSubmitting(true);
setError('');
try {
const payload = buildSubmissionPayload();
await submitSurvey(payload);
setShowSuccessPopup(true);
setHasSubmitted(true);
showToast('success', 'Survey submitted successfully!');
} catch (error) {
const message = error?.response?.data?.message || error?.message || 'Failed to submit survey. Please try again.';
setError(message);
showToast('error', message);
} finally {
setIsSubmitting(false);
}
};
const StepBadge = ({ state, number }) => { const StepBadge = ({ state, number }) => {
if (state === 'active') { if (state === 'active') {
return ( return (
@ -634,7 +773,8 @@ const Survey = () => {
establishment={establishmentData} establishment={establishmentData}
products={productsData} products={productsData}
onBack={() => setStep(2)} onBack={() => setStep(2)}
onSubmit={handleSubmit} onSubmit={handleFinalSubmit}
submitButtonText={isResubmit ? 'Resubmit' : 'Submit'}
toast={toast} toast={toast}
onToastClose={() => { onToastClose={() => {
if (toastTimeoutRef.current) { if (toastTimeoutRef.current) {
@ -644,7 +784,7 @@ const Survey = () => {
setToast(null); setToast(null);
}} }}
isSubmitting={isSubmitting} isSubmitting={isSubmitting}
hasSubmitted={hasSubmitted} hasSubmitted={false}
/> />
)} )}
</div> </div>
@ -674,12 +814,12 @@ const Survey = () => {
{/* Title */} {/* Title */}
<h3 className="text-lg font-semibold text-gray-900"> <h3 className="text-lg font-semibold text-gray-900">
Submission successful {isResubmit ? 'Resubmission successful' : 'Submission successful'}
</h3> </h3>
{/* Message */} {/* Message */}
<p className="text-sm text-gray-700"> <p className="text-sm text-gray-700">
Thank you. Your IP Quarterly Survey for <span className="font-semibold text-gray-900">{establishmentData?.quarter} {establishmentData?.year}</span> has been submitted. Thank you. Your IP Quarterly Survey for <span className="font-semibold text-gray-900">{establishmentData?.quarter} {establishmentData?.year}</span> has been {isResubmit ? 'resubmitted' : 'submitted'}.
</p> </p>
{/* Button */} {/* Button */}