Initial commit: HOA Financial Intelligence Platform MVP
Multi-tenant financial management platform for homeowner associations featuring: - NestJS backend with 16 modules (auth, accounts, transactions, budgets, units, invoices, payments, vendors, reserves, investments, capital projects, reports) - React + Mantine frontend with dashboard, CRUD pages, and financial reports - Schema-per-tenant PostgreSQL isolation with JWT-based tenant resolution - Docker Compose infrastructure (nginx, backend, frontend, postgres, redis) - Comprehensive seed data for Sunrise Valley HOA demo - 39 API endpoints with Swagger documentation - Double-entry bookkeeping with journal entries - Budget vs actual reporting and Sankey cash flow visualization Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
86
frontend/src/components/layout/Sidebar.tsx
Normal file
86
frontend/src/components/layout/Sidebar.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
import { NavLink, ScrollArea } from '@mantine/core';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
IconDashboard,
|
||||
IconListDetails,
|
||||
IconReceipt,
|
||||
IconHome,
|
||||
IconFileInvoice,
|
||||
IconCash,
|
||||
IconReportAnalytics,
|
||||
IconChartSankey,
|
||||
IconShieldCheck,
|
||||
IconPigMoney,
|
||||
IconBuildingBank,
|
||||
IconCalendarEvent,
|
||||
IconUsers,
|
||||
IconFileText,
|
||||
IconSettings,
|
||||
} from '@tabler/icons-react';
|
||||
|
||||
const navItems = [
|
||||
{ label: 'Dashboard', icon: IconDashboard, path: '/dashboard' },
|
||||
{ label: 'Chart of Accounts', icon: IconListDetails, path: '/accounts' },
|
||||
{ label: 'Transactions', icon: IconReceipt, path: '/transactions' },
|
||||
{ label: 'Units / Homeowners', icon: IconHome, path: '/units' },
|
||||
{ label: 'Invoices', icon: IconFileInvoice, path: '/invoices' },
|
||||
{ label: 'Payments', icon: IconCash, path: '/payments' },
|
||||
{ label: 'Budgets', icon: IconReportAnalytics, path: '/budgets/2026' },
|
||||
{
|
||||
label: 'Reports',
|
||||
icon: IconChartSankey,
|
||||
children: [
|
||||
{ label: 'Balance Sheet', path: '/reports/balance-sheet' },
|
||||
{ label: 'Income Statement', path: '/reports/income-statement' },
|
||||
{ label: 'Cash Flow', path: '/reports/cash-flow' },
|
||||
{ label: 'Budget vs Actual', path: '/reports/budget-vs-actual' },
|
||||
{ label: 'Aging Report', path: '/reports/aging' },
|
||||
{ label: 'Sankey Diagram', path: '/reports/sankey' },
|
||||
],
|
||||
},
|
||||
{ label: 'Reserves', icon: IconShieldCheck, path: '/reserves' },
|
||||
{ label: 'Investments', icon: IconPigMoney, path: '/investments' },
|
||||
{ label: 'Capital Projects', icon: IconBuildingBank, path: '/capital-projects' },
|
||||
{ label: 'Vendors', icon: IconUsers, path: '/vendors' },
|
||||
{ label: 'Year-End', icon: IconFileText, path: '/year-end' },
|
||||
{ label: 'Settings', icon: IconSettings, path: '/settings' },
|
||||
];
|
||||
|
||||
export function Sidebar() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
return (
|
||||
<ScrollArea p="sm">
|
||||
{navItems.map((item) =>
|
||||
item.children ? (
|
||||
<NavLink
|
||||
key={item.label}
|
||||
label={item.label}
|
||||
leftSection={<item.icon size={18} />}
|
||||
defaultOpened={item.children.some((c) =>
|
||||
location.pathname.startsWith(c.path),
|
||||
)}
|
||||
>
|
||||
{item.children.map((child) => (
|
||||
<NavLink
|
||||
key={child.path}
|
||||
label={child.label}
|
||||
active={location.pathname === child.path}
|
||||
onClick={() => navigate(child.path)}
|
||||
/>
|
||||
))}
|
||||
</NavLink>
|
||||
) : (
|
||||
<NavLink
|
||||
key={item.path}
|
||||
label={item.label}
|
||||
leftSection={<item.icon size={18} />}
|
||||
active={location.pathname === item.path}
|
||||
onClick={() => navigate(item.path!)}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</ScrollArea>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user