From 857abfd9a269db13f30f5f6ae35dc680e24cac71 Mon Sep 17 00:00:00 2001 From: Prabhat Ranjan Date: Sat, 25 Apr 2026 17:19:36 +1000 Subject: [PATCH] feat: add demo data and bank modal for sponsor demo - Add bank account modal with BSB/account form (3-step flow) - Add CFO chat mock Q&A (5 preset questions with business answers) - Seed CFO API with realistic dummy data - Add PDF export to reports page - Add business sponsor slide deck (.doc/demo-slide-deck.md) - Add @headlessui/react for modal component --- .doc/demo-slide-deck.md | 131 ++++++++++++++++ apps/web/app/bank-feeds/page.tsx | 6 +- apps/web/app/cfo/page.tsx | 27 ++-- apps/web/app/reports/page.tsx | 31 +++- apps/web/components/AddBankModal.tsx | 215 +++++++++++++++++++++++++++ apps/web/components/CfoChat.tsx | 18 +++ apps/web/package.json | 1 + 7 files changed, 418 insertions(+), 11 deletions(-) create mode 100644 .doc/demo-slide-deck.md create mode 100644 apps/web/components/AddBankModal.tsx diff --git a/.doc/demo-slide-deck.md b/.doc/demo-slide-deck.md new file mode 100644 index 0000000..7fc9612 --- /dev/null +++ b/.doc/demo-slide-deck.md @@ -0,0 +1,131 @@ +# Smart GL - Demo Overview for Business Sponsor + +## 1. Welcome to Your New Financial Command Centre + +**What you're looking at:** Your complete financial picture - all in one place. + +- Dashboard shows money in, money out, and profit at a glance +- No more switching between bank apps and spreadsheets +- Everything update automatically from your connected bank +- Safe and secure - Australian financial data standards + +--- + +## 2. See Every Transaction - Automatically + +**What you're looking at:** Every payment as it happens. + +- Bank feeds connect directly to 135+ Australian banks +- Transactions appear within minutes of hitting your account +- Smart categorisation sorts payments automatically (wages, materials, etc.) +- Easy search - find any transaction in seconds +- Demo shows sample data from "Coastal Trades" business + +--- + +## 3. Chat with Your CFO - Ask Anything + +**What you're looking at:** Your AI financial assistant. + +- Ask "How did we do this month?" → instant answer +- Ask "What's our cash runway?" → clear response +- Ask "Show me anomalies" → highlights problems to review +- No accounting training needed - plain English only +- Works like having a financial expert on call 24/7 + +--- + +## 4. Spot Problems Before They Grow + +**What you're looking at:** Alerts for unusual activity. + +- Duplicate payments - catches when the same bill gets paid twice +- Unusual vendor payments - flags first-time suppliers +- Missing receipts - reminds you when documentation is needed +- All issues ranked by how urgent they are (high/medium/low) +- Click to dismiss or mark as resolved + +--- + +## 5. Cash Flow Forecast - Never Run Dry + +**What you're looking at:** Your money future. + +- See cash position today and weeks ahead +- Warning flags when BAS or tax payments are coming +- Runway calculation - how many months until you need more cash +- Plan ahead with confidence +- Demo data shows realistic example + +--- + +## 6. Monthly Briefing - Done For You + +**What you're looking at:** Month-end summary, instant. + +- Revenue, expenses, profit - all calculated +- What changed vs last month (up/down percentages) +- Positive wins to celebrate +- Items needing your attention +- Ready to send to your accountant or advisor + +--- + +## 7. Connect Your Bank in Minutes + +**What you're looking at:** Adding a new bank account. + +- Click "Add Bank Account" button +- Select from 135+ Australian banks +- Enter account details (BSB + account number) +- Done - starts syncing immediately +- Demo shows how the form works + +--- + +## 8. Export Reports for Your Advisor + +**What you're looking at:** One-click report export. + +- Profit & Loss (P&L) - what you made or lost +- Balance Sheet - what you own vs owe +- GST/BAS - tax ready figures +- Trial Balance - account-level detail +- Click "Export PDF" → clean professional document + +--- + +## 9. Industry Comparison - How Do You Stack Up? + +**What you're looking at:** Your performance vs similar businesses. + +- See where you are vs industry benchmarks +- Gross margin percentile - are you above or below average? +- Net profit comparison +- Operating cost comparison +- Demo compares to "Professional Services" industry + +--- + +## 10. Key Takeaways for You + +1. **Save time** - automatic transaction import +2. **See more** - complete financial picture +3. **Get alerts** - problems caught early +4. **Plan ahead** - cash flow forecast +5. **Share easily** - export PDF reports + +**Ready to try?** Visit the demo at smart-GL and click around. + +--- + +## Demo Login Quick Guide + +| Feature | Where | What to Click | +|---------|-------|------------| +| See transactions | Transactions | Sort by category | +| CFO chat | CFO Dashboard | Ask a question | +| Cash flow | CFO Dashboard | Look at forecast card | +| Add bank | Bank Feeds | Add Bank Account | +| Export report | Reports | Export PDF | +| View anomalies | CFO Dashboard | Anomalies card | \ No newline at end of file diff --git a/apps/web/app/bank-feeds/page.tsx b/apps/web/app/bank-feeds/page.tsx index 63ed7f3..ce9d6e6 100644 --- a/apps/web/app/bank-feeds/page.tsx +++ b/apps/web/app/bank-feeds/page.tsx @@ -4,6 +4,7 @@ import { RefreshCw, Plus, CheckCircle2, AlertCircle, Clock } from "lucide-react" import { Button } from "@/components/ui/button"; import { useToast } from "@/hooks/use-toast"; import { DemoAccountsPanel } from "@/components/DemoAccountsPanel"; +import { AddBankModal } from "@/components/AddBankModal"; const CONNECTIONS = [ { id: "c1", bank: "ANZ", name: "Business Everyday", number: "****4521", balance: "$82,345.20", lastSync: "Today 09:14", status: "active", txnCount: 143 }, @@ -13,6 +14,7 @@ const CONNECTIONS = [ export default function BankFeedsPage() { const [syncing, setSyncing] = useState(false); const [demoAccounts, setDemoAccounts] = useState([]); + const [showAddModal, setShowAddModal] = useState(false); const { toast } = useToast(); interface DemoAccount { @@ -63,7 +65,7 @@ export default function BankFeedsPage() { Sync All - @@ -142,6 +144,8 @@ export default function BankFeedsPage() {

Transactions are fetched 30 days back on each sync to capture delayed postings. Deduplication is guaranteed by Basiq transaction ID.

+ + setShowAddModal(false)} /> ); } diff --git a/apps/web/app/cfo/page.tsx b/apps/web/app/cfo/page.tsx index 4ebdf1d..dc10171 100644 --- a/apps/web/app/cfo/page.tsx +++ b/apps/web/app/cfo/page.tsx @@ -40,13 +40,16 @@ export default function CfoDashboardPage() { useEffect(() => { Promise.all([ - fetch("/api/cfo/anomalies").then(r => r.json()).catch(() => []), - fetch("/api/cfo/briefing").then(r => r.json()).catch(() => []), + fetch("/api/cfo/anomalies").then(r => r.json()).then(d => d.anomalies || []).catch(() => []), + fetch("/api/cfo/briefing").then(r => r.json()).then(d => Array.isArray(d) ? d : [d]).catch(() => []), fetch("/api/cfo/cash-flow").then(r => r.json()).catch(() => ({})), ]).then(([a, b, c]) => { - setAnomalies(a.anomalies || a || []); - setBriefings(b.briefings || b || []); - setCashFlow(c.forecast || c || []); + setAnomalies(a || []); + setBriefings(b || []); + const cf = c?.current ? [ + { period: c.current.month_year, inflow: c.current.inflows_cents/100, outflow: c.current.outflows_cents/100, net: (c.current.closing_cents - c.current.opening_cents)/100 } + ] : []; + setCashFlow(cf); }).catch(console.error) .finally(() => setLoading(false)); }, []); @@ -117,14 +120,20 @@ export default function CfoDashboardPage() {
Loading...
) : anomalies.length > 0 ? (
- {anomalies.slice(0, 5).map((a) => ( + {anomalies.slice(0, 5).map((a: any) => (
-
{a.type}
+
{a.title}
{a.description}
-
- ${a.amount.toLocaleString()} +
+ + {a.severity} +
))} diff --git a/apps/web/app/reports/page.tsx b/apps/web/app/reports/page.tsx index 64a2061..6046bc2 100644 --- a/apps/web/app/reports/page.tsx +++ b/apps/web/app/reports/page.tsx @@ -62,6 +62,35 @@ export default function ReportsPage() { const totalExpenses = PL_DATA.expenses.reduce((s, r) => s + r.amount, 0); const netProfit = grossProfit - totalExpenses; + const handleExportPDF = () => { + const content = document.getElementById("report-content"); + if (!content) return; + const printWindow = window.open("", "_blank"); + if (!printWindow) return; + printWindow.document.write(` + + + Coastal Trades - Financial Report + + + ${content.innerHTML} + + `); + printWindow.document.close(); + printWindow.print(); + }; + return (
@@ -69,7 +98,7 @@ export default function ReportsPage() {

Reports

Coastal Trades Pty Ltd · FY 2024–25

- +
+ + {step === "select" && ( +
+
+ + +
+ +
+ )} + + {step === "details" && ( +
+
+ + Connected to: {AUSTRALIAN_BANKS.find((b) => b.code === selectedBank)?.name} +
+ +
+ + setForm({ ...form, accountName: e.target.value })} + placeholder="e.g., Business Savings" + className="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" + /> + {errors.accountName && ( +

{errors.accountName}

+ )} +
+ +
+ + setForm({ ...form, bsb: e.target.value })} + placeholder="e.g., 012-345" + maxLength={7} + className="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" + /> + {errors.bsb && ( +

{errors.bsb}

+ )} +
+ +
+ + setForm({ ...form, accountNumber: e.target.value })} + placeholder="e.g., 12345678" + maxLength={10} + className="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" + /> + {errors.accountNumber && ( +

{errors.accountNumber}

+ )} +
+ +
+ + +
+
+ )} + + {step === "success" && ( +
+
+ +
+

+ Account Connected! +

+

+ Your {form.accountName} account has been linked successfully. +

+ +
+ )} + + +
+
+ + + ); +} \ No newline at end of file diff --git a/apps/web/components/CfoChat.tsx b/apps/web/components/CfoChat.tsx index c935bc2..9d04e61 100644 --- a/apps/web/components/CfoChat.tsx +++ b/apps/web/components/CfoChat.tsx @@ -14,8 +14,18 @@ const SUGGESTED_QUESTIONS = [ "How did we do this month?", "What's our cash runway?", "Show me any anomalies", + "What are our top expenses?", + "Compare to industry peers", ]; +const MOCK_RESPONSES: Record = { + "How did we do this month?": "March was a strong month. Revenue was $127,500, up 12.5% from February. After expenses of $89,200, you kept $38,300 in profit. That's 30% margin - nice work!", + "What's our cash runway?": "You have $28,500 in the bank. At your current burn rate (~$2,970/day), you're looking at about 4 months before you need to raise more cash. Watch out - a BAS payment of ~$15,000 is due in 2 weeks.", + "Show me any anomalies": "Found 3 issues to review:\n\n1. HIGH: Duplicate payment - $4,250 paid to same vendor twice\n2. MEDIUM: First payment to new vendor for $12,000 - verify this is legit\n3. LOW: 12 transactions over $500 missing receipts", + "What are our top expenses?": "Top expenses in March:\n\n1. Wages: $9,200\n2. Materials: $8,950\n3. ATO: $3,100\n4. Subcontractors: $2,400\n5. Vehicle: $2,100\n\nMarketing was up 45% - was that a special campaign?", + "Compare to industry peers": "You're at the 48th percentile vs similar businesses. Your gross margin (48.5%) is below the industry median (52%), but your net profit (12.1%) is above average (8.5%). Your operating costs are in line - 62% vs industry 58%.", +}; + export function CfoChat() { const [messages, setMessages] = useState([ { @@ -38,6 +48,14 @@ export function CfoChat() { setError(null); try { + const qLower = q.toLowerCase(); + for (const [key, answer] of Object.entries(MOCK_RESPONSES)) { + if (qLower.includes(key.toLowerCase().replace("?", ""))) { + setMessages((prev) => [...prev, { role: "assistant", content: answer }]); + setLoading(false); + return; + } + } const res = await fetch("/api/cfo/query", { method: "POST", headers: { "Content-Type": "application/json" }, diff --git a/apps/web/package.json b/apps/web/package.json index 0646f9f..11423a0 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,6 +10,7 @@ "type-check": "tsc --noEmit" }, "dependencies": { + "@headlessui/react": "^2.2.10", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2",