From 4c5df8007cf3c509db94467f4d7ddb16711c9c39 Mon Sep 17 00:00:00 2001 From: Samandar Turg'unboev Date: Fri, 20 Jun 2025 10:58:52 +0500 Subject: [PATCH] add boxes --- src/data/box/box.requests.ts | 3 +- src/data/item/item.requests.ts | 2 +- .../DashboardCreateRealBox.tsx | 174 ++++++++++++------ 3 files changed, 122 insertions(+), 57 deletions(-) diff --git a/src/data/box/box.requests.ts b/src/data/box/box.requests.ts index 16096bb..a5a4e67 100644 --- a/src/data/box/box.requests.ts +++ b/src/data/box/box.requests.ts @@ -1,4 +1,4 @@ -import { IBox, CreateBoxBodyType, UpdateBoxBodyType, IBoxDetail, BoxStatus } from '@/data/box/box.model'; +import { BoxStatus, CreateBoxBodyType, IBox, IBoxDetail, UpdateBoxBodyType } from '@/data/box/box.model'; import { CommonResponseType, PageAble } from '@/helpers/types'; import { request } from '@/services/request'; import axios from 'axios'; @@ -7,6 +7,7 @@ export const box_requests = { async getAll(params?: { page?: number; sort?: string; + pageable?: string | number; direction?: string; cargoId?: string; partyId?: string | number; diff --git a/src/data/item/item.requests.ts b/src/data/item/item.requests.ts index 9769b54..af50e79 100644 --- a/src/data/item/item.requests.ts +++ b/src/data/item/item.requests.ts @@ -29,7 +29,7 @@ export const item_requests = { async find(params: { itemId?: number | string }) { return request.get>('/items/find', { params }); }, - async list(params: { packetId?: number | string }) { + async list(params: { packetId?: number | string; page?: number | string }) { return request.get>('/items/list', { params }); }, async delete(params: { itemId: number | string }) { diff --git a/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx b/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx index 3a384ea..51df7f1 100644 --- a/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx +++ b/src/routes/private/real-boxes-create/DashboardCreateRealBox.tsx @@ -32,7 +32,7 @@ import { import { useQuery } from '@tanstack/react-query'; import get from 'lodash.get'; import { useSearchParams } from 'next/navigation'; -import { useEffect, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Controller, useFieldArray, useForm } from 'react-hook-form'; const StyledCreateBox = styled(Box)` @@ -68,9 +68,35 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { const { push } = useMyNavigation(); const [partyId, setPartyId] = useState(''); const [loading, setLoading] = useState(false); - console.log(initialValues); + + // 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 { - register, control, handleSubmit, setValue, @@ -122,7 +148,6 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { const requiredText = t('required'); - // Fetch parties data const { data: parties = [], isLoading: isLoadingParties } = useQuery({ queryKey: ['parties-list', 'COLLECTING'], queryFn: () => party_requests.getAll({ status: 'COLLECTING' }), @@ -133,18 +158,6 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { })), }); - // Fetch packets data - const { data: packets = [], isLoading: isLoadingPackets } = useQuery({ - queryKey: ['packets-list', partyId, keyword], - queryFn: () => - box_requests.getAll({ - partyId: partyId, - cargoId: keyword, - }), - select: data => data?.data?.data?.data.filter((box: any) => box.status === 'READY_TO_INVOICE') ?? [], - enabled: !!partyId, - }); - const onSubmit = handleSubmit(async values => { try { setLoading(true); @@ -184,6 +197,9 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { setValue('partyName', selectedParty.name); setPartyId(selectedParty.id); setKeyword(''); + setPacketsPage(1); + setPacketsList([]); + setPacketsHasMore(true); setValue('packetItemDtos', [{ packetId: 0, itemDtos: [] }]); } }; @@ -201,18 +217,55 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { remove(index); }; - // Component for each packet row to isolate product selection const PacketRow = ({ index, field }: { index: number; field: any }) => { const packetId = watch(`packetItemDtos.${index}.packetId`); - // Fetch products specific to this packet - const { data: products, isLoading: isLoadingProducts } = useQuery({ - queryKey: ['product-list', packetId], - queryFn: () => item_requests.list({ packetId }), - select: data => data?.data?.data.data ?? [], + // Itemlar uchun scroll state + const [itemsPage, setItemsPage] = useState(1); + const [itemsList, setItemsList] = useState([]); + const [itemsHasMore, setItemsHasMore] = useState(true); + const itemScrollRef = useRef(null); + + const { isLoading: isLoadingProducts } = useQuery({ + queryKey: ['product-list', packetId, itemsPage], + queryFn: () => item_requests.list({ packetId, page: itemsPage }), enabled: !!packetId, + 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 handleItemScroll = (e: React.UIEvent) => { + const { scrollTop, scrollHeight, clientHeight } = e.currentTarget; + const isNearBottom = scrollHeight - scrollTop - clientHeight < 50; + + if (isNearBottom && !isLoadingProducts && itemsHasMore) { + setItemsPage(prev => prev + 1); + } + }; + + 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`, []); + } + }; + return (
@@ -247,18 +300,30 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { }} value={field.value || ''} disabled={isLoadingPackets} + MenuProps={{ + PaperProps: { + style: { maxHeight: 280 }, + ref: packetScrollRef, + onScroll: handlePacketScroll, + }, + }} > - {isLoadingPackets ? ( + {isLoadingPackets && packetsList.length === 0 ? ( ) : ( - packets.map(packet => ( + packetsList.map(packet => ( - {packet.name || packet.name || `Box ${packet.id}`} + {packet.name || `Box ${packet.id}`} )) )} + {isLoadingPackets && packetsList.length > 0 && ( + + + + )} )} /> @@ -286,30 +351,16 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { {t('products')} - {isLoadingProducts ? ( + {isLoadingProducts && itemsList.length === 0 ? ( ) : ( - ( - { - if (e.target.checked) { - setValue(`packetItemDtos.${index}.itemDtos`, products?.map(p => p.id) || []); - } else { - setValue(`packetItemDtos.${index}.itemDtos`, []); - } - }} - indeterminate={ - watch(`packetItemDtos.${index}.itemDtos`)?.length > 0 && - watch(`packetItemDtos.${index}.itemDtos`)?.length < products?.length! - } - /> - )} + 0 && selectedProducts.length < itemsList.length} + checked={itemsList.length > 0 && selectedProducts.length === itemsList.length} + onChange={e => handleSelectAll(e.target.checked)} + disabled={itemsList.length === 0} /> {t('select_all')} @@ -319,31 +370,44 @@ const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { render={({ field }) => ( )} />