"use client";
import { useState } from "react";
import {
Download,
FileSpreadsheet,
FileJson,
FileText,
Calendar,
Check,
Loader2,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress";
import { Separator } from "@/components/ui/separator";
type ExportFormat = "csv" | "json" | "xlsx";
type Field = {
id: string;
label: string;
description: string;
required?: boolean;
};
const formats = [
{ id: "csv" as ExportFormat, label: "CSV", icon: FileText, description: "Comma-separated values" },
{ id: "json" as ExportFormat, label: "JSON", icon: FileJson, description: "JavaScript Object Notation" },
{ id: "xlsx" as ExportFormat, label: "Excel", icon: FileSpreadsheet, description: "Microsoft Excel format" },
];
const fields: Field[] = [
{ id: "id", label: "ID", description: "Unique identifier", required: true },
{ id: "name", label: "Name", description: "Display name" },
{ id: "email", label: "Email", description: "Email address" },
{ id: "created", label: "Created Date", description: "When the record was created" },
{ id: "updated", label: "Updated Date", description: "Last modification date" },
{ id: "status", label: "Status", description: "Current status" },
{ id: "metadata", label: "Metadata", description: "Additional information" },
];
const dateRanges = [
{ id: "all", label: "All time" },
{ id: "today", label: "Today" },
{ id: "week", label: "Last 7 days" },
{ id: "month", label: "Last 30 days" },
{ id: "quarter", label: "Last 90 days" },
{ id: "year", label: "Last year" },
];
export const title = "React Dialog Block Export Data";
export default function DialogExportData() {
const [open, setOpen] = useState(false);
const [format, setFormat] = useState<ExportFormat>("csv");
const [dateRange, setDateRange] = useState("all");
const [selectedFields, setSelectedFields] = useState<string[]>(
fields.map((f) => f.id)
);
const [isExporting, setIsExporting] = useState(false);
const [progress, setProgress] = useState(0);
const [isComplete, setIsComplete] = useState(false);
const handleFieldToggle = (fieldId: string) => {
const field = fields.find((f) => f.id === fieldId);
if (field?.required) return;
setSelectedFields((prev) =>
prev.includes(fieldId)
? prev.filter((id) => id !== fieldId)
: [...prev, fieldId]
);
};
const handleSelectAll = () => {
setSelectedFields(fields.map((f) => f.id));
};
const handleExport = async () => {
setIsExporting(true);
setProgress(0);
// Simulate export progress
for (let i = 0; i <= 100; i += 10) {
await new Promise((resolve) => setTimeout(resolve, 200));
setProgress(i);
}
setIsExporting(false);
setIsComplete(true);
};
const handleClose = () => {
setOpen(false);
setTimeout(() => {
setIsComplete(false);
setProgress(0);
}, 200);
};
const selectedFormat = formats.find((f) => f.id === format);
const FormatIcon = selectedFormat?.icon || FileText;
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<Download className="mr-2 h-4 w-4" />
Export Data
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Download className="h-5 w-5" />
Export Data
</DialogTitle>
<DialogDescription>
Configure your export settings and download your data.
</DialogDescription>
</DialogHeader>
{isComplete ? (
<div className="flex flex-col items-center py-8 text-center">
<div className="rounded-full border-2 border-primary p-3 mb-4">
<Check className="h-6 w-6 text-primary" />
</div>
<h3 className="font-semibold">Export Complete</h3>
<p className="text-sm text-muted-foreground mt-1">
Your {selectedFormat?.label} file has been downloaded.
</p>
<Button className="mt-4" onClick={handleClose}>
Done
</Button>
</div>
) : isExporting ? (
<div className="space-y-4 py-6">
<div className="flex items-center justify-center">
<Loader2 className="h-8 w-8 animate-spin text-primary" />
</div>
<div className="space-y-2">
<div className="flex justify-between text-sm">
<span>Exporting...</span>
<span className="font-mono">{progress}%</span>
</div>
<Progress value={progress} />
</div>
<p className="text-xs text-center text-muted-foreground">
Preparing {selectedFields.length} fields as {selectedFormat?.label}
</p>
</div>
) : (
<>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label>Format</Label>
<div className="grid grid-cols-3 gap-2">
{formats.map((f) => {
const Icon = f.icon;
return (
<button
key={f.id}
type="button"
onClick={() => setFormat(f.id)}
className={`flex flex-col items-center gap-1 rounded-lg border p-3 transition-colors ${
format === f.id
? "border-primary bg-primary/5"
: "hover:bg-muted"
}`}
>
<Icon className="h-5 w-5" />
<span className="text-sm font-medium">{f.label}</span>
</button>
);
})}
</div>
</div>
<div className="space-y-2">
<Label>Date Range</Label>
<Select value={dateRange} onValueChange={setDateRange}>
<SelectTrigger>
<Calendar className="mr-2 h-4 w-4" />
<SelectValue />
</SelectTrigger>
<SelectContent>
{dateRanges.map((range) => (
<SelectItem key={range.id} value={range.id}>
{range.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Separator />
<div className="space-y-2">
<div className="flex items-center justify-between">
<Label>Fields to Export</Label>
<Button
variant="ghost"
size="sm"
className="h-auto py-1 text-xs"
onClick={handleSelectAll}
>
Select All
</Button>
</div>
<div className="grid grid-cols-2 gap-2">
{fields.map((field) => (
<div
key={field.id}
className="flex items-center space-x-2"
>
<Checkbox
id={field.id}
checked={selectedFields.includes(field.id)}
onCheckedChange={() => handleFieldToggle(field.id)}
disabled={field.required}
/>
<Label
htmlFor={field.id}
className="text-sm font-normal cursor-pointer"
>
{field.label}
{field.required && (
<span className="text-xs text-muted-foreground ml-1">
(required)
</span>
)}
</Label>
</div>
))}
</div>
</div>
<div className="rounded-lg border p-3">
<div className="flex items-center justify-between text-sm">
<span className="text-muted-foreground">Export summary</span>
<Badge variant="secondary">
{selectedFields.length} fields
</Badge>
</div>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button onClick={handleExport} disabled={selectedFields.length === 0}>
<FormatIcon className="mr-2 h-4 w-4" />
Export {selectedFormat?.label}
</Button>
</DialogFooter>
</>
)}
</DialogContent>
</Dialog>
);
}