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:
104
frontend/src/App.tsx
Normal file
104
frontend/src/App.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { useAuthStore } from './stores/authStore';
|
||||
import { AppLayout } from './components/layout/AppLayout';
|
||||
import { LoginPage } from './pages/auth/LoginPage';
|
||||
import { RegisterPage } from './pages/auth/RegisterPage';
|
||||
import { SelectOrgPage } from './pages/auth/SelectOrgPage';
|
||||
import { DashboardPage } from './pages/dashboard/DashboardPage';
|
||||
import { AccountsPage } from './pages/accounts/AccountsPage';
|
||||
import { TransactionsPage } from './pages/transactions/TransactionsPage';
|
||||
import { BudgetsPage } from './pages/budgets/BudgetsPage';
|
||||
import { UnitsPage } from './pages/units/UnitsPage';
|
||||
import { InvoicesPage } from './pages/invoices/InvoicesPage';
|
||||
import { PaymentsPage } from './pages/payments/PaymentsPage';
|
||||
import { VendorsPage } from './pages/vendors/VendorsPage';
|
||||
import { ReservesPage } from './pages/reserves/ReservesPage';
|
||||
import { InvestmentsPage } from './pages/investments/InvestmentsPage';
|
||||
import { CapitalProjectsPage } from './pages/capital-projects/CapitalProjectsPage';
|
||||
import { BalanceSheetPage } from './pages/reports/BalanceSheetPage';
|
||||
import { IncomeStatementPage } from './pages/reports/IncomeStatementPage';
|
||||
import { BudgetVsActualPage } from './pages/reports/BudgetVsActualPage';
|
||||
import { SankeyPage } from './pages/reports/SankeyPage';
|
||||
import { PlaceholderPage } from './pages/PlaceholderPage';
|
||||
|
||||
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
||||
const token = useAuthStore((s) => s.token);
|
||||
if (!token) return <Navigate to="/login" replace />;
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
function OrgRequiredRoute({ children }: { children: React.ReactNode }) {
|
||||
const token = useAuthStore((s) => s.token);
|
||||
const currentOrg = useAuthStore((s) => s.currentOrg);
|
||||
if (!token) return <Navigate to="/login" replace />;
|
||||
if (!currentOrg) return <Navigate to="/select-org" replace />;
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
function AuthRoute({ children }: { children: React.ReactNode }) {
|
||||
const token = useAuthStore((s) => s.token);
|
||||
const currentOrg = useAuthStore((s) => s.currentOrg);
|
||||
if (token && currentOrg) return <Navigate to="/" replace />;
|
||||
if (token && !currentOrg) return <Navigate to="/select-org" replace />;
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
path="/login"
|
||||
element={
|
||||
<AuthRoute>
|
||||
<LoginPage />
|
||||
</AuthRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/register"
|
||||
element={
|
||||
<AuthRoute>
|
||||
<RegisterPage />
|
||||
</AuthRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/select-org"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<SelectOrgPage />
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/*"
|
||||
element={
|
||||
<OrgRequiredRoute>
|
||||
<AppLayout />
|
||||
</OrgRequiredRoute>
|
||||
}
|
||||
>
|
||||
<Route index element={<Navigate to="/dashboard" replace />} />
|
||||
<Route path="dashboard" element={<DashboardPage />} />
|
||||
<Route path="accounts" element={<AccountsPage />} />
|
||||
<Route path="transactions" element={<TransactionsPage />} />
|
||||
<Route path="budgets/:year" element={<BudgetsPage />} />
|
||||
<Route path="units" element={<UnitsPage />} />
|
||||
<Route path="invoices" element={<InvoicesPage />} />
|
||||
<Route path="payments" element={<PaymentsPage />} />
|
||||
<Route path="vendors" element={<VendorsPage />} />
|
||||
<Route path="reserves" element={<ReservesPage />} />
|
||||
<Route path="investments" element={<InvestmentsPage />} />
|
||||
<Route path="capital-projects" element={<CapitalProjectsPage />} />
|
||||
<Route path="reports/balance-sheet" element={<BalanceSheetPage />} />
|
||||
<Route path="reports/income-statement" element={<IncomeStatementPage />} />
|
||||
<Route path="reports/budget-vs-actual" element={<BudgetVsActualPage />} />
|
||||
<Route path="reports/cash-flow" element={<PlaceholderPage title="Cash Flow Statement" />} />
|
||||
<Route path="reports/aging" element={<PlaceholderPage title="Aging Report" />} />
|
||||
<Route path="reports/sankey" element={<SankeyPage />} />
|
||||
<Route path="year-end" element={<PlaceholderPage title="Year-End Package" />} />
|
||||
<Route path="settings" element={<PlaceholderPage title="Settings" />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user