this repo has no description
at content-sections 138 lines 3.8 kB view raw
1import { useState } from 'react'; 2import { Link as RouterLink, Navigate } from 'react-router-dom'; 3import Box from '@mui/material/Box'; 4import Card from '@mui/material/Card'; 5import CardContent from '@mui/material/CardContent'; 6import TextField from '@mui/material/TextField'; 7import Button from '@mui/material/Button'; 8import Typography from '@mui/material/Typography'; 9import Link from '@mui/material/Link'; 10import Alert from '@mui/material/Alert'; 11import CircularProgress from '@mui/material/CircularProgress'; 12import { useAuth } from '../hooks/useAuth'; 13import { Rambi } from '../components/mascot/Rambi'; 14 15export function LoginPage() { 16 const { login, user, loading: authLoading } = useAuth(); 17 const [email, setEmail] = useState(''); 18 const [password, setPassword] = useState(''); 19 const [error, setError] = useState(''); 20 const [loading, setLoading] = useState(false); 21 22 if (authLoading) { 23 return ( 24 <Box 25 sx={{ 26 display: 'flex', 27 justifyContent: 'center', 28 alignItems: 'center', 29 minHeight: '100vh', 30 }} 31 > 32 <CircularProgress color="primary" /> 33 </Box> 34 ); 35 } 36 37 if (user) { 38 return <Navigate to="/home" replace />; 39 } 40 41 async function handleSubmit(e: React.FormEvent) { 42 e.preventDefault(); 43 setError(''); 44 setLoading(true); 45 46 try { 47 await login(email, password); 48 } catch (err) { 49 setError(err instanceof Error ? err.message : 'Login failed'); 50 } finally { 51 setLoading(false); 52 } 53 } 54 55 return ( 56 <Box 57 sx={{ 58 display: 'flex', 59 flexDirection: 'column', 60 alignItems: 'center', 61 justifyContent: 'center', 62 minHeight: '100vh', 63 px: 2, 64 }} 65 > 66 {/* Rambi peeking over the card */} 67 <Box sx={{ mb: -3, zIndex: 1 }}> 68 <Rambi mood="peek" size={100} /> 69 </Box> 70 71 <Card sx={{ width: '100%', maxWidth: 400, position: 'relative' }}> 72 <CardContent sx={{ p: 4 }}> 73 <Typography 74 variant="h4" 75 sx={{ textAlign: 'center', mb: 1, color: '#E8453C' }} 76 > 77 Ayos 78 </Typography> 79 <Typography 80 variant="body2" 81 color="text.secondary" 82 sx={{ textAlign: 'center', mb: 3 }} 83 > 84 Learn Tagalog the fun way 85 </Typography> 86 87 {error && ( 88 <Alert severity="error" sx={{ mb: 2 }}> 89 {error} 90 </Alert> 91 )} 92 93 <Box component="form" onSubmit={handleSubmit}> 94 <TextField 95 fullWidth 96 label="Email" 97 type="email" 98 value={email} 99 onChange={(e) => setEmail(e.target.value)} 100 required 101 sx={{ mb: 2 }} 102 /> 103 <TextField 104 fullWidth 105 label="Password" 106 type="password" 107 value={password} 108 onChange={(e) => setPassword(e.target.value)} 109 required 110 sx={{ mb: 3 }} 111 /> 112 <Button 113 fullWidth 114 type="submit" 115 variant="contained" 116 color="primary" 117 disabled={loading} 118 sx={{ mb: 2 }} 119 > 120 {loading ? <CircularProgress size={24} color="inherit" /> : 'Log In'} 121 </Button> 122 </Box> 123 124 <Typography 125 variant="body2" 126 color="text.secondary" 127 sx={{ textAlign: 'center' }} 128 > 129 Don&apos;t have an account?{' '} 130 <Link component={RouterLink} to="/register" color="secondary"> 131 Sign up 132 </Link> 133 </Typography> 134 </CardContent> 135 </Card> 136 </Box> 137 ); 138}