added cargoType
This commit is contained in:
705
src/routes/private/forbidden/DashboardForbiddenPage.tsx
Normal file
705
src/routes/private/forbidden/DashboardForbiddenPage.tsx
Normal file
@@ -0,0 +1,705 @@
|
||||
'use client';
|
||||
|
||||
import type React from 'react';
|
||||
|
||||
import ActionPopMenu from '@/components/common/ActionPopMenu';
|
||||
import { type ColumnData, MyTable } from '@/components/common/MyTable';
|
||||
import BaseButton from '@/components/ui-kit/BaseButton';
|
||||
import BaseInput from '@/components/ui-kit/BaseInput';
|
||||
import BasePagination from '@/components/ui-kit/BasePagination';
|
||||
import { selectDefaultStyles } from '@/components/ui-kit/BaseReactSelect';
|
||||
import { useAuthContext } from '@/context/auth-context';
|
||||
import { type BoxStatus, type IBox, PrintStatus } from '@/data/box/box.model';
|
||||
import { box_requests } from '@/data/box/box.requests';
|
||||
import type { Product, UpdateProductBodyType } from '@/data/item/item.mode';
|
||||
import { item_requests } from '@/data/item/item.requests';
|
||||
import { party_requests } from '@/data/party/party.requests';
|
||||
import { DEFAULT_PAGE_SIZE, pageLinks } from '@/helpers/constants';
|
||||
import useInput from '@/hooks/useInput';
|
||||
import { useMyNavigation } from '@/hooks/useMyNavigation';
|
||||
import { useMyTranslation } from '@/hooks/useMyTranslation';
|
||||
import useRequest from '@/hooks/useRequest';
|
||||
import { useBoxIdStore } from '@/modalStorage/partyId';
|
||||
import { file_service } from '@/services/file-service';
|
||||
import { notifyUnknownError } from '@/services/notification';
|
||||
import { Add, CheckCircle, Delete, Edit, FilterListOff, Search } from '@mui/icons-material';
|
||||
import { Box, Button, Card, CardContent, Modal, Stack, Typography } from '@mui/material';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import AsyncSelect from 'react-select/async';
|
||||
import { useReactToPrint } from 'react-to-print';
|
||||
|
||||
type Props = {};
|
||||
|
||||
const style = {
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
width: 400,
|
||||
bgcolor: 'background.paper',
|
||||
border: '2px solid #000',
|
||||
boxShadow: 24,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '10px',
|
||||
p: 4,
|
||||
};
|
||||
|
||||
const DashboardForbiddenPage = () => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [openModal, setOpenModal] = useState(false);
|
||||
const handleClose = () => setOpen(false);
|
||||
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 [trackId, setTrackId] = useState<string>();
|
||||
const [partyFilter, setPartyFilter] = useState<{ label: string; value: number } | undefined>(undefined);
|
||||
const [boxFilter, setBoxFilter] = useState<{ label: string; value: number } | undefined>(undefined);
|
||||
|
||||
const [deleteIds, setDeleteIds] = useState<number[]>([]);
|
||||
const [downloadIds, setDownloadIds] = useState<number[]>([]);
|
||||
const [changeStatusIds, setChangeStatusIds] = useState<number[]>([]);
|
||||
const [boxAmounts, setBoxAmounts] = useState<Record<number, { totalAmount: number; totalAccepted: number }>>({});
|
||||
const [printStatuses, setPrintStatuses] = useState<Record<number, string>>({});
|
||||
const searchParams = useSearchParams();
|
||||
const boxId = searchParams.get('boxId');
|
||||
const { boxesId, setBoxId } = useBoxIdStore();
|
||||
|
||||
// Print uchun state
|
||||
const [selectedBoxForPrint, setSelectedBoxForPrint] = useState<IBox | null>(null);
|
||||
const [selectedBoxDetails, setSelectedBoxDetails] = useState<any>(null);
|
||||
|
||||
const printRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Print functionality
|
||||
const handlePrint = useReactToPrint({
|
||||
contentRef: printRef,
|
||||
onAfterPrint: () => {
|
||||
setSelectedBoxForPrint(null);
|
||||
setSelectedBoxDetails(null);
|
||||
},
|
||||
});
|
||||
const { data: defaultPartyOptions } = useRequest(() => party_requests.getAll({}), {
|
||||
enabled: true,
|
||||
selectData(data) {
|
||||
return data.data.data.data.map(p => ({ value: p.id, label: p.name }));
|
||||
},
|
||||
placeholderData: [],
|
||||
});
|
||||
|
||||
const partyOptions = (inputValue: string) => {
|
||||
return party_requests.getAll({ partyName: inputValue }).then(res => {
|
||||
return res.data.data.data.map(p => ({ label: p.name, value: p.id }));
|
||||
});
|
||||
};
|
||||
|
||||
const onPrintBox = async (boxData: IBox) => {
|
||||
try {
|
||||
const response = await box_requests.find({ packetId: boxData.id });
|
||||
const boxOne = response.data.data;
|
||||
const detailedBoxData = {
|
||||
id: +boxData.id,
|
||||
box_name: boxOne.packet.name,
|
||||
net_weight: +boxOne.packet.brutto,
|
||||
box_weight: +boxOne.packet.boxWeight,
|
||||
box_type: boxOne.packet.boxType,
|
||||
box_size: boxOne.packet.volume,
|
||||
passportName: boxOne.packet.passportName,
|
||||
status: boxOne.packet.status,
|
||||
packetId: boxData.id,
|
||||
partyId: +boxOne.packet.partyId,
|
||||
partyName: boxOne.packet.partyName,
|
||||
passportId: boxOne.client?.passportId,
|
||||
client_id: boxOne.packet?.cargoId,
|
||||
clientName: boxOne.client?.passportName,
|
||||
products_list: boxOne.items.map((item: any) => ({
|
||||
id: item.id,
|
||||
price: item.price,
|
||||
cargoId: item.cargoId,
|
||||
trekId: item.trekId,
|
||||
name: item.name,
|
||||
nameRu: item.nameRu,
|
||||
amount: +item.amount,
|
||||
acceptedNumber: item.acceptedNumber,
|
||||
weight: +item.weight,
|
||||
})),
|
||||
};
|
||||
setSelectedBoxDetails(detailedBoxData);
|
||||
setTimeout(() => {
|
||||
handlePrint();
|
||||
}, 100);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch box details:', error);
|
||||
}
|
||||
};
|
||||
const handleOpen = (data: any) => {
|
||||
setOpen(true);
|
||||
};
|
||||
|
||||
const handleOpenModal = (data: any) => {
|
||||
setOpenModal(true);
|
||||
setSelectedBoxForPrint(data);
|
||||
};
|
||||
|
||||
const boxStatusOptions = useMemo(() => {
|
||||
const p = ['READY_TO_INVOICE'] as BoxStatus[];
|
||||
if (isAdmin) {
|
||||
p.push('READY');
|
||||
}
|
||||
return p;
|
||||
}, [isAdmin]);
|
||||
|
||||
const printOptions = useMemo(() => {
|
||||
const p = ['false'] as PrintStatus[];
|
||||
if (isAdmin) {
|
||||
p.push('false');
|
||||
}
|
||||
return p;
|
||||
}, [isAdmin]);
|
||||
|
||||
const getBoxesQuery = useRequest(
|
||||
() =>
|
||||
box_requests.getAll({
|
||||
page: page,
|
||||
cargoId: keyword,
|
||||
partyId: partyFilter?.value,
|
||||
status: boxStatusFilter,
|
||||
direction: 'desc',
|
||||
sort: 'id',
|
||||
}),
|
||||
{
|
||||
dependencies: [page, boxStatusFilter],
|
||||
selectData(data) {
|
||||
return data.data.data;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const getListQuery = useRequest(
|
||||
() =>
|
||||
item_requests.getAll({
|
||||
page: page,
|
||||
trekId: trackId,
|
||||
packetId: boxFilter?.value,
|
||||
partyId: partyFilter?.value,
|
||||
}),
|
||||
{
|
||||
dependencies: [page, trackId, boxFilter?.value, partyFilter?.value],
|
||||
selectData(data) {
|
||||
return data.data.data;
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const [values, setValues] = useState<{ [trackId: string]: number | '' }>({});
|
||||
|
||||
const handleAmountChange = (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, max: number, trackId: string) => {
|
||||
const val = Number(event.target.value);
|
||||
if (val >= 1 && val <= max) {
|
||||
setValues(prev => ({ ...prev, [trackId]: val }));
|
||||
} else if (event.target.value === '') {
|
||||
setValues(prev => ({ ...prev, [trackId]: '' }));
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (boxId && defaultPartyOptions && defaultPartyOptions.length > 0) {
|
||||
const selected = defaultPartyOptions.find(p => p.value === Number(boxId));
|
||||
if (selected) {
|
||||
setPartyFilter(selected);
|
||||
}
|
||||
}
|
||||
}, [boxId, defaultPartyOptions]);
|
||||
|
||||
useEffect(() => {
|
||||
if (boxesId) {
|
||||
navigation.push(`${pageLinks.dashboard.boxes.index}?boxId=${boxesId}`);
|
||||
console.log(boxesId, 'useeffect');
|
||||
}
|
||||
}, [boxesId]);
|
||||
|
||||
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);
|
||||
setPartyFilter(undefined);
|
||||
};
|
||||
|
||||
const { data: defaultBoxOptions, refetch } = useRequest(
|
||||
() =>
|
||||
box_requests.getAll({
|
||||
partyId: partyFilter?.value,
|
||||
}),
|
||||
{
|
||||
enabled: !!partyFilter,
|
||||
selectData(data) {
|
||||
return data.data.data.data.map(p => ({ value: p.id, label: p.name }));
|
||||
},
|
||||
placeholderData: [],
|
||||
dependencies: [partyFilter],
|
||||
}
|
||||
);
|
||||
|
||||
const onDelete = async (id: number) => {
|
||||
if (deleteIds.includes(id)) return;
|
||||
|
||||
try {
|
||||
setDeleteIds(p => [...p, id]);
|
||||
await box_requests.delete({ packetId: id });
|
||||
getBoxesQuery.refetch();
|
||||
} catch (error) {
|
||||
notifyUnknownError(error);
|
||||
} finally {
|
||||
setDeleteIds(prev => prev.filter(i => i !== id));
|
||||
}
|
||||
};
|
||||
|
||||
const onDownloadExcel = async (id: number) => {
|
||||
if (downloadIds.includes(id)) return;
|
||||
|
||||
try {
|
||||
setDownloadIds(p => [...p, id]);
|
||||
const response = await box_requests.downloadExcel({ packetId: id });
|
||||
const file = new File([response.data], 'Box-excel.xlsx', { type: response.data.type });
|
||||
file_service.download(file);
|
||||
} catch (error) {
|
||||
notifyUnknownError(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));
|
||||
}
|
||||
};
|
||||
|
||||
const onChangePrint = async (id: number, newStatus: PrintStatus) => {
|
||||
if (changeStatusIds.includes(id)) return;
|
||||
|
||||
try {
|
||||
setChangeStatusIds(p => [...p, id]);
|
||||
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, partyFilter?.value, boxFilter?.value]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAmounts = async () => {
|
||||
const result: Record<number, { totalAmount: number; totalAccepted: number }> = {};
|
||||
|
||||
await Promise.all(
|
||||
list.map(async box => {
|
||||
try {
|
||||
const res = await box_requests.find({ packetId: box.id });
|
||||
const boxData = res.data.data;
|
||||
|
||||
const total = boxData.items.reduce(
|
||||
(acc, item) => {
|
||||
acc.totalAmount = boxData.packet.totalItems ?? 0;
|
||||
if (item.acceptedNumber && item.acceptedNumber > 0) {
|
||||
acc.totalAccepted += 1;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{ totalAmount: 0, totalAccepted: 0 }
|
||||
);
|
||||
|
||||
result[box.id] = total;
|
||||
} catch (e) {
|
||||
console.error(`Failed to fetch box ${box.id}`, e);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
setBoxAmounts(result);
|
||||
};
|
||||
|
||||
if (list.length > 0 && !loading) {
|
||||
fetchAmounts();
|
||||
}
|
||||
}, [list, loading]);
|
||||
|
||||
// Calculate completion statistics
|
||||
|
||||
const boxOptions = (inputValue: string) => {
|
||||
return box_requests
|
||||
.getAll({
|
||||
cargoId: inputValue,
|
||||
partyId: partyFilter?.value, // Bu qatorni qo'shing
|
||||
})
|
||||
.then(res => {
|
||||
return res.data.data.data.map(p => ({ label: p.name, value: p.id }));
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setBoxFilter(undefined);
|
||||
}, [partyFilter]);
|
||||
|
||||
const columns: ColumnData<IBox>[] = [
|
||||
{
|
||||
label: t('No'),
|
||||
width: 100,
|
||||
renderCell(data, rowIndex) {
|
||||
return (page - 1) * pageSize + rowIndex + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
dataKey: 'id',
|
||||
label: "Qo'shish",
|
||||
width: 120,
|
||||
renderCell: data => {
|
||||
return (
|
||||
<Button onClick={() => navigation.push(pageLinks.dashboard.forbidden.edit(data.id))}>
|
||||
<Add />
|
||||
</Button>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
dataKey: 'partyName',
|
||||
label: t('party_name'),
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataKey: 'name',
|
||||
label: t('name'),
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataKey: 'packetNetWeight',
|
||||
label: t('weight'),
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataKey: 'totalItems',
|
||||
label: t('count_of_items'),
|
||||
width: 120,
|
||||
renderCell: data => {
|
||||
const total = boxAmounts[data.id];
|
||||
if (!total) return <Typography>...</Typography>;
|
||||
|
||||
const isCompleted = total.totalAmount === total.totalAccepted && total.totalAmount > 0;
|
||||
|
||||
return (
|
||||
<Stack direction='row' alignItems='center' spacing={1}>
|
||||
<Typography>
|
||||
{data.totalItems} | {total.totalAccepted}
|
||||
</Typography>
|
||||
{isCompleted && <CheckCircle sx={{ color: '#22c55e', fontSize: 16 }} />}
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
dataKey: 'totalNetWeight',
|
||||
label: t('party_weight'),
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataKey: 'cargoId',
|
||||
label: t('cargo_id'),
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
dataKey: 'passportName',
|
||||
label: t('client'),
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
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.forbidden.edit(data.id));
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <Delete sx={{ path: { color: '#3489E4' } }} />,
|
||||
label: t('delete'),
|
||||
onClick: () => {
|
||||
onDelete(data.id);
|
||||
},
|
||||
dontCloseOnClick: true,
|
||||
loading: deleteIds.includes(data.id),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const [items, setItems] = useState<Product>();
|
||||
const [loaer, setLoading] = useState(false);
|
||||
const {
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
watch,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm<Product>({
|
||||
defaultValues: {
|
||||
trekId: items?.trekId,
|
||||
name: items?.name,
|
||||
nameRu: items?.nameRu,
|
||||
amount: items?.amount,
|
||||
weight: items?.weight,
|
||||
acceptedNumber: Number(values),
|
||||
},
|
||||
});
|
||||
|
||||
const updateItems = async (item: Product, acceptedNumber: number) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
const updateBody: UpdateProductBodyType = {
|
||||
itemId: item.id,
|
||||
acceptedNumber: item.amount,
|
||||
amount: item.amount,
|
||||
cargoType: item.cargoType,
|
||||
name: item.name,
|
||||
nameRu: item.nameRu,
|
||||
trekId: item.trekId,
|
||||
weight: item.weight,
|
||||
};
|
||||
|
||||
await item_requests.update(updateBody);
|
||||
|
||||
getListQuery.refetch();
|
||||
getBoxesQuery.refetch();
|
||||
|
||||
setValues(prev => ({ ...prev, [item.trekId]: '' }));
|
||||
setTrackId('');
|
||||
} catch (error) {
|
||||
notifyUnknownError(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Stack direction={'row'} mb={3} spacing={3}>
|
||||
<BaseButton colorVariant='blue' startIcon={<Add />} href={pageLinks.dashboard.forbidden.create}>
|
||||
{t('create_packet')}
|
||||
</BaseButton>
|
||||
|
||||
<Modal open={open} onClose={handleClose} aria-labelledby='modal-modal-title' aria-describedby='modal-modal-description'>
|
||||
<Box sx={style}>
|
||||
<Typography id='modal-modal-title' variant='h6' component='h2'>
|
||||
{t('product_inspection')}
|
||||
</Typography>
|
||||
<Typography id='modal-modal-description' sx={{ mt: 2 }}>
|
||||
{t('enter_product')}
|
||||
</Typography>
|
||||
<AsyncSelect
|
||||
isClearable
|
||||
value={partyFilter}
|
||||
onChange={(newValue: any) => {
|
||||
setPartyFilter(newValue);
|
||||
setPage(1);
|
||||
}}
|
||||
styles={selectDefaultStyles}
|
||||
noOptionsMessage={() => t('not_found')}
|
||||
loadingMessage={() => t('loading')}
|
||||
defaultOptions={defaultPartyOptions!}
|
||||
loadOptions={partyOptions}
|
||||
placeholder={t('filter_party_name')}
|
||||
/>
|
||||
|
||||
<AsyncSelect
|
||||
isClearable
|
||||
value={boxFilter}
|
||||
onChange={(newValue: any) => {
|
||||
setBoxFilter(newValue);
|
||||
setPage(1);
|
||||
}}
|
||||
styles={selectDefaultStyles}
|
||||
noOptionsMessage={() => t('enter_box_name_to_find')}
|
||||
loadingMessage={() => t('loading')}
|
||||
defaultOptions={defaultBoxOptions!}
|
||||
loadOptions={boxOptions}
|
||||
placeholder={t('filter_box_name')}
|
||||
/>
|
||||
<BaseInput
|
||||
InputProps={{
|
||||
startAdornment: <Search color='primary' />,
|
||||
}}
|
||||
value={trackId}
|
||||
onChange={e => setTrackId(e.target.value)}
|
||||
placeholder={t('filter_item_name')}
|
||||
/>
|
||||
{trackId && trackId.length > 0 && (
|
||||
<>
|
||||
{getListQuery.loading ? (
|
||||
<Typography sx={{ mt: 2 }}>{t('loading')}...</Typography>
|
||||
) : getListQuery.data?.data && getListQuery.data?.data.length > 0 ? (
|
||||
getListQuery.data?.data.map(e => (
|
||||
<Box key={e.id} sx={{ width: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||
<Card sx={{ minWidth: 275, mb: 2 }}>
|
||||
<CardContent>
|
||||
<Typography sx={{ fontSize: 14 }}>
|
||||
{t('track_id')}: {e.trekId}
|
||||
</Typography>
|
||||
<Typography sx={{ fontSize: 14 }}>Nomi: {e.name || e.nameRu}</Typography>
|
||||
<Typography sx={{ fontSize: 14 }}>Mahsulot soni: {e.amount}</Typography>
|
||||
<Typography sx={{ fontSize: 14 }}>Paket nomi: {e?.packetName}</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Button
|
||||
sx={{ mt: '10px' }}
|
||||
onClick={() => {
|
||||
if (values[e.trekId] !== '') {
|
||||
updateItems(e, Number(values[e.trekId]));
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('confirmation')}
|
||||
</Button>
|
||||
<audio src='/sounds/success-sound.wav' autoPlay style={{ display: 'none' }}></audio>
|
||||
</Box>
|
||||
))
|
||||
) : (
|
||||
<>
|
||||
<Typography sx={{ mt: 2 }}>{t('not_found') || 'Mahsulot topilmadi'}</Typography>
|
||||
<audio src='/sounds/not_found.wav' autoPlay style={{ display: 'none' }}></audio>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</Modal>
|
||||
</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('packet')}
|
||||
</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);
|
||||
}}
|
||||
/>
|
||||
<AsyncSelect
|
||||
isClearable
|
||||
value={partyFilter}
|
||||
onChange={(newValue: any) => {
|
||||
setPartyFilter(newValue);
|
||||
if (newValue) {
|
||||
setBoxId(newValue.value);
|
||||
navigation.push(`${pageLinks.dashboard.boxes.index}?boxId=${newValue.value}`);
|
||||
} else {
|
||||
setBoxId(undefined);
|
||||
navigation.push(`${pageLinks.dashboard.boxes.index}`);
|
||||
}
|
||||
setPage(1);
|
||||
}}
|
||||
styles={selectDefaultStyles}
|
||||
noOptionsMessage={() => t('not_found')}
|
||||
loadingMessage={() => t('loading')}
|
||||
defaultOptions={defaultPartyOptions!}
|
||||
loadOptions={partyOptions}
|
||||
placeholder={t('filter_party_name')}
|
||||
/>
|
||||
<BaseButton colorVariant='gray' startIcon={<FilterListOff />} size='small' onClick={resetFilter}>
|
||||
{t('reset_filter')}
|
||||
</BaseButton>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<Box mb={6}>
|
||||
<MyTable columns={columns} data={list} loading={loading} disableSortingAndStatusFetch={false} />
|
||||
</Box>
|
||||
<Stack direction={'row'} justifyContent={'center'}>
|
||||
<BasePagination page={page} pageSize={pageSize} totalCount={totalElements} onChange={handleChange} />
|
||||
</Stack>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardForbiddenPage;
|
||||
1
src/routes/private/forbidden/index.ts
Normal file
1
src/routes/private/forbidden/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './DashboardForbiddenPage';
|
||||
Reference in New Issue
Block a user