'use client'; import BaseButton from '@/components/ui-kit/BaseButton'; import BaseIconButton from '@/components/ui-kit/BaseIconButton'; import { useAuthContext } from '@/context/auth-context'; import { box_requests } from '@/data/box/box.requests'; import { item_requests } from '@/data/item/item.requests'; import { party_requests } from '@/data/party/party.requests'; import { FormValues, RealCreateBoxBodyType, UpdateRealBoxBodyType } from '@/data/real-box/real-box.model'; import { real_box_requests } from '@/data/real-box/real-box.requests'; import { pageLinks } from '@/helpers/constants'; import { useMyNavigation } from '@/hooks/useMyNavigation'; import { useMyTranslation } from '@/hooks/useMyTranslation'; import { notifyUnknownError } from '@/services/notification'; import { AddCircleRounded, Close } from '@mui/icons-material'; import { Box, Button, Checkbox, Chip, CircularProgress, FormControl, FormHelperText, Grid, InputLabel, ListItemText, MenuItem, OutlinedInput, Select, Stack, styled, Typography, } from '@mui/material'; import { useQuery } from '@tanstack/react-query'; import get from 'lodash.get'; import { useSearchParams } from 'next/navigation'; import { useEffect, useRef, useState } from 'react'; import { Controller, useFieldArray, useForm } from 'react-hook-form'; const StyledCreateBox = styled(Box)` .item-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; } & > * { flex: 1 1 1; } `; interface Props { partiesData?: { value: number; label: string }[]; initialValues?: { id?: number; boxId?: string; partyId?: number; partyName?: string; paketIds?: Array; }; } const DashboardCreateRealBoxPage = ({ initialValues, partiesData }: Props) => { const { user } = useAuthContext(); const editMode = !!initialValues?.id; const t = useMyTranslation(); const params = useSearchParams(); const { push } = useMyNavigation(); const [partyId, setPartyId] = useState(''); const [loading, setLoading] = useState(false); const { control, handleSubmit, setValue, reset, watch, formState: { errors }, } = useForm({ defaultValues: { partyName: initialValues?.partyName || '', packetItemDtos: initialValues?.paketIds ? initialValues.paketIds.map(paket => ({ packetId: paket.id, itemDtos: paket.items ? paket.items.map((item: any) => item.id) : [], })) : params.get('party_id') ? [{ packetId: +params.get('party_id')!, itemDtos: [] }] : [{ packetId: 0, itemDtos: [] }], id: initialValues?.id, boxId: initialValues?.boxId, partyId: initialValues?.partyId, }, }); useEffect(() => { if (initialValues) { reset({ partyName: initialValues.partyName || '', packetItemDtos: initialValues.paketIds ? initialValues.paketIds.map(paket => ({ packetId: paket.id, itemDtos: paket.items ? paket.items.map((item: any) => item.id) : [], })) : [{ packetId: 0, itemDtos: [] }], id: initialValues.id, boxId: initialValues.boxId, partyId: initialValues.partyId, }); if (initialValues.partyId) { setPartyId(initialValues.partyId); } } }, [initialValues, reset]); const { fields, append, remove } = useFieldArray({ control, name: 'packetItemDtos', keyName: 'key', }); const requiredText = t('required'); const { data: parties = [], isLoading: isLoadingParties } = useQuery({ queryKey: ['parties-list', 'COLLECTING'], queryFn: () => party_requests.getAll({ status: 'COLLECTING' }), select: data => data.data.data.data.map((p: any) => ({ id: p.id, name: p.name, })), }); const onSubmit = handleSubmit(async values => { try { setLoading(true); if (editMode) { const updateBody: UpdateRealBoxBodyType = { boxId: initialValues!.boxId!, partyName: values.partyName, packetItemDtos: values.packetItemDtos.map(packet => ({ packetId: packet.packetId, itemDtos: packet.itemDtos, })), }; await real_box_requests.update(updateBody); } else { const createBody: RealCreateBoxBodyType = { partyName: values.partyName, packetItemDtos: values.packetItemDtos.map(packet => ({ packetId: packet.packetId, itemDtos: packet.itemDtos, })), }; await real_box_requests.create(createBody); } push(pageLinks.dashboard.real_boxes.index); } catch (error) { notifyUnknownError(error); } finally { setLoading(false); } }); const handlePacketChange = (index: number, value: number) => { setValue(`packetItemDtos.${index}.packetId`, value); setValue(`packetItemDtos.${index}.itemDtos`, []); }; const appendPacket = () => { append({ packetId: 0, itemDtos: [] }); }; 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`); const [itemsPage, setItemsPage] = useState(1); const [itemsList, setItemsList] = useState([]); const [itemsHasMore, setItemsHasMore] = useState(true); const itemScrollRef = useRef(null); const [packetsPage, setPacketsPage] = useState(1); const [packetsList, setPacketsList] = useState([]); const [packetsHasMore, setPacketsHasMore] = useState(true); const [selectedProductNames, setSelectedProductNames] = useState<{ [packetIndex: number]: { [productId: number]: string } }>({}); const [paketName, setPaketName] = useState(''); const [lastPacketId, setLastPacketId] = useState(null); const { isLoading: isLoadingProducts } = useQuery({ queryKey: ['product-list', packetId, itemsPage], queryFn: () => item_requests.getAll({ packetId, page: itemsPage }), enabled: !!packetId, onSuccess: data => { const newItems = data?.data?.data?.data || []; setItemsList(prev => (itemsPage === 1 ? newItems : [...prev, ...newItems])); }, }); 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; if (isNearBottom && !isLoadingProducts && itemsHasMore) { setItemsPage(prev => prev + 1); } }; const handleProductChange = (packetIndex: number, product: any, checked: boolean) => { setSelectedProductNames(prev => { const prevNames = prev[packetIndex] || {}; if (checked) { return { ...prev, [packetIndex]: { ...prevNames, [product.id]: product.name || product.nameRu || String(product.id) } }; } else { const newNames = { ...prevNames }; delete newNames[product.id]; return { ...prev, [packetIndex]: newNames }; } }); }; const handleSelectAllProducts = async () => { if (!packetId) return; let allProducts: any[] = []; let page = 1; let totalPages = 1; try { do { const res = await item_requests.list({ packetId, page }); const data = res?.data?.data; const products = data?.data || []; totalPages = data?.totalPages || 1; allProducts = [...allProducts, ...products]; page++; } while (page <= totalPages); } catch (e) { // error silent } if (allProducts.length > 0) { setValue( `packetItemDtos.${index}.itemDtos`, allProducts.map((p: any) => p.id) ); setSelectedProductNames((prev: any) => ({ ...prev, [index]: allProducts.reduce( (acc, p) => ({ ...acc, [p.id]: p.name || p.nameRu || String(p.id), }), {} ), })); } }; const handleClearAll = () => { setValue(`packetItemDtos.${index}.itemDtos`, []); setSelectedProductNames((prev: any) => ({ ...prev, [index]: {} })); }; return (
{t('packet')}
setKeyword(e.target.value)} />
{t('packet')} ( <> )} /> {!!get(errors, `packetItemDtos.${index}.packetId`) && ( {requiredText} )}
{fields.length > 1 && ( removePacket(index)} > )}
{packetId && ( {t('products')} {isLoadingProducts && itemsList.length === 0 ? ( ) : ( ( )} /> )} )}
); }; return ( {editMode ? t('update_box') : t('create_box')} {t('party_name')} {t('party_name')} ( )} /> {!!errors.partyId && {requiredText}}
{fields.map((field, index) => ( ))} } sx={{ mt: 2 }}> {t('add_packet')}
{loading ? : editMode ? t('update_box') : t('create_box')}
); }; export default DashboardCreateRealBoxPage;