Potion/internal/app/handlers/recipe_handler.go
Hayden Hargreaves 65c73bddfa (FIX): Working on finding all of the nil-deref errors.
This may have caught a few. Next I need to actually work on the
development/testing/production environment setup.
2025-07-22 21:37:47 -07:00

139 lines
3.9 KiB
Go

package handlers
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"
templates "github.com/haydenhargreaves/Potion/internal/templates/pages"
)
const CREATE_ERROR_HTML = `
<p id="response" class="text-sm text-red-500 px-4 py-1 bg-red-100 rounded-full w-fit">
Uh oh! Something went wrong when creating your recipe. Please try again. %s
</p>
`
func CreateRecipe(ctx *gin.Context) {
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
recipe, err := deps.RecipeService.CreateRecipe(ctx)
if err != nil {
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: I don't love doing all of this here, but it seems to be the only way to get it to work...
func SearchRecipes(ctx *gin.Context) {
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
// 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 {
ctx.SetCookie(
"search-filters",
string(bytes),
int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
"/",
"", // TODO: Need an actual domain
false, // TODO: True in prod
true,
)
}
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
}
// We don't care about favorite status, so use false
recipes, err := deps.RecipeService.SearchRecipes(filters, userId, false)
if err != nil {
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 SearchRecipesFavorites(ctx *gin.Context) {
deps := ctx.MustGet("deps").(*domain.InjectedDependencies)
// 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 {
ctx.SetCookie(
"search-filters",
string(bytes),
int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()),
"/",
"", // TODO: Need an actual domain
false, // TODO: True in prod
true,
)
}
// TODO: Error here if they're not logged in?
// Get user data (they should be logged in)
if !domain.IsLoggedIn(ctx) {
ctx.JSON(http.StatusOK, gin.H{"error": "User is not logged in. User will be nil."})
}
userId := ctx.MustGet("userId").(int)
recipes, err := deps.RecipeService.SearchRecipes(filters, &userId, true)
if err != nil {
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)
}