- Rename app from "HOA Financial Platform" to "HOA LedgerIQ" across all frontend pages, backend API docs, package.json files, and seed data - Add Cash Flow Statement report (GET /reports/cash-flow) with operating and reserve fund activity breakdown, beginning/ending cash balances - Add Aging Report (GET /reports/aging) with per-unit aging buckets (current, 1-30, 31-60, 61-90, 90+ days), expandable invoice details - Add Year-End Package (GET /reports/year-end) with income statement summary, collection stats, 1099-NEC vendor report, reserve fund status - Add Settings page showing org info, user profile, and system details - Replace all PlaceholderPage references with real implementations - Bump auth store version to 3 for localStorage migration Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
82 lines
2.5 KiB
TypeScript
82 lines
2.5 KiB
TypeScript
import { useState } from 'react';
|
|
import { AppShell, Burger, Group, Title, Text, Menu, UnstyledButton, Avatar } from '@mantine/core';
|
|
import { useDisclosure } from '@mantine/hooks';
|
|
import {
|
|
IconLogout,
|
|
IconSwitchHorizontal,
|
|
IconChevronDown,
|
|
} from '@tabler/icons-react';
|
|
import { Outlet, useNavigate } from 'react-router-dom';
|
|
import { useAuthStore } from '../../stores/authStore';
|
|
import { Sidebar } from './Sidebar';
|
|
|
|
export function AppLayout() {
|
|
const [opened, { toggle }] = useDisclosure();
|
|
const { user, currentOrg, logout } = useAuthStore();
|
|
const navigate = useNavigate();
|
|
|
|
const handleLogout = () => {
|
|
logout();
|
|
navigate('/login');
|
|
};
|
|
|
|
return (
|
|
<AppShell
|
|
header={{ height: 60 }}
|
|
navbar={{ width: 260, 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" />
|
|
<Title order={3} c="blue">HOA LedgerIQ</Title>
|
|
</Group>
|
|
<Group>
|
|
{currentOrg && (
|
|
<Text size="sm" c="dimmed">{currentOrg.name}</Text>
|
|
)}
|
|
<Menu shadow="md" width={200}>
|
|
<Menu.Target>
|
|
<UnstyledButton>
|
|
<Group gap="xs">
|
|
<Avatar size="sm" radius="xl" color="blue">
|
|
{user?.firstName?.[0]}{user?.lastName?.[0]}
|
|
</Avatar>
|
|
<Text size="sm">{user?.firstName} {user?.lastName}</Text>
|
|
<IconChevronDown size={14} />
|
|
</Group>
|
|
</UnstyledButton>
|
|
</Menu.Target>
|
|
<Menu.Dropdown>
|
|
<Menu.Item
|
|
leftSection={<IconSwitchHorizontal size={14} />}
|
|
onClick={() => navigate('/select-org')}
|
|
>
|
|
Switch Organization
|
|
</Menu.Item>
|
|
<Menu.Divider />
|
|
<Menu.Item
|
|
color="red"
|
|
leftSection={<IconLogout size={14} />}
|
|
onClick={handleLogout}
|
|
>
|
|
Logout
|
|
</Menu.Item>
|
|
</Menu.Dropdown>
|
|
</Menu>
|
|
</Group>
|
|
</Group>
|
|
</AppShell.Header>
|
|
|
|
<AppShell.Navbar>
|
|
<Sidebar />
|
|
</AppShell.Navbar>
|
|
|
|
<AppShell.Main>
|
|
<Outlet />
|
|
</AppShell.Main>
|
|
</AppShell>
|
|
);
|
|
}
|