{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "settings-export-data",
  "title": "Settings Export Data",
  "description": "Export your data in various formats with category selection.",
  "registryDependencies": [
    "badge",
    "button",
    "card",
    "checkbox",
    "field",
    "input-group",
    "progress",
    "select",
    "separator"
  ],
  "files": [
    {
      "path": "registry/new-york/blocks/settings/settings-export-data.tsx",
      "content": "\"use client\";\n\nimport { Download, FileDown, Loader2 } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { Badge } from \"@/registry/new-york/ui/badge\";\nimport { Button } from \"@/registry/new-york/ui/button\";\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardHeader,\n  CardTitle,\n} from \"@/registry/new-york/ui/card\";\nimport { Checkbox } from \"@/registry/new-york/ui/checkbox\";\nimport {\n  Field,\n  FieldContent,\n  FieldDescription,\n  FieldLabel,\n} from \"@/registry/new-york/ui/field\";\nimport {\n  InputGroup,\n  InputGroupInput,\n} from \"@/registry/new-york/ui/input-group\";\nimport { Progress } from \"@/registry/new-york/ui/progress\";\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from \"@/registry/new-york/ui/select\";\nimport { Separator } from \"@/registry/new-york/ui/separator\";\n\nexport interface ExportJob {\n  id: string;\n  format: \"json\" | \"csv\" | \"pdf\" | \"zip\";\n  scope: string[];\n  status: \"pending\" | \"processing\" | \"completed\" | \"failed\";\n  progress?: number;\n  createdAt: Date;\n  completedAt?: Date;\n  downloadUrl?: string;\n  expiresAt?: Date;\n  error?: string;\n}\n\nexport interface SettingsExportDataProps {\n  exportHistory?: ExportJob[];\n  onExport?: (data: {\n    format: \"json\" | \"csv\" | \"pdf\" | \"zip\";\n    scope: string[];\n    dateRange?: { start: Date; end: Date };\n  }) => Promise<ExportJob>;\n  onDownload?: (jobId: string) => Promise<void>;\n  className?: string;\n}\n\nconst exportFormats = [\n  {\n    value: \"json\",\n    label: \"JSON\",\n    description: \"Machine-readable format, includes all data\",\n  },\n  {\n    value: \"csv\",\n    label: \"CSV\",\n    description: \"Spreadsheet format, best for tabular data\",\n  },\n  {\n    value: \"pdf\",\n    label: \"PDF\",\n    description: \"Human-readable document format\",\n  },\n  {\n    value: \"zip\",\n    label: \"ZIP\",\n    description: \"Compressed archive with multiple formats\",\n  },\n];\n\nconst dataCategories = [\n  { id: \"profile\", label: \"Profile Information\" },\n  { id: \"activity\", label: \"Activity History\" },\n  { id: \"messages\", label: \"Messages & Conversations\" },\n  { id: \"files\", label: \"Uploaded Files\" },\n  { id: \"settings\", label: \"Settings & Preferences\" },\n  { id: \"billing\", label: \"Billing & Invoices\" },\n];\n\nexport default function SettingsExportData({\n  exportHistory = [],\n  onExport,\n  onDownload,\n  className,\n}: SettingsExportDataProps) {\n  const [isExporting, setIsExporting] = useState(false);\n  const [selectedFormat, setSelectedFormat] = useState<\n    \"json\" | \"csv\" | \"pdf\" | \"zip\"\n  >(\"json\");\n  const [selectedCategories, setSelectedCategories] = useState<string[]>([]);\n  const [dateRange, setDateRange] = useState({\n    enabled: false,\n    start: \"\",\n    end: \"\",\n  });\n\n  const toggleCategory = (categoryId: string) => {\n    setSelectedCategories((prev) =>\n      prev.includes(categoryId)\n        ? prev.filter((id) => id !== categoryId)\n        : [...prev, categoryId]\n    );\n  };\n\n  const handleExport = async () => {\n    if (selectedCategories.length === 0) {\n      return;\n    }\n\n    setIsExporting(true);\n    try {\n      const exportRange = dateRange.enabled\n        ? {\n            start: new Date(dateRange.start),\n            end: new Date(dateRange.end),\n          }\n        : undefined;\n\n      await onExport?.({\n        format: selectedFormat,\n        scope: selectedCategories,\n        dateRange: exportRange,\n      });\n\n      setSelectedCategories([]);\n      setDateRange({ enabled: false, start: \"\", end: \"\" });\n    } finally {\n      setIsExporting(false);\n    }\n  };\n\n  const formatDate = (date: Date): string =>\n    new Intl.DateTimeFormat(\"en-US\", {\n      month: \"short\",\n      day: \"numeric\",\n      year: \"numeric\",\n      hour: \"numeric\",\n      minute: \"2-digit\",\n    }).format(date);\n\n  const getStatusBadge = (status: ExportJob[\"status\"]) => {\n    switch (status) {\n      case \"completed\":\n        return (\n          <Badge className=\"text-xs\" variant=\"default\">\n            Completed\n          </Badge>\n        );\n      case \"processing\":\n        return (\n          <Badge className=\"text-xs\" variant=\"secondary\">\n            Processing\n          </Badge>\n        );\n      case \"pending\":\n        return (\n          <Badge className=\"text-xs\" variant=\"outline\">\n            Pending\n          </Badge>\n        );\n      case \"failed\":\n        return (\n          <Badge className=\"text-xs\" variant=\"destructive\">\n            Failed\n          </Badge>\n        );\n    }\n  };\n\n  return (\n    <Card className={cn(\"w-full shadow-xs\", className)}>\n      <CardHeader>\n        <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n          <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n            <CardTitle className=\"wrap-break-word\">Export Data</CardTitle>\n            <CardDescription className=\"wrap-break-word\">\n              Download a copy of your data in various formats\n            </CardDescription>\n          </div>\n        </div>\n      </CardHeader>\n      <CardContent>\n        <div className=\"flex flex-col gap-6\">\n          {/* Export Options */}\n          <div className=\"flex flex-col gap-4\">\n            <Field>\n              <FieldLabel htmlFor=\"export-format\">Export Format</FieldLabel>\n              <FieldContent>\n                <Select\n                  onValueChange={(value: \"json\" | \"csv\" | \"pdf\" | \"zip\") =>\n                    setSelectedFormat(value)\n                  }\n                  value={selectedFormat}\n                >\n                  <SelectTrigger id=\"export-format\">\n                    <SelectValue>\n                      {\n                        exportFormats.find((f) => f.value === selectedFormat)\n                          ?.label\n                      }\n                    </SelectValue>\n                  </SelectTrigger>\n                  <SelectContent>\n                    {exportFormats.map((format) => (\n                      <SelectItem key={format.value} value={format.value}>\n                        <div className=\"flex flex-col\">\n                          <span>{format.label}</span>\n                          <span className=\"text-muted-foreground text-xs\">\n                            {format.description}\n                          </span>\n                        </div>\n                      </SelectItem>\n                    ))}\n                  </SelectContent>\n                </Select>\n              </FieldContent>\n            </Field>\n\n            <Field>\n              <FieldLabel>Data Categories</FieldLabel>\n              <FieldContent>\n                <div className=\"flex flex-col gap-3\">\n                  {dataCategories.map((category) => (\n                    <div\n                      className=\"flex items-center gap-3 rounded-lg border p-3\"\n                      key={category.id}\n                    >\n                      <Checkbox\n                        checked={selectedCategories.includes(category.id)}\n                        id={`category-${category.id}`}\n                        onCheckedChange={() => toggleCategory(category.id)}\n                      />\n                      <label\n                        className=\"flex-1 cursor-pointer font-medium text-sm\"\n                        htmlFor={`category-${category.id}`}\n                      >\n                        {category.label}\n                      </label>\n                    </div>\n                  ))}\n                </div>\n                <FieldDescription>\n                  Select the data categories you want to export\n                </FieldDescription>\n              </FieldContent>\n            </Field>\n\n            <Field>\n              <div className=\"flex items-center justify-between\">\n                <div className=\"flex flex-col gap-1\">\n                  <FieldLabel htmlFor=\"date-range\">\n                    Date Range (Optional)\n                  </FieldLabel>\n                  <FieldDescription>\n                    Limit export to a specific date range\n                  </FieldDescription>\n                </div>\n                <Checkbox\n                  checked={dateRange.enabled}\n                  id=\"date-range\"\n                  onCheckedChange={(checked) =>\n                    setDateRange((prev) => ({\n                      ...prev,\n                      enabled: checked === true,\n                    }))\n                  }\n                />\n              </div>\n            </Field>\n\n            {dateRange.enabled && (\n              <div className=\"flex flex-col gap-4 rounded-lg border bg-muted/30 p-4\">\n                <Field>\n                  <FieldLabel htmlFor=\"date-start\">Start Date</FieldLabel>\n                  <FieldContent>\n                    <InputGroup>\n                      <InputGroupInput\n                        id=\"date-start\"\n                        onChange={(e) =>\n                          setDateRange((prev) => ({\n                            ...prev,\n                            start: e.target.value,\n                          }))\n                        }\n                        type=\"date\"\n                        value={dateRange.start}\n                      />\n                    </InputGroup>\n                  </FieldContent>\n                </Field>\n\n                <Field>\n                  <FieldLabel htmlFor=\"date-end\">End Date</FieldLabel>\n                  <FieldContent>\n                    <InputGroup>\n                      <InputGroupInput\n                        id=\"date-end\"\n                        onChange={(e) =>\n                          setDateRange((prev) => ({\n                            ...prev,\n                            end: e.target.value,\n                          }))\n                        }\n                        type=\"date\"\n                        value={dateRange.end}\n                      />\n                    </InputGroup>\n                  </FieldContent>\n                </Field>\n              </div>\n            )}\n\n            <Button\n              className=\"w-full sm:w-auto\"\n              disabled={isExporting || selectedCategories.length === 0}\n              onClick={handleExport}\n              type=\"button\"\n            >\n              {isExporting ? (\n                <>\n                  <Loader2 className=\"size-4 animate-spin\" />\n                  Exporting…\n                </>\n              ) : (\n                <>\n                  <FileDown className=\"size-4\" />\n                  Start Export\n                </>\n              )}\n            </Button>\n          </div>\n\n          <Separator />\n\n          {/* Export History */}\n          <div className=\"flex flex-col gap-4\">\n            <h3 className=\"font-semibold text-base\">Export History</h3>\n            {exportHistory.length === 0 ? (\n              <p className=\"text-muted-foreground text-sm\">\n                No exports yet. Create your first export above.\n              </p>\n            ) : (\n              <div className=\"flex flex-col gap-3\">\n                {exportHistory.map((job) => (\n                  <div\n                    className=\"flex flex-col gap-3 rounded-lg border p-4\"\n                    key={job.id}\n                  >\n                    <div className=\"flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between\">\n                      <div className=\"flex min-w-0 flex-1 flex-col gap-2\">\n                        <div className=\"flex flex-wrap items-center gap-2\">\n                          <span className=\"font-medium text-sm\">\n                            {\n                              exportFormats.find((f) => f.value === job.format)\n                                ?.label\n                            }\n                          </span>\n                          {getStatusBadge(job.status)}\n                        </div>\n                        <div className=\"flex flex-wrap gap-2\">\n                          {job.scope.map((category) => (\n                            <Badge\n                              className=\"text-xs\"\n                              key={category}\n                              variant=\"outline\"\n                            >\n                              {dataCategories.find((c) => c.id === category)\n                                ?.label || category}\n                            </Badge>\n                          ))}\n                        </div>\n                        <div className=\"flex flex-wrap items-center gap-3 text-muted-foreground text-xs\">\n                          <span>Created: {formatDate(job.createdAt)}</span>\n                          {job.completedAt && (\n                            <span>\n                              Completed: {formatDate(job.completedAt)}\n                            </span>\n                          )}\n                          {job.expiresAt && (\n                            <span>Expires: {formatDate(job.expiresAt)}</span>\n                          )}\n                        </div>\n                        {job.status === \"processing\" &&\n                          job.progress !== undefined && (\n                            <div className=\"flex flex-col gap-2\">\n                              <Progress value={job.progress} />\n                              <p className=\"text-muted-foreground text-xs\">\n                                {job.progress}% complete\n                              </p>\n                            </div>\n                          )}\n                        {job.error && (\n                          <p className=\"text-destructive text-sm\">\n                            {job.error}\n                          </p>\n                        )}\n                      </div>\n                      {job.status === \"completed\" && job.downloadUrl && (\n                        <Button\n                          className=\"w-full sm:w-auto\"\n                          onClick={() => onDownload?.(job.id)}\n                          type=\"button\"\n                          variant=\"outline\"\n                        >\n                          <Download className=\"size-4\" />\n                          Download\n                        </Button>\n                      )}\n                    </div>\n                  </div>\n                ))}\n              </div>\n            )}\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "block",
    "settings"
  ],
  "type": "registry:ui"
}