397 lines
14 KiB
TypeScript
397 lines
14 KiB
TypeScript
'use client';
|
|
|
|
import ActionPopMenu from '@/components/common/ActionPopMenu';
|
|
import { MyTable, ColumnData } from '@/components/common/MyTable';
|
|
import StatusChangePopup from '@/components/common/StatusChangePopup';
|
|
import BaseButton from '@/components/ui-kit/BaseButton';
|
|
import BaseIconButton from '@/components/ui-kit/BaseIconButton';
|
|
import BaseInput from '@/components/ui-kit/BaseInput';
|
|
import BasePagination from '@/components/ui-kit/BasePagination';
|
|
import { useAuthContext } from '@/context/auth-context';
|
|
import { BoxStatus, BoxStatusList, IBox } from '@/data/box/box.model';
|
|
import { box_requests } from '@/data/box/box.requests';
|
|
import { IRealBox } from '@/data/real-box/real-box.model';
|
|
import { real_box_requests } from '@/data/real-box/real-box.requests';
|
|
import { DEFAULT_PAGE_SIZE, pageLinks } from '@/helpers/constants';
|
|
import useDebouncedInput from '@/hooks/useDebouncedInput';
|
|
import useInput from '@/hooks/useInput';
|
|
import { useMyNavigation } from '@/hooks/useMyNavigation';
|
|
import { useMyTranslation } from '@/hooks/useMyTranslation';
|
|
import useRequest from '@/hooks/useRequest';
|
|
import { file_service } from '@/services/file-service';
|
|
import { notifyUnknownError } from '@/services/notification';
|
|
import { getBoxStatusStyles, getStatusColor } from '@/theme/getStatusBoxStyles';
|
|
import { Add, QrCode, AddCircleOutline, Circle, Delete, Download, Edit, FilterList, FilterListOff, Search, PlusOne } from '@mui/icons-material';
|
|
import { Box, Button, Stack, Tooltip, Typography } from '@mui/material';
|
|
import { useRouter } from 'next/navigation';
|
|
import { log } from 'node:console';
|
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
|
|
type Props = {};
|
|
|
|
const DashboardRealBoxesPage = (props: Props) => {
|
|
const t = useMyTranslation();
|
|
const navigation = useMyNavigation();
|
|
const { isAdmin } = useAuthContext();
|
|
const [page, setPage] = useState(1);
|
|
const [pageSize] = useState(DEFAULT_PAGE_SIZE);
|
|
const { value: keyword, onChange: handleKeyword, setValue: setKeyword } = useInput('');
|
|
const [boxStatusFilter, setBoxStatusFilter] = useState<BoxStatus | undefined>(undefined);
|
|
|
|
const [deleteIds, setDeleteIds] = useState<number[]>([]);
|
|
const [downloadIds, setDownloadIds] = useState<number[]>([]);
|
|
const [changeStatusIds, setChangeStatusIds] = useState<number[]>([]);
|
|
|
|
const boxStatusOptions = useMemo(() => {
|
|
const p = ['READY_TO_INVOICE'] as BoxStatus[];
|
|
if (isAdmin) {
|
|
p.push('READY');
|
|
}
|
|
return p;
|
|
}, [isAdmin]);
|
|
|
|
const getBoxesQuery = useRequest(
|
|
() =>
|
|
real_box_requests.getAll({
|
|
page: page,
|
|
cargoId: keyword,
|
|
status: boxStatusFilter,
|
|
direction: 'desc',
|
|
sort: 'id',
|
|
}),
|
|
{
|
|
dependencies: [page, boxStatusFilter],
|
|
selectData(data) {
|
|
return data.data.data;
|
|
},
|
|
}
|
|
);
|
|
|
|
const {
|
|
data: list,
|
|
totalElements,
|
|
totalPages,
|
|
} = useMemo(() => {
|
|
if (getBoxesQuery.data?.data) {
|
|
return {
|
|
data: getBoxesQuery.data.data,
|
|
totalElements: getBoxesQuery.data.totalElements,
|
|
totalPages: getBoxesQuery.data.totalPages,
|
|
};
|
|
} else {
|
|
return {
|
|
data: [],
|
|
totalElements: 0,
|
|
totalPages: 0,
|
|
};
|
|
}
|
|
}, [getBoxesQuery]);
|
|
|
|
const loading = getBoxesQuery.loading;
|
|
const handleChange = (newPage: number) => {
|
|
setTimeout(() => {
|
|
setPage(newPage);
|
|
}, 100);
|
|
};
|
|
|
|
const resetFilter = () => {
|
|
setPage(1);
|
|
setKeyword('');
|
|
setBoxStatusFilter(undefined);
|
|
};
|
|
|
|
const onDelete = async (id: number) => {
|
|
if (deleteIds.includes(id)) return;
|
|
|
|
try {
|
|
setDeleteIds(p => [...p, id]);
|
|
await real_box_requests.delete({ boxId: id });
|
|
getBoxesQuery.refetch();
|
|
} catch (error) {
|
|
notifyUnknownError(error);
|
|
} finally {
|
|
setDeleteIds(prev => prev.filter(i => i !== id));
|
|
}
|
|
};
|
|
|
|
const onDownloadExcel = async (id: number, name: string) => {
|
|
if (downloadIds.includes(id)) return;
|
|
|
|
try {
|
|
setDownloadIds(p => [...p, id]);
|
|
const response = await real_box_requests.downloadExcel({ boxId: id });
|
|
const file = new File([response.data], `${name}.xlsx`, { type: response.data.type });
|
|
file_service.download(file);
|
|
} catch (error) {
|
|
notifyUnknownError(error);
|
|
} finally {
|
|
setDownloadIds(prev => prev.filter(i => i !== id));
|
|
}
|
|
};
|
|
|
|
const onDownloadQrCode = async (id: number) => {
|
|
if (downloadIds.includes(id)) return;
|
|
|
|
try {
|
|
setDownloadIds(p => [...p, id]);
|
|
const response = await real_box_requests.downloadQrCode({ boxId: id });
|
|
console.log(response, "rres");
|
|
const file = new File([response.data], 'qr.png', { type: response.data.type });
|
|
file_service.download(file);
|
|
} catch (error) {
|
|
notifyUnknownError(error);
|
|
console.log(error);
|
|
} finally {
|
|
setDownloadIds(prev => prev.filter(i => i !== id));
|
|
}
|
|
};
|
|
|
|
const onChangeStatus = async (id: number, newStatus: BoxStatus) => {
|
|
if (changeStatusIds.includes(id)) return;
|
|
|
|
try {
|
|
setChangeStatusIds(p => [...p, id]);
|
|
await box_requests.changeStatus({ packetId: id, status: newStatus });
|
|
getBoxesQuery.refetch();
|
|
} catch (error) {
|
|
notifyUnknownError(error);
|
|
} finally {
|
|
setChangeStatusIds(prev => prev.filter(i => i !== id));
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const timeoutId = setTimeout(() => {
|
|
setPage(1);
|
|
getBoxesQuery.refetch();
|
|
}, 350);
|
|
return () => clearTimeout(timeoutId);
|
|
}, [keyword]);
|
|
|
|
// No, PartyName, PacketName, PartyTozaOg'irlik, CountOfItems, WeightOfItems, CargoID, PassportNameFamily - PacketStatusForInvoice
|
|
const columns: ColumnData<IRealBox>[] = [
|
|
{
|
|
label: t('No'),
|
|
width: 100,
|
|
renderCell(data, rowIndex) {
|
|
return (page - 1) * pageSize + rowIndex + 1;
|
|
},
|
|
},
|
|
{
|
|
label: t("qr_code"),
|
|
width: 120,
|
|
renderCell: data => {
|
|
return <Button
|
|
onClick={() =>
|
|
onDownloadQrCode(data.id)
|
|
}>
|
|
<QrCode />
|
|
</Button >;
|
|
},
|
|
},
|
|
{
|
|
dataKey: 'id',
|
|
label: t("add_more"),
|
|
width: 120,
|
|
renderCell: data => {
|
|
return <Button onClick={() => navigation.push(pageLinks.dashboard.real_boxes.edit(data.id))}>
|
|
<Add />
|
|
</Button>;
|
|
},
|
|
},
|
|
{
|
|
dataKey: 'boxName',
|
|
label: t('cargo_id'),
|
|
width: 120,
|
|
},
|
|
{
|
|
dataKey: "boxName",
|
|
label: t('party_name'),
|
|
width: 120,
|
|
},
|
|
// {
|
|
// dataKey: 'name',
|
|
// label: t('name'),
|
|
// width: 120,
|
|
// },
|
|
// {
|
|
// dataKey: 'packetNetWeight',
|
|
// label: t("weight"),
|
|
// width: 120,
|
|
// },
|
|
{
|
|
dataKey: 'packetsCount',
|
|
label: t('count_of_items'),
|
|
width: 120,
|
|
},
|
|
// {
|
|
// dataKey: 'totalNetWeight',
|
|
// label: t("party_weight"),
|
|
// width: 120,
|
|
// },
|
|
// {
|
|
// dataKey: 'passportName',
|
|
// label: t('client'),
|
|
// width: 120,
|
|
// },
|
|
// {
|
|
// dataKey: 'status',
|
|
// label: t('status'),
|
|
// width: 240,
|
|
// renderHeaderCell(rowIndex) {
|
|
// return (
|
|
// <Stack direction={'row'} alignItems={'center'}>
|
|
// <span>{t('box_status')}</span>
|
|
// <ActionPopMenu
|
|
// buttons={BoxStatusList.map(stat => {
|
|
// return {
|
|
// icon: <Circle sx={{ path: { color: getStatusColor(stat) } }} />,
|
|
// label: t(stat),
|
|
// onClick() {
|
|
// setBoxStatusFilter(stat);
|
|
// setPage(1);
|
|
// },
|
|
// };
|
|
// })}
|
|
// mainIcon={<FilterList />}
|
|
// placement={{
|
|
// anchorOrigin: {
|
|
// vertical: 'bottom',
|
|
// horizontal: 'center',
|
|
// },
|
|
// transformOrigin: {
|
|
// horizontal: 'center',
|
|
// vertical: 'top',
|
|
// },
|
|
// }}
|
|
// />
|
|
// </Stack>
|
|
// );
|
|
// },
|
|
// renderCell(data) {
|
|
// return (
|
|
// <StatusChangePopup
|
|
// anchor={{
|
|
// status: data.status,
|
|
// text: t(data.status),
|
|
// }}
|
|
// loading={changeStatusIds.includes(data.id)}
|
|
// buttons={boxStatusOptions.map(stat => {
|
|
// return {
|
|
// icon: (
|
|
// <Circle
|
|
// sx={{
|
|
// path: {
|
|
// color: getStatusColor(stat),
|
|
// },
|
|
// }}
|
|
// />
|
|
// ),
|
|
// label: t(stat),
|
|
// onClick: () => {
|
|
// onChangeStatus(data.id, stat);
|
|
// },
|
|
// };
|
|
// })}
|
|
// />
|
|
// );
|
|
// },
|
|
// },
|
|
{
|
|
label: '',
|
|
width: 100,
|
|
numeric: true,
|
|
renderCell(data, rowIndex) {
|
|
return (
|
|
<ActionPopMenu
|
|
buttons={[
|
|
{
|
|
icon: <Edit sx={{ path: { color: '#3489E4' } }} />,
|
|
label: t('edit'),
|
|
onClick: () => {
|
|
navigation.push(pageLinks.dashboard.real_boxes.edit(data.id));
|
|
},
|
|
},
|
|
{
|
|
icon: <Delete sx={{ path: { color: '#3489E4' } }} />,
|
|
label: t('delete'),
|
|
onClick: () => {
|
|
onDelete(data.id);
|
|
},
|
|
dontCloseOnClick: true,
|
|
loading: deleteIds.includes(data.id),
|
|
},
|
|
{
|
|
icon: <Download sx={{ path: { color: '#3489E4' } }} />,
|
|
label: t('download_excel'),
|
|
onClick: () => {
|
|
onDownloadExcel(data.id, data.boxName);
|
|
},
|
|
loading: downloadIds.includes(data.id),
|
|
dontCloseOnClick: true,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
},
|
|
},
|
|
];
|
|
|
|
return (
|
|
<Box>
|
|
<Stack direction={'row'} mb={3} spacing={3}>
|
|
<BaseButton colorVariant='blue' startIcon={<Add />} href={pageLinks.dashboard.real_boxes.create}>
|
|
{t('create_box')}
|
|
</BaseButton>
|
|
</Stack>
|
|
<Box
|
|
width={1}
|
|
mb={3}
|
|
sx={{
|
|
padding: '28px',
|
|
borderRadius: '16px',
|
|
backgroundColor: '#fff',
|
|
}}
|
|
>
|
|
<Stack mb={3.5} direction={'row'} justifyContent={'space-between'} alignItems={'center'}>
|
|
<Typography
|
|
sx={{
|
|
fontSize: '20px',
|
|
lineHeight: '24px',
|
|
fontWeight: 600,
|
|
textTransform: 'capitalize',
|
|
color: '#000',
|
|
}}
|
|
>
|
|
{t('boxes')}
|
|
</Typography>
|
|
<Stack direction={'row'} alignItems={'center'} spacing={2}>
|
|
<BaseInput
|
|
InputProps={{
|
|
startAdornment: <Search color='primary' />,
|
|
}}
|
|
placeholder={t('filter_packet_name')}
|
|
value={keyword}
|
|
onChange={e => {
|
|
setKeyword(e.target.value);
|
|
}}
|
|
/>
|
|
|
|
<BaseButton colorVariant='gray' startIcon={<FilterListOff />} size='small' onClick={resetFilter}>
|
|
{t('reset_filter')}
|
|
</BaseButton>
|
|
</Stack>
|
|
</Stack>
|
|
<Box mb={6}>
|
|
<MyTable columns={columns as any} data={list} loading={loading} />
|
|
</Box>
|
|
<Stack direction={'row'} justifyContent={'center'}>
|
|
<BasePagination page={page} pageSize={pageSize} totalCount={totalElements} onChange={handleChange} />
|
|
</Stack>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default DashboardRealBoxesPage;
|