feat(ui): 🎉 More ui work
* Implement EventLogsPage for viewing system activity logs with search and filter capabilities. * Create HooksPage for managing webhook configurations with create, edit, and delete functionalities. * Develop LoginPage for user authentication with error handling and loading states. * Add UsersPage for managing system users, including role assignment and status toggling. * Introduce authStore for managing user authentication state and actions. * Define TypeScript types for User, Hook, EventLog, and other entities. * Set up TypeScript configuration for the project. * Configure Vite for development with proxy settings for API calls. * Update dependencies for improved functionality and security.
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
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 { 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);
|
||||
navigate('/');
|
||||
} catch (err) {
|
||||
// Error is handled in the store
|
||||
console.error('Login failed:', err);
|
||||
}
|
||||
};
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user