From 2e1bd35f244591a95b23dfc81bf2c39fbe1dd5bb Mon Sep 17 00:00:00 2001 From: Malini Date: Mon, 2 Mar 2026 17:40:16 +0530 Subject: [PATCH] CR Bug fixed --- .../src/components/common/FormControls.jsx | 166 +++++++++++- .../EstablishmentInfo/EstablishmentInfo.jsx | 17 +- .../survey/ProductData/ProductData.jsx | 245 ++++++++++++++++-- .../Admin/configuration/CompanyProfile.jsx | 14 +- .../configuration/EditCompanyProfile.jsx | 146 +++++------ 5 files changed, 462 insertions(+), 126 deletions(-) diff --git a/ipi-survey-platform/src/components/common/FormControls.jsx b/ipi-survey-platform/src/components/common/FormControls.jsx index 231b4fc..444e47d 100644 --- a/ipi-survey-platform/src/components/common/FormControls.jsx +++ b/ipi-survey-platform/src/components/common/FormControls.jsx @@ -313,6 +313,7 @@ export const SelectField = ({ error = '', readOnly = false, required = false, + forceDropdownBelow = false, }) => { const wrapperStyle = {}; if (width !== 'auto') { @@ -321,20 +322,84 @@ export const SelectField = ({ const baseStyle = baseInputStyles[variant] || baseInputStyles.default; const inputStyle = { ...baseStyle, ...style }; const [focused, setFocused] = React.useState(false); + const [isOpen, setIsOpen] = React.useState(false); + const [searchTerm, setSearchTerm] = React.useState(''); + const dropdownRef = React.useRef(null); + const inputRef = React.useRef(null); const normalizedClear = clearValue ?? ''; const hasValue = value !== undefined && value !== null && value !== '' && value !== normalizedClear; const showClear = allowClear && hasValue && !readOnly; + if (rightIcon) { inputStyle.paddingRight = '40px'; } + + // Filter options based on search term + const filteredOptions = React.useMemo(() => { + if (!searchTerm) return options; + return options.filter(opt => + opt.label.toLowerCase().includes(searchTerm.toLowerCase()) + ); + }, [options, searchTerm]); + + // Close dropdown when clicking outside + React.useEffect(() => { + const handleClickOutside = (event) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + setIsOpen(false); + setSearchTerm(''); + } + }; + + if (isOpen) { + document.addEventListener('mousedown', handleClickOutside); + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [isOpen]); + const handleFocus = (event) => { setFocused(true); onFocus?.(event); }; + const handleBlur = (event) => { setFocused(false); onBlur?.(event); }; + + const handleClear = (event) => { + event.preventDefault(); + event.stopPropagation(); + if (onClear) { + onClear(); + } else if (onChange) { + onChange({ target: { value: normalizedClear } }); + } + }; + + const handleSelect = (selectedValue) => { + if (!readOnly) { + onChange({ target: { value: selectedValue } }); + setIsOpen(false); + setSearchTerm(''); + } + }; + + const toggleDropdown = () => { + if (!readOnly) { + setIsOpen(!isOpen); + setSearchTerm(''); + } + }; + + const getDisplayValue = () => { + const selected = options.find(opt => opt.value === value); + return selected ? selected.label : (placeholder || ''); + }; + const hasError = Boolean(error); inputStyle.borderColor = hasError ? '#B91C1C' @@ -353,15 +418,98 @@ export const SelectField = ({ inputStyle.backgroundColor = '#F9FAFB'; inputStyle.cursor = 'not-allowed'; } - const handleClear = (event) => { - event.preventDefault(); - event.stopPropagation(); - if (onClear) { - onClear(); - } else if (onChange) { - onChange({ target: { value: normalizedClear } }); - } - }; + + // Custom dropdown implementation + if (forceDropdownBelow) { + return ( +
+ {label && ( + + )} +
+
+ + {getDisplayValue()} + + {showClear ? ( + + ) : ( + rightIcon && + )} +
+ + {isOpen && !readOnly && ( +
+ {/* Search input */} +
+ setSearchTerm(e.target.value)} + onClick={(e) => e.stopPropagation()} + /> +
+ + {/* Options list */} + {filteredOptions.length === 0 ? ( +
No options found
+ ) : ( + filteredOptions.map((opt) => ( +
handleSelect(opt.value)} + > + {opt.label} +
+ )) + )} +
+ )} +
+ {readOnly &&
} + {error &&

{error}

} +
+ ); + } + + // Original native select implementation return (
{label && ( diff --git a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx index a89a538..ea9f236 100644 --- a/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx +++ b/ipi-survey-platform/src/components/survey/EstablishmentInfo/EstablishmentInfo.jsx @@ -7,6 +7,7 @@ const getSafeEstablishmentId = () => { }; import { useNavigate, useLocation } from 'react-router-dom'; import { getEstablishmentProducts } from '../../../services/submissions/submissionService'; +import { fetchEstablishmentDetail } from '../../../services/establishments/establishmentService'; import { getEmirates } from '../../../services/masters/masterService'; import Table from '@/components/common/Table'; @@ -154,11 +155,11 @@ const EstablishmentInfo = ({ setLoadingProducts(true); try { - const response = await getEstablishmentProducts(establishmentId); - if (response.status === 'success') { - setProducts(response.data || []); + const response = await fetchEstablishmentDetail(establishmentId); + if (response?.data?.establishment_products) { + setProducts(response.data.establishment_products || []); } else { - setProductsError(response.message || 'Failed to load products'); + setProductsError('Failed to load products'); } } catch (error) { console.error('Error fetching products:', error); @@ -652,7 +653,7 @@ React.useEffect(() => { -

Products

+

Productss

{loadingProducts ? (
@@ -663,9 +664,9 @@ React.useEffect(() => { [ - product['product.product_name'] || 'N/A', - product['product.hs_code'] || 'N/A', - product['product.hs_description'] || 'N/A' + product.product.product_name || '-', + product.product.hs_code || '-', + product.product.hs_description || '-' ])} columnWidths={['33.33%', '33.33%', '33.33%']} separated={true} diff --git a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx index b392211..34fb2f6 100644 --- a/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx +++ b/ipi-survey-platform/src/components/survey/ProductData/ProductData.jsx @@ -91,7 +91,8 @@ const SearchableSelect = ({ disabled = false, error = false, className = '', - displayValue = undefined + displayValue = undefined, + allowNull = false // New prop to allow null values for no selection }) => { const [isOpen, setIsOpen] = React.useState(false); const [searchTerm, setSearchTerm] = React.useState(''); @@ -153,22 +154,25 @@ const SearchableSelect = ({ // Get selected option label const [internalDisplayValue, setInternalDisplayValue] = React.useState(displayValue || ''); - const selectedOption = options.find(opt => opt.value === value); + const selectedOption = allowNull ? (value === null ? null : options.find(opt => opt.value === value)) : options.find(opt => opt.value === value); // Update internal display value when value, displayValue prop or options change React.useEffect(() => { if (displayValue !== undefined && displayValue !== '') { setInternalDisplayValue(displayValue); + } else if (allowNull && value === null) { + // When allowNull is true and value is null, show empty (no selection) + setInternalDisplayValue(''); } else if (selectedOption) { setInternalDisplayValue(selectedOption.label); - } else if (value) { + } else if (value !== null && value !== undefined && value !== '') { // If we have a value but no matching option, try to find it in the options const matchedOption = options.find(opt => opt.value === value); setInternalDisplayValue(matchedOption?.label || ''); } else { setInternalDisplayValue(''); } - }, [value, displayValue, selectedOption, options]); + }, [value, displayValue, selectedOption, options, allowNull]); const displayValueToShow = internalDisplayValue; @@ -197,7 +201,7 @@ const SearchableSelect = ({ if (error) { borderColor = 'border-red-500'; bgColor = 'bg-red-50'; - } else if (value || isOpen) { + } else if ((value !== null && value !== undefined && value !== '') || isOpen) { borderColor = 'border-[#92722A]'; } @@ -241,7 +245,7 @@ const SearchableSelect = ({
handleSelect(option)} > @@ -267,7 +271,9 @@ const Select = ({ loading = false, disabled = false, error = false, - className = '' + className = '', + allowClear = false, + onClear }) => { const [isFocused, setIsFocused] = React.useState(false); @@ -281,6 +287,19 @@ const Select = ({ } else if (value || isFocused) { borderColor = 'border-[#92722A]'; } + + const hasValue = value !== undefined && value !== null && value !== ''; + const showClear = allowClear && hasValue && !disabled && !loading; + + const handleClear = (event) => { + event.preventDefault(); + event.stopPropagation(); + if (onClear) { + onClear(); + } else if (onChange) { + onChange({ target: { value: '' } }); + } + }; return (
@@ -317,8 +336,17 @@ const Select = ({ }) )} -
- {loading ? ( +
+ {showClear ? ( + + ) : loading ? (
) : ( open @@ -418,6 +446,11 @@ const ProductData = ({ const [unitsError, setUnitsError] = React.useState(null); const [isSavingDraft, setIsSavingDraft] = React.useState(false); + const latestDraftRef = React.useRef({ products: [], deletedProducts: [], remarks: '' }); + const draftKeyRef = React.useRef(''); + const restoredDraftKeyRef = React.useRef(''); + const restoredDraftSignatureRef = React.useRef(''); + const location = useLocation(); // Add this line @@ -441,6 +474,57 @@ const ProductData = ({ return ''; }); + const getLocalDraftKey = React.useCallback(() => { + if (typeof window === 'undefined') return ''; + + const currentSubmissionStr = localStorage.getItem('currentSubmission'); + let currentSubmission = null; + try { + currentSubmission = currentSubmissionStr ? JSON.parse(currentSubmissionStr) : null; + } catch (e) { + currentSubmission = null; + } + + const establishmentId = + currentSubmission?.establishment_id || + currentSubmission?.establishment?.id || + localStorage.getItem('establishment_id') || + localStorage.getItem('establishmentId') || + ''; + + const effectiveQuarter = quarter || localStorage.getItem('currentQuarter') || localStorage.getItem('current_quarter') || ''; + const effectiveYear = year || localStorage.getItem('currentYear') || localStorage.getItem('current_year') || ''; + + if (!establishmentId || !effectiveQuarter || !effectiveYear) return ''; + const formattedQuarter = String(effectiveQuarter).startsWith('Q') + ? String(effectiveQuarter) + : `Q${effectiveQuarter}`; + + return `productDataDraft:${establishmentId}:${effectiveYear}:${formattedQuarter}`; + }, [quarter, year]); + + const persistLocalDraft = React.useCallback((payload) => { + if (typeof window === 'undefined') return; + const key = draftKeyRef.current || getLocalDraftKey(); + if (!key) return; + + try { + localStorage.setItem( + key, + JSON.stringify({ + ...payload, + updatedAt: Date.now(), + }) + ); + } catch (e) { + // ignore localStorage errors + } + }, [getLocalDraftKey]); + + const flushLocalDraft = React.useCallback(() => { + persistLocalDraft(latestDraftRef.current); + }, [persistLocalDraft]); + const handleRemarksChange = (e) => { const value = e.target.value; setRemarks(value); @@ -449,6 +533,109 @@ const ProductData = ({ } }; + // Keep latest draft snapshot in a ref (used by beforeunload/offline handlers) + React.useEffect(() => { + latestDraftRef.current = { + products, + deletedProducts, + remarks, + }; + }, [products, deletedProducts, remarks]); + + // Initialize draft key and restore any existing draft for this establishment/period + React.useEffect(() => { + if (typeof window === 'undefined') return; + const key = getLocalDraftKey(); + draftKeyRef.current = key; + if (!key) return; + + try { + const raw = localStorage.getItem(key); + if (!raw) return; + const parsed = JSON.parse(raw); + if (!parsed) return; + + const parsedSignature = JSON.stringify({ + products: Array.isArray(parsed.products) ? parsed.products : [], + deletedProducts: Array.isArray(parsed.deletedProducts) ? parsed.deletedProducts : [], + remarks: typeof parsed.remarks === 'string' ? parsed.remarks : '', + }); + + // Restore only when the incoming props don't already have meaningful user-entered data + const hasExistingData = Array.isArray(products) && products.some((p) => { + if (!p) return false; + return Boolean( + p.product || p.productId || p.product_id || + p.unit || p.unit_id || + p.capacity || + p.octQuantity || p.novQuantity || p.decQuantity || + p.janQuantity || p.febQuantity || p.marQuantity || + p.aprQuantity || p.mayQuantity || p.junQuantity || + p.octCost || p.novCost || p.decCost || + p.janCost || p.febCost || p.marCost || + p.aprCost || p.mayCost || p.junCost || + p.variationReason || p.zeroTargetReason || p.remarks + ); + }); + + if (!hasExistingData && Array.isArray(parsed.products)) { + // If we've already restored this exact payload for this key, don't keep re-applying. + if (restoredDraftKeyRef.current === key && restoredDraftSignatureRef.current === parsedSignature) { + return; + } + onProductsChange(parsed.products); + if (Array.isArray(parsed.deletedProducts)) setDeletedProducts(parsed.deletedProducts); + if (typeof parsed.remarks === 'string') setRemarks(parsed.remarks); + restoredDraftKeyRef.current = key; + restoredDraftSignatureRef.current = parsedSignature; + } + } catch (e) { + // ignore parse errors + } + }, [getLocalDraftKey, onProductsChange, products]); + + // Debounced autosave to localStorage whenever user changes anything + React.useEffect(() => { + if (typeof window === 'undefined') return; + const key = draftKeyRef.current || getLocalDraftKey(); + if (!key) return; + + const handle = setTimeout(() => { + persistLocalDraft({ products, deletedProducts, remarks }); + }, 400); + + return () => clearTimeout(handle); + }, [products, deletedProducts, remarks, getLocalDraftKey, persistLocalDraft]); + + // Accidental exit handling: save on tab close, refresh, background, offline + React.useEffect(() => { + if (typeof window === 'undefined') return; + + const onBeforeUnload = () => { + flushLocalDraft(); + }; + + const onVisibilityChange = () => { + if (document.visibilityState === 'hidden') { + flushLocalDraft(); + } + }; + + const onOffline = () => { + flushLocalDraft(); + }; + + window.addEventListener('beforeunload', onBeforeUnload); + document.addEventListener('visibilitychange', onVisibilityChange); + window.addEventListener('offline', onOffline); + + return () => { + window.removeEventListener('beforeunload', onBeforeUnload); + document.removeEventListener('visibilitychange', onVisibilityChange); + window.removeEventListener('offline', onOffline); + }; + }, [flushLocalDraft]); + useEffect(() => { const fetchQuarterPeriods = async () => { try { @@ -564,9 +751,9 @@ useEffect(() => { junCost: product.forecast_cost_period_three?.toString() || '0', // Variation reasons - variationReason: product.variation_reason_master_id?.toString() || '0', + variationReason: product.variation_reason_master_id !== null && product.variation_reason_master_id !== undefined ? product.variation_reason_master_id.toString() : null, otherVariationReason: product.other_variation_reason || '', - zeroTargetReason: product.zero_target_reason_master_id?.toString() || '', + zeroTargetReason: product.zero_target_reason_master_id !== null && product.zero_target_reason_master_id !== undefined ? product.zero_target_reason_master_id.toString() : null, otherZeroTargetReason: product.other_zero_target_reason || '', remarks: product.remarks || '', @@ -730,9 +917,9 @@ const existingProduct = currentSubmission.products?.find(p => // Next quarter forecast (Q2) - December forecast_quantity: product.decQuantity || '0', forecast_cost: product.decCost || '0', - variation_reason_master_id: product.variationReason || '0', + variation_reason_master_id: product.variationReason === null ? null : (product.variationReason || '0'), other_variation_reason: product.otherVariationReason || '0', - zero_target_reason_master_id: product.zeroTargetReason || '0', + zero_target_reason_master_id: product.zeroTargetReason === null ? null : (product.zeroTargetReason || '0'), other_zero_target_reason: product.otherZeroTargetReason || '0', remarks: product.remarks || remarks || '' // Use product.remarks if available, otherwise use the component's remarks state }; @@ -775,9 +962,9 @@ const existingProduct = currentSubmission.products?.find(p => current_cost: product.novCost || '0', forecast_quantity: product.decQuantity || '0', forecast_cost: product.decCost || '0', - variation_reason_master_id: product.variationReason || '0', + variation_reason_master_id: product.variationReason === null ? null : (product.variationReason || '0'), other_variation_reason: product.otherVariationReason || '0', - zero_target_reason_master_id: product.zeroTargetReason || '0', + zero_target_reason_master_id: product.zeroTargetReason === null ? null : (product.zeroTargetReason || '0'), other_zero_target_reason: product.otherZeroTargetReason || '0', remarks: product.remarks || remarks || '', is_active: false // Mark as inactive @@ -893,9 +1080,9 @@ useEffect(() => { junCost: product.forecast_cost_period_three || '0', // Variation reasons - variationReason: product.variation_reason_master_id?.toString() || '', + variationReason: product.variation_reason_master_id !== null && product.variation_reason_master_id !== undefined ? product.variation_reason_master_id.toString() : null, otherVariationReason: product.other_variation_reason || '', - zeroTargetReason: product.zero_target_reason_master_id?.toString() || '', + zeroTargetReason: product.zero_target_reason_master_id !== null && product.zero_target_reason_master_id !== undefined ? product.zero_target_reason_master_id.toString() : null, otherZeroTargetReason: product.other_zero_target_reason || '', remarks: product.remarks || '' }; @@ -1295,8 +1482,8 @@ useEffect(() => { // Dynamic validation for variation reason based on cost variation const mandatoryVariationReason = isVariationReasonMandatory(product); if (mandatoryVariationReason) { - // Check if variation reason is selected - if (!product.variationReason || product.variationReason === '0' || product.variationReason === '') { + // Check if variation reason is selected (null means no selection) + if (product.variationReason === null || product.variationReason === undefined || product.variationReason === '') { errors[`variationReason_${index}`] = 'Reason for variation is required when cost variation exceeds ±10%'; isValid = false; } @@ -1718,8 +1905,8 @@ useEffect(() => { const newErrors = { ...formErrors }; if (mandatoryVariationReason) { - // Check if variation reason is selected - if (!updatedProduct.variationReason || updatedProduct.variationReason === '0' || updatedProduct.variationReason === '') { + // Check if variation reason is selected (null means no selection) + if (updatedProduct.variationReason === null || updatedProduct.variationReason === undefined || updatedProduct.variationReason === '') { newErrors[variationErrorKey] = 'Reason for variation is required when cost variation exceeds ±10%'; } else { delete newErrors[variationErrorKey]; @@ -1759,8 +1946,8 @@ useEffect(() => { if (mandatoryVariationReason) { if (field === 'variationReason') { - // Check if variation reason is selected - if (!updatedProduct.variationReason || updatedProduct.variationReason === '0' || updatedProduct.variationReason === '') { + // Check if variation reason is selected (null means no selection) + if (updatedProduct.variationReason === null || updatedProduct.variationReason === undefined || updatedProduct.variationReason === '') { newErrors[variationErrorKey] = 'Reason for variation is required when cost variation exceeds ±10%'; } else { delete newErrors[variationErrorKey]; @@ -2566,12 +2753,14 @@ useEffect(() => { Reason for Variation {isVariationReasonMandatory(p) && *} - updateProductField(p.id, 'zeroTargetReason', e.target.value, zeroTargetReasons)} + loading={isLoadingZeroReasons} + allowNull={true} /> {(showOtherZeroTargetReason[p.id] || (p.zeroTargetReason && (p.zeroTargetReason.toString().toLowerCase().includes('other') || (zeroTargetReasons.find(r => r.value === p.zeroTargetReason)?.name?.toLowerCase().includes('other') || zeroTargetReasons.find(r => r.value === p.zeroTargetReason)?.label?.toLowerCase().includes('other'))))) && (
diff --git a/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx b/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx index ecfa8fe..dc1c335 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/CompanyProfile.jsx @@ -696,7 +696,7 @@ const CompanyProfile = () => { { field: 'permanentFactoryCode', label: 'Permanent Factory Code' }, { field: 'uniqueLicenseNumber', label: 'Unique License Number' }, // { field: 'industryCodeBusiness', label: 'Industry Code (Business Register)' }, - { field: 'industryCodeProduction', label: 'Industry Code (Current Production)' }, + { field: 'industryCodeProduction', label: 'Principal activity Code (ISIC Rev 4 - 4 digits)' }, ], 2: [ { field: 'contactName', label: 'Name' }, @@ -1009,7 +1009,7 @@ const CompanyProfile = () => {

Details

{/* Responsive grid */} -
+
{ readOnly={modalMode === 'view'} />
- +
+
{ readOnly={modalMode === 'view'} options={isicOptions} searchable + forceDropdownBelow={true} />
-
-
{ HS Code
- Industry Code (Current Production) + Principal activity Code (ISIC Rev 4 - 4 digits)
diff --git a/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx b/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx index b1d5077..d2419cf 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx @@ -122,6 +122,7 @@ const EditCompanyProfile = () => { const [isLoadingProducts, setIsLoadingProducts] = useState(false); const [productError, setProductError] = useState(""); const [productLimitMessage, setProductLimitMessage] = useState(""); + const [isSearching, setIsSearching] = useState(false); // Flag to prevent validation during search const [isLoadingCities, setIsLoadingCities] = useState(false); const [visibleProductCount, setVisibleProductCount] = useState(14); const [isLoadingMore, setIsLoadingMore] = useState(false); @@ -150,7 +151,7 @@ const EditCompanyProfile = () => { // { field: 'permanentFactoryCode', label: 'Permanent Factory Code' }, { field: 'uniqueLicenseNumber', label: 'Unique License Number' }, // { field: 'industryCodeBusiness', label: 'Industry Code (Business Register)' }, - { field: 'industryCodeCurrent', label: 'Industry Code (Current Production)' }, + { field: 'industryCodeCurrent', label: 'Principal activity Code (ISIC Rev 4 - 4 digits)' }, ], 2: [ { field: 'contactName', label: 'Name' }, @@ -177,6 +178,11 @@ const EditCompanyProfile = () => { // Special validation for Products step if (stepIndex === 3) { + // Skip validation if search is in progress to prevent interference + if (isSearching) { + return true; + } + const checkedCount = selectedProducts.filter(p => checkedProducts.has(p.value || p.id || p.product_id)).length; if (checkedCount === 0) { setProductError("At least one product must be checked."); @@ -310,33 +316,60 @@ const EditCompanyProfile = () => { const handleProductSearch = (e) => { const searchTerm = e.target.value.toLowerCase(); setProductSearchTerm(searchTerm); + setIsSearching(true); // Set searching flag + + // Preserve current checked products state before performing search + const currentCheckedProducts = new Set(checkedProducts); if (!searchTerm) { // If search is cleared, reload all products with selected ones filtered out loadProducts(); + setIsSearching(false); // Reset searching flag return; } - // Get all products (including those not currently visible) - const allProducts = [...availableProducts, ...selectedProducts]; + // Get all products from the original full list (not the filtered availableProducts) + // We need to fetch all products again to ensure we have the complete list + const performSearch = async () => { + try { + const allProducts = await fetchProducts(); + + // Filter out selected products from the full list + const availableFromAll = allProducts.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)) + ); + }); + + // Filter products based on search term + const filtered = availableFromAll.filter(product => { + const matchesSearch = + (product.label?.toLowerCase().includes(searchTerm) || + product.hs_code?.toLowerCase().includes(searchTerm) || + (product.product_name && product.product_name.toLowerCase().includes(searchTerm))); + + return matchesSearch; + }); + + // Update availableProducts with search results (even if empty) + // This allows the "No data found" message to be displayed when search yields no results + setAvailableProducts(filtered); + // CRITICAL: Always preserve checked products state after search completes + // This prevents any accidental reset of checked state from any source + setTimeout(() => { + setCheckedProducts(currentCheckedProducts); + setIsSearching(false); // Reset searching flag after state is restored + }, 0); + + } catch (error) { + console.error('Error searching products:', error); + setIsSearching(false); // Reset searching flag on error + } + }; - // 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); + performSearch(); }; // Handle checkbox toggle for selected products @@ -401,8 +434,8 @@ const EditCompanyProfile = () => { // Clear newly added product IDs setNewlyAddedProductIds(new Set()); - // Refresh component to update UI while staying on current step - navigate(window.location.pathname); + // Note: Removed navigation to prevent component remount and state reset + // The UI will update automatically through React state changes } } } @@ -880,47 +913,10 @@ const EditCompanyProfile = () => {

Details

-
- {/* handleFormChange("permanentFactoryCode", e.target.value)} - placeholder="Enter Factory Code" - width="100%" - // required - error={fieldErrors.permanentFactoryCode} - /> */} - {/* handleFormChange("uniqueLicenseNumber", e.target.value)} - placeholder="Enter License Number" - width="100%" - required - error={fieldErrors.uniqueLicenseNumber} - /> - handleFormChange("ERN", e.target.value)} - placeholder="Enter ERN" - width="100%" - error={fieldErrors.ERN} - /> - handleFormChange("industryCodeBusiness", e.target.value)} - placeholder="Enter Code" - width="100%" - // required - error={fieldErrors.industryCodeBusiness} - /> */} -
+
+
handleFormChange("industryCodeCurrent", e.target.value)} @@ -931,17 +927,16 @@ const EditCompanyProfile = () => { error={fieldErrors.industryCodeCurrent} />
-
- handleFormChange("ERN", e.target.value)} - placeholder="Enter ERN" - width="100%" - error={fieldErrors.ERN} - readOnly - - /> +
+ handleFormChange("ERN", e.target.value)} + placeholder="Enter ERN" + width="100%" + error={fieldErrors.ERN} + readOnly + />
{/* { )}
- {/* Available Products Panel - Only show if there are available products and not all selected products are checked */} + {/* Available Products Panel - Show if there are available products and not all selected products are checked, OR if there's a search term */} {(() => { // More robust condition that handles state inconsistencies const hasAvailableProducts = availableProducts.length > 0; const hasSelectedProducts = selectedProducts.length > 0; + const hasSearchTerm = productSearchTerm.length > 0; // Count how many selected products are actually checked let actuallyCheckedCount = 0; @@ -1154,7 +1150,7 @@ const EditCompanyProfile = () => { } const hasUncheckedProducts = actuallyCheckedCount < selectedProducts.length; - const shouldShow = hasAvailableProducts && hasSelectedProducts && hasUncheckedProducts; + const shouldShow = (hasAvailableProducts && hasSelectedProducts && hasUncheckedProducts) || hasSearchTerm; return shouldShow;