fix: migrate dashboard to space handler & rm dashboard handler
This commit is contained in:
parent
2f1a7154e4
commit
d6b9eb9c59
4 changed files with 38 additions and 132 deletions
|
|
@ -1,59 +0,0 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ctxkeys"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/service"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ui/pages"
|
||||
)
|
||||
|
||||
type dashboardHandler struct {
|
||||
spaceService *service.SpaceService
|
||||
expenseService *service.ExpenseService
|
||||
}
|
||||
|
||||
func NewDashboardHandler(ss *service.SpaceService, es *service.ExpenseService) *dashboardHandler {
|
||||
return &dashboardHandler{
|
||||
spaceService: ss,
|
||||
expenseService: es,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *dashboardHandler) DashboardPage(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctxkeys.User(r.Context())
|
||||
spaces, err := h.spaceService.GetSpacesForUser(user.ID)
|
||||
if err != nil {
|
||||
slog.Error("failed to get spaces for user", "error", err, "user_id", user.ID)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
ui.Render(w, r, pages.Dashboard(spaces))
|
||||
}
|
||||
|
||||
func (h *dashboardHandler) CreateSpace(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctxkeys.User(r.Context())
|
||||
|
||||
name := strings.TrimSpace(r.FormValue("name"))
|
||||
if name == "" {
|
||||
w.Header().Set("HX-Reswap", "none")
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
fmt.Fprint(w, `<p id="create-space-error" hx-swap-oob="true" class="text-sm text-destructive">Space name is required</p>`)
|
||||
return
|
||||
}
|
||||
|
||||
space, err := h.spaceService.CreateSpace(name, user.ID)
|
||||
if err != nil {
|
||||
slog.Error("failed to create space", "error", err, "user_id", user.ID)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("HX-Redirect", "/app/spaces/"+space.ID)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.juancwu.dev/juancwu/budgit/internal/repository"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/service"
|
||||
"git.juancwu.dev/juancwu/budgit/internal/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDashboardHandler_DashboardPage(t *testing.T) {
|
||||
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
|
||||
spaceRepo := repository.NewSpaceRepository(dbi.DB)
|
||||
expenseRepo := repository.NewExpenseRepository(dbi.DB)
|
||||
spaceSvc := service.NewSpaceService(spaceRepo)
|
||||
expenseSvc := service.NewExpenseService(expenseRepo)
|
||||
h := NewDashboardHandler(spaceSvc, expenseSvc)
|
||||
|
||||
user, profile := testutil.CreateTestUserWithProfile(t, dbi.DB, "test@example.com", "Test User")
|
||||
testutil.CreateTestSpace(t, dbi.DB, user.ID, "My Space")
|
||||
|
||||
req := testutil.NewAuthenticatedRequest(t, http.MethodGet, "/app/dashboard", user, profile, nil)
|
||||
w := httptest.NewRecorder()
|
||||
h.DashboardPage(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDashboardHandler_CreateSpace(t *testing.T) {
|
||||
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
|
||||
spaceRepo := repository.NewSpaceRepository(dbi.DB)
|
||||
expenseRepo := repository.NewExpenseRepository(dbi.DB)
|
||||
spaceSvc := service.NewSpaceService(spaceRepo)
|
||||
expenseSvc := service.NewExpenseService(expenseRepo)
|
||||
h := NewDashboardHandler(spaceSvc, expenseSvc)
|
||||
|
||||
user, profile := testutil.CreateTestUserWithProfile(t, dbi.DB, "test@example.com", "Test User")
|
||||
|
||||
req := testutil.NewAuthenticatedRequest(t, http.MethodPost, "/app/dashboard/spaces", user, profile, url.Values{"name": {"New Space"}})
|
||||
w := httptest.NewRecorder()
|
||||
h.CreateSpace(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.True(t, strings.HasPrefix(w.Header().Get("HX-Redirect"), "/app/spaces/"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestDashboardHandler_CreateSpace_EmptyName(t *testing.T) {
|
||||
testutil.ForEachDB(t, func(t *testing.T, dbi testutil.DBInfo) {
|
||||
spaceRepo := repository.NewSpaceRepository(dbi.DB)
|
||||
expenseRepo := repository.NewExpenseRepository(dbi.DB)
|
||||
spaceSvc := service.NewSpaceService(spaceRepo)
|
||||
expenseSvc := service.NewExpenseService(expenseRepo)
|
||||
h := NewDashboardHandler(spaceSvc, expenseSvc)
|
||||
|
||||
user, profile := testutil.CreateTestUserWithProfile(t, dbi.DB, "test@example.com", "Test User")
|
||||
|
||||
req := testutil.NewAuthenticatedRequest(t, http.MethodPost, "/app/dashboard/spaces", user, profile, url.Values{"name": {""}})
|
||||
w := httptest.NewRecorder()
|
||||
h.CreateSpace(w, req)
|
||||
|
||||
assert.Equal(t, http.StatusUnprocessableEntity, w.Code)
|
||||
})
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.juancwu.dev/juancwu/budgit/internal/ctxkeys"
|
||||
|
|
@ -49,6 +50,40 @@ func NewSpaceHandler(ss *service.SpaceService, ts *service.TagService, sls *serv
|
|||
}
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) DashboardPage(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctxkeys.User(r.Context())
|
||||
spaces, err := h.spaceService.GetSpacesForUser(user.ID)
|
||||
if err != nil {
|
||||
slog.Error("failed to get spaces for user", "error", err, "user_id", user.ID)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
ui.Render(w, r, pages.Dashboard(spaces))
|
||||
}
|
||||
|
||||
func (h *SpaceHandler) CreateSpace(w http.ResponseWriter, r *http.Request) {
|
||||
user := ctxkeys.User(r.Context())
|
||||
|
||||
name := strings.TrimSpace(r.FormValue("name"))
|
||||
if name == "" {
|
||||
w.Header().Set("HX-Reswap", "none")
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
fmt.Fprint(w, `<p id="create-space-error" hx-swap-oob="true" class="text-sm text-destructive">Space name is required</p>`)
|
||||
return
|
||||
}
|
||||
|
||||
space, err := h.spaceService.CreateSpace(name, user.ID)
|
||||
if err != nil {
|
||||
slog.Error("failed to create space", "error", err, "user_id", user.ID)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("HX-Redirect", "/app/spaces/"+space.ID)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
// getExpenseForSpace fetches an expense and verifies it belongs to the given space.
|
||||
func (h *SpaceHandler) getExpenseForSpace(w http.ResponseWriter, spaceID, expenseID string) *model.Expense {
|
||||
exp, err := h.expenseService.GetExpense(expenseID)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
func SetupRoutes(a *app.App) http.Handler {
|
||||
auth := handler.NewAuthHandler(a.AuthService, a.InviteService, a.SpaceService)
|
||||
home := handler.NewHomeHandler()
|
||||
dashboard := handler.NewDashboardHandler(a.SpaceService, a.ExpenseService)
|
||||
settings := handler.NewSettingsHandler(a.AuthService, a.UserService)
|
||||
space := handler.NewSpaceHandler(a.SpaceService, a.TagService, a.ShoppingListService, a.ExpenseService, a.InviteService, a.MoneyAccountService, a.PaymentMethodService, a.RecurringExpenseService, a.BudgetService, a.ReportService)
|
||||
|
||||
|
|
@ -55,8 +54,9 @@ func SetupRoutes(a *app.App) http.Handler {
|
|||
mux.HandleFunc("GET /auth/onboarding", middleware.RequireAuth(auth.OnboardingPage))
|
||||
mux.Handle("POST /auth/onboarding", crudLimiter(http.HandlerFunc(middleware.RequireAuth(auth.CompleteOnboarding))))
|
||||
|
||||
mux.HandleFunc("GET /app/dashboard", middleware.RequireAuth(dashboard.DashboardPage))
|
||||
mux.Handle("POST /app/spaces", crudLimiter(http.HandlerFunc(middleware.RequireAuth(dashboard.CreateSpace))))
|
||||
mux.HandleFunc("GET /app/dashboard", middleware.Redirect("/app/spaces"))
|
||||
mux.HandleFunc("GET /app/spaces", middleware.RequireAuth(space.DashboardPage))
|
||||
mux.Handle("POST /app/spaces", crudLimiter(middleware.RequireAuth(space.CreateSpace)))
|
||||
mux.HandleFunc("GET /app/settings", middleware.RequireAuth(settings.SettingsPage))
|
||||
mux.HandleFunc("POST /app/settings/password", authRateLimiter(middleware.RequireAuth(settings.SetPassword)))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue