added checkbox in the product
This commit is contained in:
parent
d73acd947b
commit
81f8ef2081
@ -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>
|
||||
)}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user