ATC_SIMPLE/FRONTEND/src/App.tsx

1108 lines
36 KiB
TypeScript

import "@mantine/core/styles.css";
import "@mantine/dates/styles.css";
import "@mantine/notifications/styles.css";
import "./App.css";
import classes from "./App.module.css";
import componentClasses from "./components/Component.module.css";
import {
Suspense,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import {
Tabs,
Text,
Container,
Flex,
MantineProvider,
Grid,
ScrollArea,
LoadingOverlay,
Loader,
Box,
} from "@mantine/core";
import type {
DataSummaryTested,
FileInfo,
IScenario,
ReceivedFile,
ResponseData,
TBrands,
TCategories,
TLine,
TStation,
TUser,
} from "./untils/types";
import axios from "axios";
import CardLine from "./components/CardLine";
import { SocketProvider, useSocket } from "./context/SocketContext";
import // ButtonConnect,
// ButtonControlApc,
// ButtonCopy,
// ButtonDPELP,
// ButtonScenario,
// ButtonSelect,
"./components/ButtonAction";
import StationSetting from "./components/FormAddEdit";
// import DrawerScenario from "./components/DrawerScenario";
import { Notifications } from "@mantine/notifications";
import ModalTerminal from "./components/Modal/ModalTerminal";
import PageLogin from "./components/Authentication/LoginPage";
// import DrawerLogs from "./components/DrawerLogs";
import DraggableTabs from "./components/DragTabs";
import { isJsonString } from "./untils/helper";
import BottomToolBar from "./components/BottomToolBar";
import ModalConfirmSkipTestPort from "./components/Modal/ModalConfirmSkipTestPort";
import ModalConfirmRunPhysical from "./components/Modal/ModalConfirmRunPhysicalTest";
import ModalSummaryTested from "./components/Modal/ModalSummaryTested";
// import ModalConfirmRunScenario from "./components/Modal/ModalConfirmRunScenario";
const apiUrl = import.meta.env.VITE_BACKEND_URL;
// Helper: chia mảng thành các chunk theo size
const chunkArray = <T,>(array: T[], size: number): T[][] => {
const result: T[][] = [];
for (let i = 0; i < array.length; i += size) {
result.push(array.slice(i, i + size));
}
return result;
};
/**
* Main Component
*/
function App() {
const user = useMemo(() => {
return localStorage.getItem("user") &&
isJsonString(localStorage.getItem("user"))
? JSON.parse(localStorage.getItem("user") || "")
: null;
}, []);
if (!user) {
localStorage.removeItem("user");
window.location.href = "/";
}
document.title = "Automation Test";
const { socket } = useSocket();
const [stations, setStations] = useState<TStation[]>([]);
const [selectedLines, setSelectedLines] = useState<TLine[]>([]);
const [activeTab, setActiveTab] = useState("0");
const [isDisable, setIsDisable] = useState(false);
const [isOpenAddStation, setIsOpenAddStation] = useState(false);
const [isEditStation, setIsEditStation] = useState(false);
const [stationEdit, setStationEdit] = useState<TStation | undefined>();
const [scenarios, setScenarios] = useState<IScenario[]>([]);
const [openModalTerminal, setOpenModalTerminal] = useState(false);
const [selectedLine, setSelectedLine] = useState<TLine | undefined>();
const [loadingTerminal, setLoadingTerminal] = useState(false);
const [usersConnecting, setUsersConnecting] = useState<TUser[]>([]);
const [testLogContent, setTestLogContent] = useState("");
const [isLogModalOpen, setIsLogModalOpen] = useState(false);
const [expandedBottomBar, setExpandedBottomBar] = useState(true);
const [activeTabBottom, setActiveTabBottom] = useState<string>("command");
const lineBuffersRef = useRef(new Map<number, string>());
const flushScheduledRef = useRef(false);
const [listBrands, setListBrands] = useState<TBrands[]>([]);
const [listCategories, setListCategories] = useState<TCategories[]>([]);
const [listIos, setListIos] = useState<FileInfo[]>([]);
const [listLicense, setListLicense] = useState<FileInfo[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [linesConfirmSkipPort, setLinesConfirmSkipPort] = useState<TLine[]>([]);
const [linesConfirmRunPhysical, setLinesConfirmRunPhysical] = useState<
TLine[]
>([]);
const [dataSummaryTested, setDataSummaryTested] =
useState<DataSummaryTested | null>(null);
const connectApcSwitch = (station: TStation) => {
if (!station?.is_active) return;
if (station?.apc_1_ip && station?.apc_1_port) {
socket?.emit("connect_apc", {
station: station,
apcIp: station?.apc_1_ip,
apcName: "apc_1",
});
}
if (station?.apc_2_ip && station?.apc_2_port) {
socket?.emit("connect_apc", {
station: station,
apcIp: station?.apc_2_ip,
apcName: "apc_2",
});
}
if (station?.switch_control_ip && station?.switch_control_port) {
socket?.emit("connect_switch", {
station: station,
ip: station?.switch_control_ip,
});
}
};
// function get list station
const getStation = async () => {
try {
const response = await axios.get(apiUrl + "api/stations");
if (response.status) {
if (Array.isArray(response.data)) {
setStations(
response.data.map((station) => {
connectApcSwitch(station);
const lines = (station?.lines || []).sort(
(a: TLine, b: TLine) => a?.lineNumber - b?.lineNumber,
);
return { ...station, lines };
}),
);
}
}
} catch (error) {
console.log("Error get station", error);
}
};
// function get list station
const getScenarios = async () => {
try {
const response = await axios.get(apiUrl + "api/scenarios");
if (response.data.status) {
if (Array.isArray(response.data.data.data)) {
setScenarios(response.data.data.data);
}
}
} catch (error) {
console.log("Error get station", error);
}
};
// function get list brand
const getBrands = async () => {
try {
const response = await axios.get(apiUrl + "api/brands");
if (response.data) {
if (response.data && Array.isArray(response.data)) {
setListBrands(response.data);
}
}
} catch (error) {
console.log("Error get brand", error);
}
};
// function get list brand
const getCategories = async () => {
try {
const response = await axios.get(apiUrl + "api/categories");
if (response.data && Array.isArray(response.data)) {
setListCategories(response.data);
}
} catch (error) {
console.log("Error get brand", error);
}
};
// function get list ios
const getListIos = async () => {
try {
const response = await axios.get(apiUrl + "api/ios");
if (response.data && Array.isArray(response.data)) {
setListIos(response.data);
}
} catch (error) {
console.log("Error get ios", error);
}
};
// function get list license
const getListLicense = async () => {
try {
const response = await axios.get(apiUrl + "api/license");
if (response.data && Array.isArray(response.data)) {
setListLicense(response.data);
}
} catch (error) {
console.log("Error get ios", error);
}
};
useEffect(() => {
if (!socket) return;
getStation();
getScenarios();
getBrands();
getCategories();
getListIos();
getListLicense();
}, [socket]);
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 2000);
}, []);
useEffect(() => {
if (!socket || !stations?.length) return;
socket.on("line_connected", (data) =>
updateValueLineStation(
data?.lineId,
{ status: data.status, connecting: false },
data?.stationId,
),
);
socket.on("line_disconnected", (data) =>
updateValueLineStation(
data?.lineId,
{
status: data.status,
connecting: false,
netOutput: "[CLEAR_TERMINAL_SCROLL_BACK]",
output: "[CLEAR_TERMINAL_SCROLL_BACK]",
listFeatureTested: [],
latestScenario: undefined,
isReady: false,
},
data?.stationId,
),
);
socket?.on("line_output", (data) => {
const { lineId, data: text } = data;
// updateValueLineStation(
// data?.lineId,
// { isReady: data.isReady },
// data?.stationId
// );
const buf = lineBuffersRef.current.get(lineId) || "";
lineBuffersRef.current.set(lineId, buf + text);
if (!flushScheduledRef.current) {
flushScheduledRef.current = true;
setTimeout(() => flushBuffers(), 50);
}
});
socket?.on("update_status_ready", (data) => {
const { isReady } = data;
updateValueLineStation(
data?.lineId,
{ isReady: isReady },
data?.stationId,
);
});
socket?.on("line_error", (data) => {
updateValueLineStation(
data?.lineId,
{ netOutput: data.error, connecting: false },
data?.stationId,
);
});
socket?.on("init", (data) => {
if (Array.isArray(data)) {
// console.log(data);
setLoadingTerminal(true);
data.forEach((value) => {
updateValueLineStation(
value?.id,
{ ...value, netOutput: value.output },
value?.stationId,
);
});
}
});
socket?.on("user_connecting", (data) => {
if (Array.isArray(data)) {
setUsersConnecting(data);
}
});
socket?.on("user_open_cli", (data) => {
setTimeout(() => {
updateValueLineStation(
data.lineId,
{
cliOpened: true,
userEmailOpenCLI: data.userEmailOpenCLI,
userOpenCLI: data.userOpenCLI,
},
data?.stationId,
);
}, 100);
});
socket?.on("user_close_cli", (data) => {
setTimeout(() => {
updateValueLineStation(
data.lineId,
{
cliOpened: false,
userEmailOpenCLI: undefined,
userOpenCLI: undefined,
},
data?.stationId,
);
}, 100);
});
const receivedFiles: Record<string, ReceivedFile> = {};
socket?.on("response_content_log", (data: ResponseData) => {
if (!data.chunk) {
const decoder = new TextDecoder("utf-8");
const str = decoder.decode(data as unknown as ArrayBuffer);
setTestLogContent(str);
return;
}
const { fileId, chunkIndex, totalChunks, chunk } = data.chunk;
if (!receivedFiles[fileId]) {
receivedFiles[fileId] = {
chunks: [],
receivedChunks: 0,
totalChunks,
};
}
let bufferChunk: Buffer;
if (chunk instanceof ArrayBuffer) {
bufferChunk = Buffer.from(new Uint8Array(chunk)); // ✅ convert properly
} else if (chunk instanceof Uint8Array) {
bufferChunk = Buffer.from(chunk); // ✅ direct support
} else {
bufferChunk = chunk as Buffer; // fallback if server sends Buffer
}
receivedFiles[fileId].chunks[chunkIndex] = bufferChunk;
receivedFiles[fileId].receivedChunks++;
if (receivedFiles[fileId].receivedChunks === totalChunks) {
const fileBuffer = Buffer.concat(receivedFiles[fileId].chunks);
const decoder = new TextDecoder("utf-8");
const str = decoder.decode(fileBuffer);
setTestLogContent(str);
delete receivedFiles[fileId]; // cleanup ✅
}
});
socket?.on("data_textfsm", (data) => {
setTimeout(() => {
updateValueLineStation(
data.lineId,
{
data: data.data,
inventory: data.inventory,
latestScenario: data.latestScenario,
},
data?.stationId,
);
}, 100);
});
socket?.on("update_ticket", (data) => {
setTimeout(() => {
updateValueLineStation(
data.lineId,
{
tickets: data.data,
},
data?.stationId,
);
}, 100);
});
socket?.on("update_baud", (data) => {
setTimeout(() => {
updateValueLineStation(
data.lineId,
{
baud: data.data,
},
data?.stationId,
);
}, 100);
});
socket?.on("line_connecting", (data) => {
setTimeout(() => {
updateValueLineStation(
data?.lineId,
{ connecting: true },
data?.stationId,
);
}, 100);
});
socket?.on("running_scenario", (data) => {
setTimeout(() => {
updateValueLineStation(
data?.lineId,
{
runningScenario: data?.title || "",
runningPhysical: data?.physical || false,
ports: data?.ports || [],
listPortsPhysical: [],
},
data?.stationId,
);
}, 100);
});
socket?.on("user_clear_terminal", (data) => {
updateValueLineStation(
data?.lineId,
{ netOutput: "", output: "", loadingClearTerminal: true },
data?.stationId,
);
});
socket?.on("test_port_physical", (data) => {
if (data?.data && data?.data.length > 0)
updateValueLineStation(
data?.lineId,
{ listPortsPhysical: data?.data },
data?.stationId,
);
});
socket?.on("feature_tested", (data) => {
if (data?.listFeatureTested) {
updateValueLineStation(
data?.lineId,
{
listFeatureTested: data?.listFeatureTested,
isSkipPhysical: data?.isSkipPhysical,
reasonSkipPhysical: data?.reasonSkipPhysical,
},
data?.stationId,
);
if (data?.isSkipPhysical && !data?.reasonSkipPhysical) {
const valueLine = findLineByLineId(data?.lineId, data?.stationId);
if (
valueLine &&
openModalTerminal &&
selectedLine?.id === valueLine?.id &&
(!valueLine?.listPortsPhysical ||
valueLine?.listPortsPhysical?.length === 0)
)
setLinesConfirmSkipPort((pre) => [
...pre,
{
...valueLine,
inventory: {
...valueLine.inventory,
pid: data?.pid,
sn: data?.sn,
vid: data?.vid,
},
},
]);
}
if (
!data?.listFeatureTested?.includes("PHYSICAL") &&
data?.listFeatureTested?.includes("DPELP")
) {
const valueLine = findLineByLineId(data?.lineId, data?.stationId);
if (
valueLine &&
openModalTerminal &&
selectedLine?.id === valueLine?.id
)
setLinesConfirmRunPhysical((pre) => [
...pre,
{
...valueLine,
inventory: {
...valueLine.inventory,
pid: data?.pid,
sn: data?.sn,
vid: data?.vid,
},
},
]);
}
}
});
socket?.on("summary_tested", (data) => {
if (
data?.body &&
openModalTerminal &&
selectedLine?.id === data?.lineId
) {
setDataSummaryTested({
body: data?.body || "",
title: data?.title || "",
});
}
});
// ✅ cleanup on unmount or when socket changes
return () => {
socket.off("init");
socket.off("line_output");
socket.off("line_error");
socket.off("line_connected");
socket.off("line_disconnected");
socket.off("user_connecting");
socket.off("user_open_cli");
socket.off("user_close_cli");
socket.off("response_content_log");
socket.off("data_textfsm");
socket.off("update_ticket");
socket.off("update_baud");
socket.off("line_connecting");
socket.off("running_scenario");
socket.off("user_clear_terminal");
socket.off("test_port_physical");
socket.off("feature_tested");
socket.off("summary_tested");
};
}, [socket, stations, selectedLine]);
const flushBuffers = useCallback(() => {
setStations((prev) =>
prev.map((station) => ({
...station,
lines: station.lines.map((line) => {
const buffered = lineBuffersRef.current.get(line.id || 0);
if (!buffered) return line; // không có update
const data = {
...line,
netOutput: (line.netOutput || "") + buffered,
output: buffered,
loadingOutput: line.loadingOutput ? false : true,
loadingClearTerminal: false,
};
updateValueSelectedLine(line?.id || 0, data);
return data;
}),
})),
);
// clear
lineBuffersRef.current.clear();
flushScheduledRef.current = false;
}, []);
const updateValueLineStation = useCallback(
(lineId: number, updates: Partial<TLine>, stationId?: number) => {
setStations((prevStations) =>
prevStations?.map((station: TStation) =>
station.id === stationId
? {
...station,
lines: station.lines?.map((lineItem: TLine) => {
if (lineItem.id !== lineId) return lineItem;
const isNetOutput = typeof updates?.netOutput !== "undefined";
return {
...lineItem,
...updates,
lineNumber: lineItem.lineNumber,
line_number: lineItem.line_number,
ports:
updates?.ports && updates?.ports?.length > 0
? updates?.ports
: lineItem.ports || [],
...(isNetOutput && {
netOutput: updates?.loadingClearTerminal
? ""
: (lineItem.netOutput || "") +
(updates.netOutput || ""),
output: updates.netOutput, // Nếu netOutput thì update luôn output
loadingOutput: lineItem.loadingOutput ? false : true,
loadingClearTerminal: updates?.loadingClearTerminal
? updates?.loadingClearTerminal
: false,
}),
};
}),
}
: station,
),
);
// Update selectedLine nếu nó đang được chọn
setSelectedLine((prevSelected) => {
if (!prevSelected || prevSelected.id !== lineId) return prevSelected;
const isNetOutput = typeof updates?.netOutput !== "undefined";
return {
...prevSelected,
...updates,
ports:
updates?.ports && updates?.ports?.length > 0
? updates?.ports
: prevSelected.ports || [],
...(isNetOutput && {
netOutput: updates?.loadingClearTerminal
? ""
: (prevSelected.netOutput || "") + (updates.netOutput || ""),
output: updates.netOutput,
loadingOutput: prevSelected.loadingOutput ? false : true,
loadingClearTerminal: updates?.loadingClearTerminal
? updates?.loadingClearTerminal
: false,
}),
};
});
updateValueSelectedLines(lineId, updates);
},
[],
);
const updateValueSelectedLines = (
lineId: number,
updates: Partial<TLine>,
) => {
// Update selectedLine nếu nó đang được chọn
setSelectedLines((prevSelected) =>
prevSelected?.map((line) => {
if (line.id === lineId) {
return { ...line, ...updates };
}
return line;
}),
);
};
const updateValueSelectedLine = (lineId: number, updates: Partial<TLine>) => {
// Update selectedLine nếu nó đang được chọn
setSelectedLine((prevSelected) => {
if (!prevSelected || prevSelected.id !== lineId) return prevSelected;
return {
...prevSelected,
...updates,
};
});
};
// const getLine = (lineId: number, stationId: number) => {
// const station = stations?.find((sta) => sta.id === stationId);
// if (station) {
// const line = station.lines?.find((li) => li.id === lineId);
// return line;
// } else return null;
// };
const openTerminal = (line: TLine) => {
setOpenModalTerminal(true);
const data = { ...line };
if (!line.userOpenCLI) {
data.cliOpened = true;
data.userEmailOpenCLI = user?.email;
data.userOpenCLI = user?.userName;
socket?.emit("open_cli", {
lineId: line.id,
stationId: line.stationId || line.station_id,
userEmail: user?.email,
userName: user?.userName,
});
}
setSelectedLine(data);
};
useEffect(() => {
if (!expandedBottomBar) {
setActiveTabBottom("command");
}
}, [expandedBottomBar]);
const findLineByLineId = (lineId: number, stationId?: number) => {
const valueStation = stations.find((el) => el.id === stationId);
if (!valueStation || !stationId) return null;
const valueLine = valueStation?.lines?.find((el) => el.id === lineId);
return valueLine;
};
return (
<Container w={"100%"} style={{ maxWidth: "100%" }}>
<DraggableTabs
socket={socket}
usersConnecting={usersConnecting}
setIsEditStation={setIsEditStation}
setIsOpenAddStation={setIsOpenAddStation}
setStationEdit={setStationEdit}
tabsData={stations}
scenarios={scenarios}
setScenarios={setScenarios}
panels={stations.map((station) => (
<Tabs.Panel
className={classes.content}
key={station.id}
value={station.id.toString()}
pt="md"
>
<Flex className={classes.containerMain}>
<Grid>
<Grid.Col
span={12}
style={{
borderRadius: 8,
}}
>
<ScrollArea
// h={expandedBottomBar ? "80vh" : "85vh"}
h={expandedBottomBar ? "73vh" : "83vh"}
type="scroll"
scrollbars="y"
style={{ overflowX: "hidden" }}
className={componentClasses.hideScrollBar}
>
{isLoading ? (
<Box
style={{
height: "15vh",
width: "100%",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Loader color="blue" />
</Box>
) : station.lines.length > 0 ? (
station.lines.length < 9 ? (
<Grid
gutter="md"
style={{
margin: 0,
width: "100%",
}}
>
{station.lines.map((line, i) => (
<Grid.Col
key={line.id ?? i}
span={3}
style={{
display: "flex",
height: "100%",
maxWidth: "100%",
overflow: "hidden",
}}
>
<CardLine
socket={socket}
stationItem={station}
line={line}
selectedLines={selectedLines}
setSelectedLines={setSelectedLines}
openTerminal={openTerminal}
loadTerminal={
loadingTerminal &&
Number(station.id) === Number(activeTab)
}
scenarios={scenarios}
/>
</Grid.Col>
))}
</Grid>
) : (
// >= 9 lines: chia làm 2 cột, mỗi cột chứa 1/2 số line,
// mỗi cột hiển thị 2 item trên một "hàng" như ví dụ yêu cầu
(() => {
// const total = station.lines.length;
const half = 8;
const leftLines = station.lines.slice(0, half);
const rightLines = station.lines.slice(half);
const leftChunks = chunkArray(leftLines, 2);
const rightChunks = chunkArray(rightLines, 2);
const numRows = Math.max(
leftChunks.length,
rightChunks.length,
);
return (
<>
{Array.from({ length: numRows }).map(
(_, rowIndex) => {
const leftRow = leftChunks[rowIndex] || [];
const rightRow = rightChunks[rowIndex] || [];
return (
<Grid
key={rowIndex}
gutter="md"
style={{
margin: 0,
width: "100%",
}}
>
{/* Cột A */}
<Grid.Col span={6}>
<Grid gutter="md">
{leftRow.map((line, i) => (
<Grid.Col
key={
line.id ?? `L-${rowIndex}-${i}`
}
span={6}
style={{
display: "flex",
height: "100%",
maxWidth: "100%",
overflow: "hidden",
}}
>
<CardLine
socket={socket}
stationItem={station}
line={line}
selectedLines={selectedLines}
setSelectedLines={
setSelectedLines
}
openTerminal={openTerminal}
loadTerminal={
loadingTerminal &&
Number(station.id) ===
Number(activeTab)
}
scenarios={scenarios}
/>
</Grid.Col>
))}
</Grid>
</Grid.Col>
{/* Cột B */}
<Grid.Col span={6}>
<Grid gutter="md">
{rightRow.map((line, i) => (
<Grid.Col
key={
line.id ?? `R-${rowIndex}-${i}`
}
span={6}
style={{
display: "flex",
height: "100%",
maxWidth: "100%",
overflow: "hidden",
}}
>
<CardLine
socket={socket}
stationItem={station}
line={line}
selectedLines={selectedLines}
setSelectedLines={
setSelectedLines
}
openTerminal={openTerminal}
loadTerminal={
loadingTerminal &&
Number(station.id) ===
Number(activeTab)
}
scenarios={scenarios}
/>
</Grid.Col>
))}
</Grid>
</Grid.Col>
</Grid>
);
},
)}
</>
);
})()
)
) : (
<Text ta="center" c="dimmed" mt="lg">
No lines configured
</Text>
)}
</ScrollArea>
</Grid.Col>
</Grid>
<BottomToolBar
selectedLines={selectedLines}
socket={socket}
setSelectedLines={setSelectedLines}
isDisable={isDisable}
setIsDisable={setIsDisable}
station={station}
stationId={Number(activeTab)}
testLogContent={testLogContent}
isLogModalOpen={isLogModalOpen}
setIsLogModalOpen={setIsLogModalOpen}
setTestLogContent={setTestLogContent}
scenarios={scenarios}
setScenarios={setScenarios}
setExpanded={setExpandedBottomBar}
activeTabBottom={activeTabBottom}
setActiveTabBottom={setActiveTabBottom}
isExpand={expandedBottomBar}
listBrands={listBrands}
listCategories={listCategories}
/>
</Flex>
</Tabs.Panel>
))}
onChange={(id) => {
const station = stations.find((el) => el.id === Number(activeTab));
if (station) {
(station?.lines || [])?.forEach((el) => {
if (el?.userOpenCLI === user?.userName)
socket?.emit("close_cli", {
lineId: el?.id,
stationId: Number(activeTab),
});
});
}
setActiveTab(id?.toString() || "0");
setSelectedLines([]);
setLoadingTerminal(false);
setTimeout(() => {
setLoadingTerminal(true);
}, 500);
}}
setActive={setActiveTab}
active={activeTab}
onSendCommand={(value) => {
const listLine = selectedLines.length
? selectedLines
: stations.find((el) => el.id === Number(activeTab))?.lines;
if (listLine?.length) {
socket?.emit("write_command_line_from_web", {
lineIds: listLine.map((line) => line.id),
stationId: Number(activeTab),
command: value + "\n",
});
setTimeout(() => {
socket?.emit("write_command_line_from_web", {
lineIds: listLine.map((line) => line.id),
stationId: Number(activeTab),
command: " \n",
});
}, 1000);
}
}}
listBrands={listBrands}
listCategories={listCategories}
/>
<StationSetting
dataStation={stationEdit}
isOpen={isOpenAddStation}
onClose={() => {
setIsOpenAddStation(false);
setIsEditStation(false);
setStationEdit(undefined);
}}
isEdit={isEditStation}
setStations={setStations}
setActiveTab={(id: string) => {
setActiveTab(id);
setLoadingTerminal(false);
setTimeout(() => {
setLoadingTerminal(true);
}, 100);
}}
stations={stations}
socket={socket}
/>
<ModalTerminal
selectedLines={selectedLines}
opened={openModalTerminal}
onClose={() => {
setOpenModalTerminal(false);
setSelectedLine(undefined);
}}
line={selectedLine}
socket={socket}
stationItem={stations.find((el) => el.id === Number(activeTab))}
scenarios={scenarios}
listIos={listIos}
listLicense={listLicense}
getListIos={getListIos}
getListLicense={getListLicense}
setScenarios={setScenarios}
listBrands={listBrands}
listCategories={listCategories}
setLinesConfirmSkipPort={setLinesConfirmSkipPort}
linesConfirmSkipPort={linesConfirmSkipPort}
dataSummaryTested={dataSummaryTested}
/>
{/* <ModalConfirmRunScenario
socket={socket}
station={stations.find((el) => el.id === Number(activeTab))}
scenarios={scenarios}
/> */}
<ModalConfirmSkipTestPort
listLines={linesConfirmSkipPort}
setListLines={setLinesConfirmSkipPort}
socket={socket}
station={stations.find((el) => el.id === Number(activeTab))}
/>
<ModalConfirmRunPhysical
listLines={linesConfirmRunPhysical}
setListLines={setLinesConfirmRunPhysical}
socket={socket}
station={stations.find((el) => el.id === Number(activeTab))}
/>
<ModalSummaryTested
data={dataSummaryTested}
setData={setDataSummaryTested}
/>
</Container>
);
}
export default function Main() {
const user = useMemo(() => {
return localStorage.getItem("user") &&
isJsonString(localStorage.getItem("user"))
? JSON.parse(localStorage.getItem("user") || "")
: null;
}, []);
return (
<MantineProvider>
<SocketProvider>
<Suspense
fallback={
<LoadingOverlay
visible={true}
zIndex={1000}
overlayProps={{ radius: "sm", blur: 1 }}
/>
}
>
<Notifications position="top-right" autoClose={5000} />
{user ? (
<App />
) : (
<Container w={"100%"} style={{ maxWidth: "100%", padding: 0 }}>
<PageLogin />
</Container>
)}
</Suspense>
</SocketProvider>
</MantineProvider>
);
}