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

411 lines
11 KiB
TypeScript

import { ActionIcon, Badge, Box, Menu, Text, Tooltip } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import {
IconAd,
IconAdOff,
IconEdit,
IconHammer,
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,
ShowHistoriesBidGraysApiModal,
ShowHistoriesBidPicklesApiModal,
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 { mappingStatusColors } from "../system/constants";
import { IBid } from "../system/type";
import { formatTime } from "../utils";
import constants, { haveHistories } from "../constant";
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 [openedHistoriesGraysApi, historiesGraysApiModel] =
useDisclosure(false);
const [openedHistoriesPicklesApi, historiesPicklesApiModel] =
useDisclosure(false);
const [openedBid, bidModal] = useDisclosure(false);
const columns: IColumn<IBid>[] = [
{
key: "id",
title: "ID",
typeFilter: "number",
},
{
key: "name",
title: "Name",
typeFilter: "text",
},
{
key: "web_bid",
title: "Web",
typeFilter: "text",
renderRow(row) {
return <span>{row.web_bid.origin_url}</span>;
},
},
{
key: "lot_id",
title: "Lot ID",
typeFilter: "text",
},
{
key: "model",
title: "Model",
typeFilter: "text",
},
{
key: "plus_price",
title: "Plus price",
typeFilter: "number",
},
{
key: "max_price",
title: "Max price",
typeFilter: "number",
},
{
key: "current_price",
title: "Current price",
typeFilter: "number",
},
{
key: "reserve_price",
title: "Reserve 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>
);
},
},
];
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
onClickRow={(row) => {
window.open(row.url, "_blank");
}}
tableChildProps={{
trbody: {
className: "cursor-pointer",
},
}}
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
onClick={(e) => e.stopPropagation()}
className="flex w-full items-center justify-center"
>
<ActionIcon size="sm" variant="light">
<IconMenu size={14} />
</ActionIcon>
</Box>
</Menu.Target>
<Menu.Dropdown onClick={(e) => e.stopPropagation()}>
<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>
{haveHistories.includes(row?.web_bid.origin_url) && (
<Menu.Item
onClick={() => {
setClickData(row);
switch (row.web_bid.origin_url) {
case constants.grays: {
historiesGraysApiModel.open();
break;
}
case constants.pickles: {
historiesPicklesApiModel.open();
break;
}
default: {
historiesGraysApiModel.open();
}
}
}}
leftSection={<IconHammer size={14} />}
>
Bids
</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}
/>
{/* Grays */}
{openedHistoriesGraysApi && (
<ShowHistoriesBidGraysApiModal
onUpdated={() => {
if (refTableFn.current?.fetchData) {
refTableFn.current.fetchData();
}
setClickData(null);
}}
opened={openedHistoriesGraysApi}
onClose={() => {
historiesGraysApiModel.close();
setClickData(null);
}}
data={clickData}
/>
)}
{openedHistoriesPicklesApi && (
<ShowHistoriesBidPicklesApiModal
onUpdated={() => {
if (refTableFn.current?.fetchData) {
refTableFn.current.fetchData();
}
setClickData(null);
}}
opened={true}
onClose={() => {
historiesPicklesApiModel.close();
setClickData(null);
}}
data={clickData}
/>
)}
</Box>
);
}