From 8dca1f0a84953db74eb075757f442d4ab2bfa63c Mon Sep 17 00:00:00 2001 From: Malini Date: Thu, 11 Dec 2025 17:10:44 +0530 Subject: [PATCH] bug fixed --- .../pages/Admin/configuration/IsicHsCodes.jsx | 198 +++++++++--------- 1 file changed, 100 insertions(+), 98 deletions(-) diff --git a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx index 865562e..f5099c9 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/IsicHsCodes.jsx @@ -29,7 +29,7 @@ const createEmptyCodeForm = () => ({ }); // Toast notification component -const Toast = ({ message, type = 'success', onClose, position = 'modal' }) => { +const Toast = ({ message, type = 'success', onClose, position = 'page' }) => { React.useEffect(() => { const timer = setTimeout(() => { onClose(); @@ -50,20 +50,10 @@ const Toast = ({ message, type = 'success', onClose, position = 'modal' }) => { } }; - // For modal toasts, we'll use relative positioning - if (position === 'modal') { - return ( -
-
- {message} -
-
- ); - } - - // Default page-level toast return ( -
+
{message}
@@ -72,14 +62,48 @@ const Toast = ({ message, type = 'success', onClose, position = 'modal' }) => { }; // Import Modal Component -const ImportModal = ({ isOpen, onClose, onImport }) => { +const ImportModal = ({ isOpen, onClose, onImport, showToast: showToastProp }) => { const [file, setFile] = React.useState(null); const [dragActive, setDragActive] = React.useState(false); const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(''); + const [toast, setToast] = React.useState({ + show: false, + message: '', + type: 'success', + position: 'modal' + }); const fileInputRef = React.useRef(null); + const showToast = (message, type = 'success', position = 'modal') => { + console.log('showToast called with:', { message, type, position }); + + // Always use local toast state for the modal + setToast(prev => { + console.log('Updating toast state'); + return { + ...prev, + show: true, + message, + type, + position + }; + }); + + // Auto-hide after delay + const timer = setTimeout(() => { + console.log('Hiding toast after timeout'); + setToast(prev => ({ ...prev, show: false })); + }, 3000); + + // Cleanup + return () => { + console.log('Cleaning up toast timeout'); + clearTimeout(timer); + }; + }; + const handleDrag = (e) => { e.preventDefault(); e.stopPropagation(); @@ -128,6 +152,7 @@ const ImportModal = ({ isOpen, onClose, onImport }) => { }; const handleImport = async () => { + console.log('handleImport called'); if (!file) { setError('Please select a file to import'); return; @@ -137,42 +162,33 @@ const ImportModal = ({ isOpen, onClose, onImport }) => { setLoading(true); setError(''); - // Call the uploadCSV API from productService + console.log('Calling productService.uploadCSV'); const response = await productService.uploadCSV(file); + console.log('Upload response:', response); // Check the response status if (response.status === 'failed') { + console.log('Import failed with response:', response); let errorMsg = response.message || 'Import failed'; - // Add duplicate HS codes to the error message if they exist - // if (response.duplicate_hs_codes_in_system?.length > 0) { - // errorMsg += `\nDuplicate HS codes found: ${response.duplicate_hs_codes_in_system.join(', ')}`; - // } - - // // Show error summary if available - // if (response.summary) { - // errorMsg += `\nTotal records: ${response.summary.total_records}`; - // errorMsg += `\nImported: ${response.summary.imported}`; - // errorMsg += `\nSkipped: ${response.summary.skipped}`; - - if (response.summary.errors?.length > 0) { - errorMsg += '\n\nErrors:'; - response.summary.errors.forEach(err => { - errorMsg += `\nRow ${err.row}: ${err.error}`; - }); - } - + if (response.summary?.errors?.length > 0) { + errorMsg += '\n\nErrors:'; + response.summary.errors.forEach(err => { + errorMsg += `\nRow ${err.row}: ${err.error}`; + }); + } setError(errorMsg); return; } - // Call the onImport callback with the response data - await onImport(response); - - // Reset and close on success + // Close the modal first setFile(null); onClose(); + + // Then call onImport which will trigger the parent's success handling + console.log('Calling onImport'); + await onImport(response); } catch (err) { console.error('Error uploading CSV:', err); let errorMessage = 'Failed to import file. Please try again.'; @@ -206,27 +222,7 @@ 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 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 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(); @@ -272,6 +268,18 @@ const ImportModal = ({ isOpen, onClose, onImport }) => { {/* Content */}
+ {/* Toast notification within modal */} + {toast.show && toast.position === 'modal' && ( + { + console.log('Toast onClose called'); + setToast(prev => ({ ...prev, show: false })); + }} + /> + )} {/* File Upload Area */}
{ show: false, message: '', type: 'success', - position: 'modal' // 'page' or 'modal' + position: 'page' // 'page' or 'modal' }); const [showImportModal, setShowImportModal] = React.useState(false); const [isRefreshing, setIsRefreshing] = React.useState(false); @@ -693,11 +701,11 @@ const IsicHsCodes = () => { setModalMode('view'); } else { console.error('Invalid product data received from API'); - showToast('Failed to load product details', 'error'); + setToast({ show: true, message: 'Failed to load product details', type: 'error' }); } } catch (error) { console.error('Error fetching product details:', error); - showToast('Error loading product details', 'error'); + setToast({ show: true, message: 'Error loading product details', type: 'error' }); } finally { setIsLoading(false); } @@ -734,11 +742,11 @@ const IsicHsCodes = () => { setModalMode('edit'); } else { console.error('Empty response received from API'); - showToast('Failed to load product details for editing', 'error'); + setToast({ show: true, message: 'Failed to load product details for editing', type: 'error' }); } } catch (error) { console.error('Error fetching product details for edit:', error); - showToast('Error loading product details for editing', 'error'); + setToast({ show: true, message: 'Error loading product details for editing', type: 'error' }); } finally { setIsLoading(false); } @@ -752,7 +760,7 @@ const IsicHsCodes = () => { if (!selected || !selected.id) { console.error('No product selected or missing ID'); - showToast('Cannot delete: Product information is incomplete', 'error'); + setToast({ show: true, message: 'Cannot delete: Product information is incomplete', type: 'error' }); return; } @@ -778,7 +786,7 @@ const IsicHsCodes = () => { setShowDeleteConfirm(true); } catch (error) { console.error('Error preparing product for deletion:', error); - showToast('Error loading product details for deletion', 'error'); + setToast({ show: true, message: 'Error loading product details for deletion', type: 'error' }); } finally { setIsLoading(false); } @@ -799,7 +807,7 @@ const IsicHsCodes = () => { if (deletingRowIndex === null || deletingRowIndex < 0 || deletingRowIndex >= rowsData.length) { const errorMsg = 'Invalid row selected for deletion'; console.error(errorMsg, { deletingRowIndex, rowsDataLength: rowsData.length }); - showToast(errorMsg, 'error'); + setToast({ show: true, message: errorMsg, type: 'error' }); setShowDeleteConfirm(false); setDeletingRowIndex(null); return; @@ -832,7 +840,7 @@ const IsicHsCodes = () => { newData.splice(deletingRowIndex, 1); setRowsData(newData); - showToast('Product deleted successfully!', 'success'); + setToast({ show: true, message: 'Product deleted successfully!', type: 'success' }); } catch (apiError) { console.error('API Error:', apiError); if (apiError.response && apiError.response.status === 204) { @@ -850,18 +858,18 @@ const IsicHsCodes = () => { newData.splice(deletingRowIndex, 1); setRowsData(newData); - showToast('Product deleted successfully!', 'success'); + setToast({ show: true, message: 'Product deleted successfully!', type: 'success' }); } else { const errorMessage = apiError.response?.data?.message || 'Failed to delete product. Please try again.'; setError(errorMessage); - showToast(errorMessage, 'error'); + setToast({ show: true, message: errorMessage, type: 'error' }); } } } catch (error) { console.error('Error in delete process:', error); const errorMessage = error.message || 'An unexpected error occurred'; setError(errorMessage); - showToast(errorMessage, 'error'); + setToast({ show: true, message: errorMessage, type: 'error' }); } finally { setIsLoading(false); setShowDeleteConfirm(false); @@ -886,8 +894,8 @@ const IsicHsCodes = () => { setForm(createEmptyCodeForm()); }; - const showToast = (message, type = 'success', position = 'modal') => { - setToast({ show: true, message, type, position }); + const showToast = (message, type = 'success') => { + setToast({ show: true, message, type }); setTimeout(() => { setToast(prev => ({ ...prev, show: false })); }, 3000); @@ -905,7 +913,7 @@ const IsicHsCodes = () => { await new Promise(resolve => setTimeout(resolve, 1500)); // Show success message - showToast('HS Codes imported successfully! New codes appear in the list.', 'success'); + setToast({ show: true, message: 'HS Codes imported successfully! New codes appear in the list.', type: 'success' }); // In a real implementation, you would: // 1. Call your import API endpoint @@ -913,7 +921,7 @@ const IsicHsCodes = () => { // 3. Update the rowsData state with the new data } catch (error) { - showToast('Failed to import CSV file. Please try again.', 'error'); + setToast({ show: true, message: 'Failed to import CSV file. Please try again.', type: 'error' }); } }; @@ -945,14 +953,14 @@ const IsicHsCodes = () => { document.body.removeChild(link); URL.revokeObjectURL(url); - showToast('CSV exported successfully!', 'success'); + setToast({ show: true, message: 'CSV exported successfully!', type: 'success' }); }; const handleSaveForm = async () => { if (!form.code || !form.product) { const errorMsg = 'Please fill in all required fields'; console.error(errorMsg); - showToast(errorMsg, 'error'); + setToast({ show: true, message: errorMsg, type: 'error' }); return; } @@ -996,7 +1004,7 @@ const IsicHsCodes = () => { if (!productId) { const errorMsg = 'Cannot update product: Product ID not found'; console.error(errorMsg); - showToast(errorMsg, 'error'); + setToast({ show: true, message: errorMsg, type: 'error' }); return; } @@ -1040,7 +1048,7 @@ const IsicHsCodes = () => { }); // Show success message and reload the page after a short delay - showToast('Product updated successfully!', 'success'); + setToast({ show: true, message: 'Product updated successfully!', type: 'success' }); closeModal(); setTimeout(() => { window.location.reload(); @@ -1052,7 +1060,7 @@ const IsicHsCodes = () => { if (error.response?.data?.message) { errorMessage = error.response.data.message; } - showToast(errorMessage, 'error'); + setToast({ show: true, message: errorMessage, type: 'error' }); } } @@ -1077,7 +1085,7 @@ const IsicHsCodes = () => { setRowsData(prev => [newProduct, ...prev]); setFilteredData(prev => [newProduct, ...prev]); - showToast('Product created successfully!', 'success'); + setToast({ show: true, message: 'Product created successfully!', type: 'success' }); closeModal(); // Reload the page after a short delay to reflect changes @@ -1090,7 +1098,7 @@ const IsicHsCodes = () => { if (createError.response?.data?.message) { errorMessage = createError.response.data.message; } - showToast(errorMessage, 'error'); + setToast({ show: true, message: errorMessage, type: 'error' }); } } catch (error) { console.error('Error in handleSaveForm:', error); @@ -1172,20 +1180,12 @@ const IsicHsCodes = () => { setRowsData(formattedData); setFilteredData(formattedData); + setToast({ show: true, message: 'HS Codes imported successfully!', type: 'success' }); } - setToast({ - show: true, - message: 'Data imported successfully!', - type: 'success' - }); - } catch (err) { - console.error('Error refreshing product list:', err); - setToast({ - show: true, - message: 'Data imported but failed to refresh the list. ' + (err.response?.data?.message || 'Please refresh the page manually.'), - type: 'error' - }); + } catch (error) { + console.error('Error refreshing HS codes:', error); + setToast({ show: true, message: 'Failed to refresh HS codes', type: 'error' }); } finally { setIsRefreshing(false); } @@ -1194,12 +1194,11 @@ const IsicHsCodes = () => { return (
{/* Page-level toasts */} - {toast.show && toast.position === 'page' && ( + {toast.show && ( setToast(prev => ({ ...prev, show: false }))} + onClose={() => setToast(prev => ({ ...prev, show: false }))} /> )} @@ -1207,7 +1206,10 @@ const IsicHsCodes = () => { setShowImportModal(false)} - onImport={handleImportSuccess} + onImport={(response) => { + handleImportSuccess(response); + setToast({ show: true, message: 'HS Codes imported successfully!', type: 'success' }); + }} />