bug fixed in products

This commit is contained in:
Malini 2026-02-20 16:15:08 +05:30
parent 0d4ae03789
commit 52df438da4

View File

@ -102,6 +102,7 @@ const EditCompanyProfile = () => {
const [productSearchTerm, setProductSearchTerm] = useState('');
const [isLoadingProducts, setIsLoadingProducts] = useState(false);
const [productError, setProductError] = useState("");
const [productLimitMessage, setProductLimitMessage] = useState("");
const [isLoadingCities, setIsLoadingCities] = useState(false);
const [visibleProductCount, setVisibleProductCount] = useState(14);
const [isLoadingMore, setIsLoadingMore] = useState(false);
@ -157,8 +158,9 @@ const EditCompanyProfile = () => {
// Special validation for Products step
if (stepIndex === 3) {
if (selectedProducts.length === 0) {
setProductError("At least one product is required.");
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.");
return false;
} else {
setProductError("");
@ -181,7 +183,7 @@ const EditCompanyProfile = () => {
return nextErrors;
});
return valid;
}, [form, requiredFieldsByStep, selectedProducts]);
}, [form, requiredFieldsByStep, selectedProducts, checkedProducts]);
const handleFormChange = useCallback((field, value) => {
// Clear remarks if either industry code field is changed
@ -408,15 +410,47 @@ const EditCompanyProfile = () => {
}
return; // Don't add duplicate, don't modify available products
}
// Count current newly added products (excluding original products)
const currentNewlyAdded = selectedProducts.filter(p => newlyAddedProductIds.has(p.value || p.id || p.product_id));
// Allow up to 4 newly added products
if (currentNewlyAdded.length >= 4) {
alert('Maximum of 4 replacement products can be added.');
return; // Don't add product, don't modify available products
const MAX_TOTAL_SELECTED_PRODUCTS = 15;
const MAX_NEW_PRODUCTS_PER_ACTION = 4;
const checkedCountTotal = selectedProducts.filter(p => checkedProducts.has(p.value || p.id || p.product_id)).length;
if (checkedCountTotal >= MAX_TOTAL_SELECTED_PRODUCTS) {
setProductLimitMessage(`Maximum of ${MAX_TOTAL_SELECTED_PRODUCTS} products can be selected.`);
return;
}
// Count newly added products (current action) that are selected/checked
const newlyAddedCheckedCount = selectedProducts.filter(p => {
const productId = p.value || p.id || p.product_id;
return !p.isExisting && checkedProducts.has(productId);
}).length;
// Base count should represent selected products excluding the newly added ones
const baseSelectedCount = checkedCountTotal - newlyAddedCheckedCount;
// Allowed additions are capped by both per-action limit and remaining total slots (<= logic)
const allowedAddCount = Math.min(
MAX_NEW_PRODUCTS_PER_ACTION,
Math.max(0, MAX_TOTAL_SELECTED_PRODUCTS - baseSelectedCount)
);
if (newlyAddedCheckedCount >= allowedAddCount) {
if (allowedAddCount === 0) {
setProductLimitMessage(`Maximum of ${MAX_TOTAL_SELECTED_PRODUCTS} products can be selected.`);
} else {
setProductLimitMessage(`You can add up to ${allowedAddCount} new product${allowedAddCount !== 1 ? 's' : ''}.`);
}
return;
}
if (baseSelectedCount + newlyAddedCheckedCount + 1 > MAX_TOTAL_SELECTED_PRODUCTS) {
setProductLimitMessage(`Maximum of ${MAX_TOTAL_SELECTED_PRODUCTS} products can be selected.`);
return;
}
// Clear any previous limit message when product can be added
setProductLimitMessage("");
// Only proceed with adding the product if we pass all checks
setSelectedProducts(prev => [...prev, { ...product, isExisting: false }]);
@ -473,6 +507,9 @@ const EditCompanyProfile = () => {
return newIds;
});
// Clear limit message when product is removed
setProductLimitMessage("");
// Always add back to available products
setAvailableProducts(prev => {
// Check if already in available products
@ -1106,6 +1143,53 @@ const EditCompanyProfile = () => {
<div className="bg-white rounded-lg border border-[#E5E7EB] overflow-hidden">
<div className="bg-[#F9FAFB] px-4 py-3 border-b border-[#E5E7EB]">
<h5 className="text-sm font-medium text-[#111827]">Available Products</h5>
{(() => {
const MAX_TOTAL_SELECTED_PRODUCTS = 15;
const MAX_NEW_PRODUCTS_PER_ACTION = 4;
const checkedCountTotal = selectedProducts.filter(p => checkedProducts.has(p.value || p.id || p.product_id)).length;
const newlyAddedCheckedCount = selectedProducts.filter(p => {
const productId = p.value || p.id || p.product_id;
return !p.isExisting && checkedProducts.has(productId);
}).length;
const baseSelectedCount = checkedCountTotal - newlyAddedCheckedCount;
const allowedAddCount = Math.min(
MAX_NEW_PRODUCTS_PER_ACTION,
Math.max(0, MAX_TOTAL_SELECTED_PRODUCTS - baseSelectedCount)
);
const remainingToAdd = Math.max(0, allowedAddCount - newlyAddedCheckedCount);
if (productLimitMessage) return null;
if (checkedCountTotal >= MAX_TOTAL_SELECTED_PRODUCTS || allowedAddCount === 0) {
return (
<p className="text-xs text-[#B91C1C] mt-1">Maximum of {MAX_TOTAL_SELECTED_PRODUCTS} products can be selected.</p>
);
}
if (newlyAddedCheckedCount >= allowedAddCount) {
return (
<p className="text-xs text-[#B91C1C] mt-1">You can add up to {allowedAddCount} new product{allowedAddCount !== 1 ? 's' : ''}.</p>
);
}
if (remainingToAdd < MAX_NEW_PRODUCTS_PER_ACTION) {
return (
<p className="text-xs text-[#B91C1C] mt-1">You can add {remainingToAdd} more product{remainingToAdd !== 1 ? 's' : ''}.</p>
);
}
if (allowedAddCount < MAX_NEW_PRODUCTS_PER_ACTION) {
return (
<p className="text-xs text-[#B91C1C] mt-1">You can add up to {allowedAddCount} new product{allowedAddCount !== 1 ? 's' : ''}.</p>
);
}
return null;
})()}
{productLimitMessage && (
<p className="text-xs text-[#B91C1C] mt-1">{productLimitMessage}</p>
)}
</div>
<div className="p-4">
<div className="relative mb-4">
@ -1149,7 +1233,39 @@ const EditCompanyProfile = () => {
<button
type="button"
onClick={() => handleAddProduct(product)}
className="text-[#92722A] hover:text-[#7A5F1E] text-sm font-medium"
disabled={(() => {
const MAX_TOTAL_SELECTED_PRODUCTS = 15;
const MAX_NEW_PRODUCTS_PER_ACTION = 4;
const checkedCountTotal = selectedProducts.filter(p => checkedProducts.has(p.value || p.id || p.product_id)).length;
const newlyAddedCheckedCount = selectedProducts.filter(p => {
const productId = p.value || p.id || p.product_id;
return !p.isExisting && checkedProducts.has(productId);
}).length;
const baseSelectedCount = checkedCountTotal - newlyAddedCheckedCount;
const allowedAddCount = Math.min(
MAX_NEW_PRODUCTS_PER_ACTION,
Math.max(0, MAX_TOTAL_SELECTED_PRODUCTS - baseSelectedCount)
);
return checkedCountTotal >= MAX_TOTAL_SELECTED_PRODUCTS || newlyAddedCheckedCount >= allowedAddCount;
})()}
className={`text-sm font-medium ${(() => {
const MAX_TOTAL_SELECTED_PRODUCTS = 15;
const MAX_NEW_PRODUCTS_PER_ACTION = 4;
const checkedCountTotal = selectedProducts.filter(p => checkedProducts.has(p.value || p.id || p.product_id)).length;
const newlyAddedCheckedCount = selectedProducts.filter(p => {
const productId = p.value || p.id || p.product_id;
return !p.isExisting && checkedProducts.has(productId);
}).length;
const baseSelectedCount = checkedCountTotal - newlyAddedCheckedCount;
const allowedAddCount = Math.min(
MAX_NEW_PRODUCTS_PER_ACTION,
Math.max(0, MAX_TOTAL_SELECTED_PRODUCTS - baseSelectedCount)
);
const disabled = checkedCountTotal >= MAX_TOTAL_SELECTED_PRODUCTS || newlyAddedCheckedCount >= allowedAddCount;
return disabled
? 'text-gray-400 cursor-not-allowed'
: 'text-[#92722A] hover:text-[#7A5F1E]';
})()}`}
>
Add
</button>
@ -1170,94 +1286,93 @@ const EditCompanyProfile = () => {
</div>
</div>
)}
{/* Selected Products Panel */}
<div className="bg-white rounded-lg border border-[#E5E7EB] overflow-hidden">
<div className="bg-[#F9FAFB] px-4 py-3 border-b border-[#E5E7EB] flex justify-between items-center">
<h5 className="text-sm font-medium text-[#111827]">Selected Products</h5>
<div className="bg-white rounded-lg border border-[#E5E7EB] overflow-hidden">
<div className="bg-[#F9FAFB] px-4 py-3 border-b border-[#E5E7EB] flex justify-between items-center">
<h5 className="text-sm font-medium text-[#111827]">Selected Products</h5>
{selectedProducts.length > 0 && (
<span className="bg-[#FEF3C7] text-[#92400E] text-xs font-medium px-2 py-0.5 rounded-full">
{selectedProducts.length} selected
</span>
)}
</div>
<div className="p-4">
{selectedProducts.length > 0 ? (
<ul className="divide-y divide-[#E5E7EB] max-h-96 overflow-y-auto">
{selectedProducts.map((product) => {
const isNewlyAdded = newlyAddedProductIds.has(product.value);
// extract hs + name
const hsCode = product.label?.split(" - ")[0] ?? "";
const productName = product.label?.split(" - ")[1] ?? product.label;
return (
<li
key={product.value}
className="p-3 hover:bg-[#F9FAFB] flex justify-between items-center"
>
<div className="flex items-center gap-2">
{!isNewlyAdded && (
<button
type="button"
onClick={() => handleCheckboxToggle(product.value)}
className="flex-shrink-0 w-5 h-5"
>
{checkedProducts.has(product.value) ? (
<IoMdCheckbox className="text-[#92722A] text-lg" />
) : (
<MdOutlineCheckBoxOutlineBlank className="text-[#92722A] text-lg" />
)}
</button>
)}
{product.action_done_by === "admin_users" ? (
<MdAdminPanelSettings
className="text-[#92722A] text-lg flex-shrink-0 w-6 h-6"
title="Added by Admin"
/>
) : (
<FaBuilding
className="text-[#92722A] flex-shrink-0 w-6 h-5"
title="Added by Establishment"
/>
)}
<div>
<div className="text-sm font-medium text-[#111827]">
{productName}
</div>
<div className="text-xs text-gray-500 mt-1">
HS Code: {hsCode}
<div className="flex items-center gap-2">
<span className="bg-[#FEF3C7] text-[#92400E] text-xs font-medium px-2 py-0.5 rounded-full">
{selectedProducts.filter(p => checkedProducts.has(p.value || p.id || p.product_id)).length}/15 selected
</span>
</div>
</div>
<div className="p-4">
{selectedProducts.length > 0 ? (
<ul className="divide-y divide-[#E5E7EB] max-h-96 overflow-y-auto">
{selectedProducts.map((product) => {
const isNewlyAdded = newlyAddedProductIds.has(product.value);
// extract hs + name
const hsCode = product.label?.split(" - ")[0] ?? "";
const productName = product.label?.split(" - ")[1] ?? product.label;
return (
<li
key={product.value}
className="p-3 hover:bg-[#F9FAFB] flex justify-between items-center"
>
<div className="flex items-center gap-2">
{!isNewlyAdded && (
<button
type="button"
onClick={() => handleCheckboxToggle(product.value)}
className="flex-shrink-0 w-5 h-5"
>
{checkedProducts.has(product.value) ? (
<IoMdCheckbox className="text-[#92722A] text-lg" />
) : (
<MdOutlineCheckBoxOutlineBlank className="text-[#92722A] text-lg" />
)}
</button>
)}
{product.action_done_by === "admin_users" ? (
<MdAdminPanelSettings
className="text-[#92722A] text-lg flex-shrink-0 w-6 h-6"
title="Added by Admin"
/>
) : (
<FaBuilding
className="text-[#92722A] flex-shrink-0 w-6 h-5"
title="Added by Establishment"
/>
)}
<div>
<div className="text-sm font-medium text-[#111827]">
{productName}
</div>
<div className="text-xs text-gray-500 mt-1">
HS Code: {hsCode}
</div>
</div>
</div>
{isNewlyAdded && (
<button
type="button"
onClick={() => handleRemoveProduct(product)}
className="text-[#EF4444] hover:text-[#DC2626] text-sm font-medium"
title="Remove product"
>
Remove
</button>
)}
</li>
);
})}
</ul>
) : (
<div className="p-4 text-center text-sm text-[#6B7280] border border-[#E5E7EB] rounded-md">
No products selected
</div>
)}
</div>
</div>
{isNewlyAdded && (
<button
type="button"
onClick={() => handleRemoveProduct(product)}
className="text-[#EF4444] hover:text-[#DC2626] text-sm font-medium"
title="Remove product"
>
Remove
</button>
)}
</li>
);
})}
</ul>
) : (
<div className="p-4 text-center text-sm text-[#6B7280] border border-[#E5E7EB] rounded-md">
No products selected
</div>
)}
</div>
</div>
</div>
</div>
);