From a7d5f21fe834c78d4851f73d5d0f172bfecf4779 Mon Sep 17 00:00:00 2001 From: juancwu Date: Sun, 15 Feb 2026 23:00:58 +0000 Subject: [PATCH] feat: replace overview with reports page --- internal/handler/space.go | 64 ++-------- internal/routes/routes.go | 4 - internal/ui/components/expense/expense.templ | 9 -- internal/ui/layouts/space.templ | 16 +-- internal/ui/pages/app_space_overview.templ | 119 ------------------- 5 files changed, 12 insertions(+), 200 deletions(-) delete mode 100644 internal/ui/pages/app_space_overview.templ diff --git a/internal/handler/space.go b/internal/handler/space.go index bd28c68..f2b21c7 100644 --- a/internal/handler/space.go +++ b/internal/handler/space.go @@ -97,40 +97,24 @@ func (h *SpaceHandler) DashboardPage(w http.ResponseWriter, r *http.Request) { space, err := h.spaceService.GetSpace(spaceID) if err != nil { slog.Error("failed to get space", "error", err, "space_id", spaceID) - // The RequireSpaceAccess middleware should prevent this, but as a fallback. http.Error(w, "Space not found.", http.StatusNotFound) return } - lists, err := h.listService.GetListsForSpace(spaceID) + // Default to this month + now := time.Now() + presets := service.GetPresetDateRanges(now) + from := presets[0].From + to := presets[0].To + + report, err := h.reportService.GetSpendingReport(spaceID, from, to) if err != nil { - slog.Error("failed to get shopping lists for space", "error", err, "space_id", spaceID) + slog.Error("failed to get spending report", "error", err, "space_id", spaceID) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } - tags, err := h.tagService.GetTagsForSpace(spaceID) - if err != nil { - slog.Error("failed to get tags for space", "error", err, "space_id", spaceID) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - listsWithItems, err := h.listService.GetListsWithUncheckedItems(spaceID) - if err != nil { - slog.Error("failed to get lists with unchecked items", "error", err, "space_id", spaceID) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - accounts, err := h.accountService.GetAccountsForSpace(spaceID) - if err != nil { - slog.Error("failed to get accounts for space", "error", err, "space_id", spaceID) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - ui.Render(w, r, pages.SpaceOverviewPage(space, lists, tags, listsWithItems, accounts)) + ui.Render(w, r, pages.SpaceReportsPage(space, report, presets, "this_month")) } func (h *SpaceHandler) ListsPage(w http.ResponseWriter, r *http.Request) { @@ -644,12 +628,6 @@ func (h *SpaceHandler) CreateExpense(w http.ResponseWriter, r *http.Request) { } balance -= totalAllocated - if r.URL.Query().Get("from") == "overview" { - w.Header().Set("HX-Redirect", "/app/spaces/"+spaceID+"/expenses?created=true") - w.WriteHeader(http.StatusOK) - return - } - // Return the full paginated list for page 1 so the new expense appears expenses, totalPages, err := h.expenseService.GetExpensesWithTagsAndMethodsForSpacePaginated(spaceID, 1) if err != nil { @@ -2127,30 +2105,6 @@ func (h *SpaceHandler) GetBudgetsList(w http.ResponseWriter, r *http.Request) { // --- Reports --- -func (h *SpaceHandler) ReportsPage(w http.ResponseWriter, r *http.Request) { - spaceID := r.PathValue("spaceID") - space, err := h.spaceService.GetSpace(spaceID) - if err != nil { - http.Error(w, "Space not found", http.StatusNotFound) - return - } - - // Default to this month - now := time.Now() - presets := service.GetPresetDateRanges(now) - from := presets[0].From - to := presets[0].To - - report, err := h.reportService.GetSpendingReport(spaceID, from, to) - if err != nil { - slog.Error("failed to get spending report", "error", err, "space_id", spaceID) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - - ui.Render(w, r, pages.SpaceReportsPage(space, report, presets, "this_month")) -} - func (h *SpaceHandler) GetReportCharts(w http.ResponseWriter, r *http.Request) { spaceID := r.PathValue("spaceID") diff --git a/internal/routes/routes.go b/internal/routes/routes.go index 1b719d7..90bf910 100644 --- a/internal/routes/routes.go +++ b/internal/routes/routes.go @@ -212,10 +212,6 @@ func SetupRoutes(a *app.App) http.Handler { mux.Handle("GET /app/spaces/{spaceID}/components/budgets", budgetsListWithAccess) // Report routes - reportsPageHandler := middleware.RequireAuth(space.ReportsPage) - reportsPageWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(reportsPageHandler) - mux.Handle("GET /app/spaces/{spaceID}/reports", reportsPageWithAccess) - reportChartsHandler := middleware.RequireAuth(space.GetReportCharts) reportChartsWithAccess := middleware.RequireSpaceAccess(a.SpaceService)(reportChartsHandler) mux.Handle("GET /app/spaces/{spaceID}/components/report-charts", reportChartsWithAccess) diff --git a/internal/ui/components/expense/expense.templ b/internal/ui/components/expense/expense.templ index 74889d8..c5f9e80 100644 --- a/internal/ui/components/expense/expense.templ +++ b/internal/ui/components/expense/expense.templ @@ -22,19 +22,10 @@ type AddExpenseFormProps struct { ListsWithItems []model.ListWithUncheckedItems PaymentMethods []*model.PaymentMethod DialogID string // which dialog to close on success - FromOverview bool // if true, POSTs with ?from=overview; server redirects to expenses page } func (p AddExpenseFormProps) formAttrs() templ.Attributes { closeScript := "on htmx:afterOnLoad if event.detail.xhr.status == 200 then call window.tui.dialog.close('" + p.DialogID + "') then reset() me then show #item-selector-section end" - if p.FromOverview { - return templ.Attributes{ - "hx-post": "/app/spaces/" + p.Space.ID + "/expenses?from=overview", - "hx-target": "body", - "hx-swap": "beforeend", - "_": closeScript, - } - } return templ.Attributes{ "hx-post": "/app/spaces/" + p.Space.ID + "/expenses", "hx-target": "#expenses-list-wrapper", diff --git a/internal/ui/layouts/space.templ b/internal/ui/layouts/space.templ index e20fc4f..26c82e9 100644 --- a/internal/ui/layouts/space.templ +++ b/internal/ui/layouts/space.templ @@ -44,10 +44,10 @@ templ Space(title string, space *model.Space) { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: "/app/spaces/" + space.ID, IsActive: ctxkeys.URLPath(ctx) == "/app/spaces/"+space.ID, - Tooltip: "Space Dashboard", + Tooltip: "Reports", }) { - @icon.House(icon.Props{Class: "size-4"}) - Overview + @icon.ChartPie(icon.Props{Class: "size-4"}) + Reports } } @sidebar.MenuItem() { @@ -80,16 +80,6 @@ templ Space(title string, space *model.Space) { Budgets } } - @sidebar.MenuItem() { - @sidebar.MenuButton(sidebar.MenuButtonProps{ - Href: "/app/spaces/" + space.ID + "/reports", - IsActive: ctxkeys.URLPath(ctx) == "/app/spaces/"+space.ID+"/reports", - Tooltip: "Reports", - }) { - @icon.ChartPie(icon.Props{Class: "size-4"}) - Reports - } - } @sidebar.MenuItem() { @sidebar.MenuButton(sidebar.MenuButtonProps{ Href: "/app/spaces/" + space.ID + "/accounts", diff --git a/internal/ui/pages/app_space_overview.templ b/internal/ui/pages/app_space_overview.templ deleted file mode 100644 index 256c5a4..0000000 --- a/internal/ui/pages/app_space_overview.templ +++ /dev/null @@ -1,119 +0,0 @@ -package pages - -import ( - "fmt" - "git.juancwu.dev/juancwu/budgit/internal/model" - "git.juancwu.dev/juancwu/budgit/internal/ui/components/badge" - "git.juancwu.dev/juancwu/budgit/internal/ui/components/button" - "git.juancwu.dev/juancwu/budgit/internal/ui/components/dialog" - "git.juancwu.dev/juancwu/budgit/internal/ui/components/expense" - "git.juancwu.dev/juancwu/budgit/internal/ui/layouts" -) - -templ SpaceOverviewPage(space *model.Space, lists []*model.ShoppingList, tags []*model.Tag, listsWithItems []model.ListWithUncheckedItems, accounts []model.MoneyAccountWithBalance) { - @layouts.Space("Overview", space) { -
-
-

Welcome to { space.Name }!

- @dialog.Dialog(dialog.Props{ID: "add-expense-overview-dialog"}) { - @dialog.Trigger() { - @button.Button() { - Add Expense - } - } - @dialog.Content() { - @dialog.Header() { - @dialog.Title() { - Add Transaction - } - @dialog.Description() { - Add a new expense or top-up to your space. - } - } - @expense.AddExpenseForm(expense.AddExpenseFormProps{ - Space: space, - Tags: tags, - ListsWithItems: listsWithItems, - DialogID: "add-expense-overview-dialog", - FromOverview: true, - }) - } - } -
-
- // Shopping Lists section -
-

Shopping Lists

- if len(lists) > 0 { - - - View all shopping lists - - } else { -

No shopping lists yet.

- } -
- // Tags section -
-

Tags

- if len(tags) > 0 { -
- for _, tag := range tags { - @badge.Badge(badge.Props{Variant: badge.VariantSecondary}) { - { tag.Name } - } - } -
- } else { -

No tags yet.

- } -
- // Money Accounts section -
-

Money Accounts

- if len(accounts) > 0 { - - - View all accounts - - } else { -

No accounts yet.

- } -
-
-
- } -}