added checkbox in the product

This commit is contained in:
Malini 2026-02-12 16:46:35 +05:30
parent d73acd947b
commit 81f8ef2081
2 changed files with 152 additions and 38 deletions

View File

@ -1899,7 +1899,7 @@ useEffect(() => {
<h3 className="font-semibold mb-4 text-base">Data definitions</h3>
<p className="mb-3"><strong>Product (HS Code Name):</strong> Standard trade classification. Start typing to search by code or name.</p>
<p className="mb-3"><strong>Quantity (Qty):</strong> Physical output produced in the month, measured in the selected unit.</p>
<p className="mb-3"><strong>Value (AED <img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5" />):</strong> Total production value for that month for a single product, excluding VAT/ duties. sales value for that product - VAT.</p>
<p className="mb-3"><strong>Value (AED <img src={uae_currency} alt="AED" className="inline-block w-5 h-5 -mt-0.5" />):</strong> The net monthly sales value of a single product excluding VAT and any applicable duties. Do not include sales margins.<br /><em><strong>Formula:</strong></em> Sales Value (VAT, Duties, etc)</p>
<p className="mb-0"><strong>Annual Installed Capacity:</strong> Maximum achievable annual output under normal operating conditions with existing equipment; do not include extraordinary overtime.</p>
</div>
)}

View File

@ -1,7 +1,8 @@
import React, { useState, useMemo, useCallback, useEffect, useRef } from "react";
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { FaBuilding } from 'react-icons/fa6';
import { MdAdminPanelSettings } from "react-icons/md";
import { MdAdminPanelSettings, MdOutlineCheckBoxOutlineBlank } from "react-icons/md";
import { IoMdCheckbox, IoMdCheckboxOutline } from "react-icons/io";
import { TextField, SelectField, PhoneField } from "@/components/common/FormControls";
import Loader from "@/components/common/Loader";
import { fetchEstablishmentDetail, updateEstablishment } from '@/services/establishments/establishmentService';
@ -101,6 +102,7 @@ const EditCompanyProfile = () => {
const [isLoadingCities, setIsLoadingCities] = useState(false);
const [visibleProductCount, setVisibleProductCount] = useState(14);
const [isLoadingMore, setIsLoadingMore] = useState(false);
const [checkedProducts, setCheckedProducts] = useState(new Set());
const initialSnapshotRef = useRef(null);
const productListRef = useRef(null);
@ -312,7 +314,91 @@ const EditCompanyProfile = () => {
setAvailableProducts(filtered);
};
// Handle checkbox toggle for selected products
const handleCheckboxToggle = (productValue) => {
setCheckedProducts(prev => {
const newChecked = new Set(prev);
const product = selectedProducts.find(p =>
(p.value && (p.value === productValue || p.value === productValue || p.value === productValue)) ||
(p.id && (p.id === productValue || p.id === productValue || p.id === productValue)) ||
(p.product_id && (p.product_id === productValue || p.product_id === productValue || p.product_id === productValue))
);
if (newChecked.has(productValue)) {
// Unchecking: move product from selected to available
newChecked.delete(productValue);
if (product) {
// Add product back to available products
setAvailableProducts(prev => {
const alreadyExists = prev.some(p =>
(p.value && (p.value === product.value || p.value === product.id || p.value === product.product_id)) ||
(p.id && (p.id === product.id || p.id === product.value || p.id === product.product_id)) ||
(p.product_id && (p.product_id === product.product_id || p.product_id === product.id || p.product_id === product.value))
);
if (!alreadyExists) {
return [...prev, product];
}
return prev;
});
}
} else {
// Re-checking: remove newly added products and restore original
newChecked.add(productValue);
// Remove from available products
setAvailableProducts(prev =>
prev.filter(p =>
!(p.value && (p.value === productValue || p.value === productValue || p.value === productValue)) &&
!(p.id && (p.id === productValue || p.id === productValue || p.id === productValue)) &&
!(p.product_id && (p.product_id === productValue || p.product_id === productValue || p.product_id === productValue))
)
);
// If this is an original product being re-checked, remove newly added products
if (product && product.isExisting) {
// Find all newly added products (not original)
const newlyAddedProducts = selectedProducts.filter(p =>
!p.isExisting && newlyAddedProductIds.has(p.value || p.id || p.product_id)
);
if (newlyAddedProducts.length > 0) {
// Remove newly added products from selected list
setSelectedProducts(prev =>
prev.filter(p =>
!(p.value && newlyAddedProducts.some(np => np.value === p.value || np.value === p.id || np.value === p.product_id)) &&
!(p.id && newlyAddedProducts.some(np => np.id === p.id || np.id === p.value || np.id === p.product_id)) &&
!(p.product_id && newlyAddedProducts.some(np => np.product_id === p.product_id || np.product_id === p.id || np.product_id === p.value))
)
);
// Add newly added products back to available products
setAvailableProducts(prev => {
const productsToAdd = newlyAddedProducts.filter(np =>
!prev.some(p =>
(p.value && (p.value === np.value || p.value === np.id || p.value === np.product_id)) ||
(p.id && (p.id === np.id || p.id === np.value || p.id === np.product_id)) ||
(p.product_id && (p.product_id === np.product_id || p.product_id === np.id || p.product_id === np.value))
)
);
return [...prev, ...productsToAdd];
});
// Clear newly added product IDs
setNewlyAddedProductIds(new Set());
// Show alert to user
alert('Original product restored. Replacement products have been removed.');
}
}
}
return newChecked;
});
};
// Handle adding a product
const handleAddProduct = (product) => {
setSelectedProducts(prev => {
@ -327,6 +413,15 @@ const EditCompanyProfile = () => {
return prev; // Don't add duplicate
}
// Count current newly added products (excluding original products)
const currentNewlyAdded = prev.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 prev;
}
return [...prev, product];
});
@ -343,18 +438,17 @@ const EditCompanyProfile = () => {
setNewlyAddedProductIds(prev =>
new Set([...prev, product.value || product.id || product.product_id])
);
// Set newly added product as checked by default
setCheckedProducts(prev =>
new Set([...prev, product.value || product.id || product.product_id])
);
};
// Remove product handler
const handleRemoveProduct = (product) => {
// First, add the removed product back to available products if it matches the search
const searchTerm = productSearchTerm.toLowerCase();
const shouldAddToAvailable =
!productSearchTerm ||
(product.label?.toLowerCase().includes(searchTerm) ||
product.hs_code?.toLowerCase().includes(searchTerm) ||
(product.product_name && product.product_name.toLowerCase().includes(searchTerm)));
const productId = product.value || product.id || product.product_id;
// Remove from selected products
setSelectedProducts(prev =>
prev.filter(p =>
@ -364,31 +458,34 @@ const EditCompanyProfile = () => {
)
);
// Add back to available products if it matches the current search
if (shouldAddToAvailable) {
setAvailableProducts(prev => {
// Check if already in available products
const alreadyExists = prev.some(p =>
(p.value && (p.value === product.value || p.value === product.id || p.value === product.product_id)) ||
// Remove from checked products
setCheckedProducts(prev => {
const newChecked = new Set(prev);
newChecked.delete(productId);
return newChecked;
});
// Remove from newly added product IDs if it's a newly added product
setNewlyAddedProductIds(prev => {
const newIds = new Set(prev);
newIds.delete(productId);
return newIds;
});
// Always add back to available products
setAvailableProducts(prev => {
// Check if already in available products
const alreadyExists = prev.some(p =>
(p.value && (p.value === product.value || p.value === product.id || p.value === product.product_id)) ||
(p.id && (p.id === product.id || p.id === product.value || p.id === product.product_id)) ||
(p.product_id && (p.product_id === product.product_id || p.product_id === product.id || p.product_id === product.value))
);
if (!alreadyExists) {
// Get all products (including the one being removed)
const allProducts = [...prev, ...selectedProducts];
const uniqueProducts = allProducts.filter((p, index, self) =>
index === self.findIndex(t =>
(t.value && (t.value === p.value || t.value === p.id || t.value === p.product_id)) ||
(t.id && (t.id === p.id || t.id === p.value || t.id === p.product_id)) ||
(t.product_id && (t.product_id === p.product_id || t.product_id === p.id || t.product_id === p.value))
)
);
return uniqueProducts;
}
return prev;
});
}
);
if (!alreadyExists) {
return [...prev, product];
}
return prev;
});
};
// Reset visible count when products change or search is performed
@ -508,6 +605,8 @@ const EditCompanyProfile = () => {
setSelectedProducts(formattedSelectedProducts);
// Initialize newly added products as empty since we're loading existing data
setNewlyAddedProductIds(new Set());
// Initialize all selected products as checked by default
setCheckedProducts(new Set(formattedSelectedProducts.map(p => p.value || p.id || p.product_id)));
// Now load available products with selected ones filtered out
const filteredAvailable = allProducts.filter(product => {
@ -625,11 +724,12 @@ const EditCompanyProfile = () => {
(Number(form.employmentNonEmiratiFemale) || 0),
updated_by: 1,
establishment_products: Array.isArray(selectedProducts) && selectedProducts.length > 0
? selectedProducts.map(p => ({
? selectedProducts
.filter(p => checkedProducts.has(p.value || p.id || p.product_id))
.map(p => ({
product_id: Number(p.value) || 0,
action_done_by: p.action_done_by || "establishment_users",
created_by: p.created_by || establishmentId
}))
: [],
};
@ -710,6 +810,7 @@ const EditCompanyProfile = () => {
error={fieldErrors.permanentFactoryCode}
/> */}
{/* <TextField
label="Unique License Number"
value={form.uniqueLicenseNumber || ""}
onChange={(e) => handleFormChange("uniqueLicenseNumber", e.target.value)}
@ -933,7 +1034,8 @@ const EditCompanyProfile = () => {
)}
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Available Products Panel */}
{/* Available Products Panel - Only show if not all selected products are checked */}
{selectedProducts.length > 0 && checkedProducts.size < selectedProducts.length && (
<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>
@ -1000,6 +1102,7 @@ const EditCompanyProfile = () => {
</div>
</div>
</div>
)}
{/* Selected Products Panel */}
<div className="bg-white rounded-lg border border-[#E5E7EB] overflow-hidden">
@ -1023,12 +1126,23 @@ const EditCompanyProfile = () => {
const hsCode = product.label?.split(" - ")[0] ?? "";
const productName = product.label?.split(" - ")[1] ?? product.label;
return (
return (
<li
key={product.value}
className="p-3 hover:bg-[#F9FAFB] flex justify-between items-center"
>
<div className="flex items-center gap-2">
<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