From 6ae90c0c387d1b9d52d5de8ab800ce6a6729eebb Mon Sep 17 00:00:00 2001 From: Catherine Renelle <32781029+catrenelle@users.noreply.github.com> Date: Sun, 8 Feb 2026 13:02:14 -0500 Subject: [PATCH] Implement Phase 4: reports & investments frontend Add interactive reports dashboard with 4 chart types (spending by category donut, income vs expense bar, net worth area, cash flow bar) using ApexCharts, date range presets, and account filtering. Add investment portfolio view with holdings table, allocation chart, and gain/loss color coding. Includes TypeScript types and API services. Co-Authored-By: Claude Opus 4.6 --- frontend/src/services/investments.ts | 10 + frontend/src/services/reports.ts | 24 + frontend/src/types/index.ts | 71 +++ .../src/views/investments/InvestmentsView.vue | 213 +++++++- frontend/src/views/reports/ReportsView.vue | 512 +++++++++++++++++- 5 files changed, 818 insertions(+), 12 deletions(-) create mode 100644 frontend/src/services/investments.ts create mode 100644 frontend/src/services/reports.ts diff --git a/frontend/src/services/investments.ts b/frontend/src/services/investments.ts new file mode 100644 index 0000000..9d978a9 --- /dev/null +++ b/frontend/src/services/investments.ts @@ -0,0 +1,10 @@ +import api from './api' +import type { InvestmentHolding, InvestmentPerformance } from '@/types' + +export const investmentsApi = { + getHoldings: (accountId: string) => + api.get(`/investments/${accountId}/holdings`), + + getPerformance: (accountId: string) => + api.get(`/investments/${accountId}/performance`), +} diff --git a/frontend/src/services/reports.ts b/frontend/src/services/reports.ts new file mode 100644 index 0000000..a64a9fe --- /dev/null +++ b/frontend/src/services/reports.ts @@ -0,0 +1,24 @@ +import api from './api' +import type { SpendingByCategoryReport, IncomeVsExpenseReport, NetWorthReport, CashFlowReport } from '@/types' + +export const reportsApi = { + spendingByCategory: (startDate: string, endDate: string, accountId?: string) => + api.get('/reports/spending-by-category', { + params: { startDate, endDate, accountId }, + }), + + incomeVsExpense: (startDate: string, endDate: string) => + api.get('/reports/income-vs-expense', { + params: { startDate, endDate }, + }), + + netWorth: (startDate: string, endDate: string) => + api.get('/reports/net-worth', { + params: { startDate, endDate }, + }), + + cashFlow: (startDate: string, endDate: string) => + api.get('/reports/cash-flow', { + params: { startDate, endDate }, + }), +} diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 5d3e763..f745eec 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -261,3 +261,74 @@ export interface DuplicateResolution { export interface ResolveDuplicatesRequest { resolutions: DuplicateResolution[] } + +// Reports +export interface SpendingByCategoryReport { + startDate: string + endDate: string + totalSpending: number + categories: CategorySpending[] +} + +export interface IncomeVsExpenseReport { + startDate: string + endDate: string + months: MonthlyIncomeExpense[] +} + +export interface MonthlyIncomeExpense { + year: number + month: number + income: number + expenses: number + net: number +} + +export interface NetWorthReport { + entries: NetWorthEntry[] +} + +export interface NetWorthEntry { + date: string + assets: number + liabilities: number + netWorth: number +} + +export interface CashFlowReport { + startDate: string + endDate: string + totalInflow: number + totalOutflow: number + netCashFlow: number + entries: CashFlowEntry[] +} + +export interface CashFlowEntry { + date: string + inflow: number + outflow: number + net: number +} + +// Investments +export interface InvestmentHolding { + id: string + symbol: string + securityName: string + shares: number + costBasis: number + currentPrice: number + marketValue: number + gainLoss: number + gainLossPercent: number + asOfDate: string +} + +export interface InvestmentPerformance { + totalMarketValue: number + totalCostBasis: number + totalGainLoss: number + totalGainLossPercent: number + holdings: InvestmentHolding[] +} diff --git a/frontend/src/views/investments/InvestmentsView.vue b/frontend/src/views/investments/InvestmentsView.vue index d345951..c9fb05a 100644 --- a/frontend/src/views/investments/InvestmentsView.vue +++ b/frontend/src/views/investments/InvestmentsView.vue @@ -1,6 +1,217 @@ + + diff --git a/frontend/src/views/reports/ReportsView.vue b/frontend/src/views/reports/ReportsView.vue index 860b8dd..bfe6525 100644 --- a/frontend/src/views/reports/ReportsView.vue +++ b/frontend/src/views/reports/ReportsView.vue @@ -1,22 +1,512 @@