refactor(frontend): Improve consent and success UX

- Move ConsentCheckboxes below DescriptionInput for better flow
- Replace success dialog with inline success display
- Add copy-to-clipboard button for group ID
- Show detailed next steps and GDPR contact info inline
This commit is contained in:
Matthias Lotz 2025-11-09 21:49:33 +01:00
parent 76aa028686
commit 5bc2b0d222

View File

@ -12,7 +12,6 @@ import DescriptionInput from '../ComponentUtils/MultiUpload/DescriptionInput';
import UploadProgress from '../ComponentUtils/MultiUpload/UploadProgress';
import Loading from '../ComponentUtils/LoadingAnimation/Loading';
import ConsentCheckboxes from '../ComponentUtils/MultiUpload/ConsentCheckboxes';
import UploadSuccessDialog from '../ComponentUtils/MultiUpload/UploadSuccessDialog';
// Utils
import { uploadImageBatch } from '../../Utils/batchUpload';
@ -42,7 +41,6 @@ function MultiUploadPage() {
const [uploadResult, setUploadResult] = useState(null);
const [isEditMode, setIsEditMode] = useState(false);
const [imageDescriptions, setImageDescriptions] = useState({});
const [showSuccessDialog, setShowSuccessDialog] = useState(false);
// Cleanup object URLs when component unmounts
useEffect(() => {
@ -189,11 +187,10 @@ function MultiUploadPage() {
clearInterval(progressInterval);
setUploadProgress(100);
// Show success dialog
// Show success content
setTimeout(() => {
setUploadComplete(true);
setUploadResult(result);
setShowSuccessDialog(true);
}, 500);
} catch (error) {
@ -247,17 +244,17 @@ function MultiUploadPage() {
{selectedImages.length > 0 && (
<>
<DescriptionInput
metadata={metadata}
onMetadataChange={setMetadata}
/>
<ConsentCheckboxes
consents={consents}
onConsentChange={setConsents}
disabled={uploading}
/>
<DescriptionInput
metadata={metadata}
onMetadataChange={setMetadata}
/>
<Box sx={{ display: 'flex', gap: '15px', justifyContent: 'center', mt: '20px', flexWrap: 'wrap' }}>
<Button
sx={{
@ -317,31 +314,172 @@ function MultiUploadPage() {
</>
) : (
<div style={{ textAlign: 'center', padding: '40px 0' }}>
<Loading />
<UploadProgress
progress={uploadProgress}
totalFiles={selectedImages.length}
isUploading={uploading}
/>
{!uploadComplete ? (
<>
<Loading />
<UploadProgress
progress={uploadProgress}
totalFiles={selectedImages.length}
isUploading={uploading}
/>
</>
) : (
<Box sx={{
mt: 4,
p: 4,
borderRadius: '16px',
background: 'linear-gradient(135deg, #4CAF50 0%, #45a049 100%)',
color: 'white',
boxShadow: '0 8px 32px rgba(76, 175, 80, 0.4)',
animation: 'slideIn 0.5s ease-out',
'@keyframes slideIn': {
from: {
opacity: 0,
transform: 'translateY(-20px)'
},
to: {
opacity: 1,
transform: 'translateY(0)'
}
}
}}>
{/* Success Icon & Title */}
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 2, mb: 2 }}>
<Box sx={{
bgcolor: 'white',
borderRadius: '50%',
width: 60,
height: 60,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 4px 12px rgba(0,0,0,0.2)'
}}>
<Typography sx={{ fontSize: '32px' }}></Typography>
</Box>
<Typography sx={{ fontSize: '32px', fontWeight: 'bold' }}>
Upload erfolgreich!
</Typography>
</Box>
{/* Upload Count */}
<Typography sx={{ fontSize: '18px', mb: 3 }}>
<strong>{uploadResult?.imageCount || 0}</strong> {uploadResult?.imageCount === 1 ? 'Bild wurde' : 'Bilder wurden'} erfolgreich hochgeladen
und {uploadResult?.imageCount === 1 ? 'wird' : 'werden'} nach der Prüfung durch das Hobbyhimmel-Team angezeigt.
</Typography>
{/* Group ID Box */}
<Box sx={{
bgcolor: 'rgba(255,255,255,0.2)',
borderRadius: '12px',
p: 3,
mb: 3,
border: '2px solid rgba(255,255,255,0.3)'
}}>
<Typography sx={{ fontSize: '14px', mb: 1, opacity: 0.9 }}>
Ihre Referenz-Nummer:
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 2 }}>
<Typography sx={{
fontSize: '24px',
fontFamily: 'monospace',
fontWeight: 'bold',
letterSpacing: '2px'
}}>
{uploadResult?.groupId}
</Typography>
<Button
sx={{
bgcolor: 'white',
color: '#4CAF50',
minWidth: 'auto',
px: 2,
py: 1,
'&:hover': {
bgcolor: '#f0f0f0'
}
}}
onClick={() => {
navigator.clipboard.writeText(uploadResult?.groupId || '');
}}
>
📋 Kopieren
</Button>
</Box>
<Typography sx={{ fontSize: '12px', mt: 1, opacity: 0.8 }}>
Notieren Sie sich diese Nummer für spätere Anfragen
</Typography>
</Box>
{/* Next Steps */}
<Box sx={{
bgcolor: 'rgba(255,255,255,0.15)',
borderRadius: '8px',
p: 2,
mb: 3,
textAlign: 'left'
}}>
<Typography sx={{ fontSize: '16px', fontWeight: 600, mb: 1.5 }}>
Was passiert jetzt?
</Typography>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
<Box sx={{ display: 'flex', gap: 1 }}>
<Typography sx={{ fontSize: '14px' }}></Typography>
<Typography sx={{ fontSize: '14px' }}>
Ihre Bilder werden vom Team geprüft
</Typography>
</Box>
<Box sx={{ display: 'flex', gap: 1 }}>
<Typography sx={{ fontSize: '14px' }}></Typography>
<Typography sx={{ fontSize: '14px' }}>
Nach Freigabe erscheinen sie auf dem Werkstatt-Monitor
</Typography>
</Box>
<Box sx={{ display: 'flex', gap: 1 }}>
<Typography sx={{ fontSize: '14px' }}></Typography>
<Typography sx={{ fontSize: '14px' }}>
Bei gewählter Social Media Einwilligung werden sie entsprechend veröffentlicht
</Typography>
</Box>
</Box>
</Box>
{/* GDPR Contact */}
<Typography sx={{ fontSize: '12px', opacity: 0.9, mb: 3 }}>
<strong>Fragen oder Widerruf?</strong> Kontaktieren Sie uns mit Ihrer Referenz-Nummer unter: <strong>it@hobbyhimmel.de</strong>
</Typography>
{/* Action Button */}
<Button
sx={{
bgcolor: 'white',
color: '#4CAF50',
fontWeight: 'bold',
fontSize: '16px',
px: 5,
py: 1.5,
borderRadius: '25px',
textTransform: 'none',
boxShadow: '0 4px 12px rgba(0,0,0,0.2)',
'&:hover': {
bgcolor: '#f0f0f0',
transform: 'scale(1.05)',
boxShadow: '0 6px 16px rgba(0,0,0,0.3)'
},
transition: 'all 0.3s ease'
}}
onClick={() => window.location.reload()}
>
👍 Weitere Bilder hochladen
</Button>
</Box>
)}
</div>
)}
</CardContent>
</Card>
</Container>
{/* Success Dialog */}
{showSuccessDialog && uploadResult && (
<UploadSuccessDialog
open={showSuccessDialog}
onClose={() => {
setShowSuccessDialog(false);
window.location.reload();
}}
groupId={uploadResult.groupId}
uploadCount={uploadResult.imageCount}
/>
)}
<div className="footerContainer">
<Footer />
</div>