feat(ui): 🎉 More ui work
Some checks failed
CI / Test (1.23) (push) Failing after -22m35s
CI / Test (1.22) (push) Failing after -22m33s
CI / Build (push) Failing after -23m42s
CI / Lint (push) Failing after -23m17s

* 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:
Hein
2026-02-05 19:41:49 +02:00
parent f9773bd07f
commit 8b1eed6c42
32 changed files with 7293 additions and 38 deletions

View File

@@ -0,0 +1,109 @@
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
import { AppShell, Burger, Group, Text, NavLink, Button, Avatar, Stack, Badge } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import {
IconDashboard,
IconUsers,
IconWebhook,
IconBrandWhatsapp,
IconFileText,
IconLogout
} from '@tabler/icons-react';
import { useAuthStore } from '../stores/authStore';
export default function DashboardLayout() {
const { user, logout } = useAuthStore();
const navigate = useNavigate();
const location = useLocation();
const [opened, { toggle }] = useDisclosure();
const handleLogout = () => {
logout();
navigate('/login');
};
const isActive = (path: string) => {
return location.pathname === path;
};
const navItems = [
{ path: '/dashboard', label: 'Dashboard', icon: IconDashboard },
{ path: '/users', label: 'Users', icon: IconUsers },
{ path: '/hooks', label: 'Hooks', icon: IconWebhook },
{ path: '/accounts', label: 'WhatsApp Accounts', icon: IconBrandWhatsapp },
{ path: '/event-logs', label: 'Event Logs', icon: IconFileText },
];
return (
<AppShell
header={{ height: 60 }}
navbar={{
width: 280,
breakpoint: 'sm',
collapsed: { mobile: !opened },
}}
padding="md"
>
<AppShell.Header>
<Group h="100%" px="md" justify="space-between">
<Group>
<Burger opened={opened} onClick={toggle} hiddenFrom="sm" size="sm" />
<Text size="xl" fw={700}>WhatsHooked</Text>
<Badge color="blue" variant="light">Admin</Badge>
</Group>
<Group>
<Text size="sm" c="dimmed">{user?.username || 'User'}</Text>
<Avatar color="blue" radius="xl" size="sm">
{user?.username?.[0]?.toUpperCase() || 'U'}
</Avatar>
</Group>
</Group>
</AppShell.Header>
<AppShell.Navbar p="md">
<AppShell.Section grow>
<Stack gap="xs">
{navItems.map((item) => (
<NavLink
key={item.path}
href={item.path}
label={item.label}
leftSection={<item.icon size={20} stroke={1.5} />}
active={isActive(item.path)}
onClick={(e) => {
e.preventDefault();
navigate(item.path);
if (opened) toggle();
}}
/>
))}
</Stack>
</AppShell.Section>
<AppShell.Section>
<Stack gap="xs">
<Group justify="space-between" px="sm">
<div>
<Text size="sm" fw={500}>{user?.username || 'User'}</Text>
<Text size="xs" c="dimmed">{user?.role || 'user'}</Text>
</div>
</Group>
<Button
leftSection={<IconLogout size={16} />}
variant="light"
color="red"
fullWidth
onClick={handleLogout}
>
Logout
</Button>
</Stack>
</AppShell.Section>
</AppShell.Navbar>
<AppShell.Main>
<Outlet />
</AppShell.Main>
</AppShell>
);
}