Project-Image-Uploader/frontend/src/Components/Pages/MultiUploadPage.js

284 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;