diff --git a/internal/app/handlers/page_handler.go b/internal/app/handlers/page_handler.go index b8b2885..d375b78 100644 --- a/internal/app/handlers/page_handler.go +++ b/internal/app/handlers/page_handler.go @@ -58,9 +58,18 @@ func ProfilePage(ctx *gin.Context) { // Else, get the user data deps := ctx.MustGet("deps").(*domainServer.InjectedDependencies) user := deps.UserService.GetAuthenicatedUser(ctx) + recipes, err := deps.RecipeService.GetUserRecipes(user.Id) + if err != nil { + fmt.Printf("Error getting recipes. %s\n", err.Error()) + ctx.JSON(http.StatusInternalServerError, gin.H{ + "status": http.StatusInternalServerError, + "message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()), + }) + return + } title := "Potion - Profile" - page := pages.ProfilePage(user) + page := pages.ProfilePage(user, recipes) ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page)) } diff --git a/internal/app/handlers/user_handler.go b/internal/app/handlers/user_handler.go index 5ac8282..261e199 100644 --- a/internal/app/handlers/user_handler.go +++ b/internal/app/handlers/user_handler.go @@ -1 +1,49 @@ package handlers + +import ( + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + domain "github.com/haydenhargreaves/Potion/internal/domain/server" +) + +func GetUserRecipes(ctx *gin.Context) { + deps := ctx.MustGet("deps").(*domain.InjectedDependencies) + + // Ensure logged in + if !domain.IsLoggedIn(ctx) { + ctx.JSON(http.StatusUnauthorized, gin.H{ + "status": http.StatusUnauthorized, + "message": "User is not authorized to access this endpoint. Please login to continue.", + "recipes": nil, + }) + return + } + + userId, ok := ctx.MustGet("userId").(int) + if !ok { + ctx.JSON(http.StatusInternalServerError, gin.H{ + "status": http.StatusInternalServerError, + "message": "Unable to access user id from store.", + "recipes": nil, + }) + return + } + + recipes, err := deps.RecipeService.GetUserRecipes(userId) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{ + "status": http.StatusBadRequest, + "message": fmt.Sprintf("Could not get user recipes. %s", err.Error()), + "recipes": nil, + }) + return + } + + ctx.JSON(http.StatusOK, gin.H{ + "status": http.StatusOK, + "message": "User recipes successfully retrieved.", + "recipes": recipes, + }) +} diff --git a/internal/app/server/server.go b/internal/app/server/server.go index f46e8bd..406169b 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -181,6 +181,7 @@ func (s *Server) Setup() *Server { // Recipe endpoints router_api.POST("/recipe", handlers.CreateRecipe) router_api.POST("/recipe/search", handlers.SearchRecipes) + router_api.GET("/user/recipes", handlers.GetUserRecipes) // Catch un-routed URLS s.Router.NoRoute(func(ctx *gin.Context) { diff --git a/internal/app/service/recipe_service.go b/internal/app/service/recipe_service.go index 82e9696..870f053 100644 --- a/internal/app/service/recipe_service.go +++ b/internal/app/service/recipe_service.go @@ -134,8 +134,8 @@ func (s *RecipeService) GetRecipe(id int) (*domain.Recipe, error) { } // SearchRecipes will search the database using the filters provided. The recipes can be passed into -// a template and displayed in the UI as the search result. A more detailed definition of the -// filters is provided below. +// a template and displayed in the UI as the search result. A more detailed definition of the +// filters is provided below. // // 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 @@ -150,3 +150,7 @@ func (s *RecipeService) GetRecipe(id int) (*domain.Recipe, error) { func (s *RecipeService) SearchRecipes(filters domain.SearchFilters) ([]domain.Recipe, error) { return s.recipeRepository.SearchRecipes(filters) } + +func (s *RecipeService) GetUserRecipes(id int) ([]domain.Recipe, error) { + return s.recipeRepository.GetUserRecipes(id) +} diff --git a/internal/domain/recipe/repository.go b/internal/domain/recipe/repository.go index b47ccd9..a5c57d9 100644 --- a/internal/domain/recipe/repository.go +++ b/internal/domain/recipe/repository.go @@ -5,4 +5,6 @@ type RecipeRepository interface { GetRecipe(id int) (*Recipe, error) SearchRecipes(filters SearchFilters) ([]Recipe, error) CreateRecipeTags(recipe Recipe, tags []string) error + GetUserRecipes(id int) ([]Recipe, error) + GetRecipeTags(recipe *Recipe) error } diff --git a/internal/domain/recipe/service.go b/internal/domain/recipe/service.go index cf6723e..b3466f4 100644 --- a/internal/domain/recipe/service.go +++ b/internal/domain/recipe/service.go @@ -6,4 +6,5 @@ type RecipeService interface { CreateRecipe(ctx *gin.Context) (*Recipe, error) GetRecipe(id int) (*Recipe, error) SearchRecipes(filters SearchFilters) ([]Recipe, error) + GetUserRecipes(id int) ([]Recipe, error) } diff --git a/internal/infrastructure/database/repository/recipe_repository.go b/internal/infrastructure/database/repository/recipe_repository.go index 293f9c8..e92739a 100644 --- a/internal/infrastructure/database/repository/recipe_repository.go +++ b/internal/infrastructure/database/repository/recipe_repository.go @@ -128,34 +128,6 @@ func (r *RecipeRepository) GetRecipe(id int) (*domain.Recipe, error) { return nil, fmt.Errorf("Failed to location recipe in database: %s", err.Error()) } - // Get tags from external tables - query = ` - SELECT t.* FROM tags t - JOIN recipetags rt ON rt.tagid = t.id - WHERE rt.recipeid = $1; - ` - rows, err := tx.Query(query, recipe.Id) - if err != nil { - return nil, fmt.Errorf("Failed to get tags for recipe. %s\n", err.Error()) - } - defer rows.Close() - - for rows.Next() { - var tag domain.Tag - - err := rows.Scan(&tag.Id, &tag.Name, &tag.Created) - if err != nil { - return nil, fmt.Errorf("Failed to scan tag onto domain model. %s\n", err.Error()) - } - - recipe.Tags = append(recipe.Tags, tag) - } - - if err := tx.Commit(); err != nil { - tx.Rollback() - return nil, err - } - // Parse duration if len(durationBytes) > 0 { var duration domain.RecipeDuration @@ -180,6 +152,14 @@ func (r *RecipeRepository) GetRecipe(id int) (*domain.Recipe, error) { recipe.Ingredients = []domain.RecipeIngredient{} } + // Add tags + r.GetRecipeTags(&recipe) + + if err := tx.Commit(); err != nil { + tx.Rollback() + return nil, err + } + return &recipe, nil } @@ -387,6 +367,9 @@ func (r *RecipeRepository) SearchRecipes(filters domain.SearchFilters) ([]domain recipe.Ingredients = []domain.RecipeIngredient{} } + // Add tags + r.GetRecipeTags(&recipe) + recipes = append(recipes, recipe) } @@ -456,3 +439,135 @@ func (r *RecipeRepository) CreateRecipeTags(recipe domain.Recipe, tags []string) return nil } + +// GetUserRecipes gets a list of a users owned recipes. This function does not ensure the user is +// authenticated or exists. If nothing is found, a blank slice will be returned. The resulting list +// is sorted by the created dates, newest first. Any errors will be bubbled to the caller. +func (r *RecipeRepository) GetUserRecipes(id int) ([]domain.Recipe, error) { + tx, err := r.db.Begin() + if err != nil { + tx.Rollback() + return nil, err + } + + query := ` + SELECT id, title, description, instructions, serves, difficulty, duration, category, ingredients, + userid, modified, created + FROM recipes + WHERE userid = $1 + ORDER BY created DESC; + ` + + rows, err := tx.Query(query, id) + if err != nil { + return nil, fmt.Errorf("Failed to query DB for user recipes. %s\n", err.Error()) + } + defer rows.Close() + + // Prepare statement for tag query + // tagQuery := ` + // ` + + var recipes []domain.Recipe + for rows.Next() { + var recipe domain.Recipe + var durationBytes []byte + var ingredientBytes []byte + + // Scan results from recipe query onto recipe object + if err := rows.Scan( + &recipe.Id, + &recipe.Title, + &recipe.Description, + pq.Array(&recipe.Instructions), + &recipe.Serves, + &recipe.Difficulty, + &durationBytes, + &recipe.Category, + &ingredientBytes, + &recipe.UserId, + &recipe.Modified, + &recipe.Created, + ); err != nil { + return nil, fmt.Errorf("Failed to scan row onto recipe object. %s\n", err.Error()) + } + + // Parse duration + if len(durationBytes) > 0 { + var duration domain.RecipeDuration + if err := json.Unmarshal(durationBytes, &duration); err != nil { + return nil, fmt.Errorf("Failed to parse duration from database: %s", err.Error()) + } + + recipe.Duration = duration + } else { + recipe.Duration = domain.RecipeDuration{} + } + + // Parse ingredient + if len(ingredientBytes) > 0 { + var ingredients []domain.RecipeIngredient + if err := json.Unmarshal(ingredientBytes, &ingredients); err != nil { + return nil, fmt.Errorf("Failed to parse ingredients from database: %s", err.Error()) + } + + recipe.Ingredients = ingredients + } else { + recipe.Ingredients = []domain.RecipeIngredient{} + } + + // Add tags + r.GetRecipeTags(&recipe) + + recipes = append(recipes, recipe) + } + + if err := tx.Commit(); err != nil { + tx.Rollback() + return nil, err + } + + return recipes, nil +} + +// GetRecipeTags requires a recipe to be filled with at least an ID. This function will use the ID +// defined in the provided recipe to fill the Tags array with the recipe's tags from the database. +// The recipe is modified in place and is not returned. Any errors will be bubbled to the caller. +func (r *RecipeRepository) GetRecipeTags(recipe *domain.Recipe) error { + tx, err := r.db.Begin() + if err != nil { + tx.Rollback() + return err + } + + recipe.Tags = []domain.Tag{} + + query := ` + SELECT t.* FROM tags t + JOIN recipetags rt ON rt.tagid = t.id + WHERE rt.recipeid = $1; + ` + rows, err := tx.Query(query, recipe.Id) + if err != nil { + return fmt.Errorf("Failed to get tags for recipe. %s\n", err.Error()) + } + defer rows.Close() + + for rows.Next() { + var tag domain.Tag + + err := rows.Scan(&tag.Id, &tag.Name, &tag.Created) + if err != nil { + return fmt.Errorf("Failed to scan tag onto domain model. %s\n", err.Error()) + } + + recipe.Tags = append(recipe.Tags, tag) + } + + if err := tx.Commit(); err != nil { + tx.Rollback() + return err + } + + return nil +} diff --git a/internal/templates/pages/profile.templ b/internal/templates/pages/profile.templ index 51a406b..c631efa 100644 --- a/internal/templates/pages/profile.templ +++ b/internal/templates/pages/profile.templ @@ -1,10 +1,38 @@ package templates import "github.com/haydenhargreaves/Potion/internal/templates/components" +import "fmt" +import "strings" import domain "github.com/haydenhargreaves/Potion/internal/domain/server" -import domain_user "github.com/haydenhargreaves/Potion/internal/domain/user" +import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" +import domainUser "github.com/haydenhargreaves/Potion/internal/domain/user" -templ userDetailsSection(user domain_user.User) { +func displayDifficulty(diff int) string { + switch diff { + case 1: + return "Beginner" + case 2: + return "Easy" + case 3: + return "Intermediate" + case 4: + return "Challenging" + case 5: + return "Extreme" + default: + return "" + } +} + +func displayTags(tags []domainRecipe.Tag) string { + names := make([]string, 0, len(tags)) + for _, tag := range tags { + names = append(names, tag.Name) + } + return strings.Join(names, ", ") +} + +templ userDetailsSection(user domainUser.User, recipeCount int) {
{ user.Email }

-

10 recipes

-

14 favorites

+

{ recipeCount } recipes

+

0 favorites

} -templ recipesSection() { +templ recipesSection(recipes []domainRecipe.Recipe) {

My Recipes

} -templ ProfilePage(user domain_user.User) { +templ ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe) { @components.Navbar(" profile")
- @userDetailsSection(user) - @recipesSection() - @favoritesSection() + @userDetailsSection(user, len(recipes)) + @recipesSection(recipes) + @favoritesSection(recipes) @activitySection() @logoutSection()
diff --git a/internal/templates/pages/profile_templ.go b/internal/templates/pages/profile_templ.go index a116777..6ea849b 100644 --- a/internal/templates/pages/profile_templ.go +++ b/internal/templates/pages/profile_templ.go @@ -9,10 +9,38 @@ import "github.com/a-h/templ" import templruntime "github.com/a-h/templ/runtime" import "github.com/haydenhargreaves/Potion/internal/templates/components" +import "fmt" +import "strings" import domain "github.com/haydenhargreaves/Potion/internal/domain/server" -import domain_user "github.com/haydenhargreaves/Potion/internal/domain/user" +import domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe" +import domainUser "github.com/haydenhargreaves/Potion/internal/domain/user" -func userDetailsSection(user domain_user.User) templ.Component { +func displayDifficulty(diff int) string { + switch diff { + case 1: + return "Beginner" + case 2: + return "Easy" + case 3: + return "Intermediate" + case 4: + return "Challenging" + case 5: + return "Extreme" + default: + return "" + } +} + +func displayTags(tags []domainRecipe.Tag) string { + names := make([]string, 0, len(tags)) + for _, tag := range tags { + names = append(names, tag.Name) + } + return strings.Join(names, ", ") +} + +func userDetailsSection(user domainUser.User, recipeCount int) 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 { @@ -40,7 +68,7 @@ func userDetailsSection(user domain_user.User) templ.Component { var templ_7745c5c3_Var2 string templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(user.ImageUrl) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 12, Col: 23} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 40, Col: 23} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) if templ_7745c5c3_Err != nil { @@ -53,7 +81,7 @@ func userDetailsSection(user domain_user.User) templ.Component { var templ_7745c5c3_Var3 string templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(user.Name) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 16, Col: 62} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 44, Col: 62} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) if templ_7745c5c3_Err != nil { @@ -66,13 +94,26 @@ func userDetailsSection(user domain_user.User) templ.Component { var templ_7745c5c3_Var4 string templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(user.Email) if templ_7745c5c3_Err != nil { - return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 17, Col: 47} + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 45, Col: 47} } _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

10 recipes

14 favorites

") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "

") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var5 string + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(recipeCount) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 48, Col: 72} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, " recipes

0 favorites

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -80,56 +121,7 @@ func userDetailsSection(user domain_user.User) templ.Component { }) } -func recipesSection() 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 { - return templ_7745c5c3_CtxErr - } - templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) - if !templ_7745c5c3_IsBuffer { - defer func() { - templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) - if templ_7745c5c3_Err == nil { - templ_7745c5c3_Err = templ_7745c5c3_BufErr - } - }() - } - ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var5 := templ.GetChildren(ctx) - if templ_7745c5c3_Var5 == nil { - templ_7745c5c3_Var5 = templ.NopComponent - } - ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "

My Recipes

") - if templ_7745c5c3_Err != nil { - return templ_7745c5c3_Err - } - return nil - }) -} - -func favoritesSection() templ.Component { +func recipesSection(recipes []domainRecipe.Recipe) 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 { @@ -150,36 +142,83 @@ func favoritesSection() templ.Component { templ_7745c5c3_Var6 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "

My Favorites

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -203,12 +242,12 @@ func activitySection() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var8 := templ.GetChildren(ctx) - if templ_7745c5c3_Var8 == nil { - templ_7745c5c3_Var8 = templ.NopComponent + templ_7745c5c3_Var9 := templ.GetChildren(ctx) + if templ_7745c5c3_Var9 == nil { + templ_7745c5c3_Var9 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "

My Favorites

") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -244,7 +283,7 @@ func activitySection() templ.Component { }) } -func recipeListItem() templ.Component { +func recipeListItem(recipe domainRecipe.Recipe) 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 { @@ -260,12 +299,135 @@ func recipeListItem() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var9 := templ.GetChildren(ctx) - if templ_7745c5c3_Var9 == nil { - templ_7745c5c3_Var9 = templ.NopComponent + templ_7745c5c3_Var10 := templ.GetChildren(ctx) + if templ_7745c5c3_Var10 == nil { + templ_7745c5c3_Var10 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "
  • My Awesome Chili Recipe

    Difficulty: Medium | Duration: 60 min | Category: Dinner

    Difficulty: Medium

    Duration: 60 min

    Category: Dinner

    Tags: comfort food, spicy, beef

  • ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
  • ") + 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: 129, Col: 18} + } + _, 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, 15, "

    Difficulty: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var13 string + templ_7745c5c3_Var13, 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: 133, Col: 81} + } + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, " | Duration: ") + 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) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 134, Col: 66} + } + _, 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, 17, " min | Category: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var15 string + templ_7745c5c3_Var15, 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: 135, Col: 60} + } + _, 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, 18, "

    Difficulty: ") + 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)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 138, Col: 81} + } + _, 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, 19, "

    Duration: ") + 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) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 141, Col: 64} + } + _, 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, 20, " min

    Category: ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + var templ_7745c5c3_Var18 string + templ_7745c5c3_Var18, 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: 144, Col: 58} + } + _, 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, 21, "

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + if len(recipe.Tags) > 0 { + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "

    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)) + if templ_7745c5c3_Err != nil { + return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 148, Col: 36} + } + _, 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, 23, "

    ") + if templ_7745c5c3_Err != nil { + return templ_7745c5c3_Err + } + } + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
  • ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -289,12 +451,12 @@ func activityListItem() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var10 := templ.GetChildren(ctx) - if templ_7745c5c3_Var10 == nil { - templ_7745c5c3_Var10 = templ.NopComponent + templ_7745c5c3_Var20 := templ.GetChildren(ctx) + if templ_7745c5c3_Var20 == nil { + templ_7745c5c3_Var20 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "
  • Rated \"Spicy Chicken Wings\"

    2 days ago

  • ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
  • Rated \"Spicy Chicken Wings\"

    2 days ago

  • ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -318,21 +480,21 @@ func logoutSection() templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var11 := templ.GetChildren(ctx) - if templ_7745c5c3_Var11 == nil { - templ_7745c5c3_Var11 = templ.NopComponent + templ_7745c5c3_Var21 := templ.GetChildren(ctx) + if templ_7745c5c3_Var21 == nil { + templ_7745c5c3_Var21 = templ.NopComponent } ctx = templ.ClearChildren(ctx) - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "
    Logout
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" class=\"text-center border border-red-500 text-red-500 w-9/10 md:w-1/3 py-2 rounded-lg hover:cursor-pointer hover:bg-red-100 duration-300\">Logout") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -340,7 +502,7 @@ func logoutSection() templ.Component { }) } -func ProfilePage(user domain_user.User) templ.Component { +func ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe) 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 { @@ -356,28 +518,28 @@ func ProfilePage(user domain_user.User) templ.Component { }() } ctx = templ.InitializeContext(ctx) - templ_7745c5c3_Var13 := templ.GetChildren(ctx) - if templ_7745c5c3_Var13 == nil { - templ_7745c5c3_Var13 = templ.NopComponent + templ_7745c5c3_Var23 := templ.GetChildren(ctx) + if templ_7745c5c3_Var23 == nil { + templ_7745c5c3_Var23 = templ.NopComponent } ctx = templ.ClearChildren(ctx) templ_7745c5c3_Err = components.Navbar(" profile").Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = userDetailsSection(user).Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = userDetailsSection(user, len(recipes)).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = recipesSection().Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = recipesSection(recipes).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = favoritesSection().Render(ctx, templ_7745c5c3_Buffer) + templ_7745c5c3_Err = favoritesSection(recipes).Render(ctx, templ_7745c5c3_Buffer) if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } @@ -389,7 +551,7 @@ func ProfilePage(user domain_user.User) templ.Component { if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
    ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
    ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err }