bug fixed
This commit is contained in:
parent
821c913b59
commit
2e14579ec5
@ -97,16 +97,39 @@ const SearchableSelect = ({
|
||||
}, [options, searchTerm]);
|
||||
|
||||
// Get selected option label
|
||||
const [internalDisplayValue, setInternalDisplayValue] = React.useState(displayValue || '');
|
||||
const selectedOption = options.find(opt => opt.value === value);
|
||||
const displayValueToShow = displayValue !== undefined
|
||||
? displayValue
|
||||
: (selectedOption ? selectedOption.label : '');
|
||||
|
||||
// Update internal display value when value, displayValue prop or options change
|
||||
React.useEffect(() => {
|
||||
if (displayValue !== undefined && displayValue !== '') {
|
||||
setInternalDisplayValue(displayValue);
|
||||
} else if (selectedOption) {
|
||||
setInternalDisplayValue(selectedOption.label);
|
||||
} else if (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]);
|
||||
|
||||
const displayValueToShow = internalDisplayValue;
|
||||
|
||||
// Handle option selection
|
||||
const handleSelect = (option) => {
|
||||
if (onChange) {
|
||||
const event = { target: { value: option.value } };
|
||||
const event = {
|
||||
target: {
|
||||
value: option.value,
|
||||
name: name,
|
||||
selectedDisplay: option.label,
|
||||
option: option
|
||||
}
|
||||
};
|
||||
onChange(event);
|
||||
setInternalDisplayValue(option.label);
|
||||
}
|
||||
setSearchTerm('');
|
||||
setIsOpen(false);
|
||||
@ -1235,7 +1258,6 @@ const location = useLocation();
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div data-field={`product_${idx}`}>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Product (HS Code - Name) <span className="text-red-500">*</span></label>
|
||||
<div>
|
||||
<SearchableSelect
|
||||
placeholder={isLoadingProducts ? 'Loading products...' : 'Search product HS code...'}
|
||||
options={getAvailableProducts(p.id)}
|
||||
@ -1366,10 +1388,6 @@ const location = useLocation();
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{productsError && productOptions.length === 0 && (
|
||||
<p className="mt-1 text-xs text-red-600">{productsError}</p>
|
||||
)}
|
||||
</div>
|
||||
<div data-field={`unit_${idx}`}>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Unit <span className="text-red-500">*</span></label>
|
||||
<SearchableSelect
|
||||
@ -1379,17 +1397,24 @@ const location = useLocation();
|
||||
displayValue={p.unitName || ''}
|
||||
onChange={(e) => {
|
||||
const unitId = e.target.value;
|
||||
const selectedUnit = unitOptions.find(u => u.value === unitId);
|
||||
const originalUnit = selectedUnit?.originalData || {};
|
||||
const displayName = originalUnit.uom_short_name && originalUnit.uom
|
||||
? `${originalUnit.uom_short_name.toUpperCase()} - ${originalUnit.uom}`
|
||||
: selectedUnit?.label || '';
|
||||
updateProductField(idx, 'unit', unitId);
|
||||
updateProductField(idx, 'unitName', displayName);
|
||||
const displayName = e.target.selectedDisplay ||
|
||||
unitOptions.find(u => u.value === unitId)?.label ||
|
||||
'';
|
||||
|
||||
// Update both unit and unitName in a single update
|
||||
const updatedProduct = {
|
||||
...p,
|
||||
unit: unitId,
|
||||
unitName: displayName
|
||||
};
|
||||
|
||||
const updatedProducts = [...products];
|
||||
updatedProducts[idx] = updatedProduct;
|
||||
onProductsChange(updatedProducts);
|
||||
}}
|
||||
loading={isLoadingUnits}
|
||||
error={!!formErrors[`unit_${idx}`]}
|
||||
// disabled={!!p.unitName} // Disable if unit is auto-filled from product
|
||||
name={`unit_${idx}`}
|
||||
/>
|
||||
<div className="h-5">
|
||||
{formErrors[`unit_${idx}`] && (
|
||||
|
||||
@ -28,7 +28,7 @@ const createEmptyCodeForm = () => ({
|
||||
});
|
||||
|
||||
// Toast notification component
|
||||
const Toast = ({ message, type = 'success', onClose }) => {
|
||||
const Toast = ({ message, type = 'success', onClose, position = 'page' }) => {
|
||||
React.useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
onClose();
|
||||
@ -49,6 +49,18 @@ const Toast = ({ message, type = 'success', onClose }) => {
|
||||
}
|
||||
};
|
||||
|
||||
// For modal toasts, we'll use relative positioning
|
||||
if (position === 'modal') {
|
||||
return (
|
||||
<div className="w-full mb-4">
|
||||
<div className={`px-4 py-2 rounded-md text-sm ${getToastStyles()}`}>
|
||||
{message}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Default page-level toast
|
||||
return (
|
||||
<div className="fixed top-0 left-0 w-full flex justify-center z-50 mt-4">
|
||||
<div className={`px-6 py-3 rounded-md shadow-lg font-medium ${getToastStyles()}`}>
|
||||
@ -354,7 +366,12 @@ const IsicHsCodes = () => {
|
||||
const [modalMode, setModalMode] = React.useState(null);
|
||||
const [form, setForm] = React.useState(createEmptyCodeForm());
|
||||
const [unitOptions, setUnitOptions] = React.useState([]);
|
||||
const [toast, setToast] = React.useState({ show: false, message: '', type: 'success' });
|
||||
const [toast, setToast] = React.useState({
|
||||
show: false,
|
||||
message: '',
|
||||
type: 'success',
|
||||
position: 'page' // 'page' or 'modal'
|
||||
});
|
||||
const [showImportModal, setShowImportModal] = React.useState(false);
|
||||
const [isRefreshing, setIsRefreshing] = React.useState(false);
|
||||
|
||||
@ -767,8 +784,8 @@ const IsicHsCodes = () => {
|
||||
setForm(createEmptyCodeForm());
|
||||
};
|
||||
|
||||
const showToast = (message, type = 'success') => {
|
||||
setToast({ show: true, message, type });
|
||||
const showToast = (message, type = 'success', position = 'page') => {
|
||||
setToast({ show: true, message, type, position });
|
||||
setTimeout(() => {
|
||||
setToast(prev => ({ ...prev, show: false }));
|
||||
}, 3000);
|
||||
@ -833,7 +850,7 @@ const IsicHsCodes = () => {
|
||||
if (!form.code || !form.product) {
|
||||
const errorMsg = 'Please fill in all required fields';
|
||||
console.error(errorMsg);
|
||||
setError(errorMsg);
|
||||
showToast(errorMsg, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -875,8 +892,9 @@ const IsicHsCodes = () => {
|
||||
const productId = form.id || (editingRow !== null ? rowsData[editingRow]?.id : null);
|
||||
|
||||
if (!productId) {
|
||||
console.error('Product ID not found for editing');
|
||||
setError('Cannot update product: Product ID not found');
|
||||
const errorMsg = 'Cannot update product: Product ID not found';
|
||||
console.error(errorMsg);
|
||||
showToast(errorMsg, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -934,7 +952,7 @@ const IsicHsCodes = () => {
|
||||
if (error.response?.data?.message) {
|
||||
errorMessage = error.response.data.message;
|
||||
}
|
||||
setError(errorMessage);
|
||||
showToast(errorMessage, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@ -972,7 +990,7 @@ const IsicHsCodes = () => {
|
||||
if (createError.response?.data?.message) {
|
||||
errorMessage = createError.response.data.message;
|
||||
}
|
||||
setError(errorMessage);
|
||||
showToast(errorMessage, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error in handleSaveForm:', error);
|
||||
@ -1075,10 +1093,12 @@ const IsicHsCodes = () => {
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
{toast.show && (
|
||||
{/* Page-level toasts */}
|
||||
{toast.show && toast.position === 'page' && (
|
||||
<Toast
|
||||
message={toast.message}
|
||||
type={toast.type}
|
||||
position="page"
|
||||
onClose={() => setToast(prev => ({ ...prev, show: false }))}
|
||||
/>
|
||||
)}
|
||||
@ -1373,6 +1393,15 @@ const IsicHsCodes = () => {
|
||||
|
||||
{/* Form */}
|
||||
<div className="p-6 space-y-4">
|
||||
{/* Modal-level toast */}
|
||||
{toast.show && toast.position === 'modal' && (
|
||||
<Toast
|
||||
message={toast.message}
|
||||
type={toast.type}
|
||||
position="modal"
|
||||
onClose={() => setToast(prev => ({ ...prev, show: false }))}
|
||||
/>
|
||||
)}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-[#374151] mb-1">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user