refactor + bilder injection safer

This commit is contained in:
2026-04-13 15:22:47 +02:00
parent 57dd2f5955
commit ccb1e912df
15 changed files with 36 additions and 36 deletions

View File

@@ -0,0 +1,141 @@
import { useState } from 'react';
import { useNavigate, Link as RouterLink } from 'react-router-dom';
import {
Box, Card, CardContent, TextField, Button, Typography,
Alert, CircularProgress, Link, Divider,
} from '@mui/material';
import PersonAddOutlinedIcon from '@mui/icons-material/PersonAddOutlined';
import axiosInstance from '../../api/axiosInstance.js';
export default function RegisterPage() {
const navigate = useNavigate();
const [form, setForm] = useState({ email: '', nickname: '', password: '', confirmPassword: '' });
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const handleChange = (e) => setForm((prev) => ({ ...prev, [e.target.name]: e.target.value }));
const handleSubmit = async (e) => {
e.preventDefault();
setError('');
if (form.password !== form.confirmPassword) {
setError('Passwörter stimmen nicht überein.');
return;
}
setLoading(true);
try {
await axiosInstance.post('/auth/register', {
email: form.email,
nickname: form.nickname,
password: form.password,
});
navigate('/login', { state: { registered: true } });
} catch (err) {
setError(err.response?.data?.message ?? 'Registrierung fehlgeschlagen');
} finally {
setLoading(false);
}
};
return (
<Box
sx={{
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
bgcolor: 'grey.50',
}}
>
<Card sx={{ width: 400, p: 1 }}>
<CardContent>
<Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', mb: 3 }}>
<Box sx={{
width: 48, height: 48, borderRadius: '50%', bgcolor: 'primary.main',
display: 'flex', alignItems: 'center', justifyContent: 'center', mb: 2,
}}>
<PersonAddOutlinedIcon sx={{ color: 'white' }} />
</Box>
<Typography variant="h5" fontWeight={600}>Account erstellen</Typography>
<Typography variant="body2" color="text.secondary" mt={0.5}>
Neuen Admin-Account registrieren
</Typography>
</Box>
{error && <Alert severity="error" sx={{ mb: 2 }}>{error}</Alert>}
<Box component="form" onSubmit={handleSubmit} sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
<TextField
label="E-Mail"
name="email"
type="email"
value={form.email}
onChange={handleChange}
required
autoFocus
fullWidth
/>
<TextField
label="Nickname"
name="nickname"
value={form.nickname}
onChange={handleChange}
required
fullWidth
inputProps={{ minLength: 3, maxLength: 30 }}
helperText="330 Zeichen"
/>
<TextField
label="Passwort"
name="password"
type="password"
value={form.password}
onChange={handleChange}
required
fullWidth
inputProps={{ minLength: 8 }}
helperText="Mindestens 8 Zeichen"
/>
<TextField
label="Passwort bestätigen"
name="confirmPassword"
type="password"
value={form.confirmPassword}
onChange={handleChange}
required
fullWidth
error={form.confirmPassword.length > 0 && form.password !== form.confirmPassword}
helperText={
form.confirmPassword.length > 0 && form.password !== form.confirmPassword
? 'Passwörter stimmen nicht überein'
: ''
}
/>
<Button
type="submit"
variant="contained"
fullWidth
size="large"
disabled={loading}
sx={{ mt: 1 }}
>
{loading ? <CircularProgress size={24} color="inherit" /> : 'Registrieren'}
</Button>
</Box>
<Divider sx={{ my: 2.5 }} />
<Typography variant="body2" color="text.secondary" textAlign="center">
Bereits ein Account?{' '}
<Link component={RouterLink} to="/login" underline="hover">
Zum Login
</Link>
</Typography>
</CardContent>
</Card>
</Box>
);
}