import React, { Component } from 'react'; import { Box, Button, Typography, IconButton, Paper, Grid, Alert } from '@mui/material'; import Delete from '@mui/icons-material/Delete'; import CloudUpload from '@mui/icons-material/CloudUpload'; class PhotoUpload extends Component { constructor(props) { super(props); this.state = { files: [], previews: [], error: null }; this.fileInputRef = React.createRef(); } handleFileSelect = (event) => { const selectedFiles = Array.from(event.target.files); const maxFiles = this.props.maxFiles || 5; const maxSize = this.props.maxSize || 50 * 1024 * 1024; // 50MB default - will be compressed // Validate file count if (this.state.files.length + selectedFiles.length > maxFiles) { this.setState({ error: `Maximal ${maxFiles} Dateien erlaubt` }); return; } // Validate file types and sizes const validTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; const validFiles = []; const newPreviews = []; for (const file of selectedFiles) { if (!validTypes.includes(file.type)) { this.setState({ error: 'Nur Bilddateien (JPEG, PNG, GIF, WebP) sind erlaubt' }); continue; } if (file.size > maxSize) { this.setState({ error: `Datei zu groß. Maximum: ${Math.round(maxSize / (1024 * 1024))}MB` }); continue; } validFiles.push(file); // Create preview and compress image const reader = new FileReader(); reader.onload = (e) => { // Compress the image this.compressImage(e.target.result, file.name, (compressedFile) => { newPreviews.push({ file: compressedFile, preview: e.target.result, name: file.name, originalSize: file.size, compressedSize: compressedFile.size }); if (newPreviews.length === validFiles.length) { const compressedFiles = newPreviews.map(p => p.file); this.setState(prevState => ({ files: [...prevState.files, ...compressedFiles], previews: [...prevState.previews, ...newPreviews], error: null }), () => { // Notify parent component if (this.props.onChange) { this.props.onChange(this.state.files); } }); } }); }; reader.readAsDataURL(file); } // Reset input event.target.value = ''; }; handleRemoveFile = (index) => { this.setState(prevState => { const newFiles = prevState.files.filter((_, i) => i !== index); const newPreviews = prevState.previews.filter((_, i) => i !== index); // Notify parent component if (this.props.onChange) { this.props.onChange(newFiles); } return { files: newFiles, previews: newPreviews }; }); }; compressImage = (dataURL, fileName, callback) => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const img = new Image(); img.onload = () => { // Calculate new dimensions (max 1920x1080 for submission) const maxWidth = 1920; const maxHeight = 1080; let { width, height } = img; if (width > height) { if (width > maxWidth) { height = (height * maxWidth) / width; width = maxWidth; } } else { if (height > maxHeight) { width = (width * maxHeight) / height; height = maxHeight; } } canvas.width = width; canvas.height = height; // Draw and compress ctx.drawImage(img, 0, 0, width, height); // Convert to blob with compression canvas.toBlob((blob) => { const compressedFile = new File([blob], fileName, { type: 'image/jpeg', lastModified: Date.now() }); callback(compressedFile); }, 'image/jpeg', 0.8); // 80% quality }; img.src = dataURL; }; // Method to reset the component reset = () => { this.setState({ files: [], previews: [], error: null }); // Also reset the file input if (this.fileInputRef.current) { this.fileInputRef.current.value = ''; } }; render() { const { files, previews, error } = this.state; const { disabled, label } = this.props; return ( {label || 'Fotos anhängen (optional)'} {error && ( {error} )} {previews.length > 0 && ( {previews.map((preview, index) => ( this.handleRemoveFile(index)} disabled={disabled} aria-label="Bild entfernen" sx={{ position: 'absolute', top: 4, right: 4, backgroundColor: 'rgba(0,0,0,0.7)', color: 'white', '&:hover': { backgroundColor: 'rgba(0,0,0,0.9)' } }} > {preview.name} ))} )} {files.length > 0 && ( {files.length} Datei(en) ausgewählt {previews.length > 0 && previews.some(p => p.originalSize && p.compressedSize) && ( (komprimiert für Upload) )} )} ); } } export default PhotoUpload;