diff --git a/packages/web-deploy/json/bank-statement.idoc.json b/packages/web-deploy/json/bank-statement.idoc.json index 3f8d2312..4bfa6f09 100644 --- a/packages/web-deploy/json/bank-statement.idoc.json +++ b/packages/web-deploy/json/bank-statement.idoc.json @@ -4,12 +4,16 @@ "style": { "css": [ "body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: #f8fafc; }", - "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }", + "body { display: grid; grid-template-areas: 'header header' 'chart summary' 'transactions transactions' 'drilldown drilldown' 'breakdown breakdown' 'trends patterns'; grid-template-columns: 1fr 1fr; gap: 20px; max-width: 1400px; margin: 0 auto; }", ".group { background: white; padding: 20px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); border: 1px solid #e2e8f0; }", "#header { grid-area: header; background: linear-gradient(135deg, #1e40af 0%, #3b82f6 100%); color: white; text-align: center; }", "#summary { grid-area: summary; text-align: center; min-width: 0; }", "#chart { grid-area: chart; min-width: 0; }", "#transactions { grid-area: transactions; min-width: 0; }", + "#drilldown { grid-area: drilldown; min-width: 0; overflow: hidden; }", + "#breakdown { grid-area: breakdown; min-width: 0; overflow: hidden; }", + "#trends { grid-area: trends; min-width: 0; overflow: hidden; }", + "#patterns { grid-area: patterns; min-width: 0; overflow: hidden; }", "h1 { margin: 0; padding: 20px 0; font-size: 2em; font-weight: 600; }", "h2 { margin: 10px 0; font-size: 2em; color: #2d3748; font-weight: 600; }", "h3 { margin: 0 0 15px 0; font-size: 1.2em; color: #4a5568; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; }", @@ -18,7 +22,7 @@ ".compact-table { font-size: 0.85em; }", ".compact-table .tabulator-header { height: 30px; }", ".compact-table .tabulator-row { height: 28px; }", - "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions'; } }" + "@media (max-width: 768px) { body { grid-template-columns: 1fr; grid-template-areas: 'header' 'summary' 'chart' 'transactions' 'drilldown' 'breakdown' 'trends' 'patterns'; } }" ] }, "dataLoaders": [ @@ -46,7 +50,35 @@ "2024-01-25,Clothing Store,Shopping,-89.99,expense", "2024-01-26,Savings Transfer,Savings,-500.00,transfer", "2024-01-28,Gas Station,Transportation,-38.75,expense", - "2024-01-30,Phone Bill,Utilities,-45.00,expense" + "2024-01-30,Phone Bill,Utilities,-45.00,expense", + "2024-02-01,Supermarket,Food,-95.20,expense", + "2024-02-02,Coffee Shop,Food,-8.50,expense", + "2024-02-03,Fast Food,Food,-15.75,expense", + "2024-02-04,Grocery Store,Food,-78.90,expense", + "2024-02-05,Dining Out,Food,-65.00,expense", + "2024-02-06,Water Bill,Utilities,-35.50,expense", + "2024-02-07,Gas Bill,Utilities,-125.75,expense", + "2024-02-08,Cable TV,Utilities,-89.99,expense", + "2024-02-09,Bus Pass,Transportation,-55.00,expense", + "2024-02-10,Uber Ride,Transportation,-18.50,expense", + "2024-02-11,Parking Fee,Transportation,-12.00,expense", + "2024-02-12,Train Ticket,Transportation,-25.75,expense", + "2024-02-13,Online Store,Shopping,-145.00,expense", + "2024-02-14,Department Store,Shopping,-89.50,expense", + "2024-02-15,Bookstore,Shopping,-35.99,expense", + "2024-02-16,Electronics Store,Shopping,-299.99,expense", + "2024-02-17,Streaming Service,Entertainment,-15.99,expense", + "2024-02-18,Concert Tickets,Entertainment,-85.00,expense", + "2024-02-19,Game Purchase,Entertainment,-49.99,expense", + "2024-02-20,Movie Theater,Entertainment,-32.50,expense", + "2024-02-21,Doctor Visit,Healthcare,-150.00,expense", + "2024-02-22,Prescription,Healthcare,-45.50,expense", + "2024-02-23,Dental Cleaning,Healthcare,-125.00,expense", + "2024-02-24,Vitamins,Healthcare,-35.99,expense", + "2024-02-25,Mortgage Payment,Housing,-1200.00,expense", + "2024-02-26,Home Insurance,Housing,-85.00,expense", + "2024-02-27,Property Tax,Housing,-450.00,expense", + "2024-02-28,Home Repairs,Housing,-125.50,expense" ] } ], @@ -160,6 +192,129 @@ "calculation": { "vegaExpression": "'$' + format(length(data('currentBalance')) > 0 ? data('currentBalance')[0].total : 0, ',.2f')" } + }, + { + "variableId": "transactionsByCategory", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["category"], + "ops": ["sum", "count", "mean", "max"], + "fields": ["absAmount", "absAmount", "absAmount", "absAmount"], + "as": ["totalAmount", "transactionCount", "avgAmount", "maxAmount"] + } + ] + } + }, + { + "variableId": "dailySpending", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["date"], + "ops": ["sum"], + "fields": ["absAmount"], + "as": ["dailyTotal"] + } + ] + } + }, + { + "variableId": "spendingByDayOfWeek", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "formula", + "expr": "datetime(datum.date)", + "as": "dateTime" + }, + { + "type": "formula", + "expr": "day(datum.dateTime)", + "as": "dayOfWeek" + }, + { + "type": "formula", + "expr": "datum.dayOfWeek === 0 ? 'Sunday' : datum.dayOfWeek === 1 ? 'Monday' : datum.dayOfWeek === 2 ? 'Tuesday' : datum.dayOfWeek === 3 ? 'Wednesday' : datum.dayOfWeek === 4 ? 'Thursday' : datum.dayOfWeek === 5 ? 'Friday' : 'Saturday'", + "as": "dayName" + }, + { + "type": "aggregate", + "groupby": ["dayOfWeek", "dayName"], + "ops": ["sum", "count"], + "fields": ["absAmount", "absAmount"], + "as": ["totalSpent", "transactionCount"] + } + ] + } + }, + { + "variableId": "expensesByDescription", + "type": "object", + "isArray": true, + "initialValue": [], + "calculation": { + "dataSourceNames": ["editableTransactions"], + "dataFrameTransformations": [ + { + "type": "filter", + "expr": "datum.type === 'expense'" + }, + { + "type": "formula", + "expr": "abs(datum.amount)", + "as": "absAmount" + }, + { + "type": "aggregate", + "groupby": ["category", "description"], + "ops": ["sum"], + "fields": ["absAmount"], + "as": ["totalAmount"] + } + ] + } } ], "groups": [ @@ -281,6 +436,97 @@ } } ] + }, + { + "groupId": "drilldown", + "elements": [ + "### 🔍 Category Deep Dive", + "**Detailed breakdown of spending patterns by category**", + { + "type": "tabulator", + "dataSourceName": "transactionsByCategory", + "editable": false, + "tabulatorOptions": { + "layout": "fitColumns", + "initialSort": [ + {"column": "totalAmount", "dir": "desc"} + ], + "columns": [ + { + "title": "Category", + "field": "category", + "sorter": "string" + }, + { + "title": "Total Spent", + "field": "totalAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Transactions", + "field": "transactionCount", + "sorter": "number" + }, + { + "title": "Avg per Transaction", + "field": "avgAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + }, + { + "title": "Largest Transaction", + "field": "maxAmount", + "formatter": "money", + "formatterParams": { + "symbol": "$", + "precision": 2 + }, + "sorter": "number" + } + ] + } + } + ] + }, + { + "groupId": "breakdown", + "elements": [ + "### 📊 Spending Breakdown by Description", + "**Amount spent per description within each category**", + { + "type": "chart", + "chartKey": "expensesByDescriptionChart" + } + ] + }, + { + "groupId": "trends", + "elements": [ + "### 📈 Spending Trends", + { + "type": "chart", + "chartKey": "dailySpendingTrend" + } + ] + }, + { + "groupId": "patterns", + "elements": [ + "### 📅 Spending Patterns", + { + "type": "chart", + "chartKey": "dayOfWeekSpending" + } + ] } ], "resources": { @@ -327,6 +573,124 @@ {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} ] } + }, + "dailySpendingTrend": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 250, + "data": { + "name": "dailySpending" + }, + "mark": { + "type": "line", + "point": true, + "strokeWidth": 3 + }, + "encoding": { + "x": { + "field": "date", + "type": "temporal", + "title": "Date" + }, + "y": { + "field": "dailyTotal", + "type": "quantitative", + "title": "Daily Spending ($)" + }, + "color": { + "value": "#667eea" + }, + "tooltip": [ + {"field": "date", "type": "temporal", "title": "Date"}, + {"field": "dailyTotal", "type": "quantitative", "title": "Amount", "format": "$,.2f"} + ] + } + }, + "dayOfWeekSpending": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "height": 250, + "data": { + "name": "spendingByDayOfWeek" + }, + "mark": "bar", + "encoding": { + "x": { + "field": "dayName", + "type": "ordinal", + "title": "Day of Week", + "sort": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"] + }, + "y": { + "field": "totalSpent", + "type": "quantitative", + "title": "Total Spent ($)" + }, + "color": { + "field": "totalSpent", + "type": "quantitative", + "scale": { + "range": ["#e8f4f8", "#2e86ab"] + }, + "legend": null + }, + "tooltip": [ + {"field": "dayName", "type": "nominal", "title": "Day"}, + {"field": "totalSpent", "type": "quantitative", "title": "Amount", "format": "$,.2f"}, + {"field": "transactionCount", "type": "quantitative", "title": "Transactions"} + ] + } + }, + "expensesByDescriptionChart": { + "$schema": "https://vega.github.io/schema/vega-lite/v6.json", + "width": "container", + "data": { + "name": "expensesByDescription" + }, + "mark": "bar", + "spacing": 20, + "encoding": { + "row": { + "field": "category", + "type": "nominal", + "title": "Category", + "header": { + "labelAngle": 0, + "labelAlign": "left", + "labelFontSize": 12, + "labelFontWeight": "bold" + } + }, + "y": { + "field": "description", + "type": "nominal", + "title": "Description", + "sort": {"field": "totalAmount", "order": "descending"} + }, + "x": { + "field": "totalAmount", + "type": "quantitative", + "title": "Amount Spent ($)" + }, + "color": { + "field": "category", + "type": "nominal", + "scale": { + "range": ["#667eea", "#764ba2", "#f093fb", "#4ecdc4", "#45b7d1", "#96ceb4", "#feca57", "#ff9ff3", "#54a0ff"] + }, + "legend": null + }, + "tooltip": [ + {"field": "category", "type": "nominal", "title": "Category"}, + {"field": "description", "type": "nominal", "title": "Description"}, + {"field": "totalAmount", "type": "quantitative", "title": "Amount", "format": "$,.2f"} + ] + }, + "resolve": { + "scale": { + "y": "independent" + } + } } } }