package server import ( "encoding/json" "fmt" "net/http" "strconv" "time" "github.com/gin-gonic/gin" domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" domain "github.com/haydenhargreaves/Potion/internal/domain/server" "github.com/haydenhargreaves/Potion/internal/templates/components" templates "github.com/haydenhargreaves/Potion/internal/templates/pages" ) const CREATE_ERROR_HTML = `

Uh oh! Something went wrong when creating your recipe. Please try again. %s

` func (s *Server) CreateRecipeHandler(ctx *gin.Context) { recipe, err := s.deps.RecipeService.CreateRecipe(ctx) if err != nil { components.RenderErrorBanner(ctx, err.Error()) ctx.String(http.StatusOK, CREATE_ERROR_HTML, err.Error()) return } // Send HTMX redirection url := fmt.Sprintf(domain.WEB_RECIPE, recipe.Id) ctx.Header("HX-Redirect", url) ctx.Status(http.StatusCreated) } // toBits converts an array of stringified numbers into a single summed value func toBits(arr []string) (bits int) { for _, x := range arr { num, _ := strconv.Atoi(x) bits += num } return } // TODO: (7/06/2025) I don't love doing all of this here, but it seems to be the only way to get it to work... func (s *Server) SearchRecipesHandler(ctx *gin.Context) { // create filters filters := domainRecipe.SearchFilters{ Search: ctx.PostForm("search"), // string, search query for titles MealType: toBits(ctx.PostFormArray("meal")), Time: toBits(ctx.PostFormArray("time")), Difficulty: toBits(ctx.PostFormArray("difficulty")), ServingSize: toBits(ctx.PostFormArray("serving")), } // Set the filters into the cookies, so they can be reloaded if bytes, err := json.Marshal(filters); err == nil { s.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24) } redirect := ctx.PostForm("redirect") if redirect == "true" { ctx.Header("HX-Redirect", domain.WEB_SEARCH) ctx.Status(http.StatusOK) return } // Get user if logged in, so we can get favorite status var userId *int = nil if domain.IsLoggedIn(ctx) { id := ctx.MustGet("userId").(int) userId = &id } // TODO: Not sure if we need to ensure the user is valid here // We don't care about favorite status, so use false recipes, err := s.deps.RecipeService.SearchRecipes(filters, userId, false) if err != nil { components.RenderErrorBanner(ctx, err.Error()) ctx.JSON(http.StatusOK, gin.H{"error": err.Error()}) } // Render content as the response ctx.Status(200) templates.ResultList(recipes).Render(ctx.Request.Context(), ctx.Writer) } func (s *Server) SearchRecipesFavoritesHandler(ctx *gin.Context) { // create filters filters := domainRecipe.SearchFilters{ Search: ctx.PostForm("search"), // string, search query for titles MealType: toBits(ctx.PostFormArray("meal")), Time: toBits(ctx.PostFormArray("time")), Difficulty: toBits(ctx.PostFormArray("difficulty")), ServingSize: toBits(ctx.PostFormArray("serving")), } // Set the filters into the cookies, so they can be reloaded if bytes, err := json.Marshal(filters); err == nil { s.SetCookie(ctx, "search-filters", string(bytes), time.Hour*24) } if !domain.IsLoggedIn(ctx) { components.RenderErrorBanner(ctx, "User is not logged in. User will be nil.") ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."}) } userId := ctx.MustGet("userId").(int) recipes, err := s.deps.RecipeService.SearchRecipes(filters, &userId, true) if err != nil { components.RenderErrorBanner(ctx, err.Error()) ctx.JSON(http.StatusOK, gin.H{"error": err.Error()}) } // Render content as the response ctx.Status(200) templates.FavoriteList(recipes).Render(ctx.Request.Context(), ctx.Writer) }