diff --git a/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx b/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx index 2e1af63..006cf52 100644 --- a/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx +++ b/ipi-survey-platform/src/components/dashboard/SubmissionHistory.jsx @@ -159,12 +159,60 @@ export const SubmissionHistory = ({ history = [], loading = false, error = '' }) const pageSize = 10; const navigate = useNavigate(); - - const handleViewDetails = (submission) => { navigate('/overview', { state: { selectedSubmission: submission } }); }; +const handleResubmit = async (submission) => { + try { + const response = await fetchSubmissionDetail(submission.id); + const submissionData = response.data; + + // Structure the data in the format expected by the component + const formattedData = { + ...submissionData, + establishment: { + ...submissionData.establishment, + establishment_contact_email: submissionData.establishment.establishment_contact_email, + emirate: submissionData.establishment.establishment_emirate_id, + establishment_emirate_id: submissionData.establishment.establishment_emirate_id + }, + employeeInfo: { + emiratiMale: submissionData.establishment.emirati_male, + emiratiFemale: submissionData.establishment.emirati_female, + nonEmiratiMale: submissionData.establishment.non_emirati_male, + nonEmiratiFemale: submissionData.establishment.non_emirati_female, + totalEmirati: submissionData.establishment.total_emirati, + totalEmployees: submissionData.establishment.total_employees + }, + products: submissionData.products || [], + quarterWindow: submissionData.quarter_window || {} + }; + + // Save the complete data to localStorage + localStorage.setItem('resubmissionData', JSON.stringify(formattedData)); + + // Save products separately + if (submissionData.products && submissionData.products.length > 0) { + localStorage.setItem('submissionProducts', JSON.stringify(submissionData.products)); + } + + // Set resubmission flags + localStorage.setItem('isResubmission', 'true'); + + // Navigate to survey with resubmission state + navigate('/survey', { + state: { + submission: formattedData, + isResubmit: true, + fromResubmit: true + } + }); + } catch (error) { + console.error('Error fetching submission details:', error); + showToast('Failed to load submission for resubmission', 'error'); + } +}; const handleEdit = async (submission) => { if (submission.status.toLowerCase() === 'draft') { try { diff --git a/ipi-survey-platform/src/components/overview/ProductDetails.jsx b/ipi-survey-platform/src/components/overview/ProductDetails.jsx index 1f0bcde..cb11604 100644 --- a/ipi-survey-platform/src/components/overview/ProductDetails.jsx +++ b/ipi-survey-platform/src/components/overview/ProductDetails.jsx @@ -52,7 +52,7 @@ const ProductDetails = ({ bgColor: 'bg-red-50', textColor: 'text-red-600', iconColor: 'text-red-500', - message: 'Your survey has been rejected. Please review and resubmit.', + message: 'Your survey has been rejected.', icon: '/assets/images/Vector-rejected.svg', iconAlt: 'Rejected', iconClassName: 'mr-2 h-5 w-5 flex-shrink-0' @@ -357,8 +357,8 @@ const ProductDetails = ({ }} className="ml-auto px-3 py-1 bg-[#FEF2F2] text-[#7C2320] text-sm font-medium rounded hover:bg-[#FEF2F2] transition-colors" > - Resubmit - + {/* Resubmit */} + {/* */} )} diff --git a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx index 007975d..879b008 100644 --- a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx +++ b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx @@ -338,41 +338,40 @@ const EstablishmentInfo = ({ }; // Store establishment data in localStorage during resubmission - React.useEffect(() => { - // Check if this is a resubmission - const isResubmit = location.state?.fromResubmit; - - if (isResubmit && data) { - try { - // Get existing resubmission data if it exists - const existingData = JSON.parse(localStorage.getItem('resubmissionData') || '{}'); - // Update with establishment data - const updatedData = { - ...existingData, - establishment: { - id: data.establishmentId, - name: data.establishmentName, - permanent_factory_code: data.permanentFactoryCode, - industry_code: data.industryCode, - license_number: data.licenseNumber, - isic_code: data.isicCode, - emirate: data.emirate, - establishment_contact_email: data.establishment_contact_email, - employeeInfo: data.employeeInfo || {} - }, - // Ensure quarter and year are included - quarter: data.quarter || surveyData.quarter, - year: data.year || surveyData.year - }; - - - // Save back to localStorage - localStorage.setItem('resubmissionData', JSON.stringify(updatedData)); - } catch (error) { - console.error('Error updating resubmission data with establishment info:', error); - } +// Store establishment data in localStorage during resubmission +React.useEffect(() => { + const isResubmit = location.state?.fromResubmit; + + if (isResubmit) { + try { + const resubmissionData = JSON.parse(localStorage.getItem('resubmissionData') || '{}'); + const establishmentData = resubmissionData.establishment || {}; + + // Update the form with the resubmission data + onChange({ + ...data, + establishmentId: establishmentData.id, + establishmentName: establishmentData.factory_name, + permanentFactoryCode: establishmentData.permanent_factory_code, + industryCode: establishmentData.industry_code, + licenseNumber: establishmentData.license_number, + isicCode: establishmentData.isic_code, + emirate: establishmentData.establishment_emirate_id, + establishment_contact_email: establishmentData.establishment_contact_email, + employeeInfo: { + emiratiMale: establishmentData.emirati_male || '', + nonEmiratiMale: establishmentData.non_emirati_male || '', + emiratiFemale: establishmentData.emirati_female || '', + nonEmiratiFemale: establishmentData.non_emirati_female || '', + totalEmployees: establishmentData.total_employees || '', + totalEmirati: establishmentData.total_emirati || '' + } + }); + } catch (error) { + console.error('Error processing resubmission data:', error); } - }, [data, location.state?.fromResubmit, surveyData.quarter, surveyData.year]); + } +}, [location.state]); const info = React.useMemo( () => ({ diff --git a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx index 8880382..5db3ef8 100644 --- a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx +++ b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx @@ -97,6 +97,8 @@ const SearchableSelect = ({ const [searchTerm, setSearchTerm] = React.useState(''); const selectRef = React.useRef(null); const inputRef = React.useRef(null); + const [savedQuarter, setSavedQuarter] = React.useState(null); + const [savedYear, setSavedYear] = React.useState(null); // Close dropdown when clicking outside React.useEffect(() => { @@ -494,6 +496,116 @@ const ProductData = ({ fetchQuarterPeriods(); }, [quarter, year]); + // Load resubmission data when component mounts +useEffect(() => { + const loadResubmissionData = async () => { + try { + // Check for resubmission data in localStorage and location state + const resubmissionData = localStorage.getItem('resubmissionData') || + (location.state?.submission && JSON.stringify(location.state.submission)); + + if (resubmissionData) { + const parsedData = JSON.parse(resubmissionData); + + if (parsedData.products && Array.isArray(parsedData.products) && parsedData.products.length > 0) { + console.log('Loading resubmission products:', parsedData.products); + + // Wait for product options to be loaded + if (productOptions.length === 0) { + await new Promise(resolve => { + const checkProducts = setInterval(() => { + if (productOptions.length > 0) { + clearInterval(checkProducts); + resolve(); + } + }, 100); + }); + } + + // Map the products to match the expected format + const mappedProducts = await Promise.all(parsedData.products.map(async (product, index) => { + // Find the matching product in productOptions + const matchedProduct = productOptions.find( + p => p.value === product.product_id?.toString() || + p.productId === product.product_id || + p.originalData?.id === product.product_id + ); + + return { + id: product.id || `resubmit-${index}-${Date.now()}`, + product: matchedProduct?.value || product.product_id?.toString() || '', + productId: product.product_id, + productName: matchedProduct?.name || product.product?.product_name || product.product_name || '', + unit: product.unit_id?.toString() || product.unit?.id?.toString() || '', + unitName: product.unit?.uom || product.unit_name || '', + capacity: product.annual_installed_capacity?.toString() || '0', + + // Previous Quarter (Q4) - October, November, December + octQuantity: product.previous_quantity_period_one?.toString() || '0', + novQuantity: product.previous_quantity_period_two?.toString() || '0', + decQuantity: product.previous_quantity_period_three?.toString() || '0', + octCost: product.previous_cost_period_one?.toString() || '0', + novCost: product.previous_cost_period_two?.toString() || '0', + decCost: product.previous_cost_period_three?.toString() || '0', + + // Current Quarter (Q1) - January, February, March + janQuantity: product.current_quantity_period_one?.toString() || '0', + febQuantity: product.current_quantity_period_two?.toString() || '0', + marQuantity: product.current_quantity_period_three?.toString() || '0', + janCost: product.current_cost_period_one?.toString() || '0', + febCost: product.current_cost_period_two?.toString() || '0', + marCost: product.current_cost_period_three?.toString() || '0', + + // Forecast Quarter (Q2) - April, May, June + aprQuantity: product.forecast_quantity_period_one?.toString() || '0', + mayQuantity: product.forecast_quantity_period_two?.toString() || '0', + junQuantity: product.forecast_quantity_period_three?.toString() || '0', + aprCost: product.forecast_cost_period_one?.toString() || '0', + mayCost: product.forecast_cost_period_two?.toString() || '0', + junCost: product.forecast_cost_period_three?.toString() || '0', + + // Variation reasons + variationReason: product.variation_reason_master_id?.toString() || '', + otherVariationReason: product.other_variation_reason || '', + zeroTargetReason: product.zero_target_reason_master_id?.toString() || '', + otherZeroTargetReason: product.other_zero_target_reason || '', + remarks: product.remarks || '', + + // Additional fields for better tracking + isResubmitted: true, + originalData: product + }; + })); + + console.log('Mapped products for resubmission:', mappedProducts); + + // Update the products state with the mapped products + if (mappedProducts.length > 0) { + onProductsChange(mappedProducts); + + // Set selected product IDs for tracking + setSelectedProductIds(mappedProducts + .map(p => p.productId || p.product) + .filter(Boolean) + ); + + // Set initial tab to show the first product + setActiveTab('current'); + } + } + } + } catch (error) { + console.error('Error loading resubmission data:', error); + } + }; + + // Only load resubmission data if we're in resubmit mode and don't have products yet + const isResubmit = location.state?.isResubmit || false; + if (isResubmit && (!products || products.length === 0)) { + loadResubmissionData(); + } +}, [onProductsChange, products, productOptions, location.state]); + const handleSaveDraft = async () => { try { setIsSavingDraft(true); @@ -882,22 +994,43 @@ useEffect(() => { const formattedProducts = productsList.map(product => { // Handle nested properties with dot notation - const productName = product['product.product_name'] || product.product_name || ''; - const hsCode = product['product.hs_code'] || product.hs_code || ''; - const unitName = product['product.unit.uom'] || ''; + const productName = product['product.product_name'] || product.product_name || product.product?.product_name || ''; + const hsCode = product['product.hs_code'] || product.hs_code || product.product?.hs_code || ''; + const unitName = product['product.unit.uom'] || product.unit?.uom || ''; + const productId = product.product_id || product.product?.id || product.id; return { - value: product.id.toString(), + value: productId.toString(), label: hsCode ? `${hsCode} - ${productName}` : productName, originalData: product, hsCode: hsCode, name: productName, - productId: product.product_id, // Use product_id instead of id - product_id: product.product_id, // Add product_id directly to the object + productId: productId, + product_id: productId, unit: unitName }; }); - setProductOptions(formattedProducts); + + setProductOptions(prevOptions => { + // Only update if there are new products to avoid unnecessary re-renders + if (JSON.stringify(prevOptions) !== JSON.stringify(formattedProducts)) { + return formattedProducts; + } + return prevOptions; + }); + + // If we're in resubmit mode and have products in localStorage, trigger the resubmission load + const isResubmit = location.state?.isResubmit || false; + const resubmissionData = localStorage.getItem('resubmissionData'); + + if (isResubmit && resubmissionData) { + const parsedData = JSON.parse(resubmissionData); + if (parsedData.products && parsedData.products.length > 0) { + // Force a re-render to trigger the resubmission data load + onProductsChange([]); + } + } + } catch (error) { console.error('Error fetching products:', error); setProductsError('Failed to load products. Please try again.'); @@ -915,7 +1048,7 @@ useEffect(() => { }; fetchEstablishmentProducts(); - }, []); + }, [location.state?.isResubmit]); // Add isResubmit to dependency array // Moved inside the component React.useEffect(() => { const maxId = products.reduce((max, item) => (item && typeof item.id === 'number' ? Math.max(max, item.id) : max), 0); diff --git a/ipi-survey-platform/src/pages/Overview/Overview.jsx b/ipi-survey-platform/src/pages/Overview/Overview.jsx index 3536fa4..85f05d9 100644 --- a/ipi-survey-platform/src/pages/Overview/Overview.jsx +++ b/ipi-survey-platform/src/pages/Overview/Overview.jsx @@ -226,6 +226,57 @@ const showToast = (message, type = 'success') => { className="w-5 h-5 text-[#92722A] opacity-60 hover:opacity-100 transition-opacity cursor-pointer" style={{ filter: 'invert(36%) sepia(49%) saturate(680%) hue-rotate(1deg) brightness(89%) contrast(91%)' }} title="Resubmit" + onClick={async (e) => { + e.stopPropagation(); + try { + const response = await fetchSubmissionDetail(record.id); + const submissionData = response.data; + + // Structure the data in the format expected by the component + const formattedData = { + ...submissionData, + establishment: { + ...submissionData.establishment, + establishment_contact_email: submissionData.establishment.establishment_contact_email, + emirate: submissionData.establishment.establishment_emirate_id, + establishment_emirate_id: submissionData.establishment.establishment_emirate_id + }, + employeeInfo: { + emiratiMale: submissionData.establishment.emirati_male, + emiratiFemale: submissionData.establishment.emirati_female, + nonEmiratiMale: submissionData.establishment.non_emirati_male, + nonEmiratiFemale: submissionData.establishment.non_emirati_female, + totalEmirati: submissionData.establishment.total_emirati, + totalEmployees: submissionData.establishment.total_employees + }, + products: submissionData.products || [], + quarterWindow: submissionData.quarter_window || {} + }; + + // Save the complete data to localStorage + localStorage.setItem('resubmissionData', JSON.stringify(formattedData)); + + // Save products separately + if (submissionData.products && submissionData.products.length > 0) { + localStorage.setItem('submissionProducts', JSON.stringify(submissionData.products)); + } + + // Set resubmission flags + localStorage.setItem('isResubmission', 'true'); + + // Navigate to survey with resubmission state + navigate('/survey', { + state: { + submission: formattedData, + isResubmit: true, + fromResubmit: true + } + }); + } catch (error) { + console.error('Error preparing resubmission:', error); + // Optionally show error to user + } + }} /> )}