bug fixed in the product data
This commit is contained in:
parent
8b1b09d8ba
commit
9b363d88bb
@ -129,7 +129,10 @@ export const DetailedOverview = ({ submission, onBack }) => {
|
||||
|
||||
const matchesStatus = selectedStatus === '' ||
|
||||
(selectedStatus === 'pending' && !product.is_active) ||
|
||||
(selectedStatus === 'approved' && product.is_active);
|
||||
(selectedStatus === 'approved' && product.is_active)
|
||||
(selectedStatus === 'resubmitted' && product.status === 'Resubmitted')
|
||||
(selectedStatus === 'submitted' && product.status === 'Submitted')
|
||||
(selectedStatus === 'rejected' && product.status === 'Rejected');
|
||||
|
||||
return matchesSearch && matchesStatus;
|
||||
});
|
||||
@ -362,6 +365,7 @@ export const DetailedOverview = ({ submission, onBack }) => {
|
||||
<option value="approved">Approved</option>
|
||||
<option value="submitted">Submitted</option>
|
||||
<option value="rejected">Rejected</option>
|
||||
<option value="resubmitted">Resubmitted</option>
|
||||
</select>
|
||||
<img
|
||||
src={caretDownSrc}
|
||||
|
||||
@ -115,9 +115,14 @@ const ProductDetails = ({ product, onBack, showToast: shouldShowToast, onToastSh
|
||||
q2_apr_cost: product.forecast_cost_period_one || '—',
|
||||
q2_may_cost: product.forecast_cost_period_two || '—',
|
||||
q2_jun_cost: product.forecast_cost_period_three || '—',
|
||||
variationReason: product.variation_reason?.reason || '—',
|
||||
zeroTargetReason: product.zero_target_reason?.reason || '—',
|
||||
remarks: product.remarks || 'NA'
|
||||
// variationReason: product.variation_reason?.reason || '—',
|
||||
// zeroTargetReason: product.zero_target_reason?.reason || '—',
|
||||
remarks: product.remarks || 'NA',
|
||||
variationReason: product.other_variation_reason || product.variation_reason?.reason || '—',
|
||||
zeroTargetReason: product.other_zero_target_reason || product.zero_target_reason?.reason || '—',
|
||||
other_variation_reason: product.other_variation_reason || '—',
|
||||
other_zero_target_reason: product.other_zero_target_reason || '—',
|
||||
remarks: product.remarks || 'NA'
|
||||
});
|
||||
|
||||
const formattedProduct = formatProductData(product);
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
// import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { getQuarterPeriods, getPreviousForecastData } from '@/services/submissions/submissionService';
|
||||
import { getQuarterPeriods, getPreviousForecastData, getEstablishmentProducts } from '@/services/submissions/submissionService';
|
||||
import {
|
||||
fetchVariationReasons,
|
||||
fetchZeroTargetReasons,
|
||||
fetchProducts,
|
||||
fetchUnits,
|
||||
} from '@/services/masters/masterService.js';
|
||||
import { fetchEstablishmentDetail } from '@/services/establishments/establishmentService';
|
||||
// import { fetchEstablishmentDetail } from '@/services/establishments/establishmentService';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
const caretDownSrc = '/assets/images/CaretDown-black.svg';
|
||||
@ -455,48 +455,59 @@ const ProductData = ({
|
||||
const fetchEstablishmentProducts = async () => {
|
||||
try {
|
||||
const establishmentId = sessionStorage.getItem('establishment_id');
|
||||
if (!establishmentId) {
|
||||
console.error('Establishment ID not found in session storage');
|
||||
return;
|
||||
}
|
||||
if (!establishmentId) return;
|
||||
|
||||
const response = await fetchEstablishmentDetail(establishmentId);
|
||||
if (response && response.data && Array.isArray(response.data.establishment_products)) {
|
||||
// Transform products data to match the expected format
|
||||
const formattedProducts = response.data.establishment_products.map(item => {
|
||||
const product = item.product || {};
|
||||
return {
|
||||
value: item.product_id, // Use product_id as the value
|
||||
label: product.product_name ?
|
||||
`${product.product_name} (${product.hs_code || 'N/A'})` :
|
||||
'Unknown Product',
|
||||
originalData: product, // Store the full product data
|
||||
hsCode: product.hs_code // Store HS code separately for display
|
||||
};
|
||||
});
|
||||
|
||||
// Update the product options state
|
||||
setProductOptions(formattedProducts);
|
||||
|
||||
// If you need to update the form with initial products, uncomment and modify:
|
||||
// if (formattedProducts.length > 0) {
|
||||
// const initialProducts = formattedProducts.map((product, index) => ({
|
||||
// id: index + 1,
|
||||
// product: product.value,
|
||||
// unit: '',
|
||||
// // ... other default values
|
||||
// }));
|
||||
// onProductsChange(initialProducts);
|
||||
// }
|
||||
}
|
||||
const fetchProducts = async () => {
|
||||
setIsLoadingProducts(true);
|
||||
setProductsError('');
|
||||
try {
|
||||
// Get products from getEstablishmentProducts
|
||||
const apiResponse = await getEstablishmentProducts(establishmentId);
|
||||
console.log('Products from API:', apiResponse); // Debug log
|
||||
|
||||
// Ensure we're working with an array and handle the response structure
|
||||
const productsList = Array.isArray(apiResponse) ? apiResponse : (apiResponse?.data || []);
|
||||
|
||||
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'] || '';
|
||||
|
||||
return {
|
||||
value: product.id.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
|
||||
unit: unitName
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
console.log('Formatted products:', formattedProducts); // Debug log
|
||||
setProductOptions(formattedProducts);
|
||||
} catch (error) {
|
||||
console.error('Error fetching products:', error);
|
||||
setProductsError('Failed to load products. Please try again.');
|
||||
} finally {
|
||||
setIsLoadingProducts(false);
|
||||
}
|
||||
};
|
||||
|
||||
await fetchProducts();
|
||||
} catch (err) {
|
||||
console.error('Error fetching establishment products:', err);
|
||||
setError('Failed to load establishment products');
|
||||
console.error('Error in fetchEstablishmentProducts:', err);
|
||||
setProductsError('Failed to load establishment products. Please try again.');
|
||||
setIsLoadingProducts(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchEstablishmentProducts();
|
||||
}, []);
|
||||
// Moved inside the component
|
||||
React.useEffect(() => {
|
||||
const maxId = products.reduce((max, item) => (item && typeof item.id === 'number' ? Math.max(max, item.id) : max), 0);
|
||||
if (maxId >= nextId.current) {
|
||||
@ -926,8 +937,8 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
<div className="space-y-6 relative">
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-40 flex items-center justify-center bg-white/80">
|
||||
<div className="h-12 w-12 animate-spin rounded-full border-[3px] border-[#92722A] border-t-transparent" />
|
||||
</div>
|
||||
<div className="h-12 w-12 animate-spin rounded-full border-[3px] border-[#92722A] border-t-transparent" />
|
||||
</div>
|
||||
)}
|
||||
<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>
|
||||
@ -1084,29 +1095,52 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
<SearchableSelect
|
||||
placeholder={isLoadingProducts ? 'Loading products...' : 'Search product HS code...'}
|
||||
options={productOptions}
|
||||
value={p.productId || p.product || ''}
|
||||
value={p.productId?.toString() || p.product?.toString() || ''}
|
||||
onChange={async (e) => {
|
||||
const selectedValue = e.target.value;
|
||||
console.log('Selected product value:', selectedValue); // Debug log
|
||||
|
||||
// Clear error when user selects a product
|
||||
if (formErrors[`product_${idx}`]) {
|
||||
const newErrors = { ...formErrors };
|
||||
delete newErrors[`product_${idx}`];
|
||||
setFormErrors(newErrors);
|
||||
}
|
||||
|
||||
// Find the selected product from options
|
||||
const selectedProduct = productOptions.find(opt => opt.value === selectedValue);
|
||||
// Update the product with all necessary fields
|
||||
console.log('Selected product:', selectedProduct); // Debug log
|
||||
// Get unit information from the selected product
|
||||
const unitId = selectedProduct?.originalData?.['product.unit.id'];
|
||||
const unitName = selectedProduct?.originalData?.['product.unit.uom'] ||
|
||||
selectedProduct?.originalData?.unit?.uom ||
|
||||
selectedProduct?.unit || '';
|
||||
|
||||
// Create updated product with all necessary fields including unit info
|
||||
const updatedProduct = {
|
||||
...p,
|
||||
product: selectedProduct?.value || selectedValue,
|
||||
productName: selectedProduct?.label || '',
|
||||
productId: selectedProduct?.productId || selectedValue, // Use the actual product ID
|
||||
product_id: selectedProduct?.productId || selectedValue // Add product_id for submission
|
||||
productId: selectedProduct?.value || selectedValue,
|
||||
product_id: selectedProduct?.value || selectedValue,
|
||||
hs_code: selectedProduct?.hsCode || p.hs_code,
|
||||
name: selectedProduct?.name || p.name,
|
||||
originalData: selectedProduct?.originalData || p.originalData,
|
||||
// Set unit information
|
||||
unit: unitId ? unitId.toString() : '',
|
||||
unitName: unitName,
|
||||
unit_id: unitId,
|
||||
// Clear any previous unit-related errors
|
||||
...(formErrors[`unit_${idx}`] && { unitError: undefined })
|
||||
};
|
||||
|
||||
// Update the products array with the updated product
|
||||
const updatedProducts = products.map(prod =>
|
||||
prod.id === p.id ? updatedProduct : prod
|
||||
const updatedProducts = products.map((prod, i) =>
|
||||
i === idx ? updatedProduct : prod
|
||||
);
|
||||
|
||||
console.log('Updated products:', updatedProducts); // Debug log
|
||||
|
||||
// Update the parent component's state
|
||||
onProductsChange(updatedProducts);
|
||||
|
||||
// After updating the product, fetch forecast data if we have a valid product and establishment ID
|
||||
@ -1134,8 +1168,8 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
capacity: data.annual_installed_capacity || ''
|
||||
};
|
||||
|
||||
const finalUpdatedProducts = updatedProducts.map(prod =>
|
||||
prod.id === p.id ? updatedWithForecast : prod
|
||||
const finalUpdatedProducts = updatedProducts.map((prod, i) =>
|
||||
i === idx ? updatedWithForecast : prod
|
||||
);
|
||||
|
||||
onProductsChange(finalUpdatedProducts);
|
||||
@ -1163,7 +1197,7 @@ 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={isLoadingUnits ? 'Loading units...' : 'Search unit...'}
|
||||
placeholder={p.unitName || (isLoadingUnits ? 'Loading units...' : 'Search unit...')}
|
||||
options={unitOptions}
|
||||
value={p.unit}
|
||||
onChange={(e) => {
|
||||
@ -1173,10 +1207,18 @@ const handleProductSelect = async (productId, establishmentId, id) => {
|
||||
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);
|
||||
}
|
||||
}}
|
||||
loading={isLoadingUnits}
|
||||
error={!!formErrors[`unit_${idx}`]}
|
||||
isDisabled={!!p.unitName} // Disable if unit is auto-filled from product
|
||||
/>
|
||||
<div className="h-5">
|
||||
{formErrors[`unit_${idx}`] && (
|
||||
|
||||
@ -170,12 +170,17 @@ const buildProductRows = (products = [], options = {}) => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Find the full product details from productOptions if available
|
||||
const fullProduct = productOptions.find(p => p.id === product.productId || p.value === product.productId);
|
||||
// Extract product details with better fallbacks
|
||||
// Find the full product details from originalData or product
|
||||
const originalData = product.originalData || {};
|
||||
const productId = product.id || `product-${Math.random().toString(36).substr(2, 9)}`;
|
||||
const productName = fullProduct?.label || fullProduct?.name || product.productName || product.product?.name || product.product;
|
||||
const productCode = fullProduct?.code || product.productCode || product.code || product.product?.code || product.id || `CODE-${index + 1}`;
|
||||
|
||||
// Get HS Code and Product Name from original data or product
|
||||
const hsCode = originalData['product.hs_code'] || product.hs_code || '';
|
||||
const productName = originalData['product.product_name'] || product.product_name || product.productName || product.product?.name || product.product;
|
||||
|
||||
// Format the display name as "HS Code - Product Name" if HS code exists
|
||||
const displayName = hsCode ? `${hsCode} - ${productName}` : productName;
|
||||
const productCode = hsCode || product.id || `CODE-${index + 1}`;
|
||||
console.log("productCode",productCode)
|
||||
// Use stored unitName if available, otherwise try to find it in unitOptions
|
||||
let unitName = product.unitName;
|
||||
@ -193,8 +198,10 @@ const buildProductRows = (products = [], options = {}) => {
|
||||
// Map the quantity and cost data from the product form
|
||||
const row = {
|
||||
id: productId,
|
||||
product: productName,
|
||||
product: displayName,
|
||||
productCode: productCode,
|
||||
hsCode: hsCode,
|
||||
productName: productName,
|
||||
unit: unitName, // Use display name instead of ID
|
||||
capacity: capacity,
|
||||
|
||||
@ -260,8 +267,20 @@ const formatSubmissionData = (establishment, products, remarks = '') => {
|
||||
const totalEmployees = totalEmirati + nonEmiratiMale + nonEmiratiFemale;
|
||||
|
||||
// Format products data
|
||||
const formattedProducts = products.map(product => ({
|
||||
product_id: parseInt(product.productId) || 0,
|
||||
console.log('Original products data:', JSON.stringify(products, null, 2));
|
||||
const formattedProducts = products.map(product => {
|
||||
// Get the actual product_id from the originalData if available
|
||||
const originalData = product.originalData || {};
|
||||
console.log('Original data for product:', JSON.stringify(originalData, null, 2));
|
||||
|
||||
// Get the product_id directly from the originalData object
|
||||
// originalData has both id (establishment product ID) and product_id (actual product ID)
|
||||
const productId = originalData.product_id || originalData.id; // Use product_id (56) with fallback to id
|
||||
|
||||
console.log('Selected product ID:', productId);
|
||||
|
||||
return {
|
||||
product_id: parseInt(productId) || 0,
|
||||
unit_id: parseInt(product.unit) || 0,
|
||||
annual_installed_capacity: product.capacity?.toString() || '',
|
||||
|
||||
@ -301,9 +320,10 @@ const formatSubmissionData = (establishment, products, remarks = '') => {
|
||||
variation_reason_master_id: product.variationReason?.toString() || '',
|
||||
other_variation_reason: product.otherVariationReason?.toString() || '',
|
||||
zero_target_reason_master_id: product.zeroTargetReason?.toString() || '',
|
||||
other_zero_target_reason: product.otherZeroTargetReason?.toString() || '',
|
||||
remarks: product.remarks || remarks || ''
|
||||
}));
|
||||
other_zero_target_reason: product.otherZeroTargetReason?.toString() || '',
|
||||
remarks: product.remarks || remarks || ''
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
establishment_id: parseInt(establishment.id) || 0,
|
||||
@ -788,11 +808,10 @@ const ReviewSubmit = ({
|
||||
</td>
|
||||
<td colSpan="3" className="border border-gray-300 py-2 text-center bg-[#F3FAF4] text-[#2F663C]">
|
||||
<div className="flex flex-col items-center">
|
||||
<div>{product.variationReasonName || product.variationReason || '—'}</div>
|
||||
{product.otherVariationReason && (
|
||||
<div className="mt-1 text-xs text-gray-600">
|
||||
{product.otherVariationReason}
|
||||
</div>
|
||||
{product.otherVariationReason ? (
|
||||
<div className="text-sm">{product.otherVariationReason}</div>
|
||||
) : (
|
||||
<div>{product.variationReasonName?.replace('Others: ', '') || product.variationReason?.replace('Others: ', '') || '—'}</div>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
@ -811,11 +830,10 @@ const ReviewSubmit = ({
|
||||
</td>
|
||||
<td colSpan="3" className="border border-gray-300 py-2 text-center bg-[#FFF7E9] text-[#F29F0E]">
|
||||
<div className="flex flex-col items-center">
|
||||
<div>{product.zeroTargetReasonName || product.zeroTargetReason || '—'}</div>
|
||||
{product.otherZeroTargetReason && (
|
||||
<div className="mt-1 text-xs text-gray-600 ">
|
||||
{product.otherZeroTargetReason}
|
||||
</div>
|
||||
{product.otherZeroTargetReason ? (
|
||||
<div className="text-sm">{product.otherZeroTargetReason}</div>
|
||||
) : (
|
||||
<div>{product.zeroTargetReasonName?.replace('Others: ', '') || product.zeroTargetReason?.replace('Others: ', '') || '—'}</div>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@ -81,7 +81,8 @@ const Overview = () => {
|
||||
!selectedStatus ||
|
||||
(selectedStatus === 'approved' && record.status === 'Approved') ||
|
||||
(selectedStatus === 'submitted' && record.status === 'Submitted') ||
|
||||
(selectedStatus === 'rejected' && record.status === 'Rejected');
|
||||
(selectedStatus === 'rejected' && record.status === 'Rejected') ||
|
||||
(selectedStatus === 'resubmitted' && record.status === 'Resubmitted');
|
||||
|
||||
return matchesSearch && matchesStatus;
|
||||
});
|
||||
@ -185,6 +186,7 @@ const Overview = () => {
|
||||
<option value="approved">Approved</option>
|
||||
<option value="submitted">Submitted</option>
|
||||
<option value="rejected">Rejected</option>
|
||||
<option value="resubmitted">Resubmitted</option>
|
||||
</select>
|
||||
<img
|
||||
src={caretDownSrc}
|
||||
|
||||
@ -488,7 +488,7 @@ const Survey = () => {
|
||||
// Map monthly data to period-specific fields
|
||||
return {
|
||||
...(isResubmitFlow && productId ? { id: productId } : {}), // Only include ID during resubmit
|
||||
product_id: parseNumber(product.productId) || parseNumber(product.product),
|
||||
product_id: parseNumber(product.originalData?.product_id) || parseNumber(product.product_id) || parseNumber(product.productId) || parseNumber(product.product),
|
||||
unit_id: parseNumber(product.unitId) || parseNumber(product.unit),
|
||||
annual_installed_capacity: stringify(product.capacity),
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import resolveEstablishmentId from '@/services/utils/establishment';
|
||||
import { putRequest } from '../api/CommonService';
|
||||
|
||||
const endpoint = '/submissions';
|
||||
const ESTABLISHMENT_PRODUCTS_ENDPOINT = '/establishment-products';
|
||||
const QUARTER_PERIODS_ENDPOINT = '/getQuarterPeriods';
|
||||
|
||||
// Add this new function to fetch submissions with pagination
|
||||
@ -141,6 +142,25 @@ export const getSubmissionAuditHistory = async (establishmentId, params = {}) =>
|
||||
}
|
||||
};
|
||||
|
||||
export const getEstablishmentProducts = async (establishmentId, config = {}) => {
|
||||
try {
|
||||
if (!establishmentId) {
|
||||
throw new Error('Establishment ID is required to fetch establishment products');
|
||||
}
|
||||
const response = await getRequest(ESTABLISHMENT_PRODUCTS_ENDPOINT, {
|
||||
...config,
|
||||
params: {
|
||||
establishment_id: establishmentId,
|
||||
...(config.params || {})
|
||||
}
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching establishment products:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
getSubmissions,
|
||||
submitSurvey,
|
||||
@ -150,5 +170,6 @@ export default {
|
||||
getQuarterPeriods,
|
||||
getPreviousForecastData,
|
||||
getSubmissionHistoryByEstablishment,
|
||||
getSubmissionAuditHistory
|
||||
getSubmissionAuditHistory,
|
||||
getEstablishmentProducts
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user