TTMT.ManageWebGUI/src/template/app-manager-template.tsx

153 lines
4.1 KiB
TypeScript
Raw Normal View History

2025-09-10 09:59:17 +07:00
import { type ColumnDef } from "@tanstack/react-table";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
2025-10-31 16:52:56 +07:00
import { FileText, Building2, Monitor } from "lucide-react";
2025-09-10 09:59:17 +07:00
import { UploadDialog } from "@/components/upload-dialog";
import { VersionTable } from "@/components/version-table";
2025-10-31 16:52:56 +07:00
import { RequestUpdateMenu } from "@/components/request-update-menu";
2025-09-24 16:13:57 +07:00
import type { AxiosProgressEvent } from "axios";
2025-09-26 17:56:55 +07:00
import { useState } from "react";
2025-10-31 16:52:56 +07:00
import { SelectDialog } from "@/components/select-dialog"; // <-- dùng dialog chung
2025-09-10 09:59:17 +07:00
interface AppManagerTemplateProps<TData> {
title: string;
description: string;
data: TData[];
isLoading: boolean;
columns: ColumnDef<TData, any>[];
2025-09-26 17:56:55 +07:00
onUpload: (
fd: FormData,
config?: { onUploadProgress?: (e: AxiosProgressEvent) => void }
) => Promise<void>;
2025-10-31 16:52:56 +07:00
onUpdate?: (targetNames: string[]) => Promise<void> | void;
2025-09-10 09:59:17 +07:00
updateLoading?: boolean;
onTableInit?: (table: any) => void;
2025-10-31 16:52:56 +07:00
rooms?: string[];
devices?: string[];
2025-09-10 09:59:17 +07:00
}
export function AppManagerTemplate<TData>({
title,
description,
data,
isLoading,
columns,
onUpload,
onUpdate,
updateLoading,
onTableInit,
2025-10-31 16:52:56 +07:00
rooms = [],
devices = [],
2025-09-10 09:59:17 +07:00
}: AppManagerTemplateProps<TData>) {
2025-09-26 17:56:55 +07:00
const [dialogOpen, setDialogOpen] = useState(false);
2025-10-31 16:52:56 +07:00
const [dialogType, setDialogType] = useState<"room" | "device" | null>(null);
const openRoomDialog = () => {
if (rooms.length > 0 && onUpdate) {
setDialogType("room");
setDialogOpen(true);
}
};
const openDeviceDialog = () => {
if (devices.length > 0 && onUpdate) {
setDialogType("device");
2025-09-26 17:56:55 +07:00
setDialogOpen(true);
}
};
2025-10-31 16:52:56 +07:00
const handleUpdateAll = async () => {
if (!onUpdate) return;
const allTargets = [...rooms, ...devices];
await onUpdate(allTargets);
};
const getDialogProps = () => {
if (dialogType === "room") {
return {
title: "Chọn phòng",
description: "Chọn các phòng cần cập nhật",
icon: <Building2 className="w-6 h-6 text-primary" />,
items: rooms,
};
}
if (dialogType === "device") {
return {
title: "Chọn thiết bị",
description: "Chọn các thiết bị cần cập nhật",
icon: <Monitor className="w-6 h-6 text-primary" />,
items: devices,
};
}
return null;
};
const dialogProps = getDialogProps();
2025-09-10 09:59:17 +07:00
return (
<div className="w-full px-6 space-y-4">
2025-10-31 16:52:56 +07:00
{/* Header */}
2025-09-10 09:59:17 +07:00
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold">{title}</h1>
<p className="text-muted-foreground mt-2">{description}</p>
</div>
<UploadDialog onSubmit={onUpload} />
</div>
2025-10-31 16:52:56 +07:00
{/* Table */}
2025-09-10 09:59:17 +07:00
<Card className="w-full">
<CardHeader>
<CardTitle className="flex items-center gap-2">
<FileText className="h-5 w-5" /> Lịch sử phiên bản
</CardTitle>
<CardDescription>Tất cả các phiên bản đã tải lên</CardDescription>
</CardHeader>
2025-10-31 16:52:56 +07:00
2025-09-10 09:59:17 +07:00
<CardContent>
<VersionTable
data={data}
isLoading={isLoading}
columns={columns}
onTableInit={onTableInit}
/>
</CardContent>
2025-10-31 16:52:56 +07:00
2025-09-10 09:59:17 +07:00
{onUpdate && (
<CardFooter>
2025-10-31 16:52:56 +07:00
<RequestUpdateMenu
onUpdateDevice={openDeviceDialog}
onUpdateRoom={openRoomDialog}
onUpdateAll={handleUpdateAll}
2025-09-26 17:56:55 +07:00
loading={updateLoading}
/>
2025-09-10 09:59:17 +07:00
</CardFooter>
)}
</Card>
2025-10-31 16:52:56 +07:00
{/* 🧩 SelectDialog tái sử dụng */}
{dialogProps && (
<SelectDialog
open={dialogOpen}
onClose={() => setDialogOpen(false)}
title={dialogProps.title}
description={dialogProps.description}
icon={dialogProps.icon}
items={dialogProps.items}
onConfirm={async (selectedItems) => {
if (!onUpdate) return;
await onUpdate(selectedItems);
setDialogOpen(false);
}}
/>
)}
2025-09-10 09:59:17 +07:00
</div>
);
2025-09-26 17:56:55 +07:00
}