From 4d1c01776f0ca0de992ee24ce68b9f4c413cd76e Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:46:21 -0500 Subject: [PATCH] feat(web): enhance transaction display and account management features --- src/FiscalOS.API/Institutions/Get/Endpoint.cs | 1 + src/FiscalOS.API/Institutions/Get/Response.cs | 4 + src/FiscalOS.Web/src/assets/css/reset.css | 20 +- .../src/components/CircleSpinner.vue | 21 + .../src/components/NavSidebar.vue | 77 ++-- .../src/components/ProtectedLayout.vue | 4 + .../src/components/TransactionCard.vue | 63 ++- src/FiscalOS.Web/src/router/index.ts | 22 +- .../src/services/institutionService.ts | 3 +- src/FiscalOS.Web/src/views/AccountsView.vue | 405 ++++++++++++++++++ src/FiscalOS.Web/src/views/HomeView.vue | 210 --------- .../src/views/TransactionsView.vue | 60 ++- 12 files changed, 616 insertions(+), 274 deletions(-) create mode 100644 src/FiscalOS.Web/src/components/CircleSpinner.vue create mode 100644 src/FiscalOS.Web/src/views/AccountsView.vue delete mode 100644 src/FiscalOS.Web/src/views/HomeView.vue diff --git a/src/FiscalOS.API/Institutions/Get/Endpoint.cs b/src/FiscalOS.API/Institutions/Get/Endpoint.cs index 5df5a15..27c5094 100644 --- a/src/FiscalOS.API/Institutions/Get/Endpoint.cs +++ b/src/FiscalOS.API/Institutions/Get/Endpoint.cs @@ -19,6 +19,7 @@ internal static class Endpoint var user = await appDbContext.Users .Include(u => u.Institutions) .ThenInclude(i => i.Accounts) + .ThenInclude(a => a.Metadata) .FirstOrDefaultAsync(u => u.Id == userId); if (user is null) diff --git a/src/FiscalOS.API/Institutions/Get/Response.cs b/src/FiscalOS.API/Institutions/Get/Response.cs index e0aa56d..55e8e8c 100644 --- a/src/FiscalOS.API/Institutions/Get/Response.cs +++ b/src/FiscalOS.API/Institutions/Get/Response.cs @@ -24,6 +24,7 @@ internal sealed record Response internal sealed record AccountDto { public string Id { get; init; } = string.Empty; + public string ProviderId { get; init; } = string.Empty; public string Name { get; init; } = string.Empty; [JsonConstructor] @@ -36,6 +37,9 @@ internal sealed record AccountDto return new() { Id = account.Id.ToString(), + ProviderId = account.Metadata is PlaidAccountMetadata plaidMetadata + ? plaidMetadata.PlaidId + : string.Empty, Name = account.Name, }; } diff --git a/src/FiscalOS.Web/src/assets/css/reset.css b/src/FiscalOS.Web/src/assets/css/reset.css index 53390eb..8dfe6f6 100644 --- a/src/FiscalOS.Web/src/assets/css/reset.css +++ b/src/FiscalOS.Web/src/assets/css/reset.css @@ -24,6 +24,24 @@ input { color: inherit; } +select { + font-family: inherit; + font-size: inherit; + color: inherit; + background-color: inherit; +} + +option { + font-family: inherit; + font-size: inherit; + color: inherit; + background-color: inherit; +} + +option :hover { + background-color: var(--bg-element); +} + a { text-decoration: none; color: inherit; @@ -41,4 +59,4 @@ img { table { width: 100%; border-collapse: collapse; -} +} \ No newline at end of file diff --git a/src/FiscalOS.Web/src/components/CircleSpinner.vue b/src/FiscalOS.Web/src/components/CircleSpinner.vue new file mode 100644 index 0000000..9cb7d85 --- /dev/null +++ b/src/FiscalOS.Web/src/components/CircleSpinner.vue @@ -0,0 +1,21 @@ + + + diff --git a/src/FiscalOS.Web/src/components/NavSidebar.vue b/src/FiscalOS.Web/src/components/NavSidebar.vue index 5911724..a2c3370 100644 --- a/src/FiscalOS.Web/src/components/NavSidebar.vue +++ b/src/FiscalOS.Web/src/components/NavSidebar.vue @@ -39,23 +39,29 @@ > - - + @@ -82,6 +88,35 @@ } } + aside.collapsed { + width: calc(0.125rem + var(--button-size) / 2); + } + + aside.collapsed .toggle-button { + transform: rotate(180deg); + } + + aside.collapsed .sidebar-content { + opacity: 0; + visibility: hidden; + pointer-events: none; + } + + .sidebar-content { + display: flex; + flex-direction: column; + justify-content: space-between; + height: 100%; + gap: 3rem; + flex: 1; + overflow: hidden; + opacity: 1; + visibility: visible; + transition-property: opacity, visibility; + transition-duration: var(--transition-duration); + transition-timing-function: var(--transition-function); + } + .logout-button { background: var(--bg-element); padding: 0.25rem 0.5rem; @@ -104,14 +139,6 @@ transition-timing-function: var(--transition-function); } - aside.collapsed { - width: calc(0.125rem + var(--button-size) / 2); - } - - aside.collapsed .toggle-button { - transform: rotate(180deg); - } - .toggle-button svg { --size: 1rem; width: var(--size); diff --git a/src/FiscalOS.Web/src/components/ProtectedLayout.vue b/src/FiscalOS.Web/src/components/ProtectedLayout.vue index 747a75c..41f6869 100644 --- a/src/FiscalOS.Web/src/components/ProtectedLayout.vue +++ b/src/FiscalOS.Web/src/components/ProtectedLayout.vue @@ -22,5 +22,9 @@ main { flex: 1; padding: 1rem; + overflow: auto; + scroll-behavior: smooth; + scrollbar-color: var(--bg-surface) var(--bg-app); + scrollbar-gutter: stable; } diff --git a/src/FiscalOS.Web/src/components/TransactionCard.vue b/src/FiscalOS.Web/src/components/TransactionCard.vue index e1c53c3..abc41d3 100644 --- a/src/FiscalOS.Web/src/components/TransactionCard.vue +++ b/src/FiscalOS.Web/src/components/TransactionCard.vue @@ -1,17 +1,72 @@ diff --git a/src/FiscalOS.Web/src/router/index.ts b/src/FiscalOS.Web/src/router/index.ts index 74ebf0c..a6063c3 100644 --- a/src/FiscalOS.Web/src/router/index.ts +++ b/src/FiscalOS.Web/src/router/index.ts @@ -23,6 +23,9 @@ const router = createRouter({ { path: 'login', component: () => import('../views/LoginView.vue'), + meta: { + title: 'Login', + }, }, ], }, @@ -60,15 +63,30 @@ const router = createRouter({ children: [ { path: '/', - component: () => import('../views/HomeView.vue'), + redirect: '/accounts', + }, + { + path: '/accounts', + component: () => import('../views/AccountsView.vue'), + meta: { + title: 'Accounts', + }, }, { path: '/transactions', component: () => import('../views/TransactionsView.vue'), - } + meta: { + title: 'Transactions', + }, + }, ], }, ], }); +router.beforeEach((to, _, next) => { + document.title = to.meta.title ? `FiscalOS - ${to.meta.title}` : 'FiscalOS'; + next(); +}); + export default router; diff --git a/src/FiscalOS.Web/src/services/institutionService.ts b/src/FiscalOS.Web/src/services/institutionService.ts index 3d89ec9..c53ae3c 100644 --- a/src/FiscalOS.Web/src/services/institutionService.ts +++ b/src/FiscalOS.Web/src/services/institutionService.ts @@ -136,8 +136,9 @@ type LinkTokenResponse = { type Account = { id: string; + providerId: string; name: string; -} +}; export type Institution = { id: string; diff --git a/src/FiscalOS.Web/src/views/AccountsView.vue b/src/FiscalOS.Web/src/views/AccountsView.vue new file mode 100644 index 0000000..dca2dfd --- /dev/null +++ b/src/FiscalOS.Web/src/views/AccountsView.vue @@ -0,0 +1,405 @@ + + + + + diff --git a/src/FiscalOS.Web/src/views/HomeView.vue b/src/FiscalOS.Web/src/views/HomeView.vue deleted file mode 100644 index 1fa4d69..0000000 --- a/src/FiscalOS.Web/src/views/HomeView.vue +++ /dev/null @@ -1,210 +0,0 @@ - - - - - diff --git a/src/FiscalOS.Web/src/views/TransactionsView.vue b/src/FiscalOS.Web/src/views/TransactionsView.vue index f5f6bc5..b475440 100644 --- a/src/FiscalOS.Web/src/views/TransactionsView.vue +++ b/src/FiscalOS.Web/src/views/TransactionsView.vue @@ -1,47 +1,45 @@ - +