From 7c16dec47acf593f00acf300a5e2ce119dd96e1a Mon Sep 17 00:00:00 2001
From: Malini
Date: Thu, 13 Nov 2025 20:18:11 +0530
Subject: [PATCH] code merged
---
.../EstablishmentInfo/EstablishmentInfo.jsx | 18 +-
.../configuration/EditCompanyProfile.jsx | 326 +++++++++---------
2 files changed, 175 insertions(+), 169 deletions(-)
diff --git a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx
index 4c7d173..81993f1 100644
--- a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx
+++ b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx
@@ -401,16 +401,18 @@ const EstablishmentInfo = ({
. Changes saved there will appear here.
*/}
-
Step 1: Review Establishment Information
diff --git a/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx b/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx
index c215e37..7758e58 100644
--- a/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx
+++ b/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx
@@ -98,6 +98,8 @@ const EditCompanyProfile = () => {
const [selectedProducts, setSelectedProducts] = useState([]);
const [productSearchTerm, setProductSearchTerm] = useState('');
const [isLoadingProducts, setIsLoadingProducts] = useState(false);
+ const [productError, setProductError] = useState("");
+ const [isLoadingCities, setIsLoadingCities] = useState(false);
const initialSnapshotRef = useRef(null);
const formSteps = React.useMemo(
@@ -126,15 +128,12 @@ const EditCompanyProfile = () => {
2: [
{ field: 'contactName', label: 'Name' },
{ field: 'contactAddress', label: 'Address' },
- { field: 'contactCityTown', label: 'City/Town' },
- { field: 'contactEmirate', label: 'Emirate' },
- { field: 'contactMakaniNumber', label: 'Makani Number' },
- { field: 'contactPersonName', label: 'Contact Person Name' },
- { field: 'contactMobileNumber', label: 'Mobile Number' },
+ { field: 'contactEmirateId', label: 'Emirate' },
+ { field: 'contactCityTownId', label: 'City/Town' },
{ field: 'contactEmail', label: 'Email' },
],
3: [
- // Products are optional, no required fields
+ // Products validation handled separately
],
4: [
{ field: 'employmentEmiratiMale', label: 'Number of Emirati Male' },
@@ -148,6 +147,18 @@ const EditCompanyProfile = () => {
const validateStepFields = useCallback((stepIndex) => {
setPasswordReuseError("");
+
+ // Special validation for Products step
+ if (stepIndex === 3) {
+ if (selectedProducts.length === 0) {
+ setProductError("At least one product is required.");
+ return false;
+ } else {
+ setProductError("");
+ return true;
+ }
+ }
+
const requiredFields = requiredFieldsByStep[stepIndex] || [];
if (!requiredFields.length) return true;
@@ -163,15 +174,15 @@ const EditCompanyProfile = () => {
return nextErrors;
});
return valid;
- }, [form, requiredFieldsByStep]);
+ }, [form, requiredFieldsByStep, selectedProducts]);
const handleFormChange = useCallback((field, value) => {
- if (field === 'contactCityTown') {
- const foundCity = contactCityOptions.find(option => option.value === value || option.label === value);
+ if (field === 'contactCityTownId') {
+ const foundCity = contactCityOptions.find(option => option.value === value);
setForm(prev => ({
...prev,
- contactCityTown: foundCity?.name || '',
- contactCityTownId: foundCity?.id || ''
+ contactCityTown: foundCity?.label || '',
+ contactCityTownId: value
}));
return;
}
@@ -200,63 +211,47 @@ const EditCompanyProfile = () => {
if (activeStep > 0) setActiveStep(activeStep - 1);
}, [activeStep]);
- // Load cities based on selected emirate
- const loadCities = useCallback(async (emirateId, setCityOptions) => {
+ // Load cities based on selected emirate using your service function
+ const loadCities = useCallback(async (emirateId) => {
if (!emirateId) {
- setCityOptions([]);
+ setContactCityOptions([]);
return [];
}
try {
- const response = await fetchCityTowns({ emirateId: Number(emirateId) });
- const options = Array.isArray(response) ? response : (response.data || []);
+ setIsLoadingCities(true);
+ const cities = await fetchCityTowns({ emirateId });
- const formatted = options.map((option) => ({
- label: option.name || option.label,
- value: String(option.id || option.value),
- name: option.name || option.label,
- id: String(option.id || option.value)
- }));
+ console.log('Loaded cities for emirate', emirateId, ':', cities);
- setCityOptions(formatted);
- return formatted;
+ setContactCityOptions(cities);
+ return cities;
} catch (error) {
console.error('Failed to load cities:', error);
- setCityOptions([]);
+ setContactCityOptions([]);
return [];
+ } finally {
+ setIsLoadingCities(false);
}
}, []);
- // Load products
+ // Load products using your service function
const loadProducts = useCallback(async () => {
try {
setIsLoadingProducts(true);
- const response = await fetchProducts();
+ const products = await fetchProducts();
- let productsData = [];
+ console.log('Processed products data:', products);
- if (Array.isArray(response)) {
- productsData = response;
- } else if (response?.data) {
- productsData = Array.isArray(response.data) ? response.data : response.data.products || [];
- }
-
- console.log('Processed products data:', productsData);
-
- // Format products data
- const formattedProducts = productsData.map(p => ({
- id: p.id || p.value,
- product_id: p.id || p.value,
- hs_code: p.hs_code || p.hsCode || '',
- hsCode: p.hs_code || p.hsCode || '',
- product_name: p.product_name || p.productName || p.label || '',
- productName: p.product_name || p.productName || p.label || '',
- label: p.product_name || p.productName || p.label || '',
- value: p.id || p.value
- }));
-
- setAvailableProducts(formattedProducts);
- return formattedProducts;
+ setAvailableProducts(prevProducts => {
+ // Only update if products have actually changed to prevent unnecessary re-renders
+ if (JSON.stringify(prevProducts) !== JSON.stringify(products)) {
+ return products;
+ }
+ return prevProducts;
+ });
+
+ return products;
} catch (error) {
console.error('Error loading products:', error);
return [];
@@ -272,7 +267,7 @@ const EditCompanyProfile = () => {
if (!searchTerm) {
setAvailableProducts(prev => prev.filter(p =>
- !selectedProducts.some(sp => sp.id === p.id)
+ !selectedProducts.some(sp => sp.value === p.value)
));
return;
}
@@ -280,7 +275,7 @@ const EditCompanyProfile = () => {
const filtered = availableProducts.filter(product =>
(product.label?.toLowerCase().includes(searchTerm) ||
product.hs_code?.toLowerCase().includes(searchTerm)) &&
- !selectedProducts.some(sp => sp.id === product.id)
+ !selectedProducts.some(sp => sp.value === product.value)
);
setAvailableProducts(filtered);
@@ -294,19 +289,22 @@ const EditCompanyProfile = () => {
});
// Remove from available products
- setAvailableProducts(prev => prev.filter(p => p.id !== product.id));
+ setAvailableProducts(prev => prev.filter(p => p.value !== product.value));
+
+ // Clear product error when a product is added
+ setProductError("");
};
// Remove product handler
const handleRemoveProduct = (product) => {
- setSelectedProducts(prev => prev.filter(p => p.id !== product.id));
+ setSelectedProducts(prev => prev.filter(p => p.value !== product.value));
// Add back to available products if not already there and matches search
if (!productSearchTerm ||
(product.hs_code && product.hs_code.toLowerCase().includes(productSearchTerm)) ||
- (product.product_name && product.product_name.toLowerCase().includes(productSearchTerm))) {
+ (product.label && product.label.toLowerCase().includes(productSearchTerm))) {
setAvailableProducts(prev => {
- if (!prev.some(p => p.id === product.id)) {
+ if (!prev.some(p => p.value === product.value)) {
return [...prev, product];
}
return prev;
@@ -314,9 +312,44 @@ const EditCompanyProfile = () => {
}
};
+ // Load emirates on component mount using your service function
+ useEffect(() => {
+ let cancelled = false;
+ const controller = new AbortController();
+
+ const loadEmirates = async () => {
+ try {
+ const emirates = await fetchEmirates({ signal: controller.signal });
+ if (cancelled) return;
+
+ console.log('Loaded emirates:', emirates);
+
+ const lookup = {};
+ emirates.forEach((emirate) => {
+ lookup[emirate.value] = emirate.label;
+ });
+
+ setEmirateOptions(emirates);
+ setEmirateLookup(lookup);
+ } catch (error) {
+ if (cancelled) return;
+ console.error('Failed to load emirates:', error);
+ }
+ };
+
+ loadEmirates();
+
+ return () => {
+ cancelled = true;
+ controller.abort();
+ };
+ }, []);
+
+ // Load establishment data and set form with API data
useEffect(() => {
console.log('useEffect triggered, establishmentId:', establishmentId);
-
+
+ // Create an async function inside the effect
const fetchData = async () => {
if (!establishmentId) {
console.log('No establishmentId found, skipping fetch');
@@ -349,98 +382,85 @@ const EditCompanyProfile = () => {
console.log('Final Form Data:', formData);
+ // First set the form data
setForm(formData);
initialSnapshotRef.current = formData;
- // Load products and set selected products
- const allProducts = await loadProducts();
+ // Then load cities and products in parallel
+ const [cities, allProducts] = await Promise.all([
+ formData.contactEmirateId ? loadCities(formData.contactEmirateId) : Promise.resolve([]),
+ loadProducts()
+ ]);
+
+ console.log('Loaded cities:', cities);
+ console.log('All products loaded:', allProducts);
// Set selected products from API response
const establishmentProducts = response.data?.establishment_products || response.establishment_products || [];
if (Array.isArray(establishmentProducts) && establishmentProducts.length > 0) {
const formattedSelectedProducts = establishmentProducts.map(ep => {
const productData = ep.product || {};
- return {
- id: ep.id || 0,
- product_id: ep.product_id || 0,
- hs_code: productData.hs_code || ep.hs_code || '',
- hsCode: productData.hs_code || ep.hs_code || '',
- product_name: productData.product_name || ep.product_name || 'Unnamed Product',
- productName: productData.product_name || ep.product_name || 'Unnamed Product',
- label: `${productData.product_name || ep.product_name || 'Unnamed Product'}${productData.hs_code ? ` (${productData.hs_code})` : ''}`,
- value: ep.product_id ? String(ep.product_id) : '',
- ...productData
+ const productId = productData.id || ep.product_id;
+
+ // Find the product in the loaded products to get the proper format
+ const foundProduct = allProducts.find(p => p.value === String(productId));
+
+ return foundProduct || {
+ value: String(productId),
+ label: productData.product_name || productData.name || 'Unnamed Product',
+ hs_code: productData.hs_code || '',
+ product_name: productData.product_name || productData.name || 'Unnamed Product'
};
});
- setSelectedProducts(formattedSelectedProducts);
- // Remove selected products from available products
- setAvailableProducts(prev =>
- prev.filter(p => !formattedSelectedProducts.some(sp => sp.id === p.id))
- );
+ setSelectedProducts(formattedSelectedProducts);
}
} catch (error) {
- console.error('Failed to load establishment details:', error);
- alert('Failed to load company details. Please try again.');
+ console.error('Error loading establishment:', error);
} finally {
setLoading(false);
}
};
fetchData();
- }, [establishmentId, loadProducts]);
-
- // Load emirates on component mount
- useEffect(() => {
- let cancelled = false;
- const controller = new AbortController();
-
- const loadEmirates = async () => {
- try {
- const options = await fetchEmirates({ signal: controller.signal });
- if (cancelled) return;
-
- const formatted = options.map((option) => ({
- label: option.name || option.label,
- value: String(option.id || option.value),
- name: option.name || option.label,
- id: String(option.id || option.value)
- }));
-
- const lookup = {};
- formatted.forEach((option) => {
- lookup[option.value] = option.label;
- });
-
- setEmirateOptions(formatted);
- setEmirateLookup(lookup);
- } catch (error) {
- if (cancelled) return;
- console.error('Failed to load emirates:', error);
- }
- };
-
- loadEmirates();
-
+
+ // Cleanup function to prevent state updates after unmount
return () => {
- cancelled = true;
- controller.abort();
+ // Any cleanup if needed
};
- }, []);
+ }, [establishmentId]); // Remove loadCities and loadProducts from dependencies
// Load contact cities when emirate ID changes
useEffect(() => {
- const loadContactCities = async () => {
+ let isMounted = true;
+
+ const loadCitiesForEmirate = async () => {
if (form.contactEmirateId) {
- await loadCities(form.contactEmirateId, setContactCityOptions);
- } else {
+ try {
+ const cities = await fetchCityTowns({ emirateId: form.contactEmirateId });
+ if (isMounted) {
+ setContactCityOptions(cities);
+ }
+ } catch (error) {
+ console.error('Failed to load cities:', error);
+ if (isMounted) {
+ setContactCityOptions([]);
+ }
+ }
+ } else if (isMounted) {
setContactCityOptions([]);
+ // Clear city selection when emirate is cleared
+ handleFormChange('contactCityTownId', '');
}
};
- loadContactCities();
- }, [form.contactEmirateId, loadCities]);
+ loadCitiesForEmirate();
+
+ return () => {
+ isMounted = false;
+ };
+ }, [form.contactEmirateId]);
// Calculate totals when employment numbers change
useEffect(() => {
@@ -497,7 +517,7 @@ const EditCompanyProfile = () => {
updated_by: 1,
establishment_products: Array.isArray(selectedProducts) && selectedProducts.length > 0
? selectedProducts.map(p => ({
- product_id: p.product_id || p.id || 0
+ product_id: Number(p.value) || 0
}))
: [],
};
@@ -650,23 +670,16 @@ const EditCompanyProfile = () => {
/>
{
+ onChange={(e) => {
const selectedValue = e.target.value;
const selectedEmirate = emirateOptions.find(opt => opt.value === selectedValue);
- handleFormChange("contactEmirate", selectedEmirate?.name || '');
- handleFormChange("contactEmirateId", selectedEmirate?.id || '');
+ handleFormChange("contactEmirate", selectedEmirate?.label || '');
+ handleFormChange("contactEmirateId", selectedValue);
handleFormChange("contactCityTown", '');
handleFormChange("contactCityTownId", '');
-
- if (selectedEmirate?.id) {
- const cities = await loadCities(selectedEmirate.id, setContactCityOptions);
- setContactCityOptions(cities);
- } else {
- setContactCityOptions([]);
- }
}}
options={emirateOptions.map(opt => ({
value: opt.value,
@@ -675,28 +688,25 @@ const EditCompanyProfile = () => {
placeholder="Select Emirate"
width="100%"
required
- error={fieldErrors.contactEmirate}
+ error={fieldErrors.contactEmirateId}
/>
{
const selectedValue = e.target.value;
- const selectedCity = contactCityOptions.find(opt => opt.value === selectedValue);
- if (selectedCity) {
- handleFormChange("contactCityTown", selectedCity.value);
- }
+ handleFormChange("contactCityTownId", selectedValue);
}}
options={contactCityOptions.map(opt => ({
value: opt.value,
label: opt.label
}))}
- placeholder={form.contactEmirate ? "Select City/Town" : "Select emirate first"}
+ placeholder={form.contactEmirateId ? (isLoadingCities ? "Loading cities..." : "Select City/Town") : "Select emirate first"}
width="100%"
required
- disabled={!form.contactEmirate}
- error={fieldErrors.contactCityTown}
+ disabled={!form.contactEmirateId || isLoadingCities}
+ error={fieldErrors.contactCityTownId}
/>
{
onChange={(e) => handleFormChange("contactMakaniNumber", e.target.value)}
placeholder="Enter Makani Number"
width="100%"
- required
- error={fieldErrors.contactMakaniNumber}
/>
{
onChange={(e) => handleFormChange("contactPersonName", e.target.value)}
placeholder="Enter Contact Person Name"
width="100%"
- required
- error={fieldErrors.contactPersonName}
/>
{
onChange={(value) => handleFormChange("contactMobileNumber", value)}
placeholder="Enter Mobile Number"
width="100%"
- required
- error={fieldErrors.contactMobileNumber}
/>
{
case 3:
return (
-
Products
+
+
Products
+ {productError && (
+
{productError}
+ )}
+
{/* Available Products Panel */}
@@ -802,12 +811,10 @@ const EditCompanyProfile = () => {
) : availableProducts.length > 0 ? (
{availableProducts.map((product) => (
- -
+
-
- {product.hsCode || ''}
- {product.hsCode && (product.productName || product.label || product.product_name) ? ' - ' : ''}
- {product.productName || product.label || product.product_name || ''}
+ {product.label}