68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
import { useRef, useState } from 'react';
|
|
import { api } from '../../api';
|
|
import { useQueryClient } from '@tanstack/react-query';
|
|
|
|
interface Props {
|
|
catalogId: string;
|
|
}
|
|
|
|
export default function ImageUploadZone({ catalogId }: Props) {
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
const [uploading, setUploading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const qc = useQueryClient();
|
|
|
|
const handleFiles = async (files: FileList | null) => {
|
|
if (!files || files.length === 0) return;
|
|
setUploading(true);
|
|
setError(null);
|
|
|
|
for (const file of Array.from(files)) {
|
|
const fd = new FormData();
|
|
fd.append('file', file);
|
|
try {
|
|
await api.gallery.upload(catalogId, fd);
|
|
qc.invalidateQueries({ queryKey: ['gallery', catalogId] });
|
|
} catch (e) {
|
|
setError(`Upload failed: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
}
|
|
}
|
|
setUploading(false);
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<div
|
|
onClick={() => inputRef.current?.click()}
|
|
onDragOver={e => e.preventDefault()}
|
|
onDrop={e => { e.preventDefault(); handleFiles(e.dataTransfer.files); }}
|
|
style={{
|
|
border: '1px dashed var(--border-hi)',
|
|
borderRadius: 4,
|
|
padding: '20px',
|
|
textAlign: 'center',
|
|
cursor: 'pointer',
|
|
color: 'var(--text-lo)',
|
|
fontFamily: 'var(--font-mono)',
|
|
fontSize: 12,
|
|
background: 'var(--bg-deep)',
|
|
transition: 'border-color 0.15s',
|
|
}}
|
|
>
|
|
{uploading ? 'Uploading...' : 'Drop images here or click to upload (JPEG, PNG, TIFF — max 50MB)'}
|
|
</div>
|
|
<input
|
|
ref={inputRef}
|
|
type="file"
|
|
accept=".jpg,.jpeg,.png,.tiff,.tif"
|
|
multiple
|
|
style={{ display: 'none' }}
|
|
onChange={e => handleFiles(e.target.files)}
|
|
/>
|
|
{error && (
|
|
<div style={{ color: 'var(--danger)', fontSize: 11, marginTop: 6 }}>{error}</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|