{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "file-upload-04",
  "type": "registry:block",
  "title": "File Upload Drag & Drop",
  "description": "A file upload drag & drop block.",
  "author": "ephraim duncan <https://ephraimduncan.com>",
  "registryDependencies": [
    "button",
    "card",
    "progress"
  ],
  "dependencies": [
    "lucide-react",
    "sonner"
  ],
  "files": [
    {
      "path": "content/components/file-upload/file-upload-04.tsx",
      "type": "registry:component",
      "target": "components/file-upload-04.tsx",
      "content": "'use client';\n\nimport { File, FileSpreadsheet, X } from 'lucide-react';\nimport { type ChangeEvent, type DragEvent, useRef, useState } from 'react';\nimport { toast } from 'sonner';\n\nimport { Button } from '@/components/ui/button';\nimport { Card } from '@/components/ui/card';\nimport { Progress } from '@/components/ui/progress';\n\nexport default function FileUpload04() {\n  const [uploadState, setUploadState] = useState<{\n    file: File | null;\n    progress: number;\n    uploading: boolean;\n  }>({\n    file: null,\n    progress: 0,\n    uploading: false,\n  });\n  const [showDummy, setShowDummy] = useState(true);\n  const fileInputRef = useRef<HTMLInputElement>(null);\n\n  const validFileTypes = [\n    'text/csv',\n    'application/vnd.ms-excel',\n    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n  ];\n\n  const handleFile = (file: File | undefined) => {\n    if (!file) return;\n\n    if (validFileTypes.includes(file.type)) {\n      setUploadState({ file, progress: 0, uploading: true });\n\n      const interval = setInterval(() => {\n        setUploadState((prev) => {\n          const newProgress = prev.progress + 5;\n          if (newProgress >= 100) {\n            clearInterval(interval);\n            return { ...prev, progress: 100, uploading: false };\n          }\n          return { ...prev, progress: newProgress };\n        });\n      }, 200);\n    } else {\n      toast.error('Please upload a CSV, XLSX, or XLS file.', {\n        position: 'bottom-right',\n        duration: 3000,\n      });\n    }\n  };\n\n  const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {\n    handleFile(event.target.files?.[0]);\n  };\n\n  const handleDrop = (event: DragEvent<HTMLDivElement>) => {\n    event.preventDefault();\n    handleFile(event.dataTransfer.files?.[0]);\n  };\n\n  const resetFile = () => {\n    setUploadState({ file: null, progress: 0, uploading: false });\n    if (fileInputRef.current) {\n      fileInputRef.current.value = '';\n    }\n  };\n\n  const getFileIcon = () => {\n    if (!uploadState.file) return <File />;\n\n    const fileExt = uploadState.file.name.split('.').pop()?.toLowerCase() || '';\n    return ['csv', 'xlsx', 'xls'].includes(fileExt) ? (\n      <FileSpreadsheet className=\"h-5 w-5 text-foreground\" />\n    ) : (\n      <File className=\"h-5 w-5 text-foreground\" />\n    );\n  };\n\n  const formatFileSize = (bytes: number) => {\n    if (bytes === 0) return '0 Bytes';\n    const k = 1024;\n    const sizes = ['Bytes', 'KB', 'MB', 'GB'];\n    const i = Math.floor(Math.log(bytes) / Math.log(k));\n    return Number.parseFloat((bytes / k ** i).toFixed(1)) + ' ' + sizes[i];\n  };\n\n  const { file, progress, uploading } = uploadState;\n\n  return (\n    <div className=\"flex w-full max-w-lg items-center justify-center p-10\">\n      <form className=\"w-full\" onSubmit={(e) => e.preventDefault()}>\n        <h3 className=\"text-balance font-semibold text-foreground text-lg\">\n          File Upload\n        </h3>\n\n        <div\n          className=\"mt-2 flex justify-center rounded-md border border-input border-dashed px-6 py-12\"\n          onDragOver={(e) => e.preventDefault()}\n          onDrop={handleDrop}\n        >\n          <div>\n            <File\n              aria-hidden={true}\n              className=\"mx-auto h-12 w-12 text-muted-foreground\"\n            />\n            <div className=\"flex text-muted-foreground text-sm leading-6\">\n              <p>Drag and drop or</p>\n              <label\n                className=\"relative cursor-pointer rounded-sm pl-1 font-medium text-primary hover:underline hover:underline-offset-4\"\n                htmlFor=\"file-upload-03\"\n              >\n                <span>choose file</span>\n                <input\n                  accept=\".csv, .xlsx, .xls\"\n                  className=\"sr-only\"\n                  id=\"file-upload-03\"\n                  name=\"file-upload-03\"\n                  onChange={handleFileChange}\n                  ref={fileInputRef}\n                  type=\"file\"\n                />\n              </label>\n              <p className=\"text-pretty pl-1\">to upload</p>\n            </div>\n          </div>\n        </div>\n\n        <p className=\"mt-2 text-pretty text-muted-foreground text-xs leading-5 sm:flex sm:items-center sm:justify-between\">\n          <span>Accepted file types: CSV, XLSX or XLS files.</span>\n          <span className=\"pl-1 sm:pl-0\">Max. size: 10MB</span>\n        </p>\n\n        {!file && showDummy && (\n          <Card className=\"relative mt-8 gap-4 bg-muted p-4 shadow-none\">\n            <Button\n              aria-label=\"Remove\"\n              className=\"absolute top-1 right-1 text-muted-foreground hover:text-foreground\"\n              onClick={() => setShowDummy(false)}\n              size=\"icon-sm\"\n              type=\"button\"\n              variant=\"ghost\"\n            >\n              <X aria-hidden={true} className=\"h-5 w-5 shrink-0\" />\n            </Button>\n\n            <div className=\"flex items-center space-x-2.5\">\n              <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-sm bg-background shadow-sm ring-1 ring-border ring-inset\">\n                <FileSpreadsheet\n                  aria-hidden={true}\n                  className=\"h-5 w-5 text-foreground\"\n                />\n              </span>\n              <div>\n                <p className=\"text-pretty font-medium text-foreground text-xs\">\n                  Revenue_Q1_2024.xlsx\n                </p>\n                <p className=\"mt-0.5 text-pretty text-muted-foreground text-xs\">\n                  3.1 MB\n                </p>\n              </div>\n            </div>\n\n            <div className=\"flex items-center space-x-3\">\n              <Progress className=\"h-1.5\" value={45} />\n              <span className=\"text-muted-foreground text-xs\">45%</span>\n            </div>\n          </Card>\n        )}\n\n        {file && (\n          <Card className=\"relative mt-8 gap-4 bg-muted p-4 shadow-none\">\n            <Button\n              aria-label=\"Remove\"\n              className=\"absolute top-1 right-1 text-muted-foreground hover:text-foreground\"\n              onClick={resetFile}\n              size=\"icon-sm\"\n              type=\"button\"\n              variant=\"ghost\"\n            >\n              <X aria-hidden={true} className=\"h-5 w-5 shrink-0\" />\n            </Button>\n\n            <div className=\"flex items-center space-x-2.5\">\n              <span className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-sm bg-background shadow-sm ring-1 ring-border ring-inset\">\n                {getFileIcon()}\n              </span>\n              <div>\n                <p className=\"text-pretty font-medium text-foreground text-xs\">\n                  {file?.name}\n                </p>\n                <p className=\"mt-0.5 text-pretty text-muted-foreground text-xs\">\n                  {file && formatFileSize(file.size)}\n                </p>\n              </div>\n            </div>\n\n            <div className=\"flex items-center space-x-3\">\n              <Progress className=\"h-1.5\" value={progress} />\n              <span className=\"text-muted-foreground text-xs\">{progress}%</span>\n            </div>\n          </Card>\n        )}\n\n        <div className=\"mt-8 flex items-center justify-end space-x-3\">\n          <Button\n            className=\"whitespace-nowrap\"\n            disabled={!file}\n            onClick={resetFile}\n            type=\"button\"\n            variant=\"outline\"\n          >\n            Cancel\n          </Button>\n          <Button\n            className=\"whitespace-nowrap\"\n            disabled={!file || uploading || progress < 100}\n            type=\"submit\"\n          >\n            Upload\n          </Button>\n        </div>\n      </form>\n    </div>\n  );\n}\n"
    }
  ],
  "categories": [
    "file-upload"
  ]
}