From 0984e79223b77655d37279ccf01eea1adc114998 Mon Sep 17 00:00:00 2001 From: Martin Bhuong Date: Tue, 19 May 2026 06:23:00 +0300 Subject: [PATCH 1/2] test(api): update test setup and fix test issues add execution of 0002_soft_flamingo.sql migration to test DB setup update COA integration test assertions for initial account fields and system account checks fix business reset test: correct category creation order, truncate M-PESA txn IDs, adjust delete order for FK safety, update preserved table checks, convert snapshot counts to numbers add explanatory comments in test files --- .../accounts-coa-integration.test.ts | 19 ++++++++- api/__tests__/business-reset.test.ts | 42 +++++++++---------- api/test/setup.ts | 15 +++++++ 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/api/__tests__/accounts-coa-integration.test.ts b/api/__tests__/accounts-coa-integration.test.ts index 742e2aa..5ba1564 100644 --- a/api/__tests__/accounts-coa-integration.test.ts +++ b/api/__tests__/accounts-coa-integration.test.ts @@ -1,7 +1,7 @@ // ABOUTME: Verifies operational account creation stays simple while enforcing valid chart-account behavior. // ABOUTME: Protects location-scoped payment method links from crossing business and branch boundaries. import { afterEach, describe, expect, it } from "vitest"; -import { and, eq, inArray } from "drizzle-orm"; +import { and, eq, inArray, isNull } from "drizzle-orm"; import { appRouter } from "../router"; import { @@ -162,8 +162,25 @@ describe("operational accounts and payment-method linking", () => { locationId: ctx.location.id, businessId: ctx.business.id, type: "cash", + }); + + expect(account.accountType).toBeNull(); + expect(account.accountSubType).toBeNull(); + + const sysAccounts = await db + .select() + .from(accounts) + .where(and( + eq(accounts.businessId, ctx.business.id), + eq(accounts.systemKey, "asset:cash"), + isNull(accounts.deletedAt), + )).limit(1); + + expect(sysAccounts.length).toBeGreaterThan(0); + expect(sysAccounts[0]).toMatchObject({ accountType: "asset", accountSubType: "cash", + isSystemGenerated: true, }); }); diff --git a/api/__tests__/business-reset.test.ts b/api/__tests__/business-reset.test.ts index a78d775..64a50d3 100644 --- a/api/__tests__/business-reset.test.ts +++ b/api/__tests__/business-reset.test.ts @@ -105,16 +105,6 @@ async function seedResetContext(seed: string): Promise { nextExpenseNumber: 27, } as any).returning()); - // Create expense category - const category = await firstRow(db.insert(expenseCategories).values({ - businessId: business.id, - locationId: location.id, - name: `Test Category ${seed}`, - color: "#C73E1D", - defaultAccountId: 0, - isActive: true, - } as any).returning()); - // Create operational (user) account const opAccount = await firstRow(db.insert(accounts).values({ businessId: business.id, @@ -141,10 +131,15 @@ async function seedResetContext(seed: string): Promise { isActive: true, } as any).returning()); - // Fix category defaultAccountId - await db.update(expenseCategories) - .set({ defaultAccountId: sysAccount.id }) - .where(eq(expenseCategories.id, category.id)); + // Create expense category (accounts must exist first due to FK constraint) + const category = await firstRow(db.insert(expenseCategories).values({ + businessId: business.id, + locationId: location.id, + name: `Test Category ${seed}`, + color: "#C73E1D", + defaultAccountId: sysAccount.id, + isActive: true, + } as any).returning()); // Create supplier const supplier = await firstRow(db.insert(suppliers).values({ @@ -255,10 +250,10 @@ async function seedResetContext(seed: string): Promise { totalPrice: "1000.00", } as any); - // Create M-PESA transaction + // Create M-PESA transaction (txnId limited to varchar(20)) await db.insert(mpesaTransactions).values({ locationId: location.id, - txnId: `MPESA-${seed}`, + txnId: `MPESA-${seed}`.slice(0, 20), txnDate: "2026-05-16", txnType: "topup", amount: "500.00", @@ -414,8 +409,9 @@ async function cleanupResetContext(accountId: string) { await db.delete(journalEntries).where(eq(journalEntries.businessId, business.id)); await db.delete(expenses).where(eq(expenses.businessId, business.id)); await db.delete(bills).where(eq(bills.businessId, business.id)); - await db.delete(accounts).where(eq(accounts.businessId, business.id)); + // Delete expense_categories FIRST (FK references accounts.id via defaultAccountId) await db.delete(expenseCategories).where(eq(expenseCategories.businessId, business.id)); + await db.delete(accounts).where(eq(accounts.businessId, business.id)); await db.delete(suppliers).where(eq(suppliers.businessId, business.id)); await db.delete(employees).where(sql`${employees.id} > 0`); await db.delete(locations).where(eq(locations.businessId, business.id)); @@ -455,7 +451,7 @@ describe("resetBusinessTransactions", () => { expect(result.success).toBe(true); expect(result.preserved).toContain("audit_log"); - expect(result.preserved).toContain("accounts (system)"); + expect(result.preserved).toContain("accounts (all)"); expect(result.resetAt).toBeTruthy(); // Verify system account preserved and balance reset @@ -641,11 +637,11 @@ describe("resetBusinessTransactions", () => { expect(snapshot.businessId).toBe(ctx.business.id); expect(snapshot.timestamp).toBeTruthy(); - expect(snapshot.tableCounts.dailySales).toBeGreaterThan(0); - expect(snapshot.tableCounts.expenses).toBeGreaterThan(0); - expect(snapshot.tableCounts.bills).toBeGreaterThan(0); - expect(snapshot.tableCounts.mpesaTransactions).toBeGreaterThan(0); - expect(snapshot.tableCounts.journalEntries).toBeGreaterThan(0); + expect(Number(snapshot.tableCounts.dailySales)).toBeGreaterThan(0); + expect(Number(snapshot.tableCounts.expenses)).toBeGreaterThan(0); + expect(Number(snapshot.tableCounts.bills)).toBeGreaterThan(0); + expect(Number(snapshot.tableCounts.mpesaTransactions)).toBeGreaterThan(0); + expect(Number(snapshot.tableCounts.journalEntries)).toBeGreaterThan(0); }); // ── Test 5: Return results structure ───────────────────────────────────── diff --git a/api/test/setup.ts b/api/test/setup.ts index 7349e79..6e88e60 100644 --- a/api/test/setup.ts +++ b/api/test/setup.ts @@ -101,6 +101,21 @@ async function ensureTestDatabase(): Promise { // continue with the next statement for idempotent setup. } } + + const migration2Path = path.resolve( + import.meta.dirname, + "../../db/migrations/0002_soft_flamingo.sql", + ); + let migration2Sql = fs.readFileSync(migration2Path, "utf8").replaceAll("--> statement-breakpoint", ""); + const migration2Statements = migration2Sql.split(";").filter((s) => s.trim()); + for (const stmt of migration2Statements) { + try { + await testPool.query(stmt); + } catch { + // Individual DDL statements may already exist; + // continue with the next statement for idempotent setup. + } + } } finally { await testPool.end(); } From 0fde5d6ea78715af6faff891dc8d4ba5eb8d3ada Mon Sep 17 00:00:00 2001 From: Martin Bhuong Date: Tue, 19 May 2026 07:22:08 +0300 Subject: [PATCH 2/2] feat(layout): add mobile nav & collapsible sidebar add mobile bottom navigation bar and hamburger menu for small screen views implement collapsible desktop sidebar with state saved to localStorage update desktop sidebar to include notifications, business selector and user info sections update main content layout to dynamically adjust for sidebar width changes remove unused Dashboard PNG asset and legacy Lucide icon imports clean up legacy mobile menu code in the Layout component --- resources/1-Dashboard-uai-258x470.png | Bin 46212 -> 0 bytes src/components/Layout.tsx | 366 ++++++++++++++++---------- src/components/MobileNavigation.tsx | 156 +++++++++++ 3 files changed, 382 insertions(+), 140 deletions(-) delete mode 100644 resources/1-Dashboard-uai-258x470.png create mode 100644 src/components/MobileNavigation.tsx diff --git a/resources/1-Dashboard-uai-258x470.png b/resources/1-Dashboard-uai-258x470.png deleted file mode 100644 index 63bf1509aca52b5dfedea2a34369eda06cb314f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 46212 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 { + const saved = localStorage.getItem("finaflow_sidebar_collapsed"); + return saved === "true"; + }); const role = user?.role ?? "viewer"; + const toggleSidebar = () => { + setSidebarCollapsed((prev) => { + const next = !prev; + localStorage.setItem("finaflow_sidebar_collapsed", String(next)); + return next; + }); + }; + const { data: alertList } = trpc.alerts.checkAll.useQuery(undefined, { refetchInterval: 60000 }); const { data: notifCount } = trpc.notifications.unreadCount.useQuery(undefined, { refetchInterval: 30000 }); const { data: notifList } = trpc.notifications.list.useQuery({ limit: 20, unreadOnly: false }); @@ -46,7 +60,6 @@ export function Layout({ children }: { children: React.ReactNode }) { const markNotifRead = trpc.notifications.markRead.useMutation({ onSuccess: () => utils.notifications.invalidate() }); const genOverdueNotifs = trpc.notifications.generateOverdueNotifications.useMutation({ onSuccess: () => utils.notifications.invalidate() }); - // Auto-generate overdue bill notifications on first load useEffect(() => { const timer = setTimeout(() => { genOverdueNotifs.mutate(); }, 3000); return () => clearTimeout(timer); @@ -61,164 +74,224 @@ export function Layout({ children }: { children: React.ReactNode }) { const navItems = allNavItems.filter((item) => hasAnyPermission(role, item.perms)); const isActive = useCallback((path: string) => location.pathname === path, [location.pathname]); + const pinnedSection = ( +
+
+ + {alertOpen && ( +
+
+ +
+ {notifList && notifList.length > 0 && ( +
+ {notifList.slice(0, 10).map(n => ( +
!n.isRead && markNotifRead.mutate({ id: n.id })} className={`cursor-pointer border-b border-[#E8E0D8] px-3 py-2 text-xs ${n.severity === "critical" ? "bg-[#D32F2F]/5 text-[#D32F2F]" : n.severity === "warning" ? "bg-[#ED6C02]/5 text-[#EDA102]" : "text-[#2D2A26]"} ${!n.isRead ? "font-medium" : "opacity-60"}`}> +

{!n.isRead && "● "}{n.title}

+

{n.message}

+
+ ))} +
+ )} + {alertList?.map((alert, i) => ( +
+

{alert.title}

+

{alert.message}

+
+ ))} + {(!notifList || notifList.length === 0) && (!alertList || alertList.length === 0) && ( +

No notifications

+ )} +
+ )} +
+ + {businesses && businesses.length > 1 && ( +
+ + {bizOpen && ( +
+ {businesses.map(b => ( + + ))} +
+ )} +
+ )} + +
+
+ +
+ {!sidebarCollapsed && ( +
+

{user?.name ?? "User"}

+

{role}

+
+ )} +
+ + +
+ ); + return (
- -
-
-
- Finaflow -
- -
- {sidebarOpen && ( -
-
setSidebarOpen(false)} /> -
-
- Menu - -
-
-
+ )} -
-
{children}
+ + {/* Main Content */} +
+
+ {children} +
); -} +} \ No newline at end of file diff --git a/src/components/MobileNavigation.tsx b/src/components/MobileNavigation.tsx new file mode 100644 index 0000000..d2c1f6b --- /dev/null +++ b/src/components/MobileNavigation.tsx @@ -0,0 +1,156 @@ +import { Link, useLocation } from "react-router"; +import { + LayoutDashboard, + Receipt, + TrendingDown, + FileText, + FileSpreadsheet, + CreditCard, + CalendarDays, + Users, + Settings, + Handshake, + Briefcase, + Building, + Building2, + Smartphone, + ShieldCheck, + Bell, + LogOut, + Menu, + X, + ChevronRight, +} from "lucide-react"; +import { useState } from "react"; + +// Primary navigation items - always visible at bottom +export const mobileBottomNavItems = [ + { path: "/dashboard", label: "Dashboard", icon: () => }, + { path: "/daily-sales", label: "Sales", icon: () => }, + { path: "/expenses", label: "Expenses", icon: () => }, + { path: "/bills", label: "Bills", icon: () => }, + { path: "/reports", label: "Reports", icon: () => }, +]; + +// Secondary navigation items - shown in hamburger menu +export const mobileSecondaryNavItems = [ + { path: "/suppliers", label: "Suppliers", icon: Building }, + { path: "/bills", label: "Bills", icon: FileText }, + { path: "/accounts", label: "Accounts", icon: CreditCard }, + { path: "/locations", label: "Branches", icon: Building2 }, + { path: "/payroll", label: "Payroll", icon: Users }, + { path: "/mpesa", label: "M-PESA", icon: Smartphone }, + { path: "/calendar", label: "Calendar", icon: CalendarDays }, + { path: "/reports", label: "Reports", icon: FileSpreadsheet }, + { path: "/users", label: "Users & Roles", icon: ShieldCheck }, + { path: "/settings", label: "Settings", icon: Settings }, + { path: "/businesses", label: "Businesses", icon: Briefcase }, + { path: "/partner", label: "Partner", icon: Handshake }, +]; + +type MobileNavItem = { + path: string; + label: string; + icon: any; +}; + +export function MobileBottomNavigation() { + const location = useLocation(); + + return ( + + ); +} + +export function MobileHamburgerMenu({ + onClose, +}: { + onClose: () => void; +}) { + const location = useLocation(); + + return ( + <> + {/* Backdrop */} +
+ + {/* Menu Panel */} +
+
+ + Menu + + +
+ + + +
+ {/* Business selector */} +
+ + + Business + +
+
+
+ + ); +}