From 75dea29b7b15d9483c71434078905ad0428f08d7 Mon Sep 17 00:00:00 2001 From: Samandar Turg'unboev Date: Fri, 20 Jun 2025 14:21:40 +0500 Subject: [PATCH] add boxes --- src/data/item/item.requests.ts | 2 +- .../DashboardCreateRealBox.tsx | 267 +++++++++++------- 2 files changed, 163 insertions(+), 106 deletions(-) diff --git a/src/data/item/item.requests.ts b/src/data/item/item.requests.ts index af50e79..664280e 100644 --- a/src/data/item/item.requests.ts +++ b/src/data/item/item.requests.ts @@ -30,7 +30,7 @@ export const item_requests = { return request.get>('/items/find', { params }); }, async list(params: { packetId?: number | string; page?: number | string }) { - return request.get>('/items/list', { params }); + return request.get>>('/items/list', { params }); }, async delete(params: { itemId: number | string }) { return request.delete('/items/delete', { params }); diff --git a/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx b/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx index 51df7f1..0917b6d 100644 --- a/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx +++ b/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx @@ -24,6 +24,7 @@ import { InputLabel, ListItemText, MenuItem, + OutlinedInput, Select, Stack, styled, @@ -62,40 +63,12 @@ interface Props { const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { const { user } = useAuthContext(); const editMode = !!initialValues?.id; - const [keyword, setKeyword] = useState(''); const t = useMyTranslation(); const params = useSearchParams(); const { push } = useMyNavigation(); const [partyId, setPartyId] = useState(''); const [loading, setLoading] = useState(false); - // Packetlar uchun scroll state - const [packetsPage, setPacketsPage] = useState(1); - const [packetsList, setPacketsList] = useState([]); - const [packetsHasMore, setPacketsHasMore] = useState(true); - const packetScrollRef = useRef(null); - - const { isFetching: isLoadingPackets } = useQuery({ - queryKey: ['packets-list', partyId, keyword, packetsPage], - queryFn: () => box_requests.getAll({ partyId, cargoId: keyword, page: packetsPage }), - enabled: !!partyId, - onSuccess: data => { - const newPackets = data?.data?.data?.data || []; - setPacketsList(prev => (packetsPage === 1 ? newPackets : [...prev, ...newPackets])); - const totalPages = data?.data?.data?.totalPages || 0; - setPacketsHasMore(packetsPage < totalPages); - }, - }); - - const handlePacketScroll = (e: React.UIEvent) => { - const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; - const isNearBottom = scrollHeight - scrollTop - clientHeight < 50; - - if (isNearBottom && !isLoadingPackets && packetsHasMore) { - setPacketsPage(prev => prev + 1); - } - }; - const { control, handleSubmit, @@ -191,19 +164,6 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { } }); - const handlePartyChange = (event: any) => { - const selectedParty = parties.find(p => p.id === event.target.value); - if (selectedParty) { - setValue('partyName', selectedParty.name); - setPartyId(selectedParty.id); - setKeyword(''); - setPacketsPage(1); - setPacketsList([]); - setPacketsHasMore(true); - setValue('packetItemDtos', [{ packetId: 0, itemDtos: [] }]); - } - }; - const handlePacketChange = (index: number, value: number) => { setValue(`packetItemDtos.${index}.packetId`, value); setValue(`packetItemDtos.${index}.itemDtos`, []); @@ -216,15 +176,32 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { const removePacket = (index: number) => { remove(index); }; + const [packetSearchTerm, setPacketSearchTerm] = useState(''); + const packetSearchInputRef = useRef(null); + + const handlePartyChange = (event: any) => { + const selectedParty = parties.find(p => p.id === event.target.value); + if (selectedParty) { + setValue('partyName', selectedParty.name); + setPartyId(selectedParty.id); + setValue('packetItemDtos', [{ packetId: 0, itemDtos: [] }]); + } + }; + + const [paketName, setPaketName] = useState(''); const PacketRow = ({ index, field }: { index: number; field: any }) => { const packetId = watch(`packetItemDtos.${index}.packetId`); - - // Itemlar uchun scroll state + // Tanlangan paketning name'ini olish const [itemsPage, setItemsPage] = useState(1); const [itemsList, setItemsList] = useState([]); const [itemsHasMore, setItemsHasMore] = useState(true); const itemScrollRef = useRef(null); + // Packetlar uchun scroll state + const [packetsPage, setPacketsPage] = useState(1); + const [packetsList, setPacketsList] = useState([]); + const selectedPacket = packetsList.find(p => p.id === packetId); + const [packetsHasMore, setPacketsHasMore] = useState(true); const { isLoading: isLoadingProducts } = useQuery({ queryKey: ['product-list', packetId, itemsPage], @@ -233,11 +210,33 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { onSuccess: data => { const newItems = data?.data?.data?.data || []; setItemsList(prev => (itemsPage === 1 ? newItems : [...prev, ...newItems])); - // const totalPages = data?.data?.data || 0; - // setItemsHasMore(itemsPage < totalPages); }, }); + const packetScrollRef = useRef(null); + const [keyword, setKeyword] = useState(''); + + const { isFetching: isLoadingPackets } = useQuery({ + queryKey: ['packets-list', partyId, keyword, packetsPage], + queryFn: () => box_requests.getAll({ partyId, cargoId: keyword, page: packetsPage }), + enabled: !!partyId, + onSuccess: data => { + const newPackets = data?.data?.data?.data || []; + setPacketsList(prev => (packetsPage === 1 ? newPackets : [...prev, ...newPackets])); + const totalPages = data?.data?.data?.totalPages || 0; + setPacketsHasMore(packetsPage < totalPages); + }, + }); + + const handlePacketScroll = (e: React.UIEvent) => { + const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; + const isNearBottom = scrollHeight - scrollTop - clientHeight < 50; + + if (isNearBottom && !isLoadingPackets && packetsHasMore) { + setPacketsPage(prev => prev + 1); + } + }; + const handleItemScroll = (e: React.UIEvent) => { const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; const isNearBottom = scrollHeight - scrollTop - clientHeight < 50; @@ -248,22 +247,51 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { }; useEffect(() => { - // Reset items list when packet changes setItemsPage(1); setItemsList([]); setItemsHasMore(true); }, [packetId]); - const selectedProducts = watch(`packetItemDtos.${index}.itemDtos`) || []; - const handleSelectAll = (checked: boolean) => { - if (checked) { - setValue( - `packetItemDtos.${index}.itemDtos`, - itemsList.map((p: any) => p.id) - ); - } else { - setValue(`packetItemDtos.${index}.itemDtos`, []); - } + const [selectedProductNames, setSelectedProductNames] = useState<{ [packetIndex: number]: { [productId: number]: string } }>({}); + + const handleSelectAll = (checked: boolean, packetIndex: number, packetId: number, itemsList: any[]) => { + setSelectedProductNames(prev => { + const prevNames = prev[packetIndex] || {}; + if (checked) { + // add all products of current page + const newNames = { ...prevNames }; + itemsList.forEach(p => { + newNames[p.id] = p.nameRu || p.name || String(p.id); + }); + return { ...prev, [packetIndex]: newNames }; + } else { + // remove all products of current page + const newNames = { ...prevNames }; + itemsList.forEach(p => { + delete newNames[p.id]; + }); + return { ...prev, [packetIndex]: newNames }; + } + }); + setValue( + `packetItemDtos.${packetIndex}.itemDtos`, + checked + ? Array.from(new Set([...(watch(`packetItemDtos.${packetIndex}.itemDtos`) || []), ...itemsList.map(p => p.id)])) + : (watch(`packetItemDtos.${packetIndex}.itemDtos`) || []).filter(id => !itemsList.some(p => p.id === id)) + ); + }; + + const handleProductChange = (packetIndex: number, product: any, checked: boolean) => { + setSelectedProductNames(prev => { + const prevNames = prev[packetIndex] || {}; + if (checked) { + return { ...prev, [packetIndex]: { ...prevNames, [product.id]: product.nameRu || product.name || String(product.id) } }; + } else { + const newNames = { ...prevNames }; + delete newNames[product.id]; + return { ...prev, [packetIndex]: newNames }; + } + }); }; return ( @@ -282,6 +310,7 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { justifyContent={'space-between'} alignItems={'center'} > + setKeyword(e.target.value)} />
{t('packet')} @@ -290,41 +319,45 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { control={control} rules={{ required: requiredText }} render={({ field }) => ( - + paketName || packetsList.find(p => p.id === selected)?.name || t('select') + } + MenuProps={{ + PaperProps: { + style: { maxHeight: 280 }, + ref: packetScrollRef, + onScroll: handlePacketScroll, + }, + disableAutoFocus: true, + autoFocus: false, + }} + onClick={e => e.stopPropagation()} + > + {isLoadingPackets && packetsList.length === 0 ? ( + + - )) - )} - {isLoadingPackets && packetsList.length > 0 && ( - - - - )} - + ) : ( + packetsList.map(packet => ( + setPaketName(packet.name)}> + {packet.name} + + )) + )} + {isLoadingPackets && packetsList.length > 0 && ( + + + + )} + + )} /> {!!get(errors, `packetItemDtos.${index}.packetId`) && ( @@ -355,7 +388,7 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { ) : ( - + {/* 0 && selectedProducts.length < itemsList.length} checked={itemsList.length > 0 && selectedProducts.length === itemsList.length} @@ -363,7 +396,7 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { disabled={itemsList.length === 0} /> {t('select_all')} - + */} { }} renderValue={selected => ( - {(selected as any[]).map(value => ( + {(selected as any[]).map(id => ( p.id === value)?.name} + key={id} + label={ + selectedProductNames[index]?.[id] || + itemsList.find(p => p.id === id)?.nameRu || + itemsList.find(p => p.id === id)?.name || + id + } onDelete={e => { e.stopPropagation(); - field.onChange(field.value.filter((id: any) => id !== value)); + field.onChange(field.value.filter((x: any) => x !== id)); + handleProductChange(index, { id }, false); }} /> ))} )} > + + 0 && field.value.length < itemsList.length} + checked={ + itemsList.length > 0 && itemsList.every((p: any) => field.value.includes(p.id)) + } + onChange={e => handleSelectAll(e.target.checked, index, packetId, itemsList)} + /> + {t('select_all')} + {itemsList.map(product => ( - e.stopPropagation()}> + { + e.stopPropagation(); + const checked = !field.value.includes(product.id); + let newValue; + if (checked) { + newValue = [...field.value, product.id]; + } else { + newValue = field.value.filter((x: any) => x !== product.id); + } + field.onChange(newValue); + handleProductChange(index, product, checked); + }} + > - + ))} - {isLoadingProducts && itemsHasMore && ( - - - - - - )} )} />