diff --git a/internal/app/handlers/page_handler.go b/internal/app/handlers/page_handler.go index 512d537..26c43a3 100644 --- a/internal/app/handlers/page_handler.go +++ b/internal/app/handlers/page_handler.go @@ -29,8 +29,41 @@ func HomePage(ctx *gin.Context) { } func FavoritesPage(ctx *gin.Context) { + // If not logged in, direct to the login page + if !domainServer.IsLoggedIn(ctx) { + ctx.Redirect(http.StatusSeeOther, domainServer.WEB_LOGIN) + return + } + title := "Potion - Favorites" - page := pages.FavoritesPage() + 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.FavoritesPage(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.FavoritesPage(domainRecipe.SearchFilters{}) + } else { + page = pages.FavoritesPage(filters) + } + } + + // Else, get the user's favorites + // BUG: Depreciated, not displaying a list, using search to drive this page as well + // deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies) + // userId := ctx.MustGet("userId").(int) + // recipes, err := deps.RecipeService.GetUserFavoriteRecipes(userId) + // if err != nil { + // ctx.JSON(http.StatusInternalServerError, gin.H{ + // "status": http.StatusInternalServerError, + // "message": fmt.Sprintf("Error getting favorites. %s\n", err.Error()), + // }) + // return + // } 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 a256307..b245a77 100644 --- a/internal/app/handlers/recipe_handler.go +++ b/internal/app/handlers/recipe_handler.go @@ -47,6 +47,48 @@ func toBits(arr []string) (bits int) { 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 + } + + // We don't care about favorite status, so use nil and false + recipes, err := deps.RecipeService.SearchRecipes(filters, nil, 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{ @@ -62,22 +104,19 @@ func SearchRecipes(ctx *gin.Context) { ctx.SetCookie( "search-filters", string(bytes), - int(time.Now().Add(24 * time.Hour).Sub(time.Now()).Seconds()), + int(time.Now().Add(24*time.Hour).Sub(time.Now()).Seconds()), "/", - "", // TODO: Need an actual domain - false, // TODO: True in prod + "", // 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 - } + // TODO: Error here if they're not logged in? + // Get user data (they should be logged in) + userId := ctx.MustGet("userId").(int) - recipes, err := deps.RecipeService.SearchRecipes(filters) + recipes, err := deps.RecipeService.SearchRecipes(filters, &userId, true) if err != nil { ctx.JSON(http.StatusOK, gin.H{"error": err.Error()}) } diff --git a/internal/app/server/server.go b/internal/app/server/server.go index 479ec37..325582a 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -184,6 +184,7 @@ func (s *Server) Setup() *Server { // Recipe endpoints router_api.POST("/recipe", handlers.CreateRecipe) router_api.POST("/recipe/search", handlers.SearchRecipes) + router_api.POST("/recipe/search/favorites", handlers.SearchRecipesFavorites) router_api.GET("/user/recipes", handlers.GetUserRecipes) router_api.GET("/user/favorites", handlers.GetUserFavoriteRecipes) diff --git a/internal/app/service/recipe_service.go b/internal/app/service/recipe_service.go index 22fe6a1..c0ceb3f 100644 --- a/internal/app/service/recipe_service.go +++ b/internal/app/service/recipe_service.go @@ -151,8 +151,10 @@ func (s *RecipeService) GetRecipe(id int, userId *int) (*domain.Recipe, error) { // the filter is provided. // A function `isBitActive` in the recipe repository provides an example of // testing of testing the filter parsing. -func (s *RecipeService) SearchRecipes(filters domain.SearchFilters) ([]domain.Recipe, error) { - return s.recipeRepository.SearchRecipes(filters) +// +// The favorites parameter is used to only return filters favorited by the userId provided. +func (s *RecipeService) SearchRecipes(filters domain.SearchFilters, userId *int, favorites bool) ([]domain.Recipe, error) { + return s.recipeRepository.SearchRecipes(filters, userId, favorites) } // GetUserRecipes returns a list of the recipes that the user has created. The user's diff --git a/internal/domain/recipe/repository.go b/internal/domain/recipe/repository.go index 639d21c..f0c69ad 100644 --- a/internal/domain/recipe/repository.go +++ b/internal/domain/recipe/repository.go @@ -3,7 +3,7 @@ package domain type RecipeRepository interface { CreateRecipe(recipe *Recipe) error GetRecipe(id int, userId *int) (*Recipe, error) - SearchRecipes(filters SearchFilters) ([]Recipe, error) + SearchRecipes(filters SearchFilters, userId *int, favorites bool) ([]Recipe, error) CreateRecipeTags(recipe Recipe, tags []string) error GetUserRecipes(id int) ([]Recipe, error) GetUserFavoriteRecipes(id int) ([]Recipe, error) diff --git a/internal/domain/recipe/service.go b/internal/domain/recipe/service.go index 425b83e..51d4bd6 100644 --- a/internal/domain/recipe/service.go +++ b/internal/domain/recipe/service.go @@ -5,7 +5,7 @@ import "github.com/gin-gonic/gin" type RecipeService interface { CreateRecipe(ctx *gin.Context) (*Recipe, error) GetRecipe(id int, userId *int) (*Recipe, error) - SearchRecipes(filters SearchFilters) ([]Recipe, error) + SearchRecipes(filters SearchFilters, userId *int, favorites bool) ([]Recipe, error) GetUserRecipes(id int) ([]Recipe, error) GetUserFavoriteRecipes(id int) ([]Recipe, error) } diff --git a/internal/domain/server/routes.go b/internal/domain/server/routes.go index b6823da..19053ce 100644 --- a/internal/domain/server/routes.go +++ b/internal/domain/server/routes.go @@ -24,6 +24,7 @@ const API_AUTH_CALLBACK = VERSION + API + "/auth/callback" const API_AUTH_LOGOUT = VERSION + API + "/auth/logout" const API_CREATE_RECIPE = VERSION + API + "/recipe" const API_SEARCH_RECIPES = VERSION + API + "/recipe/search" +const API_SEARCH_FAVORITES = VERSION + API + "/recipe/search/favorites" const API_ENGAGEMENT_VIEW = VERSION + API + "/engagement/view/%d" const API_ENGAGEMENT_SHARE = VERSION + API + "/engagement/share/%d" diff --git a/internal/infrastructure/database/repository/recipe_repository.go b/internal/infrastructure/database/repository/recipe_repository.go index 4347ce4..94f734b 100644 --- a/internal/infrastructure/database/repository/recipe_repository.go +++ b/internal/infrastructure/database/repository/recipe_repository.go @@ -184,8 +184,10 @@ func isBitActive(bits, pos int) bool { // description can be found in the recipe service implementation. Any errors will be bubbled to the // caller. // +// The favorites parameter is used to only return filters favorited by the userId provided. +// // TODO: Pagination is required, to provide infinite scroll. -func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters) ([]domain.Recipe, error) { +func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters, userId *int, favorites bool) ([]domain.Recipe, error) { tx, err := r.db.Begin() if err != nil { tx.Rollback() @@ -274,20 +276,25 @@ func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters) ([]domain // Define columns to select. More fields can be added if the full text search is required columns := []string{ - "id", - "title", - "description", - "instructions", - "serves", - "difficulty", - "duration", - "category", - "ingredients", - "userid", - "modified", - "created", + "r.id", + "r.title", + "r.description", + "r.instructions", + "r.serves", + "r.difficulty", + "r.duration", + "r.category", + "r.ingredients", + "r.userid", + "r.modified", + "r.created", } + // TODO: Need to add these to the query + + // FROM ... JOIN favorites f ON f.recipeId = r.id + // WHERE ... AND f.userId = 3 + // Create search vector query var orderBy string = "" if filters.Search != "" { @@ -295,19 +302,30 @@ func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters) ([]domain conditions = append( conditions, - fmt.Sprintf("search_vector @@ to_tsquery('english', '%s')", vector_query), + fmt.Sprintf("r.search_vector @@ to_tsquery('english', '%s')", vector_query), ) template := ` ORDER BY - ts_rank(search_vector, to_tsquery('english', '%s')) DESC, - ts_rank_cd(search_vector, to_tsquery('english', '%s')) DESC + ts_rank(r.search_vector, to_tsquery('english', '%s')) DESC, + ts_rank_cd(r.search_vector, to_tsquery('english', '%s')) DESC ` orderBy = fmt.Sprintf(template, vector_query, vector_query) } // Generate the query - query := fmt.Sprintf("SELECT %s FROM recipes", strings.Join(columns, ",")) + var query string + if favorites && userId != nil { + query = fmt.Sprintf( + "SELECT %s FROM recipes r JOIN favorites f ON f.recipeId = r.id", + strings.Join(columns, ","), + ) + + // Add new favorite condition to the conditions list + conditions = append(conditions, fmt.Sprintf("f.userid = %d", *userId)) + } else { + query = fmt.Sprintf("SELECT %s FROM recipes r", strings.Join(columns, ",")) + } // Convert and append conditions if provided if len(conditions) > 0 { @@ -323,6 +341,8 @@ func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters) ([]domain // Finish it off with a colon! query += ";" + fmt.Printf("QUERY: %s\n", query) + // Execute the query rows, err := tx.Query(query) if err != nil { diff --git a/internal/templates/components/search_bar.templ b/internal/templates/components/search_bar.templ index 3d4071f..a2e5613 100644 --- a/internal/templates/components/search_bar.templ +++ b/internal/templates/components/search_bar.templ @@ -3,9 +3,13 @@ package components import domainServer "github.com/haydenhargreaves/Potion/internal/domain/server" import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" -templ SearchBar(filters domainRecipe.SearchFilters, redirect bool, searchOnLoad bool) { +templ SearchBar(filters domainRecipe.SearchFilters, redirect, searchOnLoad, favorites bool) {
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -126,12 +154,12 @@ func filterButton() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var5 := templ.GetChildren(ctx) - if templ_7745c5c3_Var5 == nil { - templ_7745c5c3_Var5 = templ.NopComponent + templ_7745c5c3_Var6 := templ.GetChildren(ctx) + if templ_7745c5c3_Var6 == nil { + templ_7745c5c3_Var6 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/templates/pages/favorites.templ b/internal/templates/pages/favorites.templ index 853262f..b40a7de 100644 --- a/internal/templates/pages/favorites.templ +++ b/internal/templates/pages/favorites.templ @@ -1,15 +1,66 @@ package templates +import "fmt" import "github.com/haydenhargreaves/Potion/internal/templates/components" +import "github.com/haydenhargreaves/Potion/internal/domain/recipe" +import domainServer "github.com/haydenhargreaves/Potion/internal/domain/server" -templ FavoritesPage() { -@components.Navbar("favorites") -Sit tight, this page is coming soon!
-No results
+ } else { +End of results
+ } +{ recipe.Description }
+No results
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } else { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "End of results
") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var8 string + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Description) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/favorites.templ`, Line: 51, Col: 72} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
Sit tight, this page is coming soon!
- Welcome to your ultimate recipe hub! Whether you're a seasoned chef or just starting your culinary adventure, - we're here to inspire. Explore thousands of delicious recipes, from quick weeknight dinners to gourmet delights, - all at your fingertips. Find exactly what you're craving with our powerful search and intuitive filters, or - browse our trending dishes for fresh ideas. -
-+ Welcome to your ultimate recipe hub! Whether you're a seasoned chef or just starting your culinary adventure, + we're here to inspire. Explore thousands of delicious recipes, from quick weeknight dinners to gourmet delights, + all at your fingertips. Find exactly what you're craving with our powerful search and intuitive filters, or + browse our trending dishes for fresh ideas. +
+- Our 'Recipe of the Week' is the cream of the crop! We handpick it by looking at what recipes - our community loves most. This isn't just about how many people view a recipe; it's also about - how many times it's been made, liked, reviewed, and its average rating, all combined to find - the true fan favorite of the week. It's our way of highlighting the best recipes that truly - resonate with our users! -
-+ Our 'Recipe of the Week' is the cream of the crop! We handpick it by looking at what recipes + our community loves most. This isn't just about how many people view a recipe; it's also about + how many times it's been made, liked, reviewed, and its average rating, all combined to find + the true fan favorite of the week. It's our way of highlighting the best recipes that truly + resonate with our users! +
+- Have a unique recipe idea? Want to share your culinary masterpiece with the world? - It's time to bring your creations to life! -
- ++ Have a unique recipe idea? Want to share your culinary masterpiece with the world? + It's time to bring your creations to life! +
+ - Create Your Recipe! - -{ user.Email }
-{ recipeCount } recipes
-0 favorites
-{ user.Email }
+{ recipeCount } recipes
+{ favoriteCount } favorites
+Activity section is under construction!
-Activity section is under construction!
+- { recipe.Title } -
-- Difficulty: { displayDifficulty(recipe.Difficulty) } - | Duration: { recipe.Duration.Total } min - | Category: { recipe.Category } -
-- Difficulty: { displayDifficulty(recipe.Difficulty) } -
-- Duration: { recipe.Duration.Total } min -
-- Category: { recipe.Category } -
- if len(recipe.Tags) > 0 { -- Tags: { displayTags(recipe.Tags) } -
- } -+ { recipe.Title } +
++ Difficulty: { displayDifficulty(recipe.Difficulty) } + | Duration: { recipe.Duration.Total } min + | Category: { recipe.Category } +
++ Difficulty: { displayDifficulty(recipe.Difficulty) } +
++ Duration: { recipe.Duration.Total } min +
++ Category: { recipe.Category } +
+ if len(recipe.Tags) > 0 { ++ Tags: { displayTags(recipe.Tags) } +
+ } +- { engagement.Message } -
-- { engagement.Created.Format("01/02/2006") } -
-+ { engagement.Message } +
++ { engagement.Created.Format("01/02/2006") } +
+0 favorites
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " recipes") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var7 string + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(favoriteCount) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 54, Col: 77} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " favorites
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -166,12 +182,12 @@ func recipesSection(recipes []domainRecipe.Recipe) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var7 := templ.GetChildren(ctx) - if templ_7745c5c3_Var7 == nil { - templ_7745c5c3_Var7 = templ.NopComponent + templ_7745c5c3_Var8 := templ.GetChildren(ctx) + if templ_7745c5c3_Var8 == nil { + templ_7745c5c3_Var8 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "Activity section is under construction!
Activity section is under construction!
") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - var templ_7745c5c3_Var12 string - templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Title) - if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 139, Col: 17} - } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
Difficulty: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " | Duration: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "\" hx-trigger=\"click\" hx-swap=\"none\" class=\"text-base md:text-lg hover:text-blue-600 duration-100 cursor-pointer\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 string
- templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total)
+ templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Title)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 143, Col: 66}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 129, Col: 18}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " min | Category: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " Difficulty: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var15 string
- templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Category)
+ templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(displayDifficulty(recipe.Difficulty))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 144, Col: 60}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 132, Col: 82}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " Difficulty: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, " | Duration: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
- templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(displayDifficulty(recipe.Difficulty))
+ templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 147, Col: 81}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 133, Col: 67}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, " Duration: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, " min | Category: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
- templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total)
+ templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Category)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 150, Col: 64}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 134, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " min Category: ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " Difficulty: ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var18 string
- templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Category)
+ templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(displayDifficulty(recipe.Difficulty))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 153, Col: 58}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 137, Col: 82}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
Duration: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var19 string + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Duration.Total) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 140, Col: 65} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " min
Category: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var20 string + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(recipe.Category) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 143, Col: 59} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } if len(recipe.Tags) > 0 { - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "Tags: ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
Tags: ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var19 string - templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(displayTags(recipe.Tags)) + var templ_7745c5c3_Var21 string + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(displayTags(recipe.Tags)) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 157, Col: 36} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 147, Col: 36} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var21 string - templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(engagement.Message) + var templ_7745c5c3_Var23 string + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(engagement.Message) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 168, Col: 23} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 157, Col: 24} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - var templ_7745c5c3_Var22 string - templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(engagement.Created.Format("01/02/2006")) + var templ_7745c5c3_Var24 string + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(engagement.Created.Format("01/02/2006")) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 171, Col: 44} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 160, Col: 45} } - _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "