TTMT.ManageWebGUI/src/routes/_auth/rooms/$roomName/index.tsx

135 lines
4.8 KiB
TypeScript

import { createFileRoute, useParams, useNavigate } from "@tanstack/react-router";
import { useState } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { LayoutGrid, TableIcon, Monitor, FolderCheck } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useGetDeviceFromRoom } from "@/hooks/queries";
import { useDeviceEvents } from "@/hooks/useDeviceEvents";
import { DeviceGrid } from "@/components/grids/device-grid";
import { DeviceTable } from "@/components/tables/device-table";
import { useMachineNumber } from "@/hooks/useMachineNumber";
import { CommandActionButtons } from "@/components/buttons/command-action-buttons";
export const Route = createFileRoute("/_auth/rooms/$roomName/")({
head: ({ params }) => ({
meta: [{ title: `Danh sách thiết bị phòng ${params.roomName}` }],
}),
loader: async ({ context, params }) => {
context.breadcrumbs = [
{ title: "Danh sách phòng", path: "/rooms/" },
{ title: `Phòng ${params.roomName}`, path: `/rooms/${params.roomName}/` },
];
},
component: RoomDetailPage,
});
function RoomDetailPage() {
const { roomName } = useParams({ from: "/_auth/rooms/$roomName/" });
const [viewMode, setViewMode] = useState<"grid" | "table">("grid");
// SSE real-time updates
useDeviceEvents(roomName);
// Folder status from SS
const { data: devices = [] } = useGetDeviceFromRoom(roomName);
const parseMachineNumber = useMachineNumber();
const navigate = useNavigate();
const sortedDevices = [...devices].sort((a, b) => {
return parseMachineNumber(a.id) - parseMachineNumber(b.id);
});
return (
<div className="w-full px-6 space-y-6">
<Card className="shadow-sm">
<CardHeader className="bg-muted/50 space-y-4">
{/* Hàng 1: Thông tin phòng và controls */}
<div className="flex items-center justify-between w-full gap-4">
<div className="flex items-center gap-2">
<Monitor className="h-5 w-5" />
<CardTitle>Danh sách thiết bị phòng {roomName}</CardTitle>
</div>
<div className="flex items-center gap-2 bg-background rounded-lg p-1 border shrink-0">
<Button
variant={viewMode === "grid" ? "default" : "ghost"}
size="sm"
onClick={() => setViewMode("grid")}
className="flex items-center gap-2"
>
<LayoutGrid className="h-4 w-4" />
đ
</Button>
<Button
variant={viewMode === "table" ? "default" : "ghost"}
size="sm"
onClick={() => setViewMode("table")}
className="flex items-center gap-2"
>
<TableIcon className="h-4 w-4" />
Bảng
</Button>
</div>
</div>
{/* Hàng 2: Thực thi lệnh */}
<div className="flex items-center justify-between w-full gap-4">
<div className="flex items-center gap-2 text-sm font-semibold">
Thực thi lệnh
</div>
<div className="flex items-center gap-3 justify-end">
{/* Command Action Buttons */}
{devices.length > 0 && (
<>
<CommandActionButtons roomName={roomName} />
<div className="h-8 w-px bg-border" />
<Button
onClick={() =>
navigate({
to: "/rooms/$roomName/folder-status/",
params: { roomName },
} as any)
}
variant="outline"
size="sm"
className="flex items-center gap-2 shrink-0"
>
<FolderCheck className="h-4 w-4" />
Kiểm tra thư mục Setup
</Button>
</>
)}
</div>
</div>
</CardHeader>
<CardContent className="p-0">
{devices.length === 0 ? (
<div className="flex flex-col items-center justify-center py-12">
<Monitor className="h-12 w-12 text-muted-foreground mb-4" />
<h3 className="text-lg font-semibold mb-2">Không thiết bị</h3>
<p className="text-muted-foreground text-center max-w-sm">
Phòng này chưa thiết bị nào đưc kết nối.
</p>
</div>
) : viewMode === "grid" ? (
<DeviceGrid
devices={sortedDevices}
/>
) : (
<DeviceTable
devices={sortedDevices}
/>
)}
</CardContent>
</Card>
</div>
);
}