133 lines
3.6 KiB
TypeScript
133 lines
3.6 KiB
TypeScript
import { useState, type FormEvent } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import {
|
|
Container,
|
|
Paper,
|
|
Title,
|
|
Text,
|
|
TextInput,
|
|
PasswordInput,
|
|
Button,
|
|
Stack,
|
|
Alert,
|
|
Center,
|
|
Box
|
|
} from '@mantine/core';
|
|
import { notifications } from '@mantine/notifications';
|
|
import { IconAlertCircle, IconBrandWhatsapp } from '@tabler/icons-react';
|
|
import { useAuthStore } from '../stores/authStore';
|
|
|
|
export default function LoginPage() {
|
|
const [username, setUsername] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const { login, isLoading, error, clearError } = useAuthStore();
|
|
const navigate = useNavigate();
|
|
|
|
const handleSubmit = async (e: FormEvent) => {
|
|
e.preventDefault();
|
|
clearError();
|
|
|
|
try {
|
|
await login(username, password);
|
|
notifications.show({
|
|
title: 'Login successful',
|
|
message: 'Welcome back!',
|
|
color: 'green',
|
|
});
|
|
navigate('/dashboard');
|
|
} catch (err: any) {
|
|
const responseData = err?.response?.data;
|
|
const notificationMessage =
|
|
responseData?.message ||
|
|
(typeof responseData === 'string' ? responseData.trim() : '') ||
|
|
'Invalid username or password';
|
|
|
|
notifications.show({
|
|
title: 'Login failed',
|
|
message: notificationMessage,
|
|
color: 'red',
|
|
});
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Box
|
|
style={{
|
|
minHeight: '100vh',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
}}
|
|
>
|
|
<Container size={420}>
|
|
<Paper radius="md" p="xl" withBorder>
|
|
<Stack gap="lg">
|
|
<Center>
|
|
<IconBrandWhatsapp size={48} color="#25D366" />
|
|
</Center>
|
|
|
|
<div style={{ textAlign: 'center' }}>
|
|
<Title order={2}>WhatsHooked</Title>
|
|
<Text c="dimmed" size="sm" mt={5}>
|
|
Sign in to your account
|
|
</Text>
|
|
</div>
|
|
|
|
{error && (
|
|
<Alert
|
|
icon={<IconAlertCircle size={16} />}
|
|
title="Authentication Error"
|
|
color="red"
|
|
variant="light"
|
|
>
|
|
{error}
|
|
</Alert>
|
|
)}
|
|
|
|
<form onSubmit={handleSubmit}>
|
|
<Stack gap="md">
|
|
<TextInput
|
|
label="Username"
|
|
placeholder="Enter your username"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
required
|
|
disabled={isLoading}
|
|
size="md"
|
|
/>
|
|
|
|
<PasswordInput
|
|
label="Password"
|
|
placeholder="Enter your password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
required
|
|
disabled={isLoading}
|
|
size="md"
|
|
/>
|
|
|
|
<Button
|
|
type="submit"
|
|
fullWidth
|
|
size="md"
|
|
loading={isLoading}
|
|
mt="md"
|
|
>
|
|
Sign in
|
|
</Button>
|
|
</Stack>
|
|
</form>
|
|
|
|
<Alert variant="light" color="blue">
|
|
<Text size="sm" ta="center">
|
|
Default credentials: <strong>admin</strong> / <strong>admin123</strong>
|
|
</Text>
|
|
</Alert>
|
|
</Stack>
|
|
</Paper>
|
|
</Container>
|
|
</Box>
|
|
);
|
|
}
|