From eff1e0f925494972b17b3aa35ffff1a39b53e0e1 Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Fri, 13 Feb 2026 17:27:18 -0600 Subject: [PATCH 1/3] chore: install deps and add cross-env --- package-lock.json | 43 +++++++++++++++++++++++++++++++++++++------ package.json | 2 +- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index bc62ff5..c09acc5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -98,7 +98,7 @@ "@typescript-eslint/eslint-plugin": "^8.43.0", "@typescript-eslint/parser": "^8.43.0", "autoprefixer": "^10.4.20", - "cross-env": "^10.0.0", + "cross-env": "^10.1.0", "eslint": "^9.35.0", "eslint-config-next": "^15.5.9", "eslint-config-prettier": "^10.1.8", @@ -172,6 +172,7 @@ "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.2", @@ -1820,6 +1821,7 @@ "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.18.tgz", "integrity": "sha512-EjLuZWA5156dIFGdF7OnyPyWFBW43B8Ckje6Sn/W2RFxHDu0oACvW4/6TNgWT80jhEA4bVFm7ahrZe9MJ2B2UQ==", "license": "MIT", + "peer": true, "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -2047,6 +2049,7 @@ "resolved": "https://registry.npmjs.org/@effect-ts/core/-/core-0.60.5.tgz", "integrity": "sha512-qi1WrtJA90XLMnj2hnUszW9Sx4dXP03ZJtCc5DiUBIOhF4Vw7plfb65/bdBySPoC9s7zy995TdUX1XBSxUkl5w==", "license": "MIT", + "peer": true, "dependencies": { "@effect-ts/system": "^0.57.5" } @@ -2123,6 +2126,7 @@ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", "license": "MIT", + "peer": true, "dependencies": { "@emotion/memoize": "^0.9.0" } @@ -3842,6 +3846,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -3875,6 +3880,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "1.28.0" }, @@ -4063,6 +4069,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz", "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/core": "1.30.1", "@opentelemetry/resources": "1.30.1", @@ -4089,6 +4096,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.30.1.tgz", "integrity": "sha512-cBjYOINt1JxXdpw1e5MlHmFRc5fgj4GW/86vsKFxJCJ8AL4PdVtYH41gWwl4qd4uQjqEL1oJVrXkSy5cnduAnQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/context-async-hooks": "1.30.1", "@opentelemetry/core": "1.30.1", @@ -5858,6 +5866,7 @@ "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -6207,6 +6216,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -6216,6 +6226,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -6284,6 +6295,7 @@ "integrity": "sha512-B7RIQiTsCBBmY+yW4+ILd6mF5h1FUwJsVvpqkrgpszYifetQ2Ke+Z4u6aZh0CblkUGIdR59iYVyXqqZGkZ3aBw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.43.0", "@typescript-eslint/types": "8.43.0", @@ -6785,6 +6797,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7356,6 +7369,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", @@ -7939,6 +7953,7 @@ "integrity": "sha512-V9IyQtJBlRg3+vbvVb0sjKj/guFAJdCRCuXt4jKEJqMxYZ6Rp7SRAZRd4uhX67b7g6s3ss5jeBYNaPvM8A5s5Q==", "hasInstallScript": true, "license": "MIT", + "peer": true, "dependencies": { "@contentlayer2/cli": "0.5.7", "@contentlayer2/client": "0.5.7", @@ -8009,9 +8024,9 @@ } }, "node_modules/cross-env": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.0.0.tgz", - "integrity": "sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-10.1.0.tgz", + "integrity": "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==", "dev": true, "license": "MIT", "dependencies": { @@ -8693,7 +8708,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/embla-carousel-react": { "version": "8.6.0", @@ -8980,6 +8996,7 @@ "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -9048,6 +9065,7 @@ "integrity": "sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9137,6 +9155,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -9238,6 +9257,7 @@ "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.8", @@ -13486,6 +13506,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-15.5.9.tgz", "integrity": "sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "15.5.9", "@swc/helpers": "0.5.15", @@ -14143,6 +14164,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -14261,6 +14283,7 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -14462,6 +14485,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -14502,6 +14526,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz", "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -14514,6 +14539,7 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz", "integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -15548,6 +15574,7 @@ "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz", "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==", "license": "MIT", + "peer": true, "dependencies": { "@types/mdast": "^4.0.0", "remark-parse": "^11.0.0", @@ -16789,6 +16816,7 @@ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", "license": "MIT", + "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -16973,6 +17001,7 @@ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -17105,7 +17134,8 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" + "license": "0BSD", + "peer": true }, "node_modules/typanion": { "version": "3.14.0", @@ -17225,6 +17255,7 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 1288c8e..b42197b 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "@typescript-eslint/eslint-plugin": "^8.43.0", "@typescript-eslint/parser": "^8.43.0", "autoprefixer": "^10.4.20", - "cross-env": "^10.0.0", + "cross-env": "^10.1.0", "eslint": "^9.35.0", "eslint-config-next": "^15.5.9", "eslint-config-prettier": "^10.1.8", From 04ed167c15b8afb30e8bd0096ca3f347a4839b58 Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Fri, 13 Feb 2026 17:32:24 -0600 Subject: [PATCH 2/3] chore: add dashboard JSONC brief --- spec/dashboard-brief.jsonc | 99 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 spec/dashboard-brief.jsonc diff --git a/spec/dashboard-brief.jsonc b/spec/dashboard-brief.jsonc new file mode 100644 index 0000000..7fe9bd5 --- /dev/null +++ b/spec/dashboard-brief.jsonc @@ -0,0 +1,99 @@ +{ + "page": { + "route": "/dashboard", + "title": "Dashboard", + "layout": "app-shell" + }, + + "theme": { + "mood": "warm-minimal", + "background": "off-white", + "primaryAccent": "soft-yellow", + "radius": "rounded-xl", + "shadow": "soft" + }, + + "appShell": { + "topNav": { + "height": "h-16", + "container": "max-w-6xl mx-auto", + "style": "rounded-xl bg-yellow-50/80 backdrop-blur border border-yellow-100", + "left": ["brandMark", "brandName"], + "centerLinks": ["Overview", "Accounts", "Transactions", "Cards", "Insights"], + "right": ["PrimaryButton:New transfer", "IconButton:themeToggle", "AvatarMenu"] + } + }, + + "dashboard": { + "grid": { + "breakpoints": { + "mobile": "1-col", + "md": "2-col", + "lg": "12-col" + } + }, + + "sections": [ + { + "id": "kpis", + "type": "kpi-row", + "layout": "lg:col-span-12", + "cards": [ + { "label": "Balance", "value": "$24,680.12", "delta": "+2.1% this month" }, + { "label": "Spent", "value": "$3,142.55", "delta": "-4.3% vs last month" }, + { "label": "Income", "value": "$6,980.00", "delta": "+8.0% vs last month" }, + { "label": "Savings rate", "value": "31%", "delta": "+3 pts" } + ] + }, + + { + "id": "main", + "type": "two-column", + "left": [ + { + "type": "chart-card", + "title": "Cash flow", + "subtitle": "Income vs spending (last 30 days)", + "chart": "simple-area-or-bar" + }, + { + "type": "table-card", + "title": "Recent transactions", + "rows": 8, + "columns": ["Merchant", "Category", "Date", "Amount"], + "rowActions": ["View"] + } + ], + "right": [ + { + "type": "card", + "title": "Accounts", + "items": [ + { "name": "Checking", "meta": "••• 1832", "amount": "$8,420.11" }, + { "name": "Savings", "meta": "••• 9920", "amount": "$14,900.01" }, + { "name": "Card", "meta": "••• 4401", "amount": "-$1,360.00" } + ] + }, + { + "type": "card", + "title": "Budgets", + "items": [ + { "name": "Groceries", "value": "$320 / $500", "progress": 0.64 }, + { "name": "Dining", "value": "$210 / $300", "progress": 0.70 }, + { "name": "Gas", "value": "$95 / $200", "progress": 0.48 } + ] + } + ] + } + ] + }, + + "implementationRules": { + "useExistingComponentsFirst": true, + "tailwindOnly": true, + "noNewLibraries": true, + "lightDarkMode": true, + "responsive": true, + "dataInSeparateFile": true + } +} From f7e811e4dd2f15587e974601d50cc6c6e2a913d6 Mon Sep 17 00:00:00 2001 From: Alan Savage Date: Sat, 14 Feb 2026 07:42:42 -0600 Subject: [PATCH 3/3] feat: add dashboard route --- app/dashboard/page.tsx | 860 +++++++++---------------------------- data/dashboard/mockData.ts | 77 ++++ 2 files changed, 269 insertions(+), 668 deletions(-) create mode 100644 data/dashboard/mockData.ts diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx index 26d8754..15a8ccb 100644 --- a/app/dashboard/page.tsx +++ b/app/dashboard/page.tsx @@ -1,719 +1,243 @@ -'use client'; - -import { useState } from 'react'; -import { - LayoutDashboardIcon, - CreditCardIcon, - ArrowUpRightIcon, - SettingsIcon, - HelpCircleIcon, - UsersIcon, - SearchIcon, - ChevronDownIcon, - UploadIcon, - DownloadIcon, - TrendingUpIcon, - TrendingDownIcon, - MenuIcon, - XIcon, - ChevronLeftIcon, - ChevronRightIcon, -} from 'lucide-react'; import { ThemeSwitch } from '@/components/shared/ThemeSwitch'; +import { + accountItems, + budgetItems, + cashFlowData, + dashboardKpis, + dashboardNavLinks, + recentTransactions, +} from '@/data/dashboard/mockData'; +import { PlusIcon } from 'lucide-react'; +import type { Metadata } from 'next'; + +export const metadata: Metadata = { + title: 'Dashboard', +}; + +const maxCashFlow = Math.max( + ...cashFlowData.flatMap((point) => [point.income, point.spent]), +); export default function DashboardPage() { - const [sidebarOpen, setSidebarOpen] = useState(false); - const [balanceView, setBalanceView] = useState<'weekly' | 'monthly'>( - 'weekly', - ); - const [currentPage, setCurrentPage] = useState(1); - const itemsPerPage = 6; - - // Mock transaction data - const transactions = [ - { - id: 'PAY-001', - amount: 1250.0, - to: 'Acme Corp', - period: 'Jan 1 - Jan 31', - method: 'Credit Card', - date: 'Jan 31, 2024', - status: 'received' as const, - }, - { - id: 'PAY-002', - amount: 890.5, - to: 'Tech Solutions', - period: 'Feb 1 - Feb 28', - method: 'Bank Transfer', - date: 'Feb 28, 2024', - status: 'processed' as const, - }, - { - id: 'PAY-003', - amount: 2100.0, - to: 'Global Services', - period: 'Mar 1 - Mar 31', - method: 'Credit Card', - date: 'Mar 31, 2024', - status: 'received' as const, - }, - { - id: 'PAY-004', - amount: 450.75, - to: 'Local Vendor', - period: 'Apr 1 - Apr 30', - method: 'PayPal', - date: 'Apr 15, 2024', - status: 'failed' as const, - }, - { - id: 'PAY-005', - amount: 3200.0, - to: 'Enterprise Inc', - period: 'May 1 - May 31', - method: 'Wire Transfer', - date: 'May 30, 2024', - status: 'processed' as const, - }, - { - id: 'PAY-006', - amount: 675.25, - to: 'Startup Labs', - period: 'Jun 1 - Jun 30', - method: 'Credit Card', - date: 'Jun 28, 2024', - status: 'received' as const, - }, - { - id: 'PAY-007', - amount: 1820.0, - to: 'Digital Agency', - period: 'Jul 1 - Jul 31', - method: 'Bank Transfer', - date: 'Jul 29, 2024', - status: 'processed' as const, - }, - { - id: 'PAY-008', - amount: 990.5, - to: 'Cloud Services', - period: 'Aug 1 - Aug 31', - method: 'Credit Card', - date: 'Aug 30, 2024', - status: 'received' as const, - }, - ]; - - const totalPages = Math.ceil(transactions.length / itemsPerPage); - const paginatedTransactions = transactions.slice( - (currentPage - 1) * itemsPerPage, - currentPage * itemsPerPage, - ); - - const chartData = - balanceView === 'weekly' - ? [ - { label: 'Mon', value: 2400 }, - { label: 'Tue', value: 1800 }, - { label: 'Wed', value: 3200 }, - { label: 'Thu', value: 4200 }, - { label: 'Fri', value: 3600 }, - { label: 'Sat', value: 2800 }, - { label: 'Sun', value: 2200 }, - ] - : [ - { label: 'Jan', value: 12400 }, - { label: 'Feb', value: 15800 }, - { label: 'Mar', value: 18200 }, - { label: 'Apr', value: 21200 }, - { label: 'May', value: 19600 }, - { label: 'Jun', value: 17800 }, - ]; - - const maxValue = Math.max(...chartData.map((d) => d.value)); - return ( -
- {/* Outer Shell Container */} -
-
- {/* Sidebar */} - - {/* Main Content */} -
- {/* Top Bar */} -
-
- -

- Dashboard -

-
-
+
-
- {/* Summary Cards */} -
- - - +
- - {/* Cards Grid */} -
- {/* Spending Limits Card */} -
-
-

- AI-Generated Spending Limits -

- - {/* Progress */} -
-
- - $4,285 - - - of $8,000 - -
-
-
-
-
- - {/* Legend */} -
- - - - -
- - {/* Virtual Card */} -
- {/* VISA logo */} -
- VISA -
- - {/* Card number */} -
- •••• •••• •••• 4582 -
- - {/* Card meta */} -
-
-
- VALID THRU -
-
12/28
-
-
-
- CVV -
-
•••
-
-
-
+
+ + +
+
+ {dashboardKpis.map((kpi) => ( +
+

+ {kpi.label} +

+

{kpi.value}

+

+ {kpi.delta} +

+
+ ))} +
+ +
+
+
+
+

Cash flow

+

+ Income vs spending (last 30 days) +

- {/* Balance Chart Card */} -
-
-
-
-

- Available Balance -

-
- $24,582.50 -
-
-
- - +
+ {cashFlowData.map((point) => ( +
+
+
+
+

+ {point.label} +

- - {/* View Toggle */} -
- - -
- - {/* Chart */} -
- {chartData.map((item, index) => { - const isHighlight = index === 3; - const heightPercent = (item.value / maxValue) * 100; - return ( -
-
-
-
- - {item.label} - -
- ); - })} -
-
-
-
- - {/* Transaction Toolbar */} -
-
- - + ))}
-
- - +
+ + + Income + + + + Spending +
+
-
- -
-
- {/* Transaction Table */} -
- +
- - + + + + - - - - - - - {paginatedTransactions.map((transaction) => ( + {recentTransactions.map((row) => ( - - - + + + - - - - ))}
- Payment ID +
MerchantCategoryDate + Amount - Total Amount - - To - - Payment Period - - Payment Method - - Processed Date - - Status + + Action
- {transaction.id} - - ${transaction.amount.toFixed(2)} - - {transaction.to} + {row.merchant}{row.category}{row.date} + {row.amount} - {transaction.period} - - - {transaction.method} - - - {transaction.date} - - + +
- - {/* Pagination */} -
-
- Showing {(currentPage - 1) * itemsPerPage + 1} to{' '} - {Math.min(currentPage * itemsPerPage, transactions.length)} of{' '} - {transactions.length} transactions -
-
- - {Array.from({ length: totalPages }, (_, i) => i + 1).map( - (page) => ( - - ), - )} -
+ +
-
-
-
-
-
- - {/* Sidebar Overlay */} - {sidebarOpen && ( -
setSidebarOpen(false)} - /> - )} -
- ); -} - -// Helper Components - -function NavItem({ - icon: Icon, - label, - active = false, -}: { - icon: React.ComponentType<{ className?: string }>; - label: string; - active?: boolean; -}) { - return ( - - ); -} - -function SummaryCard({ - label, - value, - delta, - trending, -}: { - label: string; - value: string; - delta: string; - trending: 'up' | 'down'; -}) { - return ( -
-
- {label} -
-
- {value} -
-
- - {trending === 'up' ? ( - - ) : ( - - )} - {delta} - -
-
- ); -} - -function LegendItem({ - color, - label, - value, -}: { - color: string; - label: string; - value: string; -}) { - return ( -
-
-
-
- {label} -
-
- {value} -
+
+

{account.name}

+

+ {account.meta} +

+
+

{account.amount}

+ + ))} + + + +
+

Budgets

+
    + {budgetItems.map((budget) => ( +
  • +
    +

    {budget.name}

    +

    + {budget.value} +

    +
    +
    +
    +
    +
  • + ))} +
+
+ +
); } - -function StatusBadge({ - status, -}: { - status: 'received' | 'processed' | 'failed'; -}) { - const styles = { - received: { - bg: 'bg-gray-100 dark:bg-gray-900', - text: 'text-gray-900 dark:text-gray-300', - icon: 'text-emerald-400', - }, - processed: { - bg: 'bg-gray-100 dark:bg-gray-900', - text: 'text-gray-900 dark:text-gray-300', - icon: 'text-cyan-400', - }, - failed: { - bg: 'bg-gray-100 dark:bg-gray-900', - text: 'text-gray-900 dark:text-gray-300', - icon: 'text-red-400', - }, - }; - - const style = styles[status]; - - return ( - - - {status.charAt(0).toUpperCase() + status.slice(1)} - - ); -} diff --git a/data/dashboard/mockData.ts b/data/dashboard/mockData.ts new file mode 100644 index 0000000..a33c7be --- /dev/null +++ b/data/dashboard/mockData.ts @@ -0,0 +1,77 @@ +export type Kpi = { + label: string; + value: string; + delta: string; +}; + +export type CashFlowPoint = { + label: string; + income: number; + spent: number; +}; + +export type Transaction = { + merchant: string; + category: string; + date: string; + amount: string; +}; + +export type Account = { + name: string; + meta: string; + amount: string; +}; + +export type Budget = { + name: string; + value: string; + progress: number; +}; + +export const dashboardNavLinks = [ + 'Overview', + 'Accounts', + 'Transactions', + 'Cards', + 'Insights', +]; + +export const dashboardKpis: Kpi[] = [ + { label: 'Balance', value: '$24,680.12', delta: '+2.1% this month' }, + { label: 'Spent', value: '$3,142.55', delta: '-4.3% vs last month' }, + { label: 'Income', value: '$6,980.00', delta: '+8.0% vs last month' }, + { label: 'Savings rate', value: '31%', delta: '+3 pts' }, +]; + +export const cashFlowData: CashFlowPoint[] = [ + { label: 'Jan 15', income: 4200, spent: 1800 }, + { label: 'Jan 20', income: 4700, spent: 2200 }, + { label: 'Jan 25', income: 3900, spent: 2400 }, + { label: 'Jan 30', income: 5200, spent: 2600 }, + { label: 'Feb 04', income: 5100, spent: 2300 }, + { label: 'Feb 09', income: 5600, spent: 2800 }, +]; + +export const recentTransactions: Transaction[] = [ + { merchant: 'Fresh Market', category: 'Groceries', date: 'Feb 10', amount: '-$84.22' }, + { merchant: 'Oak Coffee', category: 'Dining', date: 'Feb 10', amount: '-$16.40' }, + { merchant: 'Payroll', category: 'Income', date: 'Feb 09', amount: '+$3,490.00' }, + { merchant: 'City Fuel', category: 'Gas', date: 'Feb 08', amount: '-$52.80' }, + { merchant: 'Nimbus Cloud', category: 'Subscriptions', date: 'Feb 08', amount: '-$29.00' }, + { merchant: 'North Gym', category: 'Health', date: 'Feb 07', amount: '-$65.00' }, + { merchant: 'Home Electric', category: 'Utilities', date: 'Feb 06', amount: '-$118.35' }, + { merchant: 'Book Corner', category: 'Shopping', date: 'Feb 05', amount: '-$42.70' }, +]; + +export const accountItems: Account[] = [ + { name: 'Checking', meta: '... 1832', amount: '$8,420.11' }, + { name: 'Savings', meta: '... 9920', amount: '$14,900.01' }, + { name: 'Card', meta: '... 4401', amount: '-$1,360.00' }, +]; + +export const budgetItems: Budget[] = [ + { name: 'Groceries', value: '$320 / $500', progress: 0.64 }, + { name: 'Dining', value: '$210 / $300', progress: 0.7 }, + { name: 'Gas', value: '$95 / $200', progress: 0.48 }, +];