+
{
return [];
}
- const cities = await fetchCityTowns({ emirateId: selectedEmirate.value });
-
- console.log('Loaded cities for emirate', emirateName, ':', cities);
-
+ const cities = await fetchCityTowns({ emirateId: selectedEmirate.value });
setContactCityOptions(cities);
return cities;
} catch (error) {
@@ -242,22 +239,21 @@ const EditCompanyProfile = () => {
}
}, [emirateOptions]);
- // Load products using your service function
+ // Load products and filter out selected ones
const loadProducts = useCallback(async () => {
try {
setIsLoadingProducts(true);
- const products = await fetchProducts();
-
- console.log('Processed products data:', products);
-
- 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;
+ const products = await fetchProducts();
+ // Filter out selected products
+ const filteredProducts = products.filter(product => {
+ return !selectedProducts.some(selected =>
+ (selected.value && (selected.value === product.value || selected.value === product.id || selected.value === product.product_id)) ||
+ (selected.id && (selected.id === product.id || selected.id === product.value || selected.id === product.product_id)) ||
+ (selected.product_id && (selected.product_id === product.product_id || selected.product_id === product.id || selected.product_id === product.value))
+ );
});
+ setAvailableProducts(filteredProducts);
return products;
} catch (error) {
console.error('Error loading products:', error);
@@ -265,75 +261,113 @@ const EditCompanyProfile = () => {
} finally {
setIsLoadingProducts(false);
}
- }, []);
+ }, [selectedProducts]);
// Product search handler
const handleProductSearch = (e) => {
const searchTerm = e.target.value.toLowerCase();
setProductSearchTerm(searchTerm);
- // Get the full list of products from the API
- const loadAndFilterProducts = async () => {
- try {
- setIsLoadingProducts(true);
- const allProducts = await fetchProducts();
-
- if (!searchTerm) {
- // If search is cleared, show all products except selected ones
- setAvailableProducts(allProducts.filter(p =>
- !selectedProducts.some(sp => sp.value === p.value)
- ));
- } else {
- // Filter products based on search term
- const filtered = allProducts.filter(product =>
- (product.label?.toLowerCase().includes(searchTerm) ||
- product.hs_code?.toLowerCase().includes(searchTerm)) &&
- !selectedProducts.some(sp => sp.value === product.value)
- );
- setAvailableProducts(filtered);
- }
- } catch (error) {
- console.error('Error searching products:', error);
- } finally {
- setIsLoadingProducts(false);
- }
- };
+ if (!searchTerm) {
+ // If search is cleared, reload all products with selected ones filtered out
+ loadProducts();
+ return;
+ }
- loadAndFilterProducts();
- };
-
- // Add product handler
- const handleAddProduct = (product) => {
- setSelectedProducts(prev => {
- const updated = [...prev, product];
- return updated;
+ // Get all products (including those not currently visible)
+ const allProducts = [...availableProducts, ...selectedProducts];
+
+ // Filter products based on search term and exclude selected ones
+ const filtered = allProducts.filter(product => {
+ const matchesSearch =
+ (product.label?.toLowerCase().includes(searchTerm) ||
+ product.hs_code?.toLowerCase().includes(searchTerm) ||
+ (product.product_name && product.product_name.toLowerCase().includes(searchTerm)));
+
+ const isSelected = selectedProducts.some(selected =>
+ (selected.value && (selected.value === product.value || selected.value === product.id || selected.value === product.product_id)) ||
+ (selected.id && (selected.id === product.id || selected.id === product.value || selected.id === product.product_id)) ||
+ (selected.product_id && (selected.product_id === product.product_id || selected.product_id === product.id || selected.product_id === product.value))
+ );
+
+ return matchesSearch && !isSelected;
+ });
+
+ setAvailableProducts(filtered);
+ };
+
+ // Handle adding a product
+ const handleAddProduct = (product) => {
+ setSelectedProducts(prev => {
+ // Check if product is already selected
+ const isAlreadySelected = prev.some(p =>
+ (p.value && (p.value === product.value || p.value === product.id || p.value === product.product_id)) ||
+ (p.id && (p.id === product.id || p.id === product.value || p.id === product.product_id)) ||
+ (p.product_id && (p.product_id === product.product_id || p.product_id === product.id || p.product_id === product.value))
+ );
+
+ if (isAlreadySelected) {
+ return prev; // Don't add duplicate
+ }
+
+ return [...prev, product];
});
- // Mark this product as newly added
- setNewlyAddedProductIds(prev => new Set([...prev, product.value]));
-
// Remove from available products
- setAvailableProducts(prev => prev.filter(p => p.value !== product.value));
-
- // Clear product error when a product is added
- setProductError("");
+ setAvailableProducts(prev =>
+ prev.filter(p =>
+ !(p.value && (p.value === product.value || p.value === product.id || p.value === product.product_id)) &&
+ !(p.id && (p.id === product.id || p.id === product.value || p.id === product.product_id)) &&
+ !(p.product_id && (p.product_id === product.product_id || p.product_id === product.id || p.product_id === product.value))
+ )
+ );
+
+ // Add to newly added products
+ setNewlyAddedProductIds(prev =>
+ new Set([...prev, product.value || product.id || product.product_id])
+ );
};
// Remove product handler
const handleRemoveProduct = (product) => {
- // Only allow removing newly added products
- if (!newlyAddedProductIds.has(product.value)) {
- return;
- }
- 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.label && product.label.toLowerCase().includes(productSearchTerm))) {
+ // First, add the removed product back to available products if it matches the search
+ const searchTerm = productSearchTerm.toLowerCase();
+ const shouldAddToAvailable =
+ !productSearchTerm ||
+ (product.label?.toLowerCase().includes(searchTerm) ||
+ product.hs_code?.toLowerCase().includes(searchTerm) ||
+ (product.product_name && product.product_name.toLowerCase().includes(searchTerm)));
+
+ // Remove from selected products
+ setSelectedProducts(prev =>
+ prev.filter(p =>
+ !(p.value && (p.value === product.value || p.value === product.id || p.value === product.product_id)) &&
+ !(p.id && (p.id === product.id || p.id === product.value || p.id === product.product_id)) &&
+ !(p.product_id && (p.product_id === product.product_id || p.product_id === product.id || p.product_id === product.value))
+ )
+ );
+
+ // Add back to available products if it matches the current search
+ if (shouldAddToAvailable) {
setAvailableProducts(prev => {
- if (!prev.some(p => p.value === product.value)) {
- return [...prev, product];
+ // Check if already in available products
+ const alreadyExists = prev.some(p =>
+ (p.value && (p.value === product.value || p.value === product.id || p.value === product.product_id)) ||
+ (p.id && (p.id === product.id || p.id === product.value || p.id === product.product_id)) ||
+ (p.product_id && (p.product_id === product.product_id || p.product_id === product.id || p.product_id === product.value))
+ );
+
+ if (!alreadyExists) {
+ // Get all products (including the one being removed)
+ const allProducts = [...prev, ...selectedProducts];
+ const uniqueProducts = allProducts.filter((p, index, self) =>
+ index === self.findIndex(t =>
+ (t.value && (t.value === p.value || t.value === p.id || t.value === p.product_id)) ||
+ (t.id && (t.id === p.id || t.id === p.value || t.id === p.product_id)) ||
+ (t.product_id && (t.product_id === p.product_id || t.product_id === p.id || t.product_id === p.value))
+ )
+ );
+ return uniqueProducts;
}
return prev;
});
@@ -373,10 +407,7 @@ const EditCompanyProfile = () => {
const loadEmirates = async () => {
try {
const emirates = await fetchEmirates({ signal: controller.signal });
- if (cancelled) return;
-
- console.log('Loaded emirates:', emirates);
-
+ if (cancelled) return;
const lookup = {};
emirates.forEach((emirate) => {
lookup[emirate.value] = emirate.label;
@@ -399,31 +430,22 @@ const EditCompanyProfile = () => {
}, []);
// Load establishment data and set form with API data
- useEffect(() => {
- console.log('useEffect triggered, establishmentId:', establishmentId);
-
+ useEffect(() => {
// Create an async function inside the effect
const fetchData = async () => {
if (!establishmentId) {
- console.log('No establishmentId found, skipping fetch');
return;
}
try {
- setLoading(true);
- console.log('Starting API call to fetch establishment details for ID:', establishmentId);
-
- const response = await fetchEstablishmentDetail(establishmentId);
- console.log('API Response received:', response);
-
+ setLoading(true);
+ const response = await fetchEstablishmentDetail(establishmentId);
if (!response) {
console.error('Empty response received');
return;
}
- const mappedProfile = mapApiEstablishmentToProfile(response);
- console.log('Mapped Profile:', mappedProfile);
-
+ const mappedProfile = mapApiEstablishmentToProfile(response);
const formData = {
...createEmptyProfile(),
...mappedProfile,
@@ -431,21 +453,13 @@ const EditCompanyProfile = () => {
};
const totals = computeEmploymentTotals(formData);
- Object.assign(formData, totals);
-
- console.log('Final Form Data:', formData);
-
+ Object.assign(formData, totals);
// First set the form data
setForm(formData);
initialSnapshotRef.current = formData;
- // Then load cities and products in parallel
- const [allProducts] = await Promise.all([
- loadProducts()
- ]);
-
- console.log('All products loaded:', allProducts);
-
+ // Load products first
+ const allProducts = await fetchProducts();
// Set selected products from API response
const establishmentProducts = response.data?.establishment_products || response.establishment_products || [];
if (Array.isArray(establishmentProducts) && establishmentProducts.length > 0) {
@@ -454,11 +468,17 @@ const EditCompanyProfile = () => {
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));
+ const foundProduct = allProducts.find(p =>
+ p.value === String(productId) ||
+ p.id === productId ||
+ p.product_id === productId
+ );
return {
...(foundProduct || {
value: String(productId),
+ id: productId,
+ product_id: productId,
label: productData.product_name || productData.name || 'Unnamed Product',
hs_code: productData.hs_code || '',
product_name: productData.product_name || productData.name || 'Unnamed Product',
@@ -471,6 +491,19 @@ const EditCompanyProfile = () => {
setSelectedProducts(formattedSelectedProducts);
// Initialize newly added products as empty since we're loading existing data
setNewlyAddedProductIds(new Set());
+
+ // Now load available products with selected ones filtered out
+ const filteredAvailable = allProducts.filter(product => {
+ return !formattedSelectedProducts.some(selected =>
+ (selected.value && (selected.value === product.value || selected.value === product.id || selected.value === product.product_id)) ||
+ (selected.id && (selected.id === product.id || selected.id === product.value || selected.id === product.product_id)) ||
+ (selected.product_id && (selected.product_id === product.product_id || selected.product_id === product.id || selected.product_id === product.value))
+ );
+ });
+ setAvailableProducts(filteredAvailable);
+ } else {
+ // If no selected products, just set all products as available
+ setAvailableProducts(allProducts);
}
} catch (error) {
@@ -534,9 +567,6 @@ const EditCompanyProfile = () => {
]);
const handleSave = async () => {
- console.log("Submitted data:", form);
- console.log("Selected products:", selectedProducts);
-
try {
setLoading(true);
@@ -584,14 +614,9 @@ const EditCompanyProfile = () => {
}))
: [],
- };
-
- console.log("Payload sent:", establishmentData);
-
+ };
if (establishmentId) {
- console.log("Updating establishment with ID:", establishmentId);
await updateEstablishment(establishmentId, establishmentData);
- console.log("Profile updated successfully!");
navigate('/survey');
} else {
console.error("No establishment ID provided for update");
diff --git a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx
index 0f93efd..707ede4 100644
--- a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx
+++ b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx
@@ -206,27 +206,49 @@ const ImportModal = ({ isOpen, onClose, onImport }) => {
onClose();
};
- const downloadSampleCSV = () => {
- const sampleData = [
- ['HS Code', 'Product Name', 'Unit'],
- ['0101', 'Live Horses', 'kg'],
- ['0102', 'Live Bovine Animals', 'kg'],
- ];
+ // const downloadSampleCSV = () => {
+ // const sampleData = [
+ // ['HS Code', 'Product Name', 'Unit'],
+ // ['0101', 'Live Horses', 'kg'],
+ // ['0102', 'Live Bovine Animals', 'kg'],
+ // ];
- const csvContent = sampleData.map(row =>
- row.map(field => `"${field}"`).join(',')
- ).join('\n');
+ // const csvContent = sampleData.map(row =>
+ // row.map(field => `"${field}"`).join(',')
+ // ).join('\n');
- const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
- const url = URL.createObjectURL(blob);
+ // const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
+ // const url = URL.createObjectURL(blob);
+ // const link = document.createElement('a');
+ // link.href = url;
+ // link.setAttribute('download', 'hs-codes-sample.csv');
+ // document.body.appendChild(link);
+ // link.click();
+ // document.body.removeChild(link);
+ // URL.revokeObjectURL(url);
+ // };
+ const downloadSampleCSV = async () => {
+ try {
+ const response = await productService.downloadSampleFile();
+
+ // Create a blob from the response
+ const blob = new Blob([response], { type: 'text/csv' });
+ const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'hs-codes-sample.csv');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
- URL.revokeObjectURL(url);
- };
+ window.URL.revokeObjectURL(url);
+
+ // Show success message
+ showToast('Sample file downloaded successfully');
+ } catch (error) {
+ console.error('Error downloading sample file:', error);
+ showToast('Failed to download sample file', 'error');
+ }
+};
if (!isOpen) return null;
@@ -689,22 +711,15 @@ const IsicHsCodes = () => {
try {
setIsLoading(true);
- const productId = selected.id;
- console.log('Fetching product with ID:', productId);
-
+ const productId = selected.id;
// Get fresh data from the server
- const response = await productService.getProductById(productId);
- console.log('API Response:', response);
-
+ const response = await productService.getProductById(productId);
if (response && response.data) {
const productData = response.data; // The actual product data is in response.data
if (!productData) {
throw new Error('No product data received in response');
- }
-
- console.log('Product data for edit:', productData);
-
+ }
// Map the API response fields to form fields
const formData = {
id: productData.id,
@@ -714,10 +729,6 @@ const IsicHsCodes = () => {
unit: productData.unit_id ? String(productData.unit_id) : '',
status: productData.is_active ? 'Active' : 'Inactive',
};
-
- console.log('Mapped form data:', formData);
-
- console.log('Setting form data:', formData); // Debug log
setForm(formData);
setEditingRow(index);
setModalMode('edit');
@@ -991,9 +1002,7 @@ const IsicHsCodes = () => {
try {
// Get the existing product data to preserve fields
- const existingProduct = editingRow !== null ? rowsData[editingRow] : null;
- console.log("existingProduct",existingProduct)
-
+ const existingProduct = editingRow !== null ? rowsData[editingRow] : null;
// Only update the specific fields we want to change
const response = await productService.updateProduct(productId, productData);
const selectedUnit = unitOptions.find(u => u.value === form.unit);
diff --git a/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx b/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx
index 277ec1b..cfdcb1e 100644
--- a/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx
+++ b/ipi-survey-platform/src/pages/Admin/configuration/UnitMaster.jsx
@@ -1,7 +1,7 @@
import React, { useState, useEffect, useMemo, useRef } from 'react';
import Table from '@/components/common/Table';
import { TextField } from '@/components/common/FormControls';
-import { getUnits, getUnitById, createUnit, updateUnit, deleteUnit, uploadUnitCSV } from '@/services/configuration/unitService';
+import { getUnits, getUnitById, createUnit, updateUnit, deleteUnit, uploadUnitCSV,downloadSampleFile } from '@/services/configuration/unitService';
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
@@ -529,9 +529,6 @@ const UnitMaster = () => {
if (error.response?.data) {
const errorData = error.response.data;
-
- console.log('Error response data:', errorData);
-
// Handle different error response formats
if (typeof errorData === 'string') {
errorMessage = errorData;
@@ -697,30 +694,57 @@ const UnitMaster = () => {
}
};
- const downloadSampleCSV = () => {
- const sampleData = [
- ['Unit Name', 'Description'],
- ['Kilogram', 'Weight measurement in kilograms'],
- ['Gram', 'Weight measurement in grams'],
- ['Liter', 'Volume measurement in liters'],
- ['Meter', 'Length measurement in meters']
- ];
+ // const downloadSampleCSV = () => {
+ // const sampleData = [
+ // ['Unit Name', 'Description'],
+ // ['Kilogram', 'Weight measurement in kilograms'],
+ // ['Gram', 'Weight measurement in grams'],
+ // ['Liter', 'Volume measurement in liters'],
+ // ['Meter', 'Length measurement in meters']
+ // ];
- const csvContent = sampleData.map(row =>
- row.map(field => `"${field}"`).join(',')
- ).join('\n');
+ // const csvContent = sampleData.map(row =>
+ // row.map(field => `"${field}"`).join(',')
+ // ).join('\n');
- const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
- const url = URL.createObjectURL(blob);
+ // const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
+ // const url = URL.createObjectURL(blob);
+ // const link = document.createElement('a');
+ // link.href = url;
+ // link.setAttribute('download', 'unit-master-template.csv');
+ // document.body.appendChild(link);
+ // link.click();
+ // document.body.removeChild(link);
+ // URL.revokeObjectURL(url);
+ // };
+const downloadSampleCSV = async () => {
+ try {
+ const response = await downloadSampleFile();
+
+ // Create a blob from the response
+ const blob = new Blob([response], { type: 'text/csv;charset=utf-8;' });
+ const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
- link.setAttribute('download', 'unit-master-template.csv');
+ link.setAttribute('download', 'unit-master-sample.csv');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
- URL.revokeObjectURL(url);
- };
-
+ window.URL.revokeObjectURL(url);
+
+ // Show success message
+ setToastData({
+ message: 'Sample file downloaded successfully',
+ type: 'success'
+ });
+ } catch (error) {
+ console.error('Error downloading sample file:', error);
+ setToastData({
+ message: 'Failed to download sample file',
+ type: 'error'
+ });
+ }
+};
const handleImport = async () => {
if (!file) {
setImportError('Please select a CSV file to import.');
diff --git a/ipi-survey-platform/src/services/configuration/productService.js b/ipi-survey-platform/src/services/configuration/productService.js
index fc419e5..37b9083 100644
--- a/ipi-survey-platform/src/services/configuration/productService.js
+++ b/ipi-survey-platform/src/services/configuration/productService.js
@@ -94,7 +94,23 @@ uploadCSV: async (file) => {
console.error('Error in productService.uploadCSV:', error);
throw error;
}
-}
+},
+
+ // Download sample CSV file
+ downloadSampleFile: async () => {
+ try {
+ const response = await getRequest('download-sample-product-upload-file', {
+ responseType: 'blob',
+ headers: {
+ 'Accept': 'text/csv'
+ }
+ });
+ return response;
+ } catch (error) {
+ console.error('Error in productService.downloadSampleFile:', error);
+ throw error;
+ }
+ }
};
export default productService;
diff --git a/ipi-survey-platform/src/services/configuration/unitService.js b/ipi-survey-platform/src/services/configuration/unitService.js
index 39e5053..af54a3c 100644
--- a/ipi-survey-platform/src/services/configuration/unitService.js
+++ b/ipi-survey-platform/src/services/configuration/unitService.js
@@ -54,7 +54,6 @@ export const updateUnit = async (id, unitData) => {
export const deleteUnit = async (id) => {
try {
const response = await deleteRequest(`${UNIT_MASTER_ENDPOINT}/${id}`);
- console.log('Unit deleted successfully:', response.data);
return response.data;
} catch (error) {
console.error('Error deleting unit:', error);
@@ -75,4 +74,23 @@ export const uploadUnitCSV = async (formData) => {
console.error('Error uploading unit CSV:', error);
throw error;
}
+
+
+
+};
+
+// In unitService.js, add this function to the exports
+export const downloadSampleFile = async () => {
+ try {
+ const response = await getRequest('unit_master_download_sample_file', {
+ responseType: 'blob',
+ headers: {
+ 'Accept': 'text/csv'
+ }
+ });
+ return response;
+ } catch (error) {
+ console.error('Error downloading sample file:', error);
+ throw error;
+ }
};
\ No newline at end of file
diff --git a/ipi-survey-platform/src/services/establishments/establishmentService.js b/ipi-survey-platform/src/services/establishments/establishmentService.js
index fe8f641..efc0669 100644
--- a/ipi-survey-platform/src/services/establishments/establishmentService.js
+++ b/ipi-survey-platform/src/services/establishments/establishmentService.js
@@ -3,6 +3,7 @@ import resolveEstablishmentId from '@/services/utils/establishment';
const dashboardEndpoint = '/establishment_dashboard';
const establishmentsEndpoint = '/establishments';
+const downloadsample = '/establishment';
const buildEstablishmentQueryParams = (params = {}) => {
const {
@@ -109,7 +110,6 @@ export const uploadCompanyProfileCSVAlternative = async (formData, config = {})
const altFormData = new FormData();
altFormData.append('csv_file', file); // Try 'csv_file' parameter
- console.log('Alternative FormData entries:');
for (let pair of altFormData.entries()) {
console.log(pair[0] + ': ', pair[1]);
}
@@ -154,6 +154,16 @@ export const bulkDeleteEstablishments = async (establishmentIds, config = {}) =>
return response.data;
};
+// Download sample CSV file
+export const downloadSampleFile = async (config = {}) => {
+ const downloadEndpoint = `${downloadsample}/download-sample-file`;
+ const response = await getRequest(downloadEndpoint, {
+ ...config,
+ responseType: 'blob',
+ });
+ return response.data;
+};
+
export default {
fetchEstablishments,
fetchEstablishmentDashboard,
@@ -165,4 +175,5 @@ export default {
uploadCompanyProfileCSVAlternative,
bulkUpdateEstablishments,
bulkDeleteEstablishments,
+ downloadSampleFile,
};
\ No newline at end of file