fcsc bug fixed

This commit is contained in:
Malini 2025-11-13 19:01:28 +05:30
parent ac4e9a98c1
commit fde8142acb
7 changed files with 159 additions and 63 deletions

View File

@ -86,14 +86,15 @@ const SubmissionTable = ({ selectedQuarter, selectedYear }) => {
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: true,
hour12: false
};
// Format the date in Dubai time
let formatted = new Intl.DateTimeFormat('en-GB', options).format(date);
// Format the date in Dubai time with 24-hour format
const formatter = new Intl.DateTimeFormat('en-GB', options);
let formatted = formatter.format(date);
// Convert to uppercase AM/PM and ensure consistent formatting
formatted = formatted.replace(/\s?(am|pm)$/i, (match) => match.toUpperCase());
// Remove any AM/PM indicator since we're using 24-hour format
formatted = formatted.replace(/\s*[AP]M$/, '').trim();
return formatted;
};

View File

@ -410,7 +410,7 @@ const ProductDetails = ({
</div>
</div>
<div className="space-y-1">
<label className="block text-sm font-medium text-[#6B7280]">Status</label>
<label className="block text-sm font-medium text-[#6B7280]">Submission Status</label>
<div className="mt-1">
{(() => {
const status = String(submissionStatus).toLowerCase();

View File

@ -328,6 +328,7 @@ const ProductData = ({
const [showOtherVariationReason, setShowOtherVariationReason] = React.useState({});
const [showOtherZeroTargetReason, setShowOtherZeroTargetReason] = React.useState({});
const [formErrors, setFormErrors] = React.useState({});
const [selectedProductIds, setSelectedProductIds] = React.useState([]);
const [remarks, setRemarks] = React.useState(() => {
if (typeof window !== 'undefined') {
return localStorage.getItem('surveyRemarks') || '';
@ -554,52 +555,68 @@ const location = useLocation();
console.log("surveyDatatest", surveyData);
const requiredMessage = 'Required';
const validateForm = () => {
const errors = {};
let isValid = true;
const getAvailableProducts = (currentProductId) => {
// Get the current product's selected value
const currentProduct = products.find(p => p.id === currentProductId);
const currentProductValue = currentProduct?.product || '';
// Get all selected product IDs except the current product's ID
const otherSelectedProductIds = products
.filter(p => p.id !== currentProductId && p.product)
.map(p => p.product);
// Filter out selected products, but include the current product's selection
return productOptions.filter(option =>
!otherSelectedProductIds.includes(option.value) ||
option.value === currentProductValue
);
};
const validateProduct = (product, index) => {
const errors = {};
let hasError = false;
// Check for duplicate products
const duplicateProductIndex = products.findIndex(
(p, i) => p.product === product.product && i !== index
);
if (duplicateProductIndex !== -1) {
errors[`product-${product.id}`] = 'This product has already been selected';
hasError = true;
}
// Validate product selection
if (!product.product) {
errors[`product-${product.id}`] = 'Product is required';
hasError = true;
}
// Validate unit selection
if (!product.unit) {
errors[`unit-${product.id}`] = 'Unit is required';
hasError = true;
}
// Validate capacity
if (!product.capacity) {
errors[`capacity-${product.id}`] = 'Capacity is required';
hasError = true;
}
return { errors, hasError };
};
const validateForm = () => {
let isValid = true;
const errors = {};
products.forEach((product, index) => {
// Product validation
if (!product.product) {
// errors[`product_${index}`] = 'Product (HS Code - Name) is required';
errors[`product_${index}`] = requiredMessage;
const { errors: productErrors, hasError } = validateProduct(product, index);
if (hasError) {
Object.assign(errors, productErrors);
isValid = false;
}
// Unit validation
if (!product.unit) {
errors[`unit_${index}`] = requiredMessage;
isValid = false;
}
// Capacity validation
if (!product.capacity) {
errors[`capacity_${index}`] = requiredMessage;
isValid = false;
}
// Monthly quantity validations
const requiredFields = [
{ key: 'janQuantity', label: 'Jan Qty' },
{ key: 'febQuantity', label: 'Feb Qty' },
{ key: 'marQuantity', label: 'Mar Qty' },
{ key: 'aprQuantity', label: 'Apr Qty' },
{ key: 'mayQuantity', label: 'May Qty' },
{ key: 'junQuantity', label: 'Jun Qty' },
{ key: 'janCost', label: 'Jan Cost' },
{ key: 'febCost', label: 'Feb Cost' },
{ key: 'marCost', label: 'Mar Cost' },
{ key: 'aprCost', label: 'Apr Cost' },
{ key: 'mayCost', label: 'May Cost' },
{ key: 'junCost', label: 'Jun Cost' }
];
requiredFields.forEach(field => {
if (product[field.key] === undefined || product[field.key] === '') {
errors[`${field.key}_${index}`] = requiredMessage;
isValid = false;
}
});
});
setFormErrors(errors);
@ -636,7 +653,13 @@ const location = useLocation();
const removeProduct = (id) => {
if (products.length === 1) return;
const productToRemove = products.find(p => p.id === id);
onProductsChange(products.filter((p) => p.id !== id));
// Remove the product ID from selectedProductIds if it exists
if (productToRemove?.product) {
setSelectedProductIds(prev => prev.filter(pid => pid !== productToRemove.product));
}
};
const fetchPreviousForecastData = async (productId, establishmentId) => {
@ -698,7 +721,43 @@ const location = useLocation();
};
const updateProductField = (id, field, value, options = null) => {
const updatedProducts = products.map(product => {
// Create a copy of the current products array to work with
let updatedProducts = [...products];
// If this is a product selection change, validate for duplicates
if (field === 'product' && value) {
// Check if this product is already selected in another row
const isDuplicate = products.some(
(p, idx) => p.product === value && p.id !== id
);
if (isDuplicate) {
// Set error for this field
setFormErrors(prev => ({
...prev,
[`product-${id}`]: 'This product has already been selected'
}));
return; // Don't update the product if it's a duplicate
}
// Clear any existing error for this field
const newErrors = { ...formErrors };
delete newErrors[`product-${id}`];
setFormErrors(newErrors);
// Update selected product IDs
const currentProduct = products.find(p => p.id === id);
if (currentProduct) {
// Remove the old product ID if it exists
setSelectedProductIds(prev =>
prev.filter(pid => pid !== currentProduct.product)
);
}
// Add the new product ID
setSelectedProductIds(prev => [...prev, value]);
}
updatedProducts = products.map(product => {
if (product.id === id) {
// Check if 'Others' is selected for variation reason
if (field === 'variationReason' || field === 'otherVariationReason') {
@ -1118,7 +1177,7 @@ const handleProductSelect = async (productId, establishmentId, id) => {
<div>
<SearchableSelect
placeholder={isLoadingProducts ? 'Loading products...' : 'Search product HS code...'}
options={productOptions}
options={getAvailableProducts(p.id)}
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) => {

View File

@ -340,6 +340,7 @@ const ReviewSubmit = ({
hasSubmitted = false,
submitButtonText = 'Submit',
quarter = 'Q1',
// remarks = '',
year = new Date().getFullYear()
}) => {
const [quarterPeriods, setQuarterPeriods] = useState(null);

View File

@ -187,6 +187,7 @@ const CompanyProfile = () => {
const [isSaving, setIsSaving] = React.useState(false);
const [saveWarning, setSaveWarning] = React.useState(false);
const [saveError, setSaveError] = React.useState('');
const [productError, setProductError] = React.useState('');
const [toast, setToast] = React.useState(null);
const [emirateOptions, setEmirateOptions] = React.useState([]);
const [emirateLookup, setEmirateLookup] = React.useState({});
@ -890,7 +891,12 @@ const CompanyProfile = () => {
case 3:
return (
<div className="space-y-6">
<h4 className="text-[16px] font-semibold text-[#232528]">Products</h4>
{productError && (
<div className="p-3 mb-4 text-sm text-red-700 bg-red-100 rounded-md">
{productError}
</div>
)}
<h4 className="text-[16px] font-semibold text-[#232528]">Products <span className="text-red-500">*</span></h4>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Available Products Panel */}
<div className="bg-white rounded-lg border border-[#E5E7EB] overflow-hidden">
@ -1133,6 +1139,9 @@ const loadProducts = async () => {
};
const handleAddProduct = (product) => {
// Clear any previous product errors
setProductError('');
setSaveError('');
setSelectedProducts(prev => {
const updated = [...prev, product];
return updated;
@ -1146,6 +1155,9 @@ const loadProducts = async () => {
};
const handleRemoveProduct = (product) => {
// Clear any previous product errors
setProductError('');
setSaveError('');
setSelectedProducts(prev => {
const updated = prev.filter(p => p.id !== product.id);
return updated;
@ -1171,6 +1183,13 @@ const loadProducts = async () => {
};
const handleNextStep = React.useCallback(() => {
if (activeStep === 3 && selectedProducts.length === 0) {
// Show error if on products step and no products are selected
setProductError('Please select at least one product');
showToast('error', 'Please select at least one product');
return;
}
if (!validateStepFields(activeStep)) {
return;
}
@ -2856,13 +2875,24 @@ const requiredFields = [
</button>
</div>
) : (
<button
type="button"
className="h-10 px-8 rounded-md bg-[#92722A] text-sm font-medium text-white shadow-[0_8px_18px_rgba(146,114,42,0.35)]"
onClick={handleNextStep}
>
Next
</button>
<div className="flex items-center gap-3">
{activeStep > 0 && (
<button
type="button"
className="h-10 px-6 rounded-md border border-[#92722A] text-sm font-medium text-[#92722A] bg-white"
onClick={() => setActiveStep(prev => Math.max(0, prev - 1))}
>
Previous
</button>
)}
<button
type="button"
className="h-10 px-8 rounded-md bg-[#92722A] text-sm font-medium text-white shadow-[0_8px_18px_rgba(146,114,42,0.35)]"
onClick={handleNextStep}
>
Next
</button>
</div>
)}
</div>
</div>

View File

@ -474,7 +474,7 @@ const UnitMaster = () => {
const downloadSampleCSV = () => {
const sampleData = [
['uom', 'description'],
['Unit Name', 'Description'],
['Kilogram', 'Weight measurement in kilograms'],
['Gram', 'Weight measurement in grams'],
['Liter', 'Volume measurement in liters'],
@ -720,7 +720,7 @@ const UnitMaster = () => {
>
<div className="flex items-center justify-between px-6 py-4 border-b border-[#F1F2F4]">
<h3 className="text-[18px] font-medium text-[#232528]">
View Unit
View Unit Master
</h3>
<button
type="button"
@ -750,7 +750,7 @@ const UnitMaster = () => {
Description <span className="text-red-500">*</span>
</label>
<div className="mt-1 px-3 py-2 border border-[#92722A] rounded-md bg-gray-50 min-h-[42px]">
<p className="text-gray-900">{selectedUnit.uom_short_name || selectedUnit.description || 'N/A'}</p>
<p className="text-gray-900">{selectedUnit.description || 'N/A'}</p>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { useEffect,useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { submitSurvey, fetchSubmissionDetail, resubmitSurvey } from '@/services/submissions/submissionService';
import { fetchEstablishmentDetail, fetchEstablishmentDashboard } from '@/services/establishments/establishmentService';
@ -66,6 +66,7 @@ const Survey = () => {
const [toast, setToast] = React.useState(null);
const [error, setError] = React.useState('');
const [submissionDetail, setSubmissionDetail] = React.useState(null);
const [remarks, setRemarks] = useState('');
const [viewLoading, setViewLoading] = React.useState(false);
const [viewError, setViewError] = React.useState('');
const [establishmentLoading, setEstablishmentLoading] = React.useState(false);
@ -606,6 +607,7 @@ const Survey = () => {
non_emirati_female: parseNumber(info.nonEmiratiFemale),
total_emirati: parseNumber(info.totalEmirati),
total_employees: parseNumber(info.totalEmployees),
remarks: remarks, // Add remarks to the payload
products: productsData.map((product) => {
const variationId = parseNumber(product.variationReason, null);
const zeroTargetId = parseNumber(product.zeroTargetReason, null);
@ -683,7 +685,7 @@ const Survey = () => {
};
}),
};
}, [establishmentData, parseNumber, productsData, stringify]);
}, [establishmentData, parseNumber, productsData,remarks, stringify]);
const handleNext = () => {
if (step < 3) {
@ -1011,6 +1013,8 @@ const Survey = () => {
error={error}
quarter={establishmentData.quarter}
year={establishmentData.year}
remarks={remarks}
onRemarksChange={setRemarks}
/>
)}
{step === 3 && (
@ -1030,6 +1034,7 @@ const Survey = () => {
}}
isSubmitting={isSubmitting}
hasSubmitted={false}
remarks={remarks}
/>
)}
</div>