From 11ac016e447dc1ec3723b4332d727f437d7e3aa1 Mon Sep 17 00:00:00 2001 From: juancwu Date: Tue, 14 Apr 2026 00:54:06 +0000 Subject: [PATCH] feat: list accounts in space overview --- internal/handler/space.go | 22 ++++++- internal/ui/blocks/account_card.templ | 32 ++++++++++ internal/ui/layouts/app.templ | 32 ++-------- .../page_app_spaces_space_overview.templ | 9 --- internal/ui/pages/space_overview.templ | 58 +++++++++++++++++++ internal/ui/pages/spaces.templ | 46 +++++++++++++-- 6 files changed, 155 insertions(+), 44 deletions(-) create mode 100644 internal/ui/blocks/account_card.templ delete mode 100644 internal/ui/pages/page_app_spaces_space_overview.templ create mode 100644 internal/ui/pages/space_overview.templ diff --git a/internal/handler/space.go b/internal/handler/space.go index 865a691..9b81afb 100644 --- a/internal/handler/space.go +++ b/internal/handler/space.go @@ -115,5 +115,25 @@ func (h *spaceHandler) SpaceOverviewPage(w http.ResponseWriter, r *http.Request) return } - ui.Render(w, r, pages.SpaceOverview(space.Name)) + accounts, err := h.accountService.GetAccountsForSpace(spaceID) + if err != nil { + slog.Error("failed to fetch accounts for space", "error", err, "spaceID", spaceID) + ui.RenderError(w, r, "Failed to load accounts", http.StatusInternalServerError) + return + } + + accountCards := make([]blocks.AccountCardInfo, 0, len(accounts)) + for _, a := range accounts { + accountCards = append(accountCards, blocks.AccountCardInfo{ + ID: a.ID, + Name: a.Name, + Balance: a.Balance, + }) + } + + ui.Render(w, r, pages.SpaceOverview(pages.SpaceOverviewProps{ + SpaceID: space.ID, + SpaceName: space.Name, + Accounts: accountCards, + })) } diff --git a/internal/ui/blocks/account_card.templ b/internal/ui/blocks/account_card.templ new file mode 100644 index 0000000..c9a8ca3 --- /dev/null +++ b/internal/ui/blocks/account_card.templ @@ -0,0 +1,32 @@ +package blocks + +import "github.com/shopspring/decimal" +import "strings" +import "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon" + +type AccountCardInfo struct { + ID string + Name string + Balance decimal.Decimal +} + +templ AccountCard(info AccountCardInfo) { +
+
+
+
+ { strings.ToUpper(string(info.Name[0])) } +
+
+

{ info.Name }

+

+ ${ info.Balance.StringFixedBank(2) } +

+
+
+
+ @icon.ChevronRight() +
+
+
+} diff --git a/internal/ui/layouts/app.templ b/internal/ui/layouts/app.templ index 544625b..95c5173 100644 --- a/internal/ui/layouts/app.templ +++ b/internal/ui/layouts/app.templ @@ -3,6 +3,7 @@ package layouts import ( "git.juancwu.dev/juancwu/budgit/internal/ctxkeys" "git.juancwu.dev/juancwu/budgit/internal/model" + "git.juancwu.dev/juancwu/budgit/internal/routeurl" "git.juancwu.dev/juancwu/budgit/internal/ui/blocks" "git.juancwu.dev/juancwu/budgit/internal/ui/components/avatar" "git.juancwu.dev/juancwu/budgit/internal/ui/components/breadcrumb" @@ -11,10 +12,9 @@ import ( "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon" "git.juancwu.dev/juancwu/budgit/internal/ui/components/sidebar" "strings" - "git.juancwu.dev/juancwu/budgit/internal/routeurl" ) -templ App(title string) { +templ App(title string, sidebarContent ...templ.Component) { {{ cfg := ctxkeys.Config(ctx) }} @Base(SEOProps{ Title: title, @@ -41,32 +41,8 @@ templ App(title string) { } } @sidebar.Content() { - @sidebar.Group() { - @sidebar.GroupLabel() { - Overview - } - @sidebar.Menu() { - @sidebar.MenuItem() { - @sidebar.MenuButton(sidebar.MenuButtonProps{ - Href: routeurl.URL("page.app.spaces"), - IsActive: ctxkeys.URLPath(ctx) == routeurl.URL("page.app.spaces"), - Tooltip: "My spaces", - }) { - @icon.User() - My spaces - } - } - @sidebar.MenuItem() { - @sidebar.MenuButton(sidebar.MenuButtonProps{ - Href: routeurl.URL("page.app.shared-with-me"), - IsActive: ctxkeys.URLPath(ctx) == routeurl.URL("page.app.shared-with-me"), - Tooltip: "Shared with me", - }) { - @icon.Users() - Shared with me - } - } - } + for _, content := range sidebarContent { + @content } } @sidebar.Footer() { diff --git a/internal/ui/pages/page_app_spaces_space_overview.templ b/internal/ui/pages/page_app_spaces_space_overview.templ deleted file mode 100644 index 05a9154..0000000 --- a/internal/ui/pages/page_app_spaces_space_overview.templ +++ /dev/null @@ -1,9 +0,0 @@ -package pages - -import "git.juancwu.dev/juancwu/budgit/internal/ui/layouts" - -templ SpaceOverview(spaceName string) { - @layouts.App("Space Overview") { -
space overview: { spaceName }
- } -} diff --git a/internal/ui/pages/space_overview.templ b/internal/ui/pages/space_overview.templ new file mode 100644 index 0000000..c89be11 --- /dev/null +++ b/internal/ui/pages/space_overview.templ @@ -0,0 +1,58 @@ +package pages + +import "git.juancwu.dev/juancwu/budgit/internal/ui/layouts" +import "git.juancwu.dev/juancwu/budgit/internal/ui/blocks" +import "git.juancwu.dev/juancwu/budgit/internal/ui/components/sidebar" + +import "git.juancwu.dev/juancwu/budgit/internal/routeurl" +import "git.juancwu.dev/juancwu/budgit/internal/ctxkeys" +import "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon" + +type SpaceOverviewProps struct { + SpaceID string + SpaceName string + Accounts []blocks.AccountCardInfo +} + +templ SpaceOverview(props SpaceOverviewProps) { + @layouts.App("Space Overview", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) { +
+
+

{ props.SpaceName }

+

Space overview

+
+
+

Accounts

+ if len(props.Accounts) == 0 { +

No accounts yet.

+ } else { +
+ for _, account := range props.Accounts { + @blocks.AccountCard(account) + } +
+ } +
+
+ } +} + +templ spaceSpecificSidebarContent(spaceID string) { + @sidebar.Group() { + @sidebar.GroupLabel() { + Space + } + @sidebar.Menu() { + @sidebar.MenuItem() { + @sidebar.MenuButton(sidebar.MenuButtonProps{ + Href: routeurl.URL("page.app.spaces.space.overview", "spaceID", spaceID), + IsActive: ctxkeys.URLPath(ctx) == routeurl.URL("page.app.spaces.space.overview", "spaceID", spaceID), + Tooltip: "Space Overview", + }) { + @icon.LayoutDashboard() + Space Overview + } + } + } + } +} diff --git a/internal/ui/pages/spaces.templ b/internal/ui/pages/spaces.templ index a4d5f48..b2574a3 100644 --- a/internal/ui/pages/spaces.templ +++ b/internal/ui/pages/spaces.templ @@ -1,13 +1,17 @@ package pages -import "git.juancwu.dev/juancwu/budgit/internal/ui/layouts" -import "git.juancwu.dev/juancwu/budgit/internal/ui/blocks" -import "git.juancwu.dev/juancwu/budgit/internal/ui/components/button" -import "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon" -import "git.juancwu.dev/juancwu/budgit/internal/routeurl" +import ( + "git.juancwu.dev/juancwu/budgit/internal/ctxkeys" + "git.juancwu.dev/juancwu/budgit/internal/routeurl" + "git.juancwu.dev/juancwu/budgit/internal/ui/blocks" + "git.juancwu.dev/juancwu/budgit/internal/ui/components/button" + "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon" + "git.juancwu.dev/juancwu/budgit/internal/ui/components/sidebar" + "git.juancwu.dev/juancwu/budgit/internal/ui/layouts" +) templ Spaces(spaces []blocks.SpaceCardInfo) { - @layouts.App("Spaces") { + @layouts.App("Spaces", spaceOverviewSidebarContent()) {
@@ -32,3 +36,33 @@ templ Spaces(spaces []blocks.SpaceCardInfo) {
} } + +templ spaceOverviewSidebarContent() { + @sidebar.Group() { + @sidebar.GroupLabel() { + Overview + } + @sidebar.Menu() { + @sidebar.MenuItem() { + @sidebar.MenuButton(sidebar.MenuButtonProps{ + Href: routeurl.URL("page.app.spaces"), + IsActive: ctxkeys.URLPath(ctx) == routeurl.URL("page.app.spaces"), + Tooltip: "My spaces", + }) { + @icon.User() + My spaces + } + } + @sidebar.MenuItem() { + @sidebar.MenuButton(sidebar.MenuButtonProps{ + Href: routeurl.URL("page.app.shared-with-me"), + IsActive: ctxkeys.URLPath(ctx) == routeurl.URL("page.app.shared-with-me"), + Tooltip: "Shared with me", + }) { + @icon.Users() + Shared with me + } + } + } + } +}