import { SimplePagination } from '@components/common/SimplePagination.js'; import { Button } from '@components/common/ui/Button.js'; import { Input } from '@components/common/ui/Input.js'; import { Check } from 'lucide-react'; import React from 'react'; import { toast } from 'react-toastify'; import { useQuery } from 'urql'; import { AtLeastOne } from '../../types/atLeastOne.js'; import { ProductListSkeleton } from './ProductListSkeleton.js'; const SearchQuery = ` query Query ($filters: [FilterInput!]) { products(filters: $filters) { items { productId uuid sku name price { regular { text } } image { url } } total } } `; type ProductIdentifier = { sku?: string; uuid?: string; productId?: string; }; const isProductSelected = ( product: ProductIdentifier, selectedProducts: Array> ): boolean => { return selectedProducts.some( (selected) => (selected?.sku && selected.sku === product.sku) || (selected?.uuid && selected.uuid === product.uuid) || (selected?.productId && selected.productId === product.productId) ); }; const ProductSelector: React.FC<{ onSelect: ( sku: string, uuid: string, productId: string ) => Promise | void; onUnSelect?: ( sku: string, uuid: string, productId: string ) => Promise | void; selectedProducts: Array>; }> = ({ onSelect, onUnSelect, selectedProducts }) => { const limit = 10; const [internalSelectedProducts, setSelectedProducts] = React.useState< Array> >(selectedProducts || []); const [inputValue, setInputValue] = React.useState(null); const [loading, setLoading] = React.useState(false); const [page, setPage] = React.useState(1); const [result, reexecuteQuery] = useQuery({ query: SearchQuery, variables: { filters: inputValue ? [ { key: 'keyword', operation: 'eq', value: inputValue }, { key: 'page', operation: 'eq', value: page.toString() }, { key: 'limit', operation: 'eq', value: limit.toString() } ] : [ { key: 'limit', operation: 'eq', value: limit.toString() }, { key: 'page', operation: 'eq', value: page.toString() } ] }, pause: true }); const selectProduct = async ( sku: string, uuid: string, productId: string ) => { setSelectedProducts((prev) => [...prev, { sku, uuid, productId }]); try { await onSelect(sku, uuid, productId); } catch (e) { toast.error(e.message); } }; const unSelectProduct = async ( sku: string, uuid: string, productId: string ) => { if (!onUnSelect) { return; } setSelectedProducts((prev) => prev.filter((product) => product?.sku !== sku) ); try { await onUnSelect(sku, uuid, productId); } catch (e) { toast.error(e.message); } }; React.useEffect(() => { reexecuteQuery({ requestPolicy: 'network-only' }); }, [page]); React.useEffect(() => { const timer = setTimeout(() => { setLoading(false); if (inputValue !== null) { reexecuteQuery({ requestPolicy: 'network-only' }); } }, 1500); return () => clearTimeout(timer); }, [inputValue]); const { data, fetching, error } = result; if (error) { return (

There was an error fetching products. {error.message}

); } return (
{ setInputValue(e.target.value); setLoading(true); }} />
{(fetching || loading) && } {!fetching && data && !loading && (
{data.products.items.length === 0 && (
{inputValue ? (

No products found for query "{inputValue}”

) : (

You have no products to display

)}
)} {data.products.items.map((product) => (
{product.image?.url && ( {product.name} )} {!product.image?.url && ( )}

{product.name}

{product.sku}

{!isProductSelected(product, internalSelectedProducts) && ( )} {isProductSelected(product, internalSelectedProducts) && ( )}
))}
)}
); }; export { ProductSelector };