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

187 lines
5.1 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-explicit-any */
import {
Box,
Button,
LoadingOverlay,
Text,
Title,
Tooltip,
} from "@mantine/core";
import { useEffect, useRef, useState } from "react";
import io from "socket.io-client";
import { WorkingPage } from "../components/dashboard";
import { IBid, IWebBid } from "../system/type";
import { checkStatus } from "../apis/auth";
import { IconPower, IconRestore } from "@tabler/icons-react";
import { useConfirmStore } from "../lib/zustand/use-confirm";
import { getStatusTool, resetTool, shutdownTool } from "../apis/dashboard";
import { cn } from "../utils";
import { useStatusToolStore } from "../lib/zustand/use-status-tool-store";
const socket = io(`${import.meta.env.VITE_SOCKET_URL}/admin-bid-ws`, {
autoConnect: true,
transports: ["websocket"],
});
export default function DashBoard() {
const [workingData, setWorkingData] = useState<
(IWebBid & { type: string })[] | (IBid & { type: string })[]
>([]);
const { setConfirm } = useConfirmStore();
const [loading, setLoading] = useState(false);
const { setStatusTool, statusTool } = useStatusToolStore();
const RETRY_CONNECT = useRef(2);
useEffect(() => {
socket.connect();
socket.on("connect", () => {
socket.emit("getBidsData");
});
socket.on("disconnect", async () => {
if (RETRY_CONNECT.current > 0) {
await checkStatus();
socket.connect();
RETRY_CONNECT.current--;
return;
}
});
socket.on("adminBidsUpdated", (data: IWebBid[]) => {
const array = data.reduce((prev, cur) => {
if (cur.children?.length > 0) {
prev = [...prev, ...cur.children];
}
prev.push(cur);
return prev;
}, [] as any[]);
const newData = array.map((item) => {
if (item.children) {
return {
...item,
type: "API_BID",
};
}
return {
...item,
type: "PRODUCT_TAB",
};
});
setWorkingData(newData);
});
return () => {
console.log("🔌 Cleanup WebSocket listeners...");
socket.off("adminBidsUpdated");
socket.off("working");
socket.off("connect");
socket.off("disconnect");
socket.disconnect();
};
}, []);
useEffect(() => {
const statusTool = async () => {
const result = await getStatusTool();
if (result?.data) {
setStatusTool(result?.data);
} else {
setStatusTool(false);
}
};
const intervalId = setInterval(statusTool, 5000);
return () => {
clearInterval(intervalId);
};
}, []);
const handleResetTool = () => {
setConfirm({
handleOk: async () => {
setLoading(true);
await resetTool();
setLoading(false);
},
title: "Confirm tool reset",
message:
"Are you sure you want to reset this tool? All current processes will be stopped and restarted.",
okButton: { value: "Ok", color: "blue" },
});
};
const handleShutdownTool = () => {
setConfirm({
handleOk: async () => {
setLoading(true);
await shutdownTool();
setLoading(false);
},
title: "Confirm tool shutdown",
message:
"Are you sure you want to shut down this tool? All running processes will be stopped and the tool will go offline.",
okButton: { value: "Ok", color: "blue" },
});
};
return (
<Box>
<Box className="flex items-center justify-between">
<Title order={2} mb="md">
Admin Dashboard
</Title>
<Tooltip label={typeof statusTool === "string" && statusTool}>
<Box
className={cn("flex gap-2 border py-3 px-4 rounded-md", {
["border-green-800"]: statusTool || statusTool === "online",
["border-red-800"]: !statusTool || statusTool !== "online",
})}
>
<Button
color={statusTool === "online" ? "blue" : "green"}
onClick={handleResetTool}
leftSection={<IconRestore size={16} />}
size="xs"
>
{statusTool === "online" ? "Reset tool" : "Start tool"}
</Button>
<Button
onClick={handleShutdownTool}
leftSection={<IconPower size={16} />}
color="red"
size="xs"
>
Shutdown tool
</Button>
</Box>
</Tooltip>
</Box>
<Box className="grid lg:grid-cols-3 2xl:grid-cols-4 gap-4 mt-5">
{workingData.length > 0 &&
workingData.map((item, index) => (
<WorkingPage socket={socket} data={item} key={item.id + index} />
))}
{workingData.length <= 0 && (
<Box className="flex items-center justify-center col-span-4">
<Text>No Pages</Text>
</Box>
)}
</Box>
<LoadingOverlay visible={loading} />
</Box>
);
}