TTMT.ManageWebGUI/src/components/folder-status-popover.tsx

148 lines
5.5 KiB
TypeScript
Raw Normal View History

2025-12-03 18:26:36 +07:00
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { CheckCircle2, AlertCircle, Loader2, AlertTriangle } from "lucide-react";
import type { ClientFolderStatus } from "@/types/folder";
2025-12-03 18:26:36 +07:00
import { ScrollArea } from "@/components/ui/scroll-area";
import { Badge } from "@/components/ui/badge";
interface FolderStatusPopoverProps {
deviceId: string;
status?: ClientFolderStatus;
isLoading?: boolean;
}
export function FolderStatusPopover({
deviceId,
status,
isLoading,
}: FolderStatusPopoverProps) {
const missing = status?.missingFiles ?? [];
const extra = status?.extraFiles ?? [];
const hasMissing = missing.length > 0;
const hasExtra = extra.length > 0;
2025-12-03 18:26:36 +07:00
const hasIssues = hasMissing || hasExtra;
// Xác định màu sắc và icon dựa trên trạng thái
let statusColor = "text-green-500";
let statusIcon = (
<CheckCircle2 className={`h-5 w-5 ${statusColor}`} />
);
if (isLoading) {
statusColor = "text-blue-500";
statusIcon = <Loader2 className={`h-5 w-5 animate-spin ${statusColor}`} />;
} else if (hasMissing && hasExtra) {
// Vừa thiếu vừa thừa -> Đỏ + Alert
statusColor = "text-red-600";
statusIcon = <AlertTriangle className={`h-5 w-5 ${statusColor}`} />;
} else if (hasMissing) {
// Chỉ thiếu -> Đỏ
statusColor = "text-red-500";
statusIcon = <AlertCircle className={`h-5 w-5 ${statusColor}`} />;
} else if (hasExtra) {
// Chỉ thừa -> Cam
statusColor = "text-orange-500";
statusIcon = <AlertCircle className={`h-5 w-5 ${statusColor}`} />;
}
return (
<Popover>
<PopoverTrigger asChild>
<button className="p-2 hover:bg-muted rounded-md transition-colors">
{statusIcon}
</button>
</PopoverTrigger>
<PopoverContent className="w-96 p-4" side="right">
<div className="space-y-4">
<div className="flex items-center gap-2">
<div className="text-sm font-semibold">Thư mục Setup: {deviceId}</div>
{hasIssues && (
<Badge variant="destructive" className="text-xs">
{hasMissing && hasExtra
? "Không đồng bộ"
: hasMissing
? "Thiếu file"
: "Thừa file"}
</Badge>
)}
</div>
{isLoading ? (
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Loader2 className="h-4 w-4 animate-spin" />
Đang kiểm tra...
</div>
) : !status ? (
<div className="text-sm text-muted-foreground">
Chưa dữ liệu
</div>
) : (
<div className="space-y-3">
{/* File thiếu */}
{hasMissing && (
<div className="border-l-4 border-red-500 pl-3">
<h4 className="text-sm font-semibold text-red-600 mb-2 flex items-center gap-2">
<AlertCircle className="h-4 w-4" />
File thiếu ({missing.length})
2025-12-03 18:26:36 +07:00
</h4>
<ScrollArea className="h-32 rounded-md border bg-red-50/30 p-2">
<div className="space-y-2">
{missing.map((file, idx) => (
2025-12-03 18:26:36 +07:00
<div
key={idx}
className="text-xs bg-white rounded p-2 border border-red-200"
>
<div className="font-mono font-semibold text-red-700">
{file.fileName}
</div>
<div className="text-xs text-muted-foreground mt-1">
{file.folderPath}
</div>
</div>
))}
</div>
</ScrollArea>
</div>
)}
{/* File thừa */}
{hasExtra && (
<div className="border-l-4 border-orange-500 pl-3">
<h4 className="text-sm font-semibold text-orange-600 mb-2 flex items-center gap-2">
<AlertCircle className="h-4 w-4" />
File thừa ({extra.length})
2025-12-03 18:26:36 +07:00
</h4>
<ScrollArea className="h-32 rounded-md border bg-orange-50/30 p-2">
<div className="space-y-2">
{extra.map((file, idx) => (
2025-12-03 18:26:36 +07:00
<div
key={idx}
className="text-xs bg-white rounded p-2 border border-orange-200"
>
<div className="font-mono font-semibold text-orange-700">
{file.fileName}
</div>
<div className="text-xs text-muted-foreground mt-1">
{file.folderPath}
</div>
</div>
))}
</div>
</ScrollArea>
</div>
)}
{/* Trạng thái OK */}
{!hasIssues && (
<div className="flex items-center gap-2 text-sm text-green-600 bg-green-50/30 rounded p-3 border border-green-200">
<CheckCircle2 className="h-4 w-4 flex-shrink-0" />
<span className="font-medium">Thư mục đt yêu cầu</span>
</div>
)}
</div>
)}
</div>
</PopoverContent>
</Popover>
);
}