bid-tool/auto-bid-admin/src/pages/bids.tsx

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>
);
}