chnages in product details
This commit is contained in:
parent
2edb38db14
commit
8eee109297
@ -1,6 +1,6 @@
|
||||
import React, { useState, useCallback, useMemo, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { fetchSubmissionDetail } from '@/services/submissions/submissionService';
|
||||
import { fetchSubmissionDetail, getQuarterPeriods } from '@/services/submissions/submissionService';
|
||||
import Table from '@/components/common/Table';
|
||||
import ProductDetails from './ProductDetails';
|
||||
|
||||
@ -196,9 +196,31 @@ export const DetailedOverview = ({ submission, onBack }) => {
|
||||
URL.revokeObjectURL(url);
|
||||
}, [filteredProducts]);
|
||||
|
||||
const handleViewDetails = (product) => {
|
||||
setSelectedProduct(product);
|
||||
setShowToast(true);
|
||||
const handleViewDetails = async (product) => {
|
||||
try {
|
||||
setLoadingProduct(true);
|
||||
// Extract quarter and year from the submission data
|
||||
const quarter = submissionData.quarter; // e.g., 'Q1'
|
||||
const year = submissionData.year; // e.g., 2025
|
||||
|
||||
// Fetch quarter periods
|
||||
const response = await getQuarterPeriods(year, quarter);
|
||||
|
||||
// Update the selected product with quarter periods data
|
||||
setSelectedProduct({
|
||||
...product,
|
||||
quarterPeriods: response.data
|
||||
});
|
||||
|
||||
setShowToast(true);
|
||||
} catch (error) {
|
||||
console.error('Error fetching quarter periods:', error);
|
||||
// Still show the product details even if quarter periods fetch fails
|
||||
setSelectedProduct(product);
|
||||
setShowToast(true);
|
||||
} finally {
|
||||
setLoadingProduct(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleToastShown = () => {
|
||||
@ -418,13 +440,15 @@ export const DetailedOverview = ({ submission, onBack }) => {
|
||||
// If a product is selected, show the product details view
|
||||
if (selectedProduct) {
|
||||
return (
|
||||
<ProductDetails
|
||||
product={selectedProduct}
|
||||
onBack={() => setSelectedProduct(null)}
|
||||
<ProductDetails
|
||||
product={selectedProduct}
|
||||
onClose={() => setShowToast(false)}
|
||||
onBack={() => setSelectedProduct(null)} // Add this line to handle back navigation
|
||||
showToast={showToast}
|
||||
onToastShown={handleToastShown}
|
||||
submissionDate={selectedProduct?.created_at || submissionData?.created_at || submissionData?.updated_at || new Date().toISOString()}
|
||||
submissionStatus={selectedProduct?.status || submissionData?.status || 'submitted'}
|
||||
quarterPeriods={selectedProduct?.quarterPeriods || quarterPeriods}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@ -2,7 +2,21 @@ import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
|
||||
const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastShown, submissionDate, submissionStatus = 'approved' }) => {
|
||||
// Default onBack function if not provided
|
||||
const defaultOnBack = () => {
|
||||
console.log('No onBack handler provided');
|
||||
};
|
||||
|
||||
const ProductDetails = ({
|
||||
product = {},
|
||||
onClose = () => {},
|
||||
showToast = false,
|
||||
onToastShown = () => {},
|
||||
submissionDate = new Date().toISOString(),
|
||||
submissionStatus = 'submitted',
|
||||
quarterPeriods = null,
|
||||
onBack = defaultOnBack
|
||||
}) => {
|
||||
const [toast, setToast] = useState(null);
|
||||
const toastShownRef = useRef(false);
|
||||
|
||||
@ -21,11 +35,12 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldShowToast && !toastShownRef.current) {
|
||||
if (showToast && !toastShownRef.current) {
|
||||
const formattedDate = formatDate(submissionDate);
|
||||
|
||||
if (submissionStatus) {
|
||||
const status = String(submissionStatus).toLowerCase();
|
||||
console.log("Status",status)
|
||||
const toastConfig = {
|
||||
approved: {
|
||||
type: 'approved',
|
||||
@ -76,7 +91,7 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
toastShownRef.current = true;
|
||||
onToastShown?.();
|
||||
}
|
||||
}, [shouldShowToast, product?.is_active, onToastShown, submissionDate, submissionStatus]);
|
||||
}, [showToast, product?.is_active, onToastShown, submissionDate, submissionStatus]);
|
||||
|
||||
const closeToast = () => {
|
||||
setToast(null);
|
||||
@ -86,6 +101,34 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
useEffect(() => {
|
||||
}, [product?.status, product?.is_active]);
|
||||
|
||||
// Default quarter periods if not provided
|
||||
const defaultQuarterPeriods = {
|
||||
previous_quarter: 'Q4',
|
||||
previous_year: new Date().getFullYear() - 1,
|
||||
current_quarter: 'Q1',
|
||||
current_year: new Date().getFullYear(),
|
||||
forecast_quarter: 'Q2',
|
||||
forecast_year: new Date().getFullYear(),
|
||||
previous_month: {
|
||||
previous_period_one: 'Oct',
|
||||
previous_period_two: 'Nov',
|
||||
previous_period_three: 'Dec'
|
||||
},
|
||||
current_month: {
|
||||
current_period_one: 'Jan',
|
||||
current_period_two: 'Feb',
|
||||
current_period_three: 'Mar'
|
||||
},
|
||||
forecast_month: {
|
||||
forecast_period_one: 'Apr',
|
||||
forecast_period_two: 'May',
|
||||
forecast_period_three: 'Jun'
|
||||
}
|
||||
};
|
||||
|
||||
// Use provided quarterPeriods or fall back to defaults
|
||||
const periods = quarterPeriods || product?.quarterPeriods || defaultQuarterPeriods;
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Function to save resubmission data to localStorage
|
||||
@ -369,13 +412,31 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
<div className="space-y-1">
|
||||
<label className="block text-sm font-medium text-[#6B7280]">Status</label>
|
||||
<div className="mt-1">
|
||||
<span className={`inline-flex items-center rounded-md px-3 py-1.5 text-sm font-medium ${
|
||||
formattedProduct.status === 'Active'
|
||||
? 'bg-[#F3FAF4] text-[#2F663C] ring-1 ring-inset ring-green-600/20'
|
||||
: 'bg-yellow-50 text-yellow-700 ring-1 ring-inset ring-yellow-600/20'
|
||||
}`}>
|
||||
{formattedProduct.status}
|
||||
</span>
|
||||
{(() => {
|
||||
const status = String(submissionStatus).toLowerCase();
|
||||
let statusClass = 'px-2 py-0.5 text-xs font-medium';
|
||||
let displayText = status.charAt(0).toUpperCase() + status.slice(1);
|
||||
|
||||
if (status === 'approved') {
|
||||
statusClass += ' bg-[#F3FAF4] text-[#2F663C]';
|
||||
} else if (status === 'rejected') {
|
||||
statusClass += ' bg-red-50 text-red-600';
|
||||
} else if (status === 'submitted' || status === 'active') {
|
||||
statusClass += ' bg-[#E7F5FF] text-[#043DFF]';
|
||||
displayText = status === 'active' ? 'Submitted' : displayText;
|
||||
} else if (status === 'resubmitted') {
|
||||
statusClass += ' bg-[#E7F5FF] text-[#043DFF]';
|
||||
} else {
|
||||
// Default/pending state
|
||||
statusClass += ' bg-amber-50 text-amber-700';
|
||||
}
|
||||
|
||||
return (
|
||||
<span className={`inline-flex items-center rounded ${statusClass}`}>
|
||||
{displayText}
|
||||
</span>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -389,28 +450,46 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
<th rowSpan="2" className="border border-gray-300 py-2 px-3 text-left bg-[#F2ECCF] w-[140px]">
|
||||
Metric
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
Q4-2024 (Previous Quarter)
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#E9F6FF]">
|
||||
{periods.previous_quarter}-{periods.previous_year} (Previous Quarter)
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
Q1-2025 (Current Quarter)
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F3FAF4]">
|
||||
{periods.current_quarter}-{periods.current_year} (Current Quarter)
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
Q2-2025 (Next Quarter)
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#FFF7E9]">
|
||||
{periods.forecast_quarter}-{periods.forecast_year} (Next Quarter)
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
{/* Second header row */}
|
||||
<tr className="bg-white text-[13px] font-medium">
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Oct</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Nov</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Dec</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Jan</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Feb</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Mar</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">Apr</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">May</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">Jun</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">
|
||||
{periods.previous_month.previous_period_one}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">
|
||||
{periods.previous_month.previous_period_two}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">
|
||||
{periods.previous_month.previous_period_three}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">
|
||||
{periods.current_month.current_period_one}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">
|
||||
{periods.current_month.current_period_two}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">
|
||||
{periods.current_month.current_period_three}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">
|
||||
{periods.forecast_month.forecast_period_one}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">
|
||||
{periods.forecast_month.forecast_period_two}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">
|
||||
{periods.forecast_month.forecast_period_three}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@ -513,17 +592,32 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
<button
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
{/* <button
|
||||
onClick={onBack}
|
||||
className="inline-flex items-center gap-2 h-9 px-4 mt-8 rounded-md border border-[#92722A] text-[#92722A] bg-transparent hover:bg-[#92722A]/10"
|
||||
className="flex items-center text-gray-600 hover:text-gray-800"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5 mr-1" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fillRule="evenodd" d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z" clipRule="evenodd" />
|
||||
</svg>
|
||||
<span>Back</span>
|
||||
</button>
|
||||
Back to List
|
||||
</button> */}
|
||||
{/* <button
|
||||
onClick={onClose}
|
||||
className="text-gray-500 hover:text-gray-700"
|
||||
aria-label="Close"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button> */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ProductDetails.defaultProps = {
|
||||
onBack: () => {}
|
||||
};
|
||||
|
||||
export default ProductDetails;
|
||||
|
||||
@ -104,6 +104,12 @@ const EstablishmentInfo = ({
|
||||
// Initialize from location state if available, otherwise use defaults
|
||||
if (location.state?.survey) {
|
||||
const { quarter, year, endDate } = location.state.survey;
|
||||
console.log('Initializing survey data from location.state:', { quarter, year, endDate });
|
||||
|
||||
// Save to localStorage
|
||||
const surveyPeriod = { quarter, year, endDate };
|
||||
localStorage.setItem('currentSurveyPeriod', JSON.stringify(surveyPeriod));
|
||||
|
||||
return {
|
||||
quarter: quarter || '',
|
||||
year: year || '',
|
||||
@ -112,12 +118,27 @@ const EstablishmentInfo = ({
|
||||
}
|
||||
// Or use current quarter/year as fallback
|
||||
const current = getCurrentQuarterAndYear();
|
||||
console.log('Using current quarter/year as fallback:', current);
|
||||
|
||||
// Save to localStorage
|
||||
const surveyPeriod = {
|
||||
quarter: current.quarter,
|
||||
year: current.year,
|
||||
endDate: current.endDate
|
||||
};
|
||||
localStorage.setItem('currentSurveyPeriod', JSON.stringify(surveyPeriod));
|
||||
|
||||
return {
|
||||
quarter: current.quarter,
|
||||
year: current.year,
|
||||
endDate: current.endDate
|
||||
};
|
||||
});
|
||||
|
||||
// Log when surveyData changes
|
||||
React.useEffect(() => {
|
||||
console.log('surveyData updated:', surveyData);
|
||||
}, [surveyData]);
|
||||
|
||||
// Update the ref whenever surveyData changes
|
||||
React.useEffect(() => {
|
||||
|
||||
@ -56,7 +56,8 @@ const SearchableSelect = ({
|
||||
loading = false,
|
||||
disabled = false,
|
||||
error = false,
|
||||
className = ''
|
||||
className = '',
|
||||
displayValue = undefined
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const [searchTerm, setSearchTerm] = React.useState('');
|
||||
@ -97,7 +98,9 @@ const SearchableSelect = ({
|
||||
|
||||
// Get selected option label
|
||||
const selectedOption = options.find(opt => opt.value === value);
|
||||
const displayValue = selectedOption ? selectedOption.label : '';
|
||||
const displayValueToShow = displayValue !== undefined
|
||||
? displayValue
|
||||
: (selectedOption ? selectedOption.label : '');
|
||||
|
||||
// Handle option selection
|
||||
const handleSelect = (option) => {
|
||||
@ -125,7 +128,7 @@ const SearchableSelect = ({
|
||||
className={`flex items-center justify-between h-10 px-4 py-2 text-sm rounded-md border-2 ${borderColor} ${bgColor} ${disabled ? 'bg-gray-50 cursor-not-allowed' : 'cursor-pointer'}`}
|
||||
onClick={() => !disabled && !loading && setIsOpen(!isOpen)}
|
||||
>
|
||||
<span className="truncate">{displayValue || placeholder}</span>
|
||||
<span className="truncate">{displayValueToShow || placeholder}</span>
|
||||
{loading ? (
|
||||
<div className="h-4 w-4 animate-spin rounded-full border-2 border-[#92722A] border-t-transparent ml-2" />
|
||||
) : (
|
||||
@ -311,7 +314,13 @@ const ProductData = ({
|
||||
const [productsError, setProductsError] = React.useState('');
|
||||
const [unitOptions, setUnitOptions] = React.useState([]);
|
||||
const [isLoadingUnits, setIsLoadingUnits] = React.useState(false);
|
||||
const [unitsError, setUnitsError] = React.useState('');
|
||||
const [unitsError, setUnitsError] = React.useState(null);
|
||||
|
||||
// Debug: Log products data when it changes
|
||||
useEffect(() => {
|
||||
console.log('Products data updated:', products);
|
||||
}, [products]);
|
||||
|
||||
const [activeTab, setActiveTab] = React.useState('current');
|
||||
const [isInitialLoad, setIsInitialLoad] = React.useState(true);
|
||||
const [quarterPeriods, setQuarterPeriods] = React.useState(null);
|
||||
@ -336,12 +345,28 @@ const ProductData = ({
|
||||
|
||||
useEffect(() => {
|
||||
const fetchQuarterPeriods = async () => {
|
||||
if (!quarter || !year) return;
|
||||
|
||||
try {
|
||||
// Try to get survey period from localStorage
|
||||
const savedSurveyPeriod = localStorage.getItem('currentSurveyPeriod');
|
||||
let periodYear = year;
|
||||
let periodQuarter = quarter;
|
||||
|
||||
if (savedSurveyPeriod) {
|
||||
const { quarter: savedQuarter, year: savedYear } = JSON.parse(savedSurveyPeriod);
|
||||
console.log('Using survey period from localStorage:', { savedQuarter, savedYear });
|
||||
periodYear = savedYear || year;
|
||||
periodQuarter = savedQuarter || quarter;
|
||||
}
|
||||
|
||||
if (!periodQuarter || !periodYear) {
|
||||
console.warn('No quarter or year available for fetching periods');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoadingPeriods(true);
|
||||
const quarterNumber = quarter.replace('Q', ''); // Convert 'Q3' to '3'
|
||||
const response = await getQuarterPeriods(parseInt(year), `Q${quarterNumber}`);
|
||||
const quarterNumber = periodQuarter.replace('Q', ''); // Convert 'Q3' to '3'
|
||||
console.log('Fetching quarter periods with:', { year: periodYear, quarter: `Q${quarterNumber}` });
|
||||
const response = await getQuarterPeriods(parseInt(periodYear), `Q${quarterNumber}`);
|
||||
setQuarterPeriods(response.data);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch quarter periods:', error);
|
||||
@ -526,6 +551,7 @@ const location = useLocation();
|
||||
year: year || ''
|
||||
}));
|
||||
}, [quarter, year]);
|
||||
console.log("surveyDatatest", surveyData);
|
||||
|
||||
const requiredMessage = 'Required';
|
||||
const validateForm = () => {
|
||||
@ -916,11 +942,24 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
)}
|
||||
<div className="flex justify-between items-center mb-2">
|
||||
<h2 className="text-xl font-semibold text-[#232528]">Step 2: Product Data — Monthly Output & Cost</h2>
|
||||
{(surveyData.quarter || surveyData.year) && (
|
||||
<div className="text-sm font-medium text-gray-600">
|
||||
Quarter: <span className="text-[#92722A]">{surveyData.quarter}-{surveyData.year}</span>
|
||||
</div>
|
||||
)}
|
||||
{(() => {
|
||||
// Try to get survey period from localStorage first
|
||||
const savedSurveyPeriod = localStorage.getItem('currentSurveyPeriod');
|
||||
let displayQuarter = quarter;
|
||||
let displayYear = year;
|
||||
|
||||
if (savedSurveyPeriod) {
|
||||
const { quarter: savedQuarter, year: savedYear } = JSON.parse(savedSurveyPeriod);
|
||||
displayQuarter = savedQuarter || quarter;
|
||||
displayYear = savedYear || year;
|
||||
}
|
||||
|
||||
return (displayQuarter || displayYear) ? (
|
||||
<div className="text-sm font-medium text-gray-600">
|
||||
Quarter: <span className="text-[#92722A]">{displayQuarter}-{displayYear}</span>
|
||||
</div>
|
||||
) : null;
|
||||
})()}
|
||||
</div>
|
||||
{!showInfoCard && (
|
||||
<button
|
||||
@ -956,15 +995,26 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
<div className="flex items-center space-x-1">
|
||||
<img src={calendarIcon} alt="" className="h-4 w-4" />
|
||||
<span className="font-medium">Due:</span>
|
||||
{surveyData.endDate ? (
|
||||
new Date(surveyData.endDate).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
})
|
||||
) : (
|
||||
<span className="text-amber-600">To be announced</span>
|
||||
)}
|
||||
{(() => {
|
||||
// Try to get endDate from localStorage first
|
||||
const savedSurveyPeriod = localStorage.getItem('currentSurveyPeriod');
|
||||
let endDateToUse = surveyData.endDate;
|
||||
|
||||
if (savedSurveyPeriod) {
|
||||
const { endDate } = JSON.parse(savedSurveyPeriod);
|
||||
endDateToUse = endDate || surveyData.endDate;
|
||||
}
|
||||
|
||||
return endDateToUse ? (
|
||||
new Date(endDateToUse).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
})
|
||||
) : (
|
||||
<span className="text-amber-600">To be announced</span>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center space-x-1">
|
||||
@ -1069,7 +1119,8 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
<SearchableSelect
|
||||
placeholder={isLoadingProducts ? 'Loading products...' : 'Search product HS code...'}
|
||||
options={productOptions}
|
||||
value={p.productId?.toString() || p.product?.toString() || ''}
|
||||
value={p.productId?.toString() || p.product_id?.toString() || p.product?.toString() || ''}
|
||||
displayValue={p.name || (p.hs_code && p.productName ? `${p.hs_code} - ${p.productName}` : p.productName) || ''}
|
||||
onChange={async (e) => {
|
||||
const selectedValue = e.target.value;
|
||||
// Clear error when user selects a product
|
||||
@ -1080,26 +1131,63 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
}
|
||||
|
||||
// Find the selected product from options
|
||||
const selectedProduct = productOptions.find(opt => opt.value === selectedValue);
|
||||
const selectedProduct = productOptions.find(opt => opt.value === selectedValue || opt.productId?.toString() === selectedValue);
|
||||
|
||||
// Get unit information from the selected product
|
||||
const unitId = selectedProduct?.originalData?.['product.unit.id'];
|
||||
const unitId = selectedProduct?.originalData?.['product.unit.id'] ||
|
||||
selectedProduct?.unitId ||
|
||||
selectedProduct?.originalData?.unit_id;
|
||||
|
||||
const unitName = selectedProduct?.originalData?.['product.unit.uom'] ||
|
||||
selectedProduct?.originalData?.unit?.uom ||
|
||||
selectedProduct?.unitName ||
|
||||
selectedProduct?.unit || '';
|
||||
|
||||
// Create updated product with all necessary fields including unit info
|
||||
// Get the display name for the product - check multiple possible locations
|
||||
let displayName = '';
|
||||
if (selectedProduct) {
|
||||
// Get HS code from various possible locations
|
||||
const hsCode = selectedProduct.hsCode ||
|
||||
selectedProduct.originalData?.['product.hs_code'] ||
|
||||
selectedProduct.originalData?.hs_code ||
|
||||
'';
|
||||
|
||||
// Get product name from various possible locations
|
||||
const productName = selectedProduct.name ||
|
||||
selectedProduct.originalData?.['product.name'] ||
|
||||
selectedProduct.originalData?.product_name ||
|
||||
selectedProduct.originalData?.name ||
|
||||
'';
|
||||
|
||||
// Combine HS Code and Product Name for display
|
||||
displayName = hsCode && productName ?
|
||||
`${hsCode} - ${productName}` :
|
||||
productName || selectedProduct.label ||
|
||||
(selectedProduct.originalData ?
|
||||
(selectedProduct.originalData['product.product_name'] ||
|
||||
selectedProduct.originalData.product_name ||
|
||||
selectedProduct.originalData.name) :
|
||||
(selectedProduct.name || '')
|
||||
);
|
||||
}
|
||||
|
||||
// Create updated product with all necessary fields
|
||||
const updatedProduct = {
|
||||
...p,
|
||||
product: selectedProduct?.value || selectedValue,
|
||||
productId: selectedProduct?.value || selectedValue,
|
||||
product_id: selectedProduct?.value || selectedValue,
|
||||
hs_code: selectedProduct?.hsCode || p.hs_code,
|
||||
name: selectedProduct?.name || p.name,
|
||||
product: selectedValue, // Store the ID as string
|
||||
productId: selectedValue, // Also store as productId for consistency
|
||||
product_id: selectedValue, // For backward compatibility
|
||||
hs_code: selectedProduct?.hsCode ||
|
||||
(selectedProduct?.originalData ?
|
||||
(selectedProduct.originalData['product.hs_code'] ||
|
||||
selectedProduct.originalData.hs_code) :
|
||||
'') || p.hs_code,
|
||||
name: displayName || p.name, // Use the formatted display name
|
||||
originalData: selectedProduct?.originalData || p.originalData,
|
||||
// Set unit information
|
||||
unit: unitId ? unitId.toString() : '',
|
||||
unitName: unitName,
|
||||
unit_id: unitId,
|
||||
unit_id: unitId ? unitId.toString() : '',
|
||||
// Clear any previous unit-related errors
|
||||
...(formErrors[`unit_${idx}`] && { unitError: undefined })
|
||||
};
|
||||
@ -1165,28 +1253,23 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Unit <span className="text-red-500">*</span></label>
|
||||
<SearchableSelect
|
||||
placeholder={p.unitName || (isLoadingUnits ? 'Loading units...' : 'Search unit...')}
|
||||
placeholder={isLoadingUnits ? 'Loading units...' : 'Select unit'}
|
||||
options={unitOptions}
|
||||
value={p.unit}
|
||||
value={p.unit?.toString() || ''}
|
||||
displayValue={p.unitName || ''}
|
||||
onChange={(e) => {
|
||||
// Clear error when user selects a unit
|
||||
if (formErrors[`unit_${idx}`]) {
|
||||
const newErrors = { ...formErrors };
|
||||
delete newErrors[`unit_${idx}`];
|
||||
setFormErrors(newErrors);
|
||||
}
|
||||
// Find the selected unit to get its name
|
||||
const selectedUnit = unitOptions.find(unit => unit.value === e.target.value);
|
||||
updateProductField(p.id, 'unit', e.target.value, unitOptions);
|
||||
// Also update unit name if a valid unit is selected
|
||||
if (selectedUnit) {
|
||||
updateProductField(p.id, 'unitName', selectedUnit.label || selectedUnit.name);
|
||||
updateProductField(p.id, 'unit_id', selectedUnit.id || e.target.value);
|
||||
}
|
||||
const unitId = e.target.value;
|
||||
const selectedUnit = unitOptions.find(u => u.value === unitId);
|
||||
const originalUnit = selectedUnit?.originalData || {};
|
||||
const displayName = originalUnit.uom_short_name && originalUnit.uom
|
||||
? `${originalUnit.uom_short_name.toUpperCase()} - ${originalUnit.uom}`
|
||||
: selectedUnit?.label || '';
|
||||
updateProductField(idx, 'unit', unitId);
|
||||
updateProductField(idx, 'unitName', displayName);
|
||||
}}
|
||||
loading={isLoadingUnits}
|
||||
error={!!formErrors[`unit_${idx}`]}
|
||||
isDisabled={!!p.unitName} // Disable if unit is auto-filled from product
|
||||
disabled={!!p.unitName} // Disable if unit is auto-filled from product
|
||||
/>
|
||||
<div className="h-5">
|
||||
{formErrors[`unit_${idx}`] && (
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Table from '@/components/common/Table';
|
||||
import { getQuarterPeriods } from '@/services/submissions/submissionService';
|
||||
const caretUpSrc = '/assets/images/caret-up.svg';
|
||||
const caretDownSrc = '/assets/images/CaretDown-black.svg';
|
||||
const establishmentIconSrc = '/assets/images/Establishment.svg';
|
||||
@ -341,7 +342,41 @@ const ReviewSubmit = ({
|
||||
quarter = 'Q1',
|
||||
year = new Date().getFullYear()
|
||||
}) => {
|
||||
const [quarterPeriods, setQuarterPeriods] = useState(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
const [confirm, setConfirm] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchQuarterPeriods = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const savedSurveyPeriod = localStorage.getItem('currentSurveyPeriod');
|
||||
if (!savedSurveyPeriod) {
|
||||
throw new Error('No survey period found in localStorage');
|
||||
}
|
||||
|
||||
const { quarter, year } = JSON.parse(savedSurveyPeriod);
|
||||
if (!quarter || !year) {
|
||||
throw new Error('Incomplete survey period data');
|
||||
}
|
||||
|
||||
const response = await getQuarterPeriods(year, quarter);
|
||||
if (response.status === 'success') {
|
||||
setQuarterPeriods(response.data);
|
||||
} else {
|
||||
throw new Error('Failed to fetch quarter periods');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching quarter periods:', err);
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchQuarterPeriods();
|
||||
}, []);
|
||||
const [remarks, setRemarks] = React.useState(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
return localStorage.getItem('surveyRemarks') || '';
|
||||
@ -728,28 +763,71 @@ const ReviewSubmit = ({
|
||||
<th rowSpan="2" className="border border-gray-300 py-2 px-3 text-left bg-[#F2ECCF] w-[140px]">
|
||||
Metric
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
Q4-2024 (Previous Quarter)
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
Q1-2025 (Current Quarter)
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
Q2-2025 (Next Quarter)
|
||||
</th>
|
||||
{isLoading ? (
|
||||
<th colSpan="9" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
Loading quarters...
|
||||
</th>
|
||||
) : error ? (
|
||||
<th colSpan="9" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF] text-red-500">
|
||||
{error}
|
||||
</th>
|
||||
) : (
|
||||
<>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
{quarterPeriods?.previous_quarter}-{quarterPeriods?.previous_year} (Previous Quarter)
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
{quarterPeriods?.current_quarter}-{quarterPeriods?.current_year} (Current Quarter)
|
||||
</th>
|
||||
<th colSpan="3" className="border border-gray-300 py-2 px-3 bg-[#F2ECCF]">
|
||||
{quarterPeriods?.forecast_quarter}-{quarterPeriods?.forecast_year} (Next Quarter)
|
||||
</th>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
|
||||
{/* Second header row */}
|
||||
<tr className="bg-white text-[13px] font-medium">
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Oct</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Nov</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">Dec</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Jan</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Feb</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">Mar</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">Apr</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">May</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">Jun</th>
|
||||
{isLoading ? (
|
||||
<th colSpan="9" className="py-2">Loading months...</th>
|
||||
) : error ? (
|
||||
<th colSpan="9" className="py-2 text-red-500">{error}</th>
|
||||
) : (
|
||||
<>
|
||||
{/* Previous Quarter Months */}
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">
|
||||
{quarterPeriods?.previous_month?.previous_period_one}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">
|
||||
{quarterPeriods?.previous_month?.previous_period_two}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#E9F6FF] text-[#286CFF]">
|
||||
{quarterPeriods?.previous_month?.previous_period_three}
|
||||
</th>
|
||||
|
||||
{/* Current Quarter Months */}
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">
|
||||
{quarterPeriods?.current_month?.current_period_one}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">
|
||||
{quarterPeriods?.current_month?.current_period_two}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#F3FAF4] text-[#2F663C]">
|
||||
{quarterPeriods?.current_month?.current_period_three}
|
||||
</th>
|
||||
|
||||
{/* Next Quarter Months */}
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">
|
||||
{quarterPeriods?.forecast_month?.forecast_period_one}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">
|
||||
{quarterPeriods?.forecast_month?.forecast_period_two}
|
||||
</th>
|
||||
<th className="border border-gray-300 py-2 px-3 bg-[#FFF7E9] text-[#F29F0E]">
|
||||
{quarterPeriods?.forecast_month?.forecast_period_three}
|
||||
</th>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
|
||||
@ -80,39 +80,51 @@ const Survey = () => {
|
||||
setStep(initialStepFromState);
|
||||
}, [initialStepFromState]);
|
||||
|
||||
useEffect(() => {
|
||||
const initializeSurvey = React.useCallback(() => {
|
||||
// First check if we have survey data in the navigation state
|
||||
if (locationState?.survey) {
|
||||
const { quarter, year, establishment } = locationState.survey;
|
||||
setSurveyData(locationState.survey);
|
||||
|
||||
// Only update if the data has changed
|
||||
setSurveyData(prevData => {
|
||||
return JSON.stringify(prevData) === JSON.stringify(locationState.survey)
|
||||
? prevData
|
||||
: locationState.survey;
|
||||
});
|
||||
|
||||
// If we have establishment data in the navigation state, use it
|
||||
if (establishment) {
|
||||
setEstablishmentData(prev => ({
|
||||
...prev,
|
||||
quarter: quarter || '',
|
||||
year: year || '',
|
||||
establishmentName: establishment.establishmentName || prev.establishmentName,
|
||||
permanentFactoryCode: establishment.permanentFactoryCode || prev.permanentFactoryCode,
|
||||
industryCode: establishment.industryCode || prev.industryCode,
|
||||
licenseNumber: establishment.licenseNumber || prev.licenseNumber,
|
||||
isicCode: establishment.isicCode || prev.isicCode,
|
||||
emirate: establishment.emirate || prev.emirate,
|
||||
employeeInfo: {
|
||||
emiratiMale: establishment.employeeInfo?.emiratiMale || prev.employeeInfo.emiratiMale,
|
||||
emiratiFemale: establishment.employeeInfo?.emiratiFemale || prev.employeeInfo.emiratiFemale,
|
||||
nonEmiratiMale: establishment.employeeInfo?.nonEmiratiMale || prev.employeeInfo.nonEmiratiMale,
|
||||
nonEmiratiFemale: establishment.employeeInfo?.nonEmiratiFemale || prev.employeeInfo.nonEmiratiFemale,
|
||||
totalEmirati: establishment.employeeInfo?.totalEmirati || prev.employeeInfo.totalEmirati,
|
||||
totalEmployees: establishment.employeeInfo?.totalEmployees || prev.employeeInfo.totalEmployees
|
||||
}
|
||||
}));
|
||||
setEstablishmentData(prev => {
|
||||
const newData = {
|
||||
...prev,
|
||||
quarter: quarter || '',
|
||||
year: year || '',
|
||||
establishmentName: establishment.establishmentName || prev.establishmentName,
|
||||
permanentFactoryCode: establishment.permanentFactoryCode || prev.permanentFactoryCode,
|
||||
industryCode: establishment.industryCode || prev.industryCode,
|
||||
licenseNumber: establishment.licenseNumber || prev.licenseNumber,
|
||||
isicCode: establishment.isicCode || prev.isicCode,
|
||||
emirate: establishment.emirate || prev.emirate,
|
||||
employeeInfo: {
|
||||
emiratiMale: establishment.employeeInfo?.emiratiMale ?? prev.employeeInfo.emiratiMale,
|
||||
emiratiFemale: establishment.employeeInfo?.emiratiFemale ?? prev.employeeInfo.emiratiFemale,
|
||||
nonEmiratiMale: establishment.employeeInfo?.nonEmiratiMale ?? prev.employeeInfo.nonEmiratiMale,
|
||||
nonEmiratiFemale: establishment.employeeInfo?.nonEmiratiFemale ?? prev.employeeInfo.nonEmiratiFemale,
|
||||
totalEmirati: establishment.employeeInfo?.totalEmirati ?? prev.employeeInfo.totalEmirati,
|
||||
totalEmployees: establishment.employeeInfo?.totalEmployees ?? prev.employeeInfo.totalEmployees
|
||||
}
|
||||
};
|
||||
return JSON.stringify(prev) === JSON.stringify(newData) ? prev : newData;
|
||||
});
|
||||
} else {
|
||||
setEstablishmentData(prev => ({
|
||||
...prev,
|
||||
quarter: quarter || '',
|
||||
year: year || ''
|
||||
}));
|
||||
setEstablishmentData(prev => {
|
||||
const newData = {
|
||||
...prev,
|
||||
quarter: quarter || '',
|
||||
year: year || ''
|
||||
};
|
||||
return JSON.stringify(prev) === JSON.stringify(newData) ? prev : newData;
|
||||
});
|
||||
}
|
||||
|
||||
// Also save to localStorage for page refreshes
|
||||
@ -122,35 +134,45 @@ const Survey = () => {
|
||||
const savedSurvey = localStorage.getItem('currentSurvey');
|
||||
if (savedSurvey) {
|
||||
const surveyData = JSON.parse(savedSurvey);
|
||||
setSurveyData(surveyData);
|
||||
|
||||
// Only update if the data has changed
|
||||
setSurveyData(prevData => {
|
||||
return JSON.stringify(prevData) === savedSurvey ? prevData : surveyData;
|
||||
});
|
||||
|
||||
if (surveyData.establishment) {
|
||||
const { establishment } = surveyData;
|
||||
setEstablishmentData(prev => ({
|
||||
...prev,
|
||||
quarter: surveyData.quarter || '',
|
||||
year: surveyData.year || '',
|
||||
establishmentName: establishment.establishmentName || prev.establishmentName,
|
||||
permanentFactoryCode: establishment.permanentFactoryCode || prev.permanentFactoryCode,
|
||||
industryCode: establishment.industryCode || prev.industryCode,
|
||||
licenseNumber: establishment.licenseNumber || prev.licenseNumber,
|
||||
isicCode: establishment.isicCode || prev.isicCode,
|
||||
emirate: establishment.emirate || prev.emirate,
|
||||
employeeInfo: {
|
||||
emiratiMale: establishment.employeeInfo?.emiratiMale || prev.employeeInfo.emiratiMale,
|
||||
emiratiFemale: establishment.employeeInfo?.emiratiFemale || prev.employeeInfo.emiratiFemale,
|
||||
nonEmiratiMale: establishment.employeeInfo?.nonEmiratiMale || prev.employeeInfo.nonEmiratiMale,
|
||||
nonEmiratiFemale: establishment.employeeInfo?.nonEmiratiFemale || prev.employeeInfo.nonEmiratiFemale,
|
||||
totalEmirati: establishment.employeeInfo?.totalEmirati || prev.employeeInfo.totalEmirati,
|
||||
totalEmployees: establishment.employeeInfo?.totalEmployees || prev.employeeInfo.totalEmployees
|
||||
}
|
||||
}));
|
||||
setEstablishmentData(prev => {
|
||||
const newData = {
|
||||
...prev,
|
||||
quarter: surveyData.quarter || '',
|
||||
year: surveyData.year || '',
|
||||
establishmentName: establishment.establishmentName || prev.establishmentName,
|
||||
permanentFactoryCode: establishment.permanentFactoryCode || prev.permanentFactoryCode,
|
||||
industryCode: establishment.industryCode || prev.industryCode,
|
||||
licenseNumber: establishment.licenseNumber || prev.licenseNumber,
|
||||
isicCode: establishment.isicCode || prev.isicCode,
|
||||
emirate: establishment.emirate || prev.emirate,
|
||||
employeeInfo: {
|
||||
emiratiMale: establishment.employeeInfo?.emiratiMale ?? prev.employeeInfo.emiratiMale,
|
||||
emiratiFemale: establishment.employeeInfo?.emiratiFemale ?? prev.employeeInfo.emiratiFemale,
|
||||
nonEmiratiMale: establishment.employeeInfo?.nonEmiratiMale ?? prev.employeeInfo.nonEmiratiMale,
|
||||
nonEmiratiFemale: establishment.employeeInfo?.nonEmiratiFemale ?? prev.employeeInfo.nonEmiratiFemale,
|
||||
totalEmirati: establishment.employeeInfo?.totalEmirati ?? prev.employeeInfo.totalEmirati,
|
||||
totalEmployees: establishment.employeeInfo?.totalEmployees ?? prev.employeeInfo.totalEmployees
|
||||
}
|
||||
};
|
||||
return JSON.stringify(prev) === JSON.stringify(newData) ? prev : newData;
|
||||
});
|
||||
} else {
|
||||
setEstablishmentData(prev => ({
|
||||
...prev,
|
||||
quarter: surveyData.quarter || '',
|
||||
year: surveyData.year || ''
|
||||
}));
|
||||
setEstablishmentData(prev => {
|
||||
const newData = {
|
||||
...prev,
|
||||
quarter: surveyData.quarter || '',
|
||||
year: surveyData.year || ''
|
||||
};
|
||||
return JSON.stringify(prev) === JSON.stringify(newData) ? prev : newData;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,53 +368,125 @@ const Survey = () => {
|
||||
|
||||
const mapProducts = (detailProducts = []) => {
|
||||
if (!Array.isArray(detailProducts)) return [];
|
||||
return detailProducts.map((product, index) => ({
|
||||
id: product?.id ?? index + 1,
|
||||
productId: product?.product_id || product?.product?.id || '',
|
||||
product: ensureString(product?.product?.product_name) || ensureString(product?.product_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),
|
||||
return detailProducts.map((product, index) => {
|
||||
// Extract product and unit information
|
||||
const productId = product?.product_id || product?.product?.id || '';
|
||||
const productName = ensureString(product?.product?.product_name) ||
|
||||
ensureString(product?.product?.name) ||
|
||||
ensureString(product?.product_name) ||
|
||||
'';
|
||||
const hsCode = ensureString(product?.product?.hs_code) ||
|
||||
ensureString(product?.hs_code) ||
|
||||
'';
|
||||
|
||||
// Previous Quarter (Q4) - October, November, December
|
||||
octQuantity: ensureString(product?.previous_quantity_period_one || ''),
|
||||
novQuantity: ensureString(product?.previous_quantity_period_two || ''),
|
||||
decQuantity: ensureString(product?.previous_quantity_period_three || ''),
|
||||
octCost: ensureString(product?.previous_cost_period_one || ''),
|
||||
novCost: ensureString(product?.previous_cost_period_two || ''),
|
||||
decCost: ensureString(product?.previous_cost_period_three || ''),
|
||||
// Combine HS Code and Product Name for display
|
||||
const displayName = (hsCode && productName)
|
||||
? `${hsCode} - ${productName}`
|
||||
: productName || `Product ${index + 1}`;
|
||||
|
||||
const unitId = product?.unit_id || product?.unit?.id || '';
|
||||
const unitName = ensureString(product?.unit?.uom) ||
|
||||
ensureString(product?.unit?.name) ||
|
||||
ensureString(unitId) || '';
|
||||
|
||||
// Current Quarter (Q1) - January, February, March
|
||||
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 || ''),
|
||||
console.log('Product mapping:', {
|
||||
id: productId,
|
||||
productName,
|
||||
hsCode,
|
||||
displayName,
|
||||
unitId,
|
||||
unitName,
|
||||
originalProduct: product
|
||||
});
|
||||
|
||||
return {
|
||||
id: product?.id ?? index + 1,
|
||||
productId: productId,
|
||||
product: productId, // This should match the value in productOptions
|
||||
productName: productName,
|
||||
hsCode: hsCode, // Store HS code separately
|
||||
name: displayName, // This will be used for display
|
||||
unit: unitId, // This should match the value in unitOptions
|
||||
unitName: unitName,
|
||||
unitId: unitId,
|
||||
capacity: ensureString(product?.annual_installed_capacity),
|
||||
|
||||
// Previous Quarter (Q4) - October, November, December
|
||||
octQuantity: ensureString(product?.previous_quantity_period_one || ''),
|
||||
novQuantity: ensureString(product?.previous_quantity_period_two || ''),
|
||||
decQuantity: ensureString(product?.previous_quantity_period_three || ''),
|
||||
octCost: ensureString(product?.previous_cost_period_one || ''),
|
||||
novCost: ensureString(product?.previous_cost_period_two || ''),
|
||||
decCost: ensureString(product?.previous_cost_period_three || ''),
|
||||
|
||||
// Current Quarter (Q1) - January, February, March
|
||||
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 || '')
|
||||
};
|
||||
});
|
||||
// decQuantity: ensureString(product?.previous_quantity_period_three || ''),
|
||||
// octCost: ensureString(product?.previous_cost_period_one || ''),
|
||||
// novCost: ensureString(product?.previous_cost_period_two || ''),
|
||||
// decCost: ensureString(product?.previous_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 || ''),
|
||||
// // Current Quarter (Q1) - January, February, March
|
||||
// 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 || ''),
|
||||
|
||||
// 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 || ''),
|
||||
// // 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 || ''),
|
||||
|
||||
// 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 || '')
|
||||
}));
|
||||
// // 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 || '')
|
||||
// }));
|
||||
};
|
||||
|
||||
const loadDetail = async () => {
|
||||
@ -466,10 +560,29 @@ const Survey = () => {
|
||||
const buildSubmissionPayload = React.useCallback((isResubmitFlow = false) => {
|
||||
const info = establishmentData?.employeeInfo ?? {};
|
||||
|
||||
// Check for resubmission data in localStorage
|
||||
let quarter = surveyData?.quarter || '';
|
||||
let year = surveyData?.year || '';
|
||||
// First try to get quarter and year from currentSurveyPeriod in localStorage
|
||||
let quarter = '';
|
||||
let year = '';
|
||||
|
||||
// Check for currentSurveyPeriod in localStorage
|
||||
const currentSurveyPeriod = localStorage.getItem('currentSurveyPeriod');
|
||||
if (currentSurveyPeriod) {
|
||||
try {
|
||||
const { quarter: storedQuarter, year: storedYear } = JSON.parse(currentSurveyPeriod);
|
||||
quarter = storedQuarter || '';
|
||||
year = storedYear || '';
|
||||
} catch (e) {
|
||||
console.error('Error parsing currentSurveyPeriod:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to surveyData if currentSurveyPeriod is not available
|
||||
if (!quarter || !year) {
|
||||
quarter = surveyData?.quarter || '';
|
||||
year = surveyData?.year || '';
|
||||
}
|
||||
|
||||
// For resubmission, check resubmission data last (highest priority)
|
||||
if (isResubmitFlow) {
|
||||
const resubmitData = localStorage.getItem('resubmissionData');
|
||||
if (resubmitData) {
|
||||
@ -616,13 +729,14 @@ const Survey = () => {
|
||||
const payload = buildSubmissionPayload();
|
||||
const response = await submitSurvey(payload);
|
||||
|
||||
// Navigate to overview page after successful submission
|
||||
// navigate('/overview');
|
||||
// Show success message and popup
|
||||
showToast('success', response?.message || 'You have successfully submitted the survey.');
|
||||
setShowSuccessPopup(true);
|
||||
setHasSubmitted(true);
|
||||
// Clear the stored survey data after successful submission
|
||||
localStorage.removeItem('currentSurvey');
|
||||
// Remove currentSurveyPeriod from localStorage
|
||||
localStorage.removeItem('currentSurveyPeriod');
|
||||
} catch (error) {
|
||||
console.error('Failed to submit survey', error);
|
||||
const message = error?.response?.data?.message || error?.message || 'Failed to submit survey.';
|
||||
@ -643,6 +757,16 @@ const Survey = () => {
|
||||
id: submissionId // Include submission ID in the payload
|
||||
};
|
||||
|
||||
// Remove currentSurveyPeriod from localStorage for resubmission
|
||||
localStorage.removeItem('currentSurveyPeriod');
|
||||
|
||||
// Store resubmission data in localStorage
|
||||
const resubmissionData = {
|
||||
...payload,
|
||||
resubmittedAt: new Date().toISOString()
|
||||
};
|
||||
localStorage.setItem('resubmissionData', JSON.stringify(resubmissionData));
|
||||
|
||||
// Use the resubmitSurvey API with the submission ID and payload
|
||||
await resubmitSurvey(submissionId, payload);
|
||||
|
||||
@ -651,7 +775,7 @@ const Survey = () => {
|
||||
showToast('success', 'Survey resubmitted successfully!');
|
||||
localStorage.removeItem('surveyRemarks');
|
||||
// Clear the stored survey data after successful resubmission
|
||||
localStorage.removeItem('currentSurvey');
|
||||
localStorage.removeItem('currentSurvey');
|
||||
} catch (error) {
|
||||
console.error('Resubmission failed:', error);
|
||||
const message = error?.response?.data?.message || error?.message || 'Failed to resubmit survey. Please try again.';
|
||||
@ -679,7 +803,9 @@ const Survey = () => {
|
||||
showToast('success', 'Survey submitted successfully!');
|
||||
localStorage.removeItem('surveyRemarks');
|
||||
// Clear the stored survey data after successful submission
|
||||
localStorage.removeItem('currentSurvey');
|
||||
localStorage.removeItem('currentSurvey');
|
||||
// Remove currentSurveyPeriod from localStorage
|
||||
localStorage.removeItem('currentSurveyPeriod');
|
||||
} catch (error) {
|
||||
const message = error?.response?.data?.message || error?.message || 'Failed to submit survey. Please try again.';
|
||||
console.error('Submission Error:', error);
|
||||
@ -939,7 +1065,20 @@ const Survey = () => {
|
||||
{/* Message */}
|
||||
<p className="text-sm text-gray-700">
|
||||
Thank you. Your IP Quarterly Survey for <span className="font-semibold text-gray-900">
|
||||
{surveyData?.quarter} {surveyData?.year}
|
||||
{(() => {
|
||||
// Try to get quarter and year from currentSurveyPeriod in localStorage first
|
||||
try {
|
||||
const currentSurveyPeriod = localStorage.getItem('currentSurveyPeriod');
|
||||
if (currentSurveyPeriod) {
|
||||
const { quarter, year } = JSON.parse(currentSurveyPeriod);
|
||||
if (quarter && year) return `${quarter} ${year}`;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error parsing currentSurveyPeriod:', e);
|
||||
}
|
||||
// Fall back to surveyData if currentSurveyPeriod is not available
|
||||
return `${surveyData?.quarter || ''} ${surveyData?.year || ''}`.trim();
|
||||
})()}
|
||||
</span> has been {isResubmit ? 'resubmitted' : 'submitted'}.
|
||||
</p>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user