update view admin
This commit is contained in:
parent
4020aef7f6
commit
7cc30dc142
|
|
@ -0,0 +1,22 @@
|
|||
import { ActionIcon } from "@mantine/core";
|
||||
import { IconTrash } from "@tabler/icons-react";
|
||||
import { useChoosesStore } from "../../lib/zustand/use-chooses-store";
|
||||
import { IBid } from "../../system/type";
|
||||
|
||||
export interface IDeleteRowActionProps {
|
||||
onClick?: () => void;
|
||||
data: IBid
|
||||
}
|
||||
|
||||
export default function DeleteRowAction({ data,onClick }: IDeleteRowActionProps) {
|
||||
|
||||
|
||||
const {chooses} = useChoosesStore()
|
||||
|
||||
|
||||
return (
|
||||
<ActionIcon disabled={!chooses.some(item => item.id === data.id)} onClick={onClick} size={"sm"} color="red">
|
||||
<IconTrash size={14} />
|
||||
</ActionIcon>
|
||||
);
|
||||
}
|
||||
|
|
@ -6,8 +6,16 @@ import { Socket } from "socket.io-client";
|
|||
import { getImagesWorking } from "../../apis/bid";
|
||||
import { useStatusToolStore } from "../../lib/zustand/use-status-tool-store";
|
||||
import { IBid, IWebBid } from "../../system/type";
|
||||
import { cn, extractDomainSmart, findNearestClosingChild, isTimeReached, stringToColor, subtractSeconds } from "../../utils";
|
||||
import {
|
||||
cn,
|
||||
extractDomainSmart,
|
||||
findNearestClosingChild,
|
||||
isTimeReached,
|
||||
stringToColor,
|
||||
subtractSeconds,
|
||||
} from "../../utils";
|
||||
import ShowImageModal from "./show-image-modal";
|
||||
import { IconExternalLink, IconImageInPicture } from "@tabler/icons-react";
|
||||
export interface IWorkingPageProps {
|
||||
data: (IBid | IWebBid) & { type: string };
|
||||
socket: Socket;
|
||||
|
|
@ -110,9 +118,8 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
|
||||
if(!isIBid(data)){
|
||||
console.log(data)
|
||||
if (!isIBid(data)) {
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -144,20 +151,24 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
<Text className="text-xs tracking-wide">{`Current price: $${data.current_price}`}</Text>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
<Text className="text-sm italic opacity-80">
|
||||
{moment(lastUpdate).format("HH:mm:ss DD/MM/YYYY")}
|
||||
</Text>
|
||||
|
||||
|
||||
{!isIBid(data) && <Tooltip label={'Time to tracking'}><Text>{`TT: ${moment(subtractSeconds(findNearestClosingChild(data)?.close_time || '', data.early_tracking_seconds)).format(
|
||||
"HH:mm:ss DD/MM/YYYY"
|
||||
)}`}</Text></Tooltip>}
|
||||
{!isIBid(data) && (
|
||||
<Tooltip label={"Time to tracking"}>
|
||||
<Text>{`TT: ${moment(
|
||||
subtractSeconds(
|
||||
findNearestClosingChild(data)?.close_time || "",
|
||||
data.early_tracking_seconds
|
||||
)
|
||||
).format("HH:mm:ss DD/MM/YYYY")}`}</Text>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Box className="flex items-center gap-3">
|
||||
{isIBid(data) && (
|
||||
<Tooltip label={'Close time'}>
|
||||
<Tooltip label={"Close time"}>
|
||||
<Text
|
||||
style={{ fontSize: "12px" }}
|
||||
className="tracking-wide"
|
||||
|
|
@ -174,7 +185,7 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
data.web_bid?.early_tracking_seconds || 0
|
||||
)
|
||||
) && (
|
||||
<Tooltip label={'Time to tracking'}>
|
||||
<Tooltip label={"Time to tracking"}>
|
||||
<Text
|
||||
style={{ fontSize: "12px" }}
|
||||
className="tracking-wide"
|
||||
|
|
@ -189,6 +200,7 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
</Box>
|
||||
<Box className="flex items-center gap-4">
|
||||
<Button
|
||||
rightSection={<IconImageInPicture size={14}/>}
|
||||
size="xs"
|
||||
color="green"
|
||||
onClick={open}
|
||||
|
|
@ -197,6 +209,7 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
Show
|
||||
</Button>
|
||||
<Button
|
||||
rightSection={<IconExternalLink size={14} />}
|
||||
target="_blank"
|
||||
component="a"
|
||||
size="xs"
|
||||
|
|
@ -218,11 +231,15 @@ export default function WorkingPage({ data, socket }: IWorkingPageProps) {
|
|||
|
||||
<Badge
|
||||
color={stringToColor(
|
||||
isIBid(data) ? extractDomainSmart(data.web_bid.origin_url) : extractDomainSmart(data.origin_url)
|
||||
isIBid(data)
|
||||
? extractDomainSmart(data.web_bid.origin_url)
|
||||
: extractDomainSmart(data.origin_url)
|
||||
)}
|
||||
size="xs"
|
||||
>
|
||||
{isIBid(data) ? extractDomainSmart(data.web_bid.origin_url) : extractDomainSmart(data.origin_url)}
|
||||
{isIBid(data)
|
||||
? extractDomainSmart(data.web_bid.origin_url)
|
||||
: extractDomainSmart(data.origin_url)}
|
||||
</Badge>
|
||||
</Box>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -1,222 +1,278 @@
|
|||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { Box, Button, ComboboxItem, Dialog, Select, SelectProps, Text, TextInput, TextInputProps } from '@mantine/core';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { IconSearch, IconX } from '@tabler/icons-react';
|
||||
import { ReactNode, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react';
|
||||
import { IActionData, ITableFilter, TRefTableActionFn } from './type';
|
||||
import { searchKey } from './ultils';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
ComboboxItem,
|
||||
Dialog,
|
||||
Select,
|
||||
SelectProps,
|
||||
Text,
|
||||
TextInput,
|
||||
TextInputProps,
|
||||
} from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { IconSearch, IconX } from "@tabler/icons-react";
|
||||
import {
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { IActionData, ITableFilter, TRefTableActionFn } from "./type";
|
||||
import { searchKey } from "./ultils";
|
||||
|
||||
export interface ITableActionsProps<R extends Record<string, string | number>> {
|
||||
actions?: IActionData[];
|
||||
chooses?: R[];
|
||||
showSearch?: boolean;
|
||||
loading?: boolean;
|
||||
showAction?: boolean;
|
||||
initFilter?: ITableFilter<R>[];
|
||||
searchOptions?: {
|
||||
props?: TextInputProps;
|
||||
render?: () => ReactNode;
|
||||
};
|
||||
refAction?: TRefTableActionFn;
|
||||
selectProps?: SelectProps;
|
||||
onSearch?: (data: ITableFilter<R>[]) => void;
|
||||
renderComfirm?: (data: IActionData) => ReactNode;
|
||||
onCloseComfirm?: () => void;
|
||||
actions?: IActionData[];
|
||||
chooses?: R[];
|
||||
showSearch?: boolean;
|
||||
loading?: boolean;
|
||||
showAction?: boolean;
|
||||
initFilter?: ITableFilter<R>[];
|
||||
searchOptions?: {
|
||||
props?: TextInputProps;
|
||||
render?: () => ReactNode;
|
||||
};
|
||||
refAction?: TRefTableActionFn;
|
||||
selectProps?: SelectProps;
|
||||
leftActionSession?: ReactNode;
|
||||
onSearch?: (data: ITableFilter<R>[]) => void;
|
||||
renderComfirm?: (data: IActionData) => ReactNode;
|
||||
onCloseComfirm?: () => void;
|
||||
}
|
||||
|
||||
export default function TableActions<R extends Record<string, string | number>>({
|
||||
showSearch = true,
|
||||
showAction = true,
|
||||
loading,
|
||||
searchOptions,
|
||||
initFilter,
|
||||
selectProps,
|
||||
actions,
|
||||
chooses,
|
||||
refAction,
|
||||
onSearch,
|
||||
renderComfirm,
|
||||
onCloseComfirm,
|
||||
export default function TableActions<
|
||||
R extends Record<string, string | number>
|
||||
>({
|
||||
showSearch = true,
|
||||
showAction = true,
|
||||
loading,
|
||||
searchOptions,
|
||||
initFilter,
|
||||
selectProps,
|
||||
actions,
|
||||
chooses,
|
||||
refAction,
|
||||
onSearch,
|
||||
renderComfirm,
|
||||
leftActionSession,
|
||||
onCloseComfirm,
|
||||
}: ITableActionsProps<R>) {
|
||||
const [opened, { toggle, close }] = useDisclosure(false);
|
||||
const [opened, { toggle, close }] = useDisclosure(false);
|
||||
|
||||
const [action, setAction] = useState<IActionData | null>(null);
|
||||
const [action, setAction] = useState<IActionData | null>(null);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(loading || false);
|
||||
const [isLoading, setIsLoading] = useState(loading || false);
|
||||
|
||||
const [selectValue, setSelectValue] = useState<string | null>(null);
|
||||
const [selectValue, setSelectValue] = useState<string | null>(null);
|
||||
|
||||
const form = useForm<{ [searchKey]: string }>({
|
||||
initialValues: {
|
||||
[searchKey]: '',
|
||||
},
|
||||
});
|
||||
const form = useForm<{ [searchKey]: string }>({
|
||||
initialValues: {
|
||||
[searchKey]: "",
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = (data: { [searchKey]: string }) => {
|
||||
const filter = { type: data[searchKey].trim(), key: searchKey } as ITableFilter<R>;
|
||||
const handleSubmit = (data: { [searchKey]: string }) => {
|
||||
const filter = {
|
||||
type: data[searchKey].trim(),
|
||||
key: searchKey,
|
||||
} as ITableFilter<R>;
|
||||
|
||||
if (onSearch) {
|
||||
onSearch(data[searchKey]?.length ? [filter] : []);
|
||||
if (onSearch) {
|
||||
onSearch(data[searchKey]?.length ? [filter] : []);
|
||||
}
|
||||
|
||||
form.reset();
|
||||
};
|
||||
|
||||
const handleClear = () => {
|
||||
form.reset();
|
||||
|
||||
if (onSearch) {
|
||||
onSearch([]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChangeAction = (value: string | null, _option: ComboboxItem) => {
|
||||
setSelectValue(value);
|
||||
|
||||
if (!actions) return;
|
||||
|
||||
const action = actions.find((action) => String(action.key) === value);
|
||||
|
||||
if (!action) return;
|
||||
|
||||
setAction(action);
|
||||
|
||||
if (action.comfirmAction) {
|
||||
toggle();
|
||||
} else {
|
||||
handleCallBack(action.callback);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCallBack = useCallback(
|
||||
async (callback: (chooses: R[]) => void) => {
|
||||
if (callback.constructor.name === "AsyncFunction") {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
await callback((chooses || []) as R[]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
} else {
|
||||
callback((chooses || []) as R[]);
|
||||
}
|
||||
|
||||
form.reset();
|
||||
};
|
||||
handleClose();
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[chooses]
|
||||
);
|
||||
|
||||
const handleClear = () => {
|
||||
form.reset();
|
||||
const actionDataMemo = useMemo(() => {
|
||||
const newActions = actions?.reduce((prev, cur) => {
|
||||
prev.push({
|
||||
value: String(cur.key),
|
||||
label: cur.title,
|
||||
disabled: cur?.disabled ? cur.disabled(chooses || []) : false,
|
||||
});
|
||||
return prev;
|
||||
}, [] as { value: string; label: string; disabled: boolean }[]);
|
||||
|
||||
if (onSearch) {
|
||||
onSearch([]);
|
||||
}
|
||||
};
|
||||
return newActions;
|
||||
}, [actions, chooses]);
|
||||
|
||||
const handleChangeAction = (value: string | null, _option: ComboboxItem) => {
|
||||
setSelectValue(value);
|
||||
const handleClose = () => {
|
||||
close();
|
||||
setAction(null);
|
||||
setSelectValue(null);
|
||||
|
||||
if (!actions) return;
|
||||
if (onCloseComfirm) {
|
||||
onCloseComfirm();
|
||||
}
|
||||
};
|
||||
|
||||
const action = actions.find((action) => String(action.key) === value);
|
||||
const handleClearAction = () => {
|
||||
setAction(null);
|
||||
setSelectValue(null);
|
||||
};
|
||||
|
||||
if (!action) return;
|
||||
const comfirmViewMemo = useMemo(() => {
|
||||
if (!action || !action.comfirmAction) return;
|
||||
|
||||
setAction(action);
|
||||
|
||||
if (action.comfirmAction) {
|
||||
toggle();
|
||||
} else {
|
||||
handleCallBack(action.callback);
|
||||
}
|
||||
};
|
||||
|
||||
const handleCallBack = useCallback(
|
||||
async (callback: (chooses: R[]) => void) => {
|
||||
if (callback.constructor.name === 'AsyncFunction') {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
await callback((chooses || []) as R[]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
} else {
|
||||
callback((chooses || []) as R[]);
|
||||
}
|
||||
|
||||
handleClose();
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[chooses],
|
||||
return renderComfirm ? (
|
||||
renderComfirm(action)
|
||||
) : (
|
||||
<Dialog
|
||||
opened={opened}
|
||||
withCloseButton
|
||||
onClose={handleClose}
|
||||
size="lg"
|
||||
radius="md"
|
||||
>
|
||||
<Text size="sm" mb="xs" fw={500}>
|
||||
{action?.comfirmOption && action?.comfirmOption(action)?.title
|
||||
? action.comfirmOption(action).title
|
||||
: "Are you sure to execute this action"}
|
||||
</Text>
|
||||
<div className="flex items-center justify-end w-full gap-3">
|
||||
<Button
|
||||
size="xs"
|
||||
disabled={isLoading}
|
||||
onClick={() => handleCallBack(action.callback)}
|
||||
>
|
||||
Ok
|
||||
</Button>
|
||||
<Button
|
||||
size="xs"
|
||||
disabled={isLoading}
|
||||
color="red"
|
||||
onClick={handleClose}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [action, opened, close, renderComfirm]);
|
||||
|
||||
const actionDataMemo = useMemo(() => {
|
||||
const newActions = actions?.reduce((prev, cur) => {
|
||||
prev.push({ value: String(cur.key), label: cur.title, disabled: cur?.disabled ? cur.disabled(chooses || []) : false });
|
||||
return prev;
|
||||
}, [] as { value: string; label: string; disabled: boolean }[]);
|
||||
useEffect(() => {
|
||||
if (!initFilter) return;
|
||||
|
||||
return newActions;
|
||||
}, [actions, chooses]);
|
||||
const params = initFilter.reduce((prev, cur) => {
|
||||
if (cur.key === searchKey) {
|
||||
prev[cur.key] = cur.type;
|
||||
}
|
||||
return prev;
|
||||
}, {} as Record<string, string | number>);
|
||||
|
||||
const handleClose = () => {
|
||||
close();
|
||||
setAction(null);
|
||||
setSelectValue(null);
|
||||
form.setValues(params);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [initFilter]);
|
||||
|
||||
if (onCloseComfirm) {
|
||||
onCloseComfirm();
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
setIsLoading(!!loading);
|
||||
}, [loading]);
|
||||
|
||||
const handleClearAction = () => {
|
||||
setAction(null);
|
||||
setSelectValue(null);
|
||||
};
|
||||
useImperativeHandle(
|
||||
refAction,
|
||||
() => {
|
||||
return {
|
||||
setAction,
|
||||
clearAction: handleClearAction,
|
||||
};
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const comfirmViewMemo = useMemo(() => {
|
||||
if (!action || !action.comfirmAction) return;
|
||||
|
||||
return renderComfirm ? (
|
||||
renderComfirm(action)
|
||||
) : (
|
||||
<Dialog opened={opened} withCloseButton onClose={handleClose} size="lg" radius="md">
|
||||
<Text size="sm" mb="xs" fw={500}>
|
||||
{action?.comfirmOption && action?.comfirmOption(action)?.title ? action.comfirmOption(action).title : 'Are you sure to execute this action'}
|
||||
</Text>
|
||||
<div className="flex items-center justify-end w-full gap-3">
|
||||
<Button size="xs" disabled={isLoading} onClick={() => handleCallBack(action.callback)}>
|
||||
Ok
|
||||
</Button>
|
||||
<Button size="xs" disabled={isLoading} color="red" onClick={handleClose}>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</Dialog>
|
||||
);
|
||||
}, [action, opened, close, renderComfirm]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initFilter) return;
|
||||
|
||||
const params = initFilter.reduce((prev, cur) => {
|
||||
if (cur.key === searchKey) {
|
||||
prev[cur.key] = cur.type;
|
||||
}
|
||||
return prev;
|
||||
}, {} as Record<string, string | number>);
|
||||
|
||||
form.setValues(params);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [initFilter]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(!!loading);
|
||||
}, [loading]);
|
||||
|
||||
useImperativeHandle(
|
||||
refAction,
|
||||
() => {
|
||||
return {
|
||||
setAction,
|
||||
clearAction: handleClearAction,
|
||||
};
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<Box className="flex justify-between items-center">
|
||||
{showSearch && searchOptions?.render ? (
|
||||
searchOptions.render()
|
||||
) : (
|
||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||
<TextInput
|
||||
{...form.getInputProps(searchKey)}
|
||||
className="min-w-[260px]"
|
||||
leftSection={<IconSearch size={'14px'} />}
|
||||
rightSection={
|
||||
form.getValues()[searchKey].length ? <IconX onClick={handleClear} className="cursor-pointer hover:text-red-400 select-none" size={'14px'} /> : undefined
|
||||
}
|
||||
placeholder="Search by keyword"
|
||||
size="xs"
|
||||
label={'Search'}
|
||||
{...searchOptions?.props}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
{showAction && (
|
||||
<Select
|
||||
size="xs"
|
||||
value={selectValue}
|
||||
onChange={handleChangeAction}
|
||||
label="Actions"
|
||||
placeholder="Pick value"
|
||||
defaultChecked={false}
|
||||
data={actionDataMemo}
|
||||
{...selectProps}
|
||||
return (
|
||||
<Box className="flex justify-between items-center">
|
||||
{showSearch && searchOptions?.render ? (
|
||||
searchOptions.render()
|
||||
) : (
|
||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||
<TextInput
|
||||
{...form.getInputProps(searchKey)}
|
||||
className="min-w-[260px]"
|
||||
leftSection={<IconSearch size={"14px"} />}
|
||||
rightSection={
|
||||
form.getValues()[searchKey].length ? (
|
||||
<IconX
|
||||
onClick={handleClear}
|
||||
className="cursor-pointer hover:text-red-400 select-none"
|
||||
size={"14px"}
|
||||
/>
|
||||
)}
|
||||
) : undefined
|
||||
}
|
||||
placeholder="Search by keyword"
|
||||
size="xs"
|
||||
label={"Search"}
|
||||
{...searchOptions?.props}
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
{showAction && (
|
||||
<Box className="flex items-end gap-4">
|
||||
{leftActionSession}
|
||||
|
||||
{comfirmViewMemo}
|
||||
<Select
|
||||
size="xs"
|
||||
value={selectValue}
|
||||
onChange={handleChangeAction}
|
||||
label="Actions"
|
||||
placeholder="Pick value"
|
||||
defaultChecked={false}
|
||||
data={actionDataMemo}
|
||||
{...selectProps}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
)}
|
||||
|
||||
{comfirmViewMemo}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
// stores/useChooseStore.ts
|
||||
import { create } from "zustand";
|
||||
import { IBid } from "../../system/type";
|
||||
|
||||
interface ChoosesStore {
|
||||
chooses: IBid[];
|
||||
setChooses: (items: IBid[]) => void;
|
||||
addChoose: (item: IBid) => void;
|
||||
}
|
||||
|
||||
export const useChoosesStore = create<ChoosesStore>((set) => ({
|
||||
chooses: [],
|
||||
setChooses: (items) => set({ chooses: items }),
|
||||
addChoose: (item) =>
|
||||
set((state) => ({
|
||||
chooses: [...state.chooses, item],
|
||||
})),
|
||||
}));
|
||||
|
|
@ -1,4 +1,13 @@
|
|||
import { ActionIcon, Anchor, Badge, Box, Menu, Text, Tooltip } from "@mantine/core";
|
||||
import {
|
||||
ActionIcon,
|
||||
Anchor,
|
||||
Badge,
|
||||
Box,
|
||||
Button,
|
||||
Menu,
|
||||
Text,
|
||||
Tooltip,
|
||||
} from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import {
|
||||
IconAd,
|
||||
|
|
@ -7,7 +16,7 @@ import {
|
|||
IconHammer,
|
||||
IconHistory,
|
||||
IconMenu,
|
||||
IconTrash
|
||||
IconPlus
|
||||
} from "@tabler/icons-react";
|
||||
import _ from "lodash";
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
|
|
@ -18,9 +27,11 @@ import {
|
|||
ShowHistoriesBidPicklesApiModal,
|
||||
ShowHistoriesModal,
|
||||
} from "../components/bid";
|
||||
import DeleteRowAction from "../components/bid/delete-row-action";
|
||||
import constants, { haveHistories } from "../constant";
|
||||
import Table from "../lib/table/table";
|
||||
import { IColumn, TRefTableFn } from "../lib/table/type";
|
||||
import { useChoosesStore } from "../lib/zustand/use-chooses-store";
|
||||
import { useConfirmStore } from "../lib/zustand/use-confirm";
|
||||
import { mappingStatusColors } from "../system/constants";
|
||||
import { IBid } from "../system/type";
|
||||
|
|
@ -31,6 +42,8 @@ export default function Bids() {
|
|||
|
||||
const [clickData, setClickData] = useState<IBid | null>(null);
|
||||
|
||||
const {setChooses} = useChoosesStore()
|
||||
|
||||
const { setConfirm } = useConfirmStore();
|
||||
|
||||
const [openedHistories, historiesModel] = useDisclosure(false);
|
||||
|
|
@ -52,9 +65,16 @@ export default function Bids() {
|
|||
title: "Name",
|
||||
typeFilter: "text",
|
||||
renderRow(row) {
|
||||
|
||||
|
||||
return <Anchor className="text-[14px]" href={row.url} size="sm" style={{color: 'inherit'}}>{row.name}</Anchor>
|
||||
return (
|
||||
<Anchor
|
||||
className="text-[14px]"
|
||||
href={row.url}
|
||||
size="sm"
|
||||
style={{ color: "inherit" }}
|
||||
>
|
||||
{row.name}
|
||||
</Anchor>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -157,7 +177,7 @@ export default function Bids() {
|
|||
const handleDelete = (bid: IBid) => {
|
||||
setConfirm({
|
||||
title: "Delete ?",
|
||||
message: "This bid will be delete",
|
||||
message: `This bid will be delete: ${bid.name || bid.model}`,
|
||||
handleOk: async () => {
|
||||
await deleteBid(bid);
|
||||
|
||||
|
|
@ -192,7 +212,7 @@ export default function Bids() {
|
|||
const table = useMemo(() => {
|
||||
return (
|
||||
<Table
|
||||
|
||||
onChooses={setChooses}
|
||||
tableChildProps={{
|
||||
trbody: {
|
||||
className: "cursor-pointer",
|
||||
|
|
@ -200,13 +220,13 @@ export default function Bids() {
|
|||
}}
|
||||
actionsOptions={{
|
||||
actions: [
|
||||
{
|
||||
key: "add",
|
||||
title: "Add",
|
||||
callback: () => {
|
||||
bidModal.open();
|
||||
},
|
||||
},
|
||||
// {
|
||||
// key: "add",
|
||||
// title: "Add",
|
||||
// callback: () => {
|
||||
// bidModal.open();
|
||||
// },
|
||||
// },
|
||||
{
|
||||
key: "delete",
|
||||
title: "Delete",
|
||||
|
|
@ -228,6 +248,9 @@ export default function Bids() {
|
|||
disabled: (data) => data.length <= 0,
|
||||
},
|
||||
],
|
||||
leftActionSession: (
|
||||
<Button onClick={bidModal.open} size="xs" rightSection={<IconPlus size={14}/>}>Add</Button>
|
||||
)
|
||||
}}
|
||||
refTableFn={refTableFn}
|
||||
striped
|
||||
|
|
@ -257,84 +280,88 @@ export default function Bids() {
|
|||
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>
|
||||
<Box className="flex items-center gap-2">
|
||||
<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.Dropdown onClick={(e) => e.stopPropagation()}>
|
||||
<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();
|
||||
}
|
||||
}
|
||||
bidModal.open();
|
||||
}}
|
||||
leftSection={<IconHammer size={14} />}
|
||||
leftSection={<IconEdit size={14} />}
|
||||
>
|
||||
Bids
|
||||
Edit
|
||||
</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={() => {
|
||||
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
|
||||
onClick={() => handleDelete(row)}
|
||||
leftSection={<IconTrash color="red" size={14} />}
|
||||
>
|
||||
Delete
|
||||
</Menu.Item>
|
||||
</Menu.Dropdown>
|
||||
</Menu>
|
||||
<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>
|
||||
|
||||
<DeleteRowAction data={row} onClick={() => handleDelete(row)} />
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -419,12 +419,6 @@ const trackingLoginStatus = async () => {
|
|||
login_status,
|
||||
});
|
||||
|
||||
console.log(
|
||||
"%cindex.js:422 ehehehehehe",
|
||||
"color: #007acc;",
|
||||
"ehehehehehe"
|
||||
);
|
||||
|
||||
// Set time to update login sau 1 phút
|
||||
const now = new Date();
|
||||
const oneMinuteLater = new Date(now.getTime() + 60 * 1000);
|
||||
|
|
|
|||
Loading…
Reference in New Issue