284 lines
7.9 KiB
JavaScript
284 lines
7.9 KiB
JavaScript
import React, { useState } from 'react';
|
||
import { makeStyles } from '@material-ui/core/styles';
|
||
import { Button, Card, CardContent, Typography, Container, Box } from '@material-ui/core';
|
||
import Swal from 'sweetalert2/dist/sweetalert2.js';
|
||
import 'sweetalert2/src/sweetalert2.scss';
|
||
|
||
// Components
|
||
import Navbar from '../ComponentUtils/Headers/Navbar';
|
||
import Footer from '../ComponentUtils/Footer';
|
||
import MultiImageDropzone from '../ComponentUtils/MultiUpload/SimpleMultiImageDropzone';
|
||
import ImagePreviewGallery from '../ComponentUtils/MultiUpload/ImagePreviewGallery';
|
||
import DescriptionInput from '../ComponentUtils/MultiUpload/DescriptionInput';
|
||
import UploadProgress from '../ComponentUtils/MultiUpload/UploadProgress';
|
||
import Loading from '../ComponentUtils/LoadingAnimation/Loading';
|
||
|
||
// Utils
|
||
import { uploadImageBatch } from '../../Utils/batchUpload';
|
||
|
||
// Styles
|
||
import '../../App.css';
|
||
import '../Pages/Css/Background.css';
|
||
|
||
const useStyles = makeStyles({
|
||
container: {
|
||
paddingTop: '20px',
|
||
paddingBottom: '40px',
|
||
minHeight: '80vh'
|
||
},
|
||
card: {
|
||
borderRadius: '12px',
|
||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
|
||
padding: '20px',
|
||
marginBottom: '20px'
|
||
},
|
||
headerText: {
|
||
fontFamily: 'roboto',
|
||
fontWeight: '400',
|
||
fontSize: '28px',
|
||
textAlign: 'center',
|
||
marginBottom: '10px',
|
||
color: '#333333'
|
||
},
|
||
subheaderText: {
|
||
fontFamily: 'roboto',
|
||
fontWeight: '300',
|
||
fontSize: '16px',
|
||
color: '#666666',
|
||
textAlign: 'center',
|
||
marginBottom: '30px'
|
||
},
|
||
actionButtons: {
|
||
display: 'flex',
|
||
gap: '15px',
|
||
justifyContent: 'center',
|
||
marginTop: '20px',
|
||
flexWrap: 'wrap'
|
||
},
|
||
uploadButton: {
|
||
borderRadius: '25px',
|
||
padding: '12px 30px',
|
||
fontSize: '16px',
|
||
fontWeight: '500',
|
||
textTransform: 'none',
|
||
background: 'linear-gradient(45deg, #4CAF50 30%, #45a049 90%)',
|
||
color: 'white',
|
||
'&:hover': {
|
||
background: 'linear-gradient(45deg, #45a049 30%, #4CAF50 90%)',
|
||
transform: 'translateY(-2px)',
|
||
boxShadow: '0 4px 12px rgba(76, 175, 80, 0.3)'
|
||
},
|
||
'&:disabled': {
|
||
background: '#cccccc',
|
||
color: '#666666'
|
||
}
|
||
},
|
||
clearButton: {
|
||
borderRadius: '25px',
|
||
padding: '12px 30px',
|
||
fontSize: '16px',
|
||
fontWeight: '500',
|
||
textTransform: 'none',
|
||
border: '2px solid #f44336',
|
||
color: '#f44336',
|
||
backgroundColor: 'transparent',
|
||
'&:hover': {
|
||
backgroundColor: '#f44336',
|
||
color: 'white',
|
||
transform: 'translateY(-2px)',
|
||
boxShadow: '0 4px 12px rgba(244, 67, 54, 0.3)'
|
||
}
|
||
}
|
||
});
|
||
|
||
function MultiUploadPage() {
|
||
const classes = useStyles();
|
||
|
||
const [selectedImages, setSelectedImages] = useState([]);
|
||
const [metadata, setMetadata] = useState({
|
||
year: new Date().getFullYear(),
|
||
title: '',
|
||
description: '',
|
||
name: ''
|
||
});
|
||
const [uploading, setUploading] = useState(false);
|
||
const [uploadProgress, setUploadProgress] = useState(0);
|
||
|
||
const handleImagesSelected = (newImages) => {
|
||
console.log('handleImagesSelected called with:', newImages);
|
||
setSelectedImages(prev => {
|
||
const updated = [...prev, ...newImages];
|
||
console.log('Updated selected images:', updated);
|
||
return updated;
|
||
});
|
||
};
|
||
|
||
const handleRemoveImage = (indexToRemove) => {
|
||
setSelectedImages(prev =>
|
||
prev.filter((_, index) => index !== indexToRemove)
|
||
);
|
||
};
|
||
|
||
const handleClearAll = () => {
|
||
setSelectedImages([]);
|
||
setMetadata({
|
||
year: new Date().getFullYear(),
|
||
title: '',
|
||
description: '',
|
||
name: ''
|
||
});
|
||
};
|
||
|
||
const handleUpload = async () => {
|
||
if (selectedImages.length === 0) {
|
||
Swal.fire({
|
||
icon: 'warning',
|
||
title: 'Keine Bilder ausgewählt',
|
||
text: 'Bitte wählen Sie mindestens ein Bild zum Upload aus.',
|
||
confirmButtonColor: '#4CAF50'
|
||
});
|
||
return;
|
||
}
|
||
|
||
if (!metadata.year || !metadata.title.trim()) {
|
||
Swal.fire({
|
||
icon: 'warning',
|
||
title: 'Pflichtfelder fehlen',
|
||
text: 'Bitte geben Sie Jahr und Titel an.',
|
||
confirmButtonColor: '#4CAF50'
|
||
});
|
||
return;
|
||
}
|
||
|
||
setUploading(true);
|
||
setUploadProgress(0);
|
||
|
||
try {
|
||
// Simuliere Progress (da wir noch keinen echten Progress haben)
|
||
const progressInterval = setInterval(() => {
|
||
setUploadProgress(prev => {
|
||
if (prev >= 90) {
|
||
clearInterval(progressInterval);
|
||
return 90;
|
||
}
|
||
return prev + 10;
|
||
});
|
||
}, 200);
|
||
|
||
const result = await uploadImageBatch(selectedImages, metadata);
|
||
|
||
clearInterval(progressInterval);
|
||
setUploadProgress(100);
|
||
|
||
// Kurze Verzögerung für UX
|
||
setTimeout(() => {
|
||
setUploading(false);
|
||
|
||
Swal.fire({
|
||
icon: 'success',
|
||
title: 'Upload erfolgreich!',
|
||
text: `${result.imageCount} Bild${result.imageCount !== 1 ? 'er' : ''} wurden hochgeladen.`,
|
||
confirmButtonColor: '#4CAF50',
|
||
timer: 2000,
|
||
showConfirmButton: false
|
||
});
|
||
|
||
// Seite neu laden für nächsten Upload
|
||
setTimeout(() => {
|
||
window.location.reload();
|
||
}, 2000);
|
||
}, 500);
|
||
|
||
} catch (error) {
|
||
setUploading(false);
|
||
console.error('Upload error:', error);
|
||
|
||
Swal.fire({
|
||
icon: 'error',
|
||
title: 'Upload fehlgeschlagen',
|
||
text: error.message || 'Ein Fehler ist beim Upload aufgetreten.',
|
||
confirmButtonColor: '#f44336'
|
||
});
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="allContainer">
|
||
<Navbar />
|
||
|
||
<Container maxWidth="lg" className={classes.container}>
|
||
<Card className={classes.card}>
|
||
<CardContent>
|
||
<Typography className={classes.headerText}>
|
||
Project Image Uploader
|
||
</Typography>
|
||
<Typography className={classes.subheaderText}>
|
||
Lade ein oder mehrere Bilder von deinem Projekt hoch und beschreibe es in wenigen Worten.
|
||
<br />
|
||
Die Bilder werden nur hier im Hobbyhimmel auf dem Monitor gezeigt, es wird an keine Dritten weiter gegeben.
|
||
</Typography>
|
||
|
||
{!uploading ? (
|
||
<>
|
||
<MultiImageDropzone
|
||
onImagesSelected={handleImagesSelected}
|
||
selectedImages={selectedImages}
|
||
/>
|
||
|
||
<ImagePreviewGallery
|
||
images={selectedImages}
|
||
onRemoveImage={handleRemoveImage}
|
||
/>
|
||
|
||
{selectedImages.length > 0 && (
|
||
<>
|
||
<DescriptionInput
|
||
metadata={metadata}
|
||
onMetadataChange={setMetadata}
|
||
/>
|
||
|
||
<div className={classes.actionButtons}>
|
||
<Button
|
||
className={classes.uploadButton}
|
||
onClick={handleUpload}
|
||
disabled={uploading || selectedImages.length === 0}
|
||
size="large"
|
||
>
|
||
🚀 {selectedImages.length} Bild{selectedImages.length !== 1 ? 'er' : ''} hochladen
|
||
</Button>
|
||
|
||
<Button
|
||
className={classes.clearButton}
|
||
onClick={handleClearAll}
|
||
size="large"
|
||
>
|
||
🗑️ Alle entfernen
|
||
</Button>
|
||
</div>
|
||
</>
|
||
)}
|
||
|
||
|
||
</>
|
||
) : (
|
||
<div style={{ textAlign: 'center', padding: '40px 0' }}>
|
||
<Loading />
|
||
<UploadProgress
|
||
progress={uploadProgress}
|
||
totalFiles={selectedImages.length}
|
||
isUploading={uploading}
|
||
/>
|
||
</div>
|
||
)}
|
||
</CardContent>
|
||
</Card>
|
||
</Container>
|
||
|
||
<div className="footerContainer">
|
||
<Footer />
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default MultiUploadPage; |