forked from MyZubster-Ecosystem/myzubster
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPhotoUpload.js
More file actions
125 lines (113 loc) 路 3.56 KB
/
Copy pathPhotoUpload.js
File metadata and controls
125 lines (113 loc) 路 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import React, { useState, useCallback } from 'react';
import './PhotoUpload.css';
const PhotoUpload = ({ gardenId, onUploadComplete }) => {
const [files, setFiles] = useState([]);
const [uploading, setUploading] = useState(false);
const [caption, setCaption] = useState('');
const [dragActive, setDragActive] = useState(false);
const handleDrag = useCallback((e) => {
e.preventDefault();
e.stopPropagation();
if (e.type === 'dragenter' || e.type === 'dragover') {
setDragActive(true);
} else if (e.type === 'dragleave') {
setDragActive(false);
}
}, []);
const handleDrop = useCallback((e) => {
e.preventDefault();
e.stopPropagation();
setDragActive(false);
const dropped = Array.from(e.dataTransfer.files).filter(f => f.type.startsWith('image/'));
if (dropped.length > 0) {
setFiles(prev => [...prev, ...dropped]);
}
}, []);
const handleFileChange = (e) => {
const selected = Array.from(e.target.files);
setFiles(prev => [...prev, ...selected]);
};
const removeFile = (index) => {
setFiles(prev => prev.filter((_, i) => i !== index));
};
const handleUpload = async () => {
if (files.length === 0) return;
setUploading(true);
const formData = new FormData();
files.forEach(f => formData.append('photos', f));
if (caption) formData.append('caption', caption);
try {
const res = await fetch(`/api/photos/garden/${gardenId}`, {
method: 'POST',
body: formData,
});
const data = await res.json();
if (data.success) {
setFiles([]);
setCaption('');
onUploadComplete?.();
} else {
alert(data.message || 'Upload fallito');
}
} catch (err) {
alert('Errore di rete: ' + err.message);
} finally {
setUploading(false);
}
};
return (
<div className="photo-upload">
<div
className={`dropzone ${dragActive ? 'active' : ''}`}
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
onDrop={handleDrop}
>
<input
type="file"
id="photo-input"
multiple
accept="image/*"
onChange={handleFileChange}
style={{ display: 'none' }}
/>
<label htmlFor="photo-input" className="dropzone-label">
<span className="dropzone-icon">馃摲</span>
<span>Trascina le foto qui oppure clicca per selezionare</span>
<span className="dropzone-hint">Max 10 foto, max 10 MB ciascuna</span>
</label>
</div>
{files.length > 0 && (
<div className="preview-grid">
{files.map((file, i) => (
<div key={i} className="preview-item">
<img src={URL.createObjectURL(file)} alt={file.name} />
<button type="button" onClick={() => removeFile(i)} className="remove-btn">脳</button>
<span className="file-name">{file.name}</span>
</div>
))}
</div>
)}
{files.length > 0 && (
<div className="upload-controls">
<input
type="text"
placeholder="Didascalia (opzionale)"
value={caption}
onChange={(e) => setCaption(e.target.value)}
className="caption-input"
/>
<button
onClick={handleUpload}
disabled={uploading}
className="upload-btn"
>
{uploading ? 'Caricamento...' : `Carica ${files.length} foto`}
</button>
</div>
)}
</div>
);
};
export default PhotoUpload;