import React, { useState, useMemo } from 'react'; import { View } from 'react-native'; import BottomDropdown, { DropdownOption } from 'common-ui/src/components/bottom-dropdown'; import { trpc } from '../src/trpc-client'; import { tw } from 'common-ui'; interface Product { id: number; name: string; price: number; unit?: string; shortDescription?: string | null; isOutOfStock?: boolean; isSuspended?: boolean; storeId?: number | null; unitNotation?: string; } interface Group { id: number; groupName: string; products: Product[]; } interface ProductsSelectorProps { value: number | number[]; onChange: (value: number | number[]) => void; multiple?: boolean; label?: string; placeholder?: string; disabled?: boolean; error?: boolean; isDisabled?: (product: Product) => boolean; labelFormat?: (product: Product) => string; groups?: Group[]; selectedGroupIds?: number[]; onGroupChange?: (groupIds: number[]) => void; showGroups?: boolean; } export default function ProductsSelector({ value, onChange, multiple = true, label = 'Select Products', placeholder = 'Select products', disabled = false, error = false, isDisabled, labelFormat, groups = [], showGroups = true, selectedGroupIds = [], onGroupChange, }: ProductsSelectorProps) { const { data: productsData } = trpc.common.product.getAllProductsSummary.useQuery({}); const products = productsData?.products || []; const [searchQuery, setSearchQuery] = useState(''); // Format product label: name (unit) (₹price) const formatProductLabel = (product: Product): string => { if (labelFormat) { return labelFormat(product); } const unit = product.unit ? ` (${product.unit})` : ''; const price = ` (₹${product.price})`; return `${product.name}${unit}${price}`; }; // Handle group selection changes const handleGroupChange = (newGroupIds: number[]) => { if (!onGroupChange) return; const previousGroupIds = selectedGroupIds; // Find which groups were added and which were removed const addedGroups = newGroupIds.filter(id => !previousGroupIds.includes(id)); const removedGroups = previousGroupIds.filter(id => !newGroupIds.includes(id)); // Get current selected products let currentProducts = Array.isArray(value) ? [...value] : value ? [value] : []; // Add products from newly selected groups const addedProducts = addedGroups.flatMap(groupId => { const group = groups.find(g => g.id === groupId); return group?.products.map(p => p.id) || []; }); // Remove products from deselected groups const removedProducts = removedGroups.flatMap(groupId => { const group = groups.find(g => g.id === groupId); return group?.products.map(p => p.id) || []; }); // Update product list: add new ones, remove deselected group ones currentProducts = [...new Set([...currentProducts, ...addedProducts])]; currentProducts = currentProducts.filter(id => !removedProducts.includes(id)); onGroupChange(newGroupIds); if (multiple) { onChange(currentProducts.length > 0 ? currentProducts : []); } else { onChange(currentProducts.length > 0 ? currentProducts[0] : 0); } }; // Filter products based on search query const filteredProducts = useMemo(() => { if (!searchQuery.trim()) return products; const query = searchQuery.toLowerCase(); return products.filter(product => product.name.toLowerCase().includes(query) || (product.shortDescription && product.shortDescription.toLowerCase().includes(query)) || (product.unit && product.unit.toLowerCase().includes(query)) ); }, [products, searchQuery]); // Build dropdown options const productOptions: DropdownOption[] = useMemo(() => { return filteredProducts.map((product) => { const isFromGroup = selectedGroupIds.length > 0 && groups.some(group => selectedGroupIds.includes(group.id) && group.products.some(p => p.id === product.id) ); const isProductDisabled = isDisabled ? isDisabled(product as Product) : false; return { label: `${formatProductLabel(product as Product)}${isFromGroup ? ' (from group)' : ''}`, value: product.id.toString(), disabled: isProductDisabled, }; }); }, [filteredProducts, selectedGroupIds, groups, isDisabled, labelFormat]); // Build group options if groups are provided const groupOptions: DropdownOption[] = useMemo(() => { return groups.map(group => ({ label: group.groupName, value: group.id.toString(), })); }, [groups]); return ( {/* Groups selector (if groups are provided and showGroups is true) */} {showGroups && groups.length > 0 && ( id.toString())} onValueChange={(value) => { const selectedValues = Array.isArray(value) ? value : typeof value === 'string' ? [value] : []; const newGroupIds = selectedValues.map(v => parseInt(v as string)); handleGroupChange(newGroupIds); }} placeholder="Select product groups (optional)" multiple={true} /> )} {/* Products selector */} id.toString()) : []) : (value ? value.toString() : '') } onValueChange={(selectedValue) => { if (multiple) { const selectedValues = Array.isArray(selectedValue) ? selectedValue : typeof selectedValue === 'string' ? [selectedValue] : []; onChange(selectedValues.map(v => Number(v))); } else { onChange(Number(selectedValue)); } }} placeholder={placeholder} multiple={multiple} disabled={disabled} error={error} onSearch={setSearchQuery} /> ); }