299 lines
11 KiB
TypeScript
299 lines
11 KiB
TypeScript
import { ActionIcon, Badge, Box, Menu, Text, Tooltip } from '@mantine/core';
|
|
import { useDisclosure } from '@mantine/hooks';
|
|
import { IconAd, IconAdOff, IconEdit, IconHistory, IconMenu, IconTrash } from '@tabler/icons-react';
|
|
import _ from 'lodash';
|
|
import { useMemo, useRef, useState } from 'react';
|
|
import { deleteBid, deletesBid, getBids, toggleBid } from '../apis/bid';
|
|
import { BidModal, ShowHistoriesModal } from '../components/bid';
|
|
import Table from '../lib/table/table';
|
|
import { IColumn, TRefTableFn } from '../lib/table/type';
|
|
import { useConfirmStore } from '../lib/zustand/use-confirm';
|
|
import { IBid } from '../system/type';
|
|
import { formatTime } from '../utils';
|
|
import { mappingStatusColors } from '../system/constants';
|
|
|
|
export default function Bids() {
|
|
const refTableFn: TRefTableFn<IBid> = useRef({});
|
|
|
|
const [clickData, setClickData] = useState<IBid | null>(null);
|
|
|
|
const { setConfirm } = useConfirmStore();
|
|
|
|
const [openedHistories, historiesModel] = useDisclosure(false);
|
|
const [openedBid, bidModal] = useDisclosure(false);
|
|
|
|
const columns: IColumn<IBid>[] = [
|
|
{
|
|
key: 'id',
|
|
title: 'ID',
|
|
typeFilter: 'number',
|
|
},
|
|
{
|
|
key: 'lot_id',
|
|
title: 'Lot ID',
|
|
typeFilter: 'text',
|
|
},
|
|
{
|
|
key: 'model',
|
|
title: 'Model',
|
|
typeFilter: 'text',
|
|
},
|
|
{
|
|
key: 'quantity',
|
|
title: 'Qty',
|
|
typeFilter: 'number',
|
|
},
|
|
{
|
|
key: 'step_price',
|
|
title: 'Step price',
|
|
typeFilter: 'number',
|
|
},
|
|
{
|
|
key: 'max_price',
|
|
title: 'Max price',
|
|
typeFilter: 'number',
|
|
},
|
|
{
|
|
key: 'current_price',
|
|
title: 'Current price',
|
|
typeFilter: 'number',
|
|
},
|
|
{
|
|
key: 'histories',
|
|
title: 'Current bid',
|
|
typeFilter: 'none',
|
|
renderRow(row) {
|
|
const bidPrice = _.maxBy(row.histories, 'price');
|
|
|
|
return <Text>{bidPrice ? bidPrice.price : 'None'}</Text>;
|
|
},
|
|
},
|
|
{
|
|
key: 'start_bid_time',
|
|
title: 'Start bid',
|
|
typeFilter: 'text',
|
|
renderRow(row) {
|
|
return (
|
|
<Tooltip hidden={!row.start_bid_time} label={row.start_bid_time}>
|
|
<Text size="sm">{row.start_bid_time ? formatTime(row.start_bid_time, 'HH:mm:ss DD/MM/YYYY') : 'None'}</Text>
|
|
</Tooltip>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
key: 'close_time',
|
|
title: 'Close time',
|
|
typeFilter: 'text',
|
|
renderRow(row) {
|
|
return (
|
|
<Tooltip hidden={!row.close_time} label={row.close_time}>
|
|
<Text size="sm">{row.close_time ? formatTime(row.close_time, 'HH:mm:ss DD/MM/YYYY') : 'None'}</Text>
|
|
</Tooltip>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
key: 'status',
|
|
title: 'Status',
|
|
typeFilter: 'text',
|
|
renderRow(row) {
|
|
return (
|
|
<Box className="flex items-center justify-center">
|
|
<Badge color={mappingStatusColors[row.status]} size="sm">
|
|
{row.status}
|
|
</Badge>
|
|
</Box>
|
|
);
|
|
},
|
|
},
|
|
|
|
{
|
|
key: 'updated_at',
|
|
title: 'Update at',
|
|
typeFilter: 'none',
|
|
renderRow(row) {
|
|
return <span className="text-sm">{formatTime(row.updated_at)}</span>;
|
|
},
|
|
},
|
|
];
|
|
|
|
const handleDelete = (bid: IBid) => {
|
|
setConfirm({
|
|
title: 'Delete ?',
|
|
message: 'This bid will be delete',
|
|
handleOk: async () => {
|
|
await deleteBid(bid);
|
|
|
|
if (refTableFn.current?.fetchData) {
|
|
refTableFn.current.fetchData();
|
|
}
|
|
},
|
|
});
|
|
};
|
|
|
|
const handleToggleBid = async (bid: IBid) => {
|
|
const isEnable = bid.status === 'biding' ? true : bid.status === 'out-bid' ? false : true;
|
|
|
|
setConfirm({
|
|
title: (isEnable ? 'Disable ' : 'Enable ') + 'ID: ' + bid.id,
|
|
message: 'This bid will be ' + (isEnable ? 'disable ' : 'enable '),
|
|
handleOk: async () => {
|
|
await toggleBid(bid);
|
|
|
|
if (refTableFn.current?.fetchData) {
|
|
refTableFn.current.fetchData();
|
|
}
|
|
},
|
|
okButton: {
|
|
value: isEnable ? 'Disable ' : 'Enable ',
|
|
color: isEnable ? 'red' : 'blue',
|
|
},
|
|
});
|
|
};
|
|
|
|
const table = useMemo(() => {
|
|
return (
|
|
<Table
|
|
actionsOptions={{
|
|
actions: [
|
|
{
|
|
key: 'add',
|
|
title: 'Add',
|
|
callback: () => {
|
|
bidModal.open();
|
|
},
|
|
},
|
|
{
|
|
key: 'delete',
|
|
title: 'Delete',
|
|
callback: (data) => {
|
|
if (!data.length) return;
|
|
setConfirm({
|
|
title: 'Delete',
|
|
message: `${data.length} will be delete`,
|
|
handleOk: async () => {
|
|
const result = await deletesBid(data);
|
|
|
|
if (!result) return;
|
|
if (refTableFn.current.fetchData) {
|
|
refTableFn.current.fetchData();
|
|
}
|
|
},
|
|
});
|
|
},
|
|
disabled: (data) => data.length <= 0,
|
|
},
|
|
],
|
|
}}
|
|
refTableFn={refTableFn}
|
|
striped
|
|
showLoading={true}
|
|
highlightOnHover
|
|
styleDefaultHead={{
|
|
justifyContent: 'flex-start',
|
|
width: 'fit-content',
|
|
}}
|
|
options={{
|
|
query: getBids,
|
|
pathToData: 'data.data',
|
|
keyOptions: {
|
|
last_page: 'lastPage',
|
|
per_page: 'perPage',
|
|
from: 'from',
|
|
to: 'to',
|
|
total: 'total',
|
|
},
|
|
}}
|
|
rows={[]}
|
|
withColumnBorders
|
|
showChooses={true}
|
|
withTableBorder
|
|
columns={columns}
|
|
actions={{
|
|
title: <Box className="w-full text-center">Action</Box>,
|
|
body: (row) => {
|
|
return (
|
|
<Menu shadow="md" width={200}>
|
|
<Menu.Target>
|
|
<Box className="flex w-full items-center justify-center">
|
|
<ActionIcon size="sm" variant="light">
|
|
<IconMenu size={14} />
|
|
</ActionIcon>
|
|
</Box>
|
|
</Menu.Target>
|
|
|
|
<Menu.Dropdown>
|
|
<Menu.Item
|
|
onClick={() => {
|
|
setClickData(row);
|
|
bidModal.open();
|
|
}}
|
|
leftSection={<IconEdit size={14} />}
|
|
>
|
|
Edit
|
|
</Menu.Item>
|
|
|
|
<Menu.Item
|
|
onClick={() => {
|
|
setClickData(row);
|
|
historiesModel.open();
|
|
}}
|
|
leftSection={<IconHistory size={14} />}
|
|
>
|
|
Histories
|
|
</Menu.Item>
|
|
|
|
<Menu.Item
|
|
disabled={row.status === 'win-bid'}
|
|
onClick={() => handleToggleBid(row)}
|
|
leftSection={row.status === 'biding' ? <IconAdOff size={14} /> : <IconAd size={14} />}
|
|
>
|
|
{row.status === 'biding' ? 'Disable' : 'Enable'}
|
|
</Menu.Item>
|
|
|
|
<Menu.Item onClick={() => handleDelete(row)} leftSection={<IconTrash color="red" size={14} />}>
|
|
Delete
|
|
</Menu.Item>
|
|
</Menu.Dropdown>
|
|
</Menu>
|
|
);
|
|
},
|
|
}}
|
|
rowKey="id"
|
|
/>
|
|
);
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
return (
|
|
<Box>
|
|
{table}
|
|
|
|
<ShowHistoriesModal
|
|
opened={openedHistories}
|
|
onClose={() => {
|
|
historiesModel.close();
|
|
setClickData(null);
|
|
}}
|
|
data={clickData}
|
|
/>
|
|
<BidModal
|
|
onUpdated={() => {
|
|
if (refTableFn.current?.fetchData) {
|
|
refTableFn.current.fetchData();
|
|
}
|
|
|
|
setClickData(null);
|
|
}}
|
|
opened={openedBid}
|
|
onClose={() => {
|
|
bidModal.close();
|
|
|
|
setClickData(null);
|
|
}}
|
|
data={clickData}
|
|
/>
|
|
</Box>
|
|
);
|
|
}
|