import { ActionIcon, Avatar, Box, CloseButton, Flex, Group, Input, Menu, Tabs, Text, Tooltip, UnstyledButton, } from "@mantine/core"; import { DndContext, useSensor, useSensors, PointerSensor, closestCenter, type DragEndEvent, } from "@dnd-kit/core"; import { arrayMove, SortableContext, useSortable, horizontalListSortingStrategy, } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { useEffect, useMemo, useState, type JSX } from "react"; import { IconChevronRight, IconEdit, IconLogout, IconSettingsPlus, IconUsersGroup, } from "@tabler/icons-react"; import classes from "./Component.module.css"; import type { TStation, TUser } from "../untils/types"; import type { Socket } from "socket.io-client"; interface DraggableTabsProps { tabsData: TStation[]; panels: JSX.Element[]; storageKey?: string; onChange: (activeTabId: string | null) => void; w?: string | number; isStationSettings?: boolean; socket: Socket | null; usersConnecting: TUser[]; setIsEditStation: (value: React.SetStateAction) => void; setIsOpenAddStation: (value: React.SetStateAction) => void; setStationEdit: (value: React.SetStateAction) => void; active: string; setActive: (value: React.SetStateAction) => void; onSendCommand: (value: string) => void; } function SortableTab({ tab, active, onChange, }: { tab: TStation; active: string | null; onChange: (id: string) => void; isStationSettings?: boolean; }) { const { attributes, listeners, setNodeRef, transform, transition } = useSortable({ id: tab.id.toString() }); return ( { listeners?.onPointerDown?.(e); onChange(tab.id.toString()); }} value={tab.id.toString()} style={{ transform: CSS.Transform.toString(transform), transition, cursor: "grab", userSelect: "none", }} color={active === tab.id.toString() ? "green" : ""} fw={600} fz="md" c="#747474" > {tab.name} ); } export default function DraggableTabs({ tabsData, panels, storageKey = "draggable-tabs-order", onChange, w, isStationSettings = false, socket, usersConnecting, setIsEditStation, setIsOpenAddStation, setStationEdit, active, setActive, onSendCommand, }: DraggableTabsProps) { const user = useMemo(() => { return localStorage.getItem("user") && typeof localStorage.getItem("user") === "string" ? JSON.parse(localStorage.getItem("user") || "") : null; }, []); const [tabs, setTabs] = useState(tabsData); const [isChangeTab, setIsChangeTab] = useState(false); const [isSetActive, setIsSetActive] = useState(false); const [valueInput, setValueInput] = useState(""); // const [active, setActive] = useState( // tabsData?.length > 0 ? tabsData[0]?.id.toString() : null // ); const sensors = useSensors(useSensor(PointerSensor)); // Load saved order from localStorage useEffect(() => { if (isChangeTab) { setTabs((pre) => pre .map((t) => { const updatedTab = tabsData.find((td) => td.id === t.id); return updatedTab ? updatedTab : t; }) .filter((t) => (tabsData.find((td) => td.id === t.id) ? true : false)) ); } else { const saved = localStorage.getItem(storageKey); let tabSelected = tabsData?.length > 0 ? tabsData[0]?.id.toString() : null; if (saved) { try { const order = JSON.parse(saved) as { id: string; index: number }[]; // Find the max index in saved order const maxIndex = Math.max(...order.map((o) => o.index), 0); const sorted = [...tabsData].sort((a, b) => { const aOrder = order.find( (o) => o.id.toString() === a.id.toString() )?.index; const bOrder = order.find( (o) => o.id.toString() === b.id.toString() )?.index; // If not found, assign index after all existing ones const aIndex = aOrder !== undefined ? aOrder : maxIndex + 1; const bIndex = bOrder !== undefined ? bOrder : maxIndex + 1; return aIndex - bIndex; }); tabSelected = sorted?.length > 0 ? sorted[0]?.id.toString() : null; setTabs(sorted); } catch { setTabs(tabsData); } } else { setTabs(tabsData); } if (!isSetActive && tabSelected) { setActive(tabSelected); setTimeout(() => { onChange(tabSelected); }, 100); setIsSetActive(true); } } }, [tabsData, storageKey]); // Handle reorder const handleDragEnd = (event: DragEndEvent) => { const { active: dragActive, over } = event; if (dragActive.id !== over?.id && over?.id) { const oldIndex = tabs.findIndex( (t) => t.id.toString() === dragActive.id.toString() ); const newIndex = tabs.findIndex( (t) => t.id.toString() === over?.id.toString() ); const newTabs = arrayMove(tabs, oldIndex, newIndex); setTabs(newTabs); const order = newTabs.map((t, i) => ({ id: t.id, index: i })); localStorage.setItem(storageKey, JSON.stringify(order)); } }; // Clean up useEffect(() => { return () => { setIsChangeTab(false); setIsSetActive(false); setTabs([]); setActive("0"); }; }, []); return ( { setIsChangeTab(true); onChange(val); setActive(val || "0"); }} w={w} > { const newValue = event.currentTarget.value; setValueInput(newValue); }} onKeyDown={(event) => { if (event.key === "Enter") { onSendCommand(valueInput); setValueInput(""); } }} rightSectionPointerEvents="all" rightSection={ setValueInput("")} style={{ display: valueInput ? undefined : "none" }} /> } /> {tabs.map((tab) => ( { setIsChangeTab(true); onChange(id); setActive(id); }} isStationSettings={isStationSettings} /> ))} {Number(active) ? ( { setStationEdit( tabsData.find((el) => el.id === Number(active)) ); setIsOpenAddStation(true); setIsEditStation(true); }} > ) : ( "" )} { setIsOpenAddStation(true); setIsEditStation(false); setStationEdit(undefined); }} > ( {el.userName} ))} >
{user?.userName || user?.user_name || ""} {user?.email}
{ localStorage.removeItem("user"); window.location.href = "/"; socket?.disconnect(); }} color="red" leftSection={} > Logout
{panels}
); }