diff --git a/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx b/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx index 621a551..0e286f7 100644 --- a/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx +++ b/ipi-survey-platform/src/pages/Admin/configuration/EditCompanyProfile.jsx @@ -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 = () => {
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; + 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 ( +

Maximum of {MAX_TOTAL_SELECTED_PRODUCTS} products can be selected.

+ ); + } + + if (newlyAddedCheckedCount >= allowedAddCount) { + return ( +

You can add up to {allowedAddCount} new product{allowedAddCount !== 1 ? 's' : ''}.

+ ); + } + + if (remainingToAdd < MAX_NEW_PRODUCTS_PER_ACTION) { + return ( +

You can add {remainingToAdd} more product{remainingToAdd !== 1 ? 's' : ''}.

+ ); + } + + if (allowedAddCount < MAX_NEW_PRODUCTS_PER_ACTION) { + return ( +

You can add up to {allowedAddCount} new product{allowedAddCount !== 1 ? 's' : ''}.

+ ); + } + + return null; + })()} + {productLimitMessage && ( +

{productLimitMessage}

+ )}
@@ -1149,7 +1233,39 @@ const EditCompanyProfile = () => { @@ -1170,94 +1286,93 @@ const EditCompanyProfile = () => {
)} - + {/* Selected Products Panel */} -
-
-
Selected Products
+
+
+
Selected Products
- {selectedProducts.length > 0 && ( - - {selectedProducts.length} selected - - )} -
- -
- {selectedProducts.length > 0 ? ( -
    - {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 ( -
  • -
    - {!isNewlyAdded && ( - - )} - - {product.action_done_by === "admin_users" ? ( - - ) : ( - - )} - -
    -
    - {productName} -
    - -
    - HS Code: {hsCode} +
    + + {selectedProducts.filter(p => checkedProducts.has(p.value || p.id || p.product_id)).length}/15 selected +
    + +
    + {selectedProducts.length > 0 ? ( +
      + {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 ( +
    • +
      + {!isNewlyAdded && ( + + )} + + {product.action_done_by === "admin_users" ? ( + + ) : ( + + )} + +
      +
      + {productName} +
      + +
      + HS Code: {hsCode} +
      +
      +
      + + {isNewlyAdded && ( + + )} +
    • + ); + })} +
    + ) : ( +
    + No products selected +
    + )} +
    - - {isNewlyAdded && ( - - )} -
  • - ); - })} -
- ) : ( -
- No products selected -
- )} -
-
-
);