React/Vite Frontend (hifi-src) + PHP/MariaDB Backend (hifi/api) fuer den Car-Hifi Umbau-Shop HifiPlanet in Amorbach, inkl. Admin-Panel, 2FA, Wartungsmodus, Cookie-Consent und rechtlichen Pflichtseiten. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
37 lines
1.2 KiB
JavaScript
37 lines
1.2 KiB
JavaScript
import { useState } from 'react';
|
|
import { api } from '../api/client.js';
|
|
|
|
export default function ImageUploadField({ value, onChange, label = 'Bild' }) {
|
|
const [uploading, setUploading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
const handleFile = async (e) => {
|
|
const file = e.target.files?.[0];
|
|
if (!file) return;
|
|
|
|
setUploading(true);
|
|
setError('');
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
const result = await api.post('/uploads', formData);
|
|
onChange(result.path);
|
|
} catch (err) {
|
|
setError(err.message);
|
|
} finally {
|
|
setUploading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<label className="mb-1 block text-sm font-medium text-slate-700 dark:text-slate-300">{label}</label>
|
|
<div className="flex items-center gap-3">
|
|
{value && <img src={value} alt="" className="h-12 w-12 rounded-md object-cover" />}
|
|
<input type="file" accept="image/png,image/jpeg,image/webp" onChange={handleFile} className="text-sm" />
|
|
{uploading && <span className="text-sm text-slate-500">Lädt hoch…</span>}
|
|
</div>
|
|
{error && <p className="mt-1 text-sm text-red-600">{error}</p>}
|
|
</div>
|
|
);
|
|
}
|