diff --git a/internal/router/filters.go b/internal/router/filters.go index 343a2a7..72e2fa4 100644 --- a/internal/router/filters.go +++ b/internal/router/filters.go @@ -1,5 +1,18 @@ package router +import ( + "bookhoard/internal/database" + "bookhoard/templates" + "bytes" + "encoding/json" + "net/http" + "strings" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5/pgtype" + "github.com/labstack/echo/v5" +) + func registerFiltersRoutes(cfg *Config) { e := cfg.Echo @@ -11,7 +24,118 @@ func registerFiltersRoutes(cfg *Config) { filters := protected.Group("/saved-filters") filters.GET("", cfg.FiltersHandler.GetSavedFilters) filters.GET("/:id", cfg.FiltersHandler.GetSavedFilterByID) - filters.POST("", cfg.FiltersHandler.CreateSavedFilter) + // POST route with HTMX support + filters.POST("", func(c *echo.Context) error { + // Check if HTMX request (expects HTML) + if c.Request().Header.Get("HX-Request") == "true" { + return handleCreateFilterHTML(c, cfg) + } + // Otherwise return JSON (API clients) + return cfg.FiltersHandler.CreateSavedFilter(c) + }) filters.PUT("/:id", cfg.FiltersHandler.UpdateSavedFilter) filters.DELETE("/:id", cfg.FiltersHandler.DeleteSavedFilter) } + +// handleCreateFilterHTML renders HTML response for HTMX requests +func handleCreateFilterHTML(c *echo.Context, cfg *Config) error { + user, ok := c.Get("user").(database.Users) + if !ok { + return c.String(http.StatusUnauthorized, "Unauthorized") + } + userUUID := uuid.UUID(user.ID.Bytes) + // Parse form data + var req struct { + Name string `form:"filter_name"` + ResourceType string `form:"resource_type"` + } + + if err := c.Bind(&req); err != nil { + return c.String(http.StatusBadRequest, "Invalid request body") + } + if req.Name == "" || req.ResourceType == "" { + return c.String(http.StatusBadRequest, "name and resource_type are required") + } + // Collect filter data from individual form fields (via hx-include) + filtersMap := collectFilterFormData(c) + // Convert to JSON for database storage + filtersJSON, err := json.Marshal(filtersMap) + if err != nil { + return c.String(http.StatusInternalServerError, "Failed to encode filters") + } + // Create filter using service layer + filter, err := cfg.Queries.CreateSavedFilter(c.Request().Context(), database.CreateSavedFilterParams{ + UserID: pgtype.UUID{Bytes: userUUID, Valid: true}, + Name: req.Name, + ResourceType: req.ResourceType, + Filters: filtersJSON, + }) + if err != nil { + errorMsg := err.Error() + // Check for duplicate name error (wrapped or unwrapped) + if strings.Contains(errorMsg, "filter with name") && strings.Contains(errorMsg, "already exists") { + if c.Request().Header.Get("HX-Request") == "true" { + return c.HTML(http.StatusConflict, `