Files
SAP-PLEX-SYNC/frontend/src/pages/LoginPage.tsx
b0rbor4d 5b447acd1c
Some checks failed
CI/CD Pipeline / Backend Tests (push) Failing after 27s
CI/CD Pipeline / Frontend Tests (push) Failing after 15s
CI/CD Pipeline / Docker Build (push) Has been skipped
CI/CD Pipeline / Security Scan (push) Has been skipped
Initial commit
2026-04-15 01:41:49 +02:00

179 lines
5.2 KiB
TypeScript
Executable File

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Box,
Button,
Container,
TextField,
Typography,
Paper,
Alert,
CircularProgress,
Select,
MenuItem,
FormControl,
} from '@mui/material';
import { useAuth } from '../contexts/AuthContext';
import { useI18n } from '../contexts/I18nContext';
import toast from 'react-hot-toast';
const LoginPage: React.FC = () => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const navigate = useNavigate();
const { login } = useAuth();
const { t, language, changeLanguage } = useI18n();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setLoading(true);
setError('');
try {
await login(username, password);
toast.success(t('login.success'));
navigate('/dashboard', { replace: true });
} catch (err: unknown) {
const message = err instanceof Error ? err.message : t('login.failedHint');
setError(message);
toast.error(t('login.failed'));
} finally {
setLoading(false);
}
};
return (
<Box
sx={{
minHeight: '100vh',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
padding: 2,
}}
>
<Container component="main" maxWidth="xs" disableGutters>
<Paper
elevation={0}
sx={{
padding: 5,
width: '100%',
background: 'rgba(255, 255, 255, 0.95)',
backdropFilter: 'blur(10px)',
borderRadius: 3,
boxShadow: '0 20px 60px rgba(0, 0, 0, 0.3)',
}}
>
<Box textAlign="center" sx={{ mb: 4 }}>
<Box
component="span"
sx={{
width: 64,
height: 64,
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
mb: 2,
}}
>
<span style={{ fontSize: 32, color: 'white' }}>🔄</span>
</Box>
<Typography component="h1" variant="h4" gutterBottom sx={{ fontWeight: 700 }}>
{t('app.title')}
</Typography>
<Typography variant="body2" color="textSecondary">
{t('login.subtitle')}
</Typography>
<FormControl sx={{ mt: 2, minWidth: 120 }}>
<Select
value={language}
onChange={(e) => changeLanguage(e.target.value)}
variant="standard"
size="small"
>
<MenuItem value="de">DE</MenuItem>
<MenuItem value="en">EN</MenuItem>
<MenuItem value="fr">FR</MenuItem>
<MenuItem value="es">ES</MenuItem>
</Select>
</FormControl>
</Box>
{error && (
<Alert severity="error" sx={{ mt: 2, mb: 2 }}>
{error}
</Alert>
)}
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="username"
label={t('login.username')}
name="username"
autoComplete="username"
autoFocus
value={username}
onChange={(e) => setUsername(e.target.value)}
disabled={loading}
sx={{
'& .MuiOutlinedInput-root': {
borderRadius: 2,
},
}}
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label={t('login.password')}
type="password"
id="password"
autoComplete="current-password"
value={password}
onChange={(e) => setPassword(e.target.value)}
disabled={loading}
sx={{
'& .MuiOutlinedInput-root': {
borderRadius: 2,
},
}}
/>
<Button
type="submit"
fullWidth
variant="contained"
size="large"
sx={{
mt: 3,
mb: 2,
py: 1.5,
borderRadius: 2,
textTransform: 'none',
fontSize: '1rem',
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
'&:hover': {
background: 'linear-gradient(135deg, #5568d3 0%, #63408a 100%)',
},
}}
disabled={loading}
>
{loading ? <CircularProgress size={24} sx={{ color: 'white' }} /> : t('login.submit')}
</Button>
</Box>
</Paper>
</Container>
</Box>
);
};
export default LoginPage;