146 lines
5.6 KiB
TypeScript
146 lines
5.6 KiB
TypeScript
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||
|
|
import { CheckCircle2, AlertCircle, Loader2, AlertTriangle } from "lucide-react";
|
||
|
|
import type { ClientFolderStatus } from "@/hooks/useClientFolderStatus";
|
||
|
|
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 hasMissing = status && status.missingFiles.length > 0;
|
||
|
|
const hasExtra = status && status.extraFiles.length > 0;
|
||
|
|
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 có 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 ({status.missingFiles.length})
|
||
|
|
</h4>
|
||
|
|
<ScrollArea className="h-32 rounded-md border bg-red-50/30 p-2">
|
||
|
|
<div className="space-y-2">
|
||
|
|
{status.missingFiles.map((file, idx) => (
|
||
|
|
<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 ({status.extraFiles.length})
|
||
|
|
</h4>
|
||
|
|
<ScrollArea className="h-32 rounded-md border bg-orange-50/30 p-2">
|
||
|
|
<div className="space-y-2">
|
||
|
|
{status.extraFiles.map((file, idx) => (
|
||
|
|
<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>
|
||
|
|
);
|
||
|
|
}
|