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