diff --git a/internal/app/handlers/page_handler.go b/internal/app/handlers/page_handler.go index 82d3d62..a01402b 100644 --- a/internal/app/handlers/page_handler.go +++ b/internal/app/handlers/page_handler.go @@ -1,12 +1,15 @@ package handlers import ( + "encoding/json" "fmt" "net/http" "strconv" + "github.com/a-h/templ" "github.com/gin-gonic/gin" - domain "github.com/haydenhargreaves/Potion/internal/domain/server" + domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" + domainServer "github.com/haydenhargreaves/Potion/internal/domain/server" layouts "github.com/haydenhargreaves/Potion/internal/templates/layouts" pages "github.com/haydenhargreaves/Potion/internal/templates/pages" ) @@ -34,8 +37,8 @@ func FavoritesPage(ctx *gin.Context) { func CreatePage(ctx *gin.Context) { // If not logged in, direct to the login page - if !domain.IsLoggedIn(ctx) { - ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN) + if !domainServer.IsLoggedIn(ctx) { + ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN) return } @@ -47,13 +50,13 @@ func CreatePage(ctx *gin.Context) { func ProfilePage(ctx *gin.Context) { // If not logged in, direct to the login page - if !domain.IsLoggedIn(ctx) { - ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN) + if !domainServer.IsLoggedIn(ctx) { + ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN) return } // Else, get the user data - deps := ctx.MustGet("deps").(*domain.InjectedDependencies) + deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies) user := deps.UserService.GetAuthenicatedUser(ctx) title := "Potion - Profile" @@ -72,7 +75,7 @@ func ListPage(ctx *gin.Context) { // TODO: Figure out how to handle errors, think we just need a simple display. func RecipePage(ctx *gin.Context) { // Call recipe service to get via ID - deps := ctx.MustGet("deps").(*domain.InjectedDependencies) + deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies) id := ctx.Param("id") // Parse ID @@ -106,10 +109,22 @@ func RecipePage(ctx *gin.Context) { } func SearchPage(ctx *gin.Context) { - title := "Potion - Recipe Search" - page := pages.SearchPage() + var page templ.Component + // Get filters from cookies + if bytes, err := ctx.Cookie("search-filters"); err != nil { + fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error()) + page = pages.SearchPage(domainRecipe.SearchFilters{}) + } else { + var filters domainRecipe.SearchFilters + if err := json.Unmarshal([]byte(bytes), &filters); err != nil { + fmt.Printf("ERROR: Failed to unmarshal search-filter cookie. %s\n", err.Error()) + page = pages.SearchPage(domainRecipe.SearchFilters{}) + } else { + page = pages.SearchPage(filters) + } + } - fmt.Println("I OPENED A PAGE!") + title := "Potion - Recipe Search" ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page)) } diff --git a/internal/app/handlers/recipe_handler.go b/internal/app/handlers/recipe_handler.go index 2490927..8e7b8bc 100644 --- a/internal/app/handlers/recipe_handler.go +++ b/internal/app/handlers/recipe_handler.go @@ -1,10 +1,14 @@ 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" ) @@ -30,10 +34,42 @@ func CreateRecipe(ctx *gin.Context) { 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) - recipes, err := deps.RecipeService.SearchRecipes(ctx) + // 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(2*time.Hour).Sub(time.Now()).Seconds()), + "/", + "localhost", // TODO: real domain + false, // TODO: True in prod + true, + ) + } + + recipes, err := deps.RecipeService.SearchRecipes(filters) if err != nil { ctx.JSON(http.StatusOK, gin.H{"error": err.Error()}) } diff --git a/internal/app/service/recipe_service.go b/internal/app/service/recipe_service.go index 4057218..f298043 100644 --- a/internal/app/service/recipe_service.go +++ b/internal/app/service/recipe_service.go @@ -130,21 +130,7 @@ func (s *RecipeService) GetRecipe(id int) (*domain.Recipe, error) { return recipe, err } -// 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 -} - -// isBitActive returns true when the bit at pos (0 indexed) is true. -func isBitActive(bits, pos int) bool { - return (bits>>pos)&1 == 1 -} - -func (s *RecipeService) SearchRecipes(ctx *gin.Context) ([]domain.Recipe, error) { +func (s *RecipeService) SearchRecipes(filters domain.SearchFilters) ([]domain.Recipe, error) { // NOTE: How are the filters handled? // Each input is given a bit value (e.g., 00001 for 1) and will be passed // back to this handler as an array. The values are then added together @@ -154,22 +140,8 @@ func (s *RecipeService) SearchRecipes(ctx *gin.Context) ([]domain.Recipe, error) // Parsing these is simple, for each filter option, use the bitwise and (&) // operator with the value we expect for the filter. When 1, we can ensure // the filter is provided. - // A function above (isBitActive) provides an example of testing of testing - // the filter parsing. - - search := ctx.PostForm("search") // string, search query for titles - meal := toBits(ctx.PostFormArray("meal")) - time := toBits(ctx.PostFormArray("time")) - difficulty := toBits(ctx.PostFormArray("difficulty")) - serving := toBits(ctx.PostFormArray("serving")) - - filters := domain.SearchFilters{ - Search: search, - MealType: meal, - Time: time, - Difficulty: difficulty, - ServingSize: serving, - } + // A function `isBitActive` in the recipe repository provides an example of + // testing of testing the filter parsing. return s.recipeRepository.SearchRecipes(filters) } diff --git a/internal/domain/recipe/service.go b/internal/domain/recipe/service.go index 558f63f..cf6723e 100644 --- a/internal/domain/recipe/service.go +++ b/internal/domain/recipe/service.go @@ -5,5 +5,5 @@ import "github.com/gin-gonic/gin" type RecipeService interface { CreateRecipe(ctx *gin.Context) (*Recipe, error) GetRecipe(id int) (*Recipe, error) - SearchRecipes(ctx *gin.Context) ([]Recipe, error) + SearchRecipes(filters SearchFilters) ([]Recipe, error) } diff --git a/internal/templates/components/dropdowns.templ b/internal/templates/components/dropdowns.templ index 43f858d..34e71ae 100644 --- a/internal/templates/components/dropdowns.templ +++ b/internal/templates/components/dropdowns.templ @@ -1,8 +1,21 @@ package components -templ dropdownButton(content, name, value string) { +import "fmt" +import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" + +// isBitActive returns true when the bit at pos (0 indexed) is true. +func isBitActive(bits, pos int) bool { +x := (bits>>pos)&1 == 1 +fmt.Printf("BITS: %d, POS: %d, VAL: %v\n", bits, pos, x) +return x +} + +templ dropdownButton(content, name, value string, selected bool) { } -templ FilterDropdown() { +templ FilterDropdown(filters domainRecipe.SearchFilters) {
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/templates/components/search_bar.templ b/internal/templates/components/search_bar.templ index 7d1f0f0..93f5354 100644 --- a/internal/templates/components/search_bar.templ +++ b/internal/templates/components/search_bar.templ @@ -1,23 +1,24 @@ package components -import "github.com/haydenhargreaves/Potion/internal/domain/server" +import domainServer "github.com/haydenhargreaves/Potion/internal/domain/server" +import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" -templ SearchBar() { +templ SearchBar(filters domainRecipe.SearchFilters) { } diff --git a/internal/templates/components/search_bar_templ.go b/internal/templates/components/search_bar_templ.go index 550e295..43125b9 100644 --- a/internal/templates/components/search_bar_templ.go +++ b/internal/templates/components/search_bar_templ.go @@ -8,9 +8,10 @@ package components import "github.com/a-h/templ" import templruntime "github.com/a-h/templ/runtime" -import "github.com/haydenhargreaves/Potion/internal/domain/server" +import domainServer "github.com/haydenhargreaves/Potion/internal/domain/server" +import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" -func SearchBar() templ.Component { +func SearchBar(filters domainRecipe.SearchFilters) templ.Component { return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { @@ -36,15 +37,28 @@ func SearchBar() templ.Component { return templ_7745c5c3_Err } var templ_7745c5c3_Var2 string - templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(domain.API_SEARCH_RECIPES) + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(domainServer.API_SEARCH_RECIPES) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/search_bar.templ`, Line: 7, Col: 37} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/components/search_bar.templ`, Line: 8, Col: 43} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\" hx-swap=\"innerHTML\" hx-target=\"#result-list\" hx-trigger=\"submit\" hx-encoding=\"multipart/form-data\" class=\"w-full px-4 my-8\">No results
- } else { -End of results
- } + for i, recipe := range recipes { + @searchResult(recipe, i%2 == 1) + } + if len(recipes) == 0 || recipes == nil { +No results
+ } else { +End of results
+ }