From 1acadd835aa43cef039f89d25de16fc8b3f76b15 Mon Sep 17 00:00:00 2001 From: Senthamilselvi Date: Fri, 31 Oct 2025 00:09:38 +0530 Subject: [PATCH] manage submission view design & integration done --- .../src/components/admin/SubmissionTable.jsx | 47 +- .../src/pages/Admin/ValidationReview.jsx | 435 ++++++++++++------ .../src/pages/Admin/Validations.jsx | 203 ++++---- ipi-survey-platform/src/pages/Login/Login.jsx | 15 +- .../src/pages/PublicContactForm.jsx | 20 +- 5 files changed, 449 insertions(+), 271 deletions(-) diff --git a/ipi-survey-platform/src/components/admin/SubmissionTable.jsx b/ipi-survey-platform/src/components/admin/SubmissionTable.jsx index 5e44fd7..bee0393 100644 --- a/ipi-survey-platform/src/components/admin/SubmissionTable.jsx +++ b/ipi-survey-platform/src/components/admin/SubmissionTable.jsx @@ -118,27 +118,32 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => { renderStatusBadge(item?.status), item?.updated_by || '-', {formatDate(item?.updated_at)}, -
- - - -
, +
+
+ + + Approve + +
+
+ + + Reject + +
+
+ navigate(`/admin/validations/${item.id}`)} + /> + + View + +
+
, ]); const columnWidths = [240, 120, 100, 100, 130, 150, 180, 150, 150, 180, 120]; diff --git a/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx b/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx index 661f85d..bddb4e3 100644 --- a/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx +++ b/ipi-survey-platform/src/pages/Admin/ValidationReview.jsx @@ -1,6 +1,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'; const caretUpSrc = '/assets/images/caret-up.svg'; const establishmentIconSrc = '/assets/images/Establishment.svg'; @@ -13,21 +14,6 @@ const femaleEmployeesIconSrc = '/assets/images/femaleemployess.svg'; const uaeIconSrc = '/assets/images/uae.svg'; const nonUaeIconSrc = '/assets/images/nonuae.svg'; -const establishmentDetails = [ - { label: 'Establishment Name', value: 'ABC Manufacturing LLC' }, - { label: 'Establishment ID', value: 'MSCensus-23-05-002829' }, - { label: 'Email', value: 'info@abcmg.com' }, - { label: 'Emirate', value: 'Abu Dhabi' }, -]; - -const employmentDetails = [ - { label: 'Total Employees', value: '120' }, - { label: 'Male Employees', value: '80' }, - { label: 'Female Employees', value: '40' }, - { label: 'UAE Nationals', value: '30' }, - { label: 'Non-UAE Nationals', value: '90' }, -]; - const employmentIcons = { 'Total Employees': totalEmployeesIconSrc, 'Male Employees': maleEmployeesIconSrc, @@ -36,75 +22,233 @@ const employmentIcons = { 'Non-UAE Nationals': nonUaeIconSrc, }; -const quarterLegend = [ - { label: 'Previous Quarter', color: '#1D4ED8' }, - { label: 'Current Quarter', color: '#1E7C34' }, - { label: 'Next Quarter', color: '#D97706' }, -]; - -const productDetails = [ - { - code: '04012000', - name: 'Milk', - submittedOn: '28/03/2025', - unit: 'Liters', - capacity: '20000', - quarters: [ - { label: 'Q1-2025', color: '#0C64F6', cellColor: '#F4F8FF' }, - { label: 'Q2-2025', color: '#1E7C34', cellColor: '#F3FAF4' }, - { label: 'Q3-2025', color: '#D97706', cellColor: '#FFF6EC' }, - ], - rows: [ - { label: 'Quantity (liters)', values: ['500', '200', '50'] }, - { label: 'Cost (AED)', values: ['40,000', '20,000', '20,000'] }, - { label: 'Reason', values: ['--', 'Seasonal production surge', 'Higher demand expected'] }, - ], - remarks: 'NA', - }, - { - code: '07028000', - name: 'Iron', - submittedOn: '18/08/2025', - unit: 'Kilogram', - capacity: '50000', - quarters: [ - { label: 'Q1-2025', color: '#0C64F6', cellColor: '#F4F8FF' }, - { label: 'Q2-2025', color: '#1E7C34', cellColor: '#F3FAF4' }, - { label: 'Q3-2025', color: '#D97706', cellColor: '#FFF6EC' }, - ], - rows: [ - { label: 'Quantity (kilograms)', values: ['800', '400', '80'] }, - { label: 'Cost (AED)', values: ['70,000', '40,000', '30,000'] }, - { label: 'Reason', values: ['--', 'Seasonal procurement', 'Higher demand expected'] }, - ], - remarks: 'NA', - }, -]; - -const infoBadgeClass = 'inline-flex items-center rounded-[10px] border border-[#E5D7AA] bg-[#FDF9EB] px-3 py-1 text-sm font-medium text-[#92722A]'; - 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 [error, setError] = React.useState(null); + const [submissionData, setSubmissionData] = React.useState(null); + + React.useEffect(() => { + const fetchSubmission = async () => { + if (!id) { + setError('No submission ID provided'); + setLoading(false); + return; + } + + try { + setLoading(true); + setError(null); + + const result = await getSubmissionById(id); + + let data = null; + if (result?.status === 'success' && result?.data) { + data = result.data; + } else if (result?.data) { + data = result.data; + } else { + data = result; + } + + if (!data) { + throw new Error('No data received from API'); + } + + setSubmissionData(data); + } catch (err) { + console.error('Failed to load submission details:', err); + setError(err.message || 'Unable to load submission details. Please try again later.'); + } finally { + setLoading(false); + } + }; + + fetchSubmission(); + }, [id]); const showApproveToast = () => { - setToast({ type: 'success', text: 'ABC Manufacturing LLC has been approved successfully.' }); - window.clearTimeout((showApproveToast._t)); - // Auto-hide after 4 seconds + 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 handleRejectSubmit = () => { - setToast({ type: 'info', text: rejectReason ? `Submission rejected. Reason: ${rejectReason}` : 'Submission rejected.' }); - window.clearTimeout((showApproveToast._t)); + 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(''); }; + if (loading) { + return ( +
+ +
+ + + + + Loading submission details... +
+
+ ); + } + + if (error || !submissionData) { + return ( +
+ +
+
+
+ + + +
+

Error Loading Submission

+

{error || 'Submission not found'}

+ +
+
+
+
+
+ ); + } + + const establishment = submissionData?.establishment || {}; + + const establishmentDetails = [ + { + label: 'Establishment Name', + value: establishment.factory_name || '—' + }, + { + label: 'Establishment ID', + value: establishment.establishment_code || '—' + }, + { + label: 'Email', + value: establishment.establishment_contact_email || '—' + }, + { + label: 'Emirate', + value: establishment.establishment_address || '—' + }, + ]; + + const totalEmiratiMale = establishment.emirati_male || 0; + const totalEmiratiFemale = establishment.emirati_female || 0; + const totalNonEmiratiMale = establishment.non_emirati_male || 0; + const totalNonEmiratiFemale = establishment.non_emirati_female || 0; + const totalMale = totalEmiratiMale + totalNonEmiratiMale; + const totalFemale = totalEmiratiFemale + totalNonEmiratiFemale; + const totalEmirati = totalEmiratiMale + totalEmiratiFemale; + const totalNonEmirati = totalNonEmiratiMale + totalNonEmiratiFemale; + + const employmentDetails = [ + { + label: 'Total Employees', + value: establishment.total_employees?.toString() || (totalMale + totalFemale).toString() || '—' + }, + { + label: 'Male Employees', + value: totalMale.toString() || '—' + }, + { + label: 'Female Employees', + value: totalFemale.toString() || '—' + }, + { + label: 'UAE Nationals', + value: totalEmirati.toString() || '—' + }, + { + label: 'Non-UAE Nationals', + value: totalNonEmirati.toString() || '—' + }, + ]; + + const quarterPeriods = submissionData?.quarter_periods || {}; + const previousQuarter = quarterPeriods.previous_quarter || 'Q1'; + const currentQuarter = quarterPeriods.current_quarter || 'Q2'; + const forecastQuarter = quarterPeriods.forecast_quarter || 'Q3'; + const year = submissionData?.year || new Date().getFullYear(); + + const products = submissionData?.products || []; + const productDetails = Array.isArray(products) ? products.map((product) => { + const quarters = [ + { label: `${previousQuarter}-${year}`, color: '#0C64F6', cellColor: '#F4F8FF', type: 'previous' }, + { label: `${currentQuarter}-${year}`, color: '#1E7C34', cellColor: '#F3FAF4', type: 'current' }, + { label: `${forecastQuarter}-${year}`, color: '#D97706', cellColor: '#FFF6EC', type: 'forecast' }, + ]; + + const unitValue = product.unit?.uom || 'units'; + const unit = String(unitValue); + + const previousQuantity = product.previous_quantity || '—'; + const previousCost = product.previous_cost || '—'; + const currentQuantity = product.current_quantity || '—'; + const currentCost = product.current_cost || '—'; + const forecastQuantity = product.forecast_quantity || '—'; + const forecastCost = product.forecast_cost || '—'; + + const variationReason = product.variation_reason?.reason || product.other_variation_reason || '—'; + const zeroTargetReason = product.zero_target_reason?.reason || product.other_zero_target_reason || '—'; + + return { + code: product.product?.hs_code || '—', + name: product.product?.product_name || '—', + submittedBy: submissionData?.created_by || 'System', + submittedOn: submissionData?.created_at ? new Date(submissionData.created_at).toLocaleDateString('en-GB') : '—', + unit: unit, + capacity: product.annual_installed_capacity?.toString() || '—', + quarters, + rows: [ + { + label: `Quantity (${unit.toLowerCase()})`, + values: [ + previousQuantity.toString(), + currentQuantity.toString(), + forecastQuantity.toString() + ] + }, + { + label: 'Cost (AED)', + values: [ + previousCost !== '—' ? Number(previousCost).toLocaleString() : '—', + currentCost !== '—' ? Number(currentCost).toLocaleString() : '—', + forecastCost !== '—' ? Number(forecastCost).toLocaleString() : '—' + ] + }, + { + label: 'Reason', + values: [ + '—', + variationReason, + zeroTargetReason + ] + }, + ], + remarks: product.remarks || 'NA', + }; + }) : []; + return (
@@ -139,20 +283,6 @@ const ValidationReview = () => { - {/*
-
-

Submission Details

-

Submission #{id || '—'}

-
- -
*/} -
@@ -210,79 +340,88 @@ const ValidationReview = () => {
-
- {productDetails.map((product) => ( -
-
-
Product: {product.code} - {product.name}
-
- Submitted By: {product.submittedOn} - Unit: {product.unit} - Capacity: {product.capacity} -
-
- -
- {quarterLegend.map((item) => ( -
- - {item.label} + {productDetails.length > 0 ? ( +
+ {productDetails.map((product, idx) => ( +
+
+
+ Product: {product.code} - {product.name}
- ))} -
-
- - - - - {product.quarters.map((quarter) => ( - - ))} - - - - {product.rows.map((row) => ( - - - {row.values.map((value, index) => ( - + {product.rows.map((row) => ( + + + {row.values.map((value, index) => ( + + ))} + + ))} + +
Description - {quarter.label} -
{row.label} +
+ Submitted By: + {product.submittedBy} +
+
+ Unit: + {product.unit} +
+
+ Capacity: + {product.capacity} +
+ + + +
+ + + + + {product.quarters.map((quarter) => ( + ))} - ))} - -
Description - {value} - + {quarter.label} +
-
+ +
{row.label} + {value} +
+
-
-
- Remarks: {product.remarks} +
+
+ Remarks: {product.remarks} +
+
+ Admin Remarks +