diff --git a/internal/handler/space.go b/internal/handler/space.go index dfc2b33..5ab7921 100644 --- a/internal/handler/space.go +++ b/internal/handler/space.go @@ -260,6 +260,13 @@ func (h *spaceHandler) SpaceAccountPage(w http.ResponseWriter, r *http.Request) return } + space, err := h.spaceService.GetSpace(spaceID) + if err != nil { + slog.Error("failed to load space", "error", err, "space_id", spaceID) + ui.RenderError(w, r, "Failed to load account", http.StatusInternalServerError) + return + } + recent, err := h.transactionService.ListByAccount(accountID, 5, 0) if err != nil { slog.Error("failed to load recent transactions", "error", err, "account_id", accountID) @@ -268,6 +275,7 @@ func (h *spaceHandler) SpaceAccountPage(w http.ResponseWriter, r *http.Request) ui.Render(w, r, pages.SpaceAccountPage(pages.SpaceAccountPageProps{ SpaceID: spaceID, + SpaceName: space.Name, AccountID: accountID, AccountName: account.Name, AccountBalance: account.Balance, @@ -290,6 +298,13 @@ func (h *spaceHandler) SpaceAccountTransactionsPage(w http.ResponseWriter, r *ht return } + space, err := h.spaceService.GetSpace(spaceID) + if err != nil { + slog.Error("failed to load space", "error", err, "space_id", spaceID) + ui.RenderError(w, r, "Failed to load transactions", http.StatusInternalServerError) + return + } + const perPage = 25 page := 1 if p := strings.TrimSpace(r.URL.Query().Get("page")); p != "" { @@ -323,6 +338,7 @@ func (h *spaceHandler) SpaceAccountTransactionsPage(w http.ResponseWriter, r *ht ui.Render(w, r, pages.SpaceAccountTransactionsPage(pages.SpaceAccountTransactionsPageProps{ SpaceID: spaceID, + SpaceName: space.Name, AccountID: accountID, AccountName: account.Name, Transactions: txns, @@ -450,8 +466,16 @@ func (h *spaceHandler) SpaceAccountSettingsPage(w http.ResponseWriter, r *http.R return } + space, err := h.spaceService.GetSpace(spaceID) + if err != nil { + slog.Error("failed to load space", "error", err, "space_id", spaceID) + ui.RenderError(w, r, "Failed to load account settings", http.StatusInternalServerError) + return + } + ui.Render(w, r, pages.SpaceAccountSettingsPage(pages.SpaceAccountSettingsPageProps{ SpaceID: spaceID, + SpaceName: space.Name, AccountID: accountID, AccountName: account.Name, UpdateForm: forms.UpdateAccountProps{ @@ -559,8 +583,16 @@ func (h *spaceHandler) SpaceCreateBillPage(w http.ResponseWriter, r *http.Reques return } + space, err := h.spaceService.GetSpace(spaceID) + if err != nil { + slog.Error("failed to load space", "error", err, "space_id", spaceID) + ui.RenderError(w, r, "Failed to load page", http.StatusInternalServerError) + return + } + ui.Render(w, r, pages.SpaceCreateBillPage(pages.SpaceCreateBillPageProps{ SpaceID: spaceID, + SpaceName: space.Name, AccountID: accountID, AccountName: account.Name, Form: forms.CreateBillProps{ @@ -587,8 +619,16 @@ func (h *spaceHandler) SpaceCreateDepositPage(w http.ResponseWriter, r *http.Req return } + space, err := h.spaceService.GetSpace(spaceID) + if err != nil { + slog.Error("failed to load space", "error", err, "space_id", spaceID) + ui.RenderError(w, r, "Failed to load page", http.StatusInternalServerError) + return + } + ui.Render(w, r, pages.SpaceCreateDepositPage(pages.SpaceCreateDepositPageProps{ SpaceID: spaceID, + SpaceName: space.Name, AccountID: accountID, AccountName: account.Name, Form: forms.CreateDepositProps{ diff --git a/internal/ui/layouts/app.templ b/internal/ui/layouts/app.templ index 7a88a74..75add0c 100644 --- a/internal/ui/layouts/app.templ +++ b/internal/ui/layouts/app.templ @@ -15,6 +15,12 @@ import ( ) templ App(title string, sidebarContent ...templ.Component) { + @AppWithBreadcrumb(title, defaultBreadcrumb(title), sidebarContent...) { + { children... } + } +} + +templ AppWithBreadcrumb(title string, breadcrumbContent templ.Component, sidebarContent ...templ.Component) { {{ cfg := ctxkeys.Config(ctx) }} @Base(SEOProps{ Title: title, @@ -80,15 +86,7 @@ templ App(title string, sidebarContent ...templ.Component) {
@sidebar.Trigger() - @breadcrumb.Breadcrumb() { - @breadcrumb.List() { - @breadcrumb.Item() { - @breadcrumb.Page() { - { title } - } - } - } - } + @breadcrumbContent
{{ user := ctxkeys.User(ctx) }} @@ -107,6 +105,18 @@ templ App(title string, sidebarContent ...templ.Component) { } } +templ defaultBreadcrumb(title string) { + @breadcrumb.Breadcrumb() { + @breadcrumb.List() { + @breadcrumb.Item() { + @breadcrumb.Page() { + { title } + } + } + } + } +} + templ AppAccountDropdown(user *model.User) { {{ displayName := user.Email }} {{ diff --git a/internal/ui/pages/breadcrumbs.templ b/internal/ui/pages/breadcrumbs.templ new file mode 100644 index 0000000..537268b --- /dev/null +++ b/internal/ui/pages/breadcrumbs.templ @@ -0,0 +1,64 @@ +package pages + +import "git.juancwu.dev/juancwu/budgit/internal/routeurl" +import "git.juancwu.dev/juancwu/budgit/internal/ui/components/breadcrumb" + +templ spaceLeafBreadcrumb(spaceName string) { + @breadcrumb.Breadcrumb() { + @breadcrumb.List() { + @breadcrumb.Item() { + @breadcrumb.Page() { + { spaceName } + } + } + } + } +} + +templ spaceChildBreadcrumb(spaceID, spaceName, leaf string) { + @breadcrumb.Breadcrumb() { + @breadcrumb.List() { + @breadcrumb.Item() { + @breadcrumb.Link(breadcrumb.LinkProps{ + Href: routeurl.URL("page.app.spaces.space.overview", "spaceID", spaceID), + }) { + { spaceName } + } + } + @breadcrumb.Separator() + @breadcrumb.Item() { + @breadcrumb.Page() { + { leaf } + } + } + } + } +} + +templ accountChildBreadcrumb(spaceID, spaceName, accountID, accountName, leaf string) { + @breadcrumb.Breadcrumb() { + @breadcrumb.List() { + @breadcrumb.Item() { + @breadcrumb.Link(breadcrumb.LinkProps{ + Href: routeurl.URL("page.app.spaces.space.overview", "spaceID", spaceID), + }) { + { spaceName } + } + } + @breadcrumb.Separator() + @breadcrumb.Item() { + @breadcrumb.Link(breadcrumb.LinkProps{ + Href: routeurl.URL("page.app.spaces.space.accounts.account.overview", "spaceID", spaceID, "accountID", accountID), + }) { + { accountName } + } + } + @breadcrumb.Separator() + @breadcrumb.Item() { + @breadcrumb.Page() { + { leaf } + } + } + } + } +} diff --git a/internal/ui/pages/space_account.templ b/internal/ui/pages/space_account.templ index d66b5d9..1e5b6e9 100644 --- a/internal/ui/pages/space_account.templ +++ b/internal/ui/pages/space_account.templ @@ -12,6 +12,7 @@ import "git.juancwu.dev/juancwu/budgit/internal/ui/utils" type SpaceAccountPageProps struct { SpaceID string + SpaceName string AccountID string AccountName string AccountBalance decimal.Decimal @@ -27,7 +28,7 @@ templ SpaceAccountPage(props SpaceAccountPageProps) { balanceTextClasses = append(balanceTextClasses, "text-red-600 dark:text-red-400") } }} - @layouts.App("Space Account", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID, props.AccountName)) { + @layouts.AppWithBreadcrumb("Space Account", accountChildBreadcrumb(props.SpaceID, props.SpaceName, props.AccountID, props.AccountName, "Overview"), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID)) {
@card.Card(card.Props{ diff --git a/internal/ui/pages/space_account_settings.templ b/internal/ui/pages/space_account_settings.templ index b10d0ce..c976f3b 100644 --- a/internal/ui/pages/space_account_settings.templ +++ b/internal/ui/pages/space_account_settings.templ @@ -10,17 +10,19 @@ import "git.juancwu.dev/juancwu/budgit/internal/ui/components/icon" type SpaceAccountSettingsPageProps struct { SpaceID string + SpaceName string AccountID string AccountName string UpdateForm forms.UpdateAccountProps } templ SpaceAccountSettingsPage(props SpaceAccountSettingsPageProps) { - @layouts.App( + @layouts.AppWithBreadcrumb( "Account Settings", + accountChildBreadcrumb(props.SpaceID, props.SpaceName, props.AccountID, props.AccountName, "Settings"), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), - spaceAccountSidebarContent(props.SpaceID, props.AccountID, props.AccountName), + spaceAccountSidebarContent(props.SpaceID, props.AccountID), ) {
diff --git a/internal/ui/pages/space_account_transactions.templ b/internal/ui/pages/space_account_transactions.templ index e153e84..7235407 100644 --- a/internal/ui/pages/space_account_transactions.templ +++ b/internal/ui/pages/space_account_transactions.templ @@ -12,6 +12,7 @@ import "git.juancwu.dev/juancwu/budgit/internal/ui/components/pagination" type SpaceAccountTransactionsPageProps struct { SpaceID string + SpaceName string AccountID string AccountName string Transactions []*model.Transaction @@ -22,7 +23,7 @@ type SpaceAccountTransactionsPageProps struct { } templ SpaceAccountTransactionsPage(props SpaceAccountTransactionsPageProps) { - @layouts.App("Transactions", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID, props.AccountName)) { + @layouts.AppWithBreadcrumb("Transactions", accountChildBreadcrumb(props.SpaceID, props.SpaceName, props.AccountID, props.AccountName, "Transactions"), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID)) {
diff --git a/internal/ui/pages/space_create_account.templ b/internal/ui/pages/space_create_account.templ index 1f99537..d439ff7 100644 --- a/internal/ui/pages/space_create_account.templ +++ b/internal/ui/pages/space_create_account.templ @@ -10,7 +10,7 @@ type SpaceCreateAccountPageProps struct { } templ SpaceCreateAccountPage(props SpaceCreateAccountPageProps) { - @layouts.App("Create Account", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) { + @layouts.AppWithBreadcrumb("Create Account", spaceChildBreadcrumb(props.SpaceID, props.SpaceName, "Create Account"), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) {

Create Account

diff --git a/internal/ui/pages/space_create_bill.templ b/internal/ui/pages/space_create_bill.templ index eb3f699..d959aaa 100644 --- a/internal/ui/pages/space_create_bill.templ +++ b/internal/ui/pages/space_create_bill.templ @@ -5,13 +5,14 @@ import "git.juancwu.dev/juancwu/budgit/internal/ui/layouts" type SpaceCreateBillPageProps struct { SpaceID string + SpaceName string AccountID string AccountName string Form forms.CreateBillProps } templ SpaceCreateBillPage(props SpaceCreateBillPageProps) { - @layouts.App("Pay Bills", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID, props.AccountName)) { + @layouts.AppWithBreadcrumb("Pay Bills", accountChildBreadcrumb(props.SpaceID, props.SpaceName, props.AccountID, props.AccountName, "Pay Bills"), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID)) {

Pay Bills

diff --git a/internal/ui/pages/space_create_deposit.templ b/internal/ui/pages/space_create_deposit.templ index 20c4a73..3105e57 100644 --- a/internal/ui/pages/space_create_deposit.templ +++ b/internal/ui/pages/space_create_deposit.templ @@ -5,13 +5,14 @@ import "git.juancwu.dev/juancwu/budgit/internal/ui/layouts" type SpaceCreateDepositPageProps struct { SpaceID string + SpaceName string AccountID string AccountName string Form forms.CreateDepositProps } templ SpaceCreateDepositPage(props SpaceCreateDepositPageProps) { - @layouts.App("Deposit Funds", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID, props.AccountName)) { + @layouts.AppWithBreadcrumb("Deposit Funds", accountChildBreadcrumb(props.SpaceID, props.SpaceName, props.AccountID, props.AccountName, "Deposit Funds"), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID), spaceAccountSidebarContent(props.SpaceID, props.AccountID)) {

Deposit Funds

diff --git a/internal/ui/pages/space_overview.templ b/internal/ui/pages/space_overview.templ index 7c5b5a8..c7a4d52 100644 --- a/internal/ui/pages/space_overview.templ +++ b/internal/ui/pages/space_overview.templ @@ -16,7 +16,7 @@ type SpaceOverviewProps struct { } templ SpaceOverview(props SpaceOverviewProps) { - @layouts.App("Space Overview", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) { + @layouts.AppWithBreadcrumb("Space Overview", spaceLeafBreadcrumb(props.SpaceName), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) {

{ props.SpaceName }

@@ -78,10 +78,10 @@ templ spaceSpecificSidebarContent(spaceID string) { } } -templ spaceAccountSidebarContent(spaceID, accountID, accountName string) { +templ spaceAccountSidebarContent(spaceID, accountID string) { @sidebar.Group() { @sidebar.GroupLabel() { - { accountName } + Account } @sidebar.Menu() { @sidebar.MenuItem() { diff --git a/internal/ui/pages/space_settings.templ b/internal/ui/pages/space_settings.templ index 1b5515d..b78293d 100644 --- a/internal/ui/pages/space_settings.templ +++ b/internal/ui/pages/space_settings.templ @@ -16,7 +16,7 @@ type SpaceSettingsPageProps struct { } templ SpaceSettingsPage(props SpaceSettingsPageProps) { - @layouts.App("Space Settings", spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) { + @layouts.AppWithBreadcrumb("Space Settings", spaceChildBreadcrumb(props.SpaceID, props.SpaceName, "Settings"), spaceOverviewSidebarContent(), spaceSpecificSidebarContent(props.SpaceID)) {

Space Settings