74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
'use client'
|
||
import { useCallback, useRef, useState } from 'react'
|
||
|
||
interface DropZoneProps {
|
||
onFiles: (files: File[]) => void
|
||
disabled?: boolean
|
||
}
|
||
|
||
const ACCEPTED_TYPES = ['.heic', '.heif', '.jpg', '.jpeg', '.png', '.zip']
|
||
const ACCEPT_ATTR = ACCEPTED_TYPES.join(',')
|
||
|
||
export function DropZone({ onFiles, disabled = false }: DropZoneProps) {
|
||
const [isDragging, setIsDragging] = useState(false)
|
||
const inputRef = useRef<HTMLInputElement>(null)
|
||
|
||
const handleFiles = useCallback(
|
||
(fileList: FileList | null) => {
|
||
if (!fileList) return
|
||
const files = Array.from(fileList).filter((f) => {
|
||
const ext = '.' + f.name.split('.').pop()?.toLowerCase()
|
||
return ACCEPTED_TYPES.includes(ext)
|
||
})
|
||
if (files.length > 0) onFiles(files)
|
||
},
|
||
[onFiles],
|
||
)
|
||
|
||
const onDragOver = (e: React.DragEvent) => {
|
||
e.preventDefault()
|
||
if (!disabled) setIsDragging(true)
|
||
}
|
||
|
||
const onDragLeave = () => setIsDragging(false)
|
||
|
||
const onDrop = (e: React.DragEvent) => {
|
||
e.preventDefault()
|
||
setIsDragging(false)
|
||
if (!disabled) handleFiles(e.dataTransfer.files)
|
||
}
|
||
|
||
return (
|
||
<div
|
||
onDragOver={onDragOver}
|
||
onDragLeave={onDragLeave}
|
||
onDrop={onDrop}
|
||
onClick={() => !disabled && inputRef.current?.click()}
|
||
className={`border-2 border-dashed rounded-xl p-8 text-center cursor-pointer transition-colors ${
|
||
isDragging
|
||
? 'border-indigo-400 bg-indigo-950/30'
|
||
: disabled
|
||
? 'border-slate-700 bg-slate-800/20 cursor-not-allowed'
|
||
: 'border-slate-600 bg-slate-800/10 hover:border-indigo-500 hover:bg-indigo-950/20'
|
||
}`}
|
||
>
|
||
<div className="text-3xl mb-2">🖼️</div>
|
||
<p className="text-sm font-semibold text-slate-300">
|
||
Déposez vos images ici ou cliquez pour parcourir
|
||
</p>
|
||
<p className="text-xs text-slate-500 mt-1">
|
||
HEIC, JPG, PNG, ZIP — le nom du fichier = référence produit
|
||
</p>
|
||
<input
|
||
ref={inputRef}
|
||
type="file"
|
||
multiple
|
||
accept={ACCEPT_ATTR}
|
||
className="hidden"
|
||
onChange={(e) => handleFiles(e.target.files)}
|
||
disabled={disabled}
|
||
/>
|
||
</div>
|
||
)
|
||
}
|