diff --git a/internal/handler/space.go b/internal/handler/space.go index 254f580..030feea 100644 --- a/internal/handler/space.go +++ b/internal/handler/space.go @@ -114,7 +114,14 @@ func (h *SpaceHandler) DashboardPage(w http.ResponseWriter, r *http.Request) { return } - ui.Render(w, r, pages.SpaceOverviewPage(space, lists, tags)) + 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 + } + + ui.Render(w, r, pages.SpaceOverviewPage(space, lists, tags, listsWithItems)) } func (h *SpaceHandler) ListsPage(w http.ResponseWriter, r *http.Request) { @@ -430,6 +437,17 @@ func (h *SpaceHandler) ExpensesPage(w http.ResponseWriter, r *http.Request) { } ui.Render(w, r, pages.SpaceExpensesPage(space, expenses, balance, tags, listsWithItems)) + + if r.URL.Query().Get("created") == "true" { + ui.Render(w, r, toast.Toast(toast.Props{ + Title: "Expense created", + Description: "Your transaction has been recorded.", + Variant: toast.VariantSuccess, + Icon: true, + Dismissible: true, + Duration: 5000, + })) + } } func (h *SpaceHandler) CreateExpense(w http.ResponseWriter, r *http.Request) { @@ -558,6 +576,12 @@ func (h *SpaceHandler) CreateExpense(w http.ResponseWriter, r *http.Request) { slog.Error("failed to get balance", "error", err, "space_id", spaceID) } + if r.URL.Query().Get("from") == "overview" { + w.Header().Set("HX-Redirect", "/app/spaces/"+spaceID+"/expenses?created=true") + w.WriteHeader(http.StatusOK) + return + } + ui.Render(w, r, pages.ExpenseCreatedResponse(newExpense, balance)) } diff --git a/internal/ui/components/expense/expense.templ b/internal/ui/components/expense/expense.templ index 0cf2e7e..2f521f8 100644 --- a/internal/ui/components/expense/expense.templ +++ b/internal/ui/components/expense/expense.templ @@ -15,13 +15,36 @@ import ( "git.juancwu.dev/juancwu/budgit/internal/ui/components/tagsinput" ) -templ AddExpenseForm(space *model.Space, tags []*model.Tag, listsWithItems []model.ListWithUncheckedItems) { +type AddExpenseFormProps struct { + Space *model.Space + Tags []*model.Tag + ListsWithItems []model.ListWithUncheckedItems + 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 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", + "hx-swap": "afterbegin", + "_": closeScript, + } +} + +templ AddExpenseForm(props AddExpenseFormProps) {