(FEAT): Created backend API to get users favorite recipes.

The UI is wired up and connected as well, for the profile page. Next
step is to create the favorites page.
This commit is contained in:
Hayden Hargreaves 2025-07-15 22:11:25 -07:00
parent d191902448
commit aacca77890
10 changed files with 234 additions and 51 deletions

View File

@ -67,6 +67,15 @@ func ProfilePage(ctx *gin.Context) {
return
}
favorites, err := deps.RecipeService.GetUserFavoriteRecipes(user.Id)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": fmt.Sprintf("Error getting recipes. %s\n", err.Error()),
})
return
}
// Get the engagement data, not sure what will happen when errors occur
engagements, err := deps.EngagementService.GetUserEngagement(user.Id, 6)
if err != nil {
@ -78,7 +87,7 @@ func ProfilePage(ctx *gin.Context) {
}
title := "Potion - Profile"
page := pages.ProfilePage(user, recipes, engagements)
page := pages.ProfilePage(user, recipes, favorites, engagements)
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}

View File

@ -47,3 +47,43 @@ func GetUserRecipes(ctx *gin.Context) {
"recipes": recipes,
})
}
func GetUserFavoriteRecipes(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.GetUserFavoriteRecipes(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,
})
}

View File

@ -185,6 +185,7 @@ func (s *Server) Setup() *Server {
router_api.POST("/recipe", handlers.CreateRecipe)
router_api.POST("/recipe/search", handlers.SearchRecipes)
router_api.GET("/user/recipes", handlers.GetUserRecipes)
router_api.GET("/user/favorites", handlers.GetUserFavoriteRecipes)
// Engagement endpoints
router_api.POST("/engagement/view/:id", handlers.EngagementViewRecipe)

View File

@ -155,6 +155,14 @@ func (s *RecipeService) SearchRecipes(filters domain.SearchFilters) ([]domain.Re
return s.recipeRepository.SearchRecipes(filters)
}
// GetUserRecipes returns a list of the recipes that the user has created. The user's
// ID should be provided. Any errors will be bubbled to the caller.
func (s *RecipeService) GetUserRecipes(id int) ([]domain.Recipe, error) {
return s.recipeRepository.GetUserRecipes(id)
}
// GetUserFavoriteRecipes returns a list of the recipes that the user has marked as a
// favorite. The user's ID should be provided. Any errors will be bubbled to the caller.
func (s *RecipeService) GetUserFavoriteRecipes(id int) ([]domain.Recipe, error) {
return s.recipeRepository.GetUserFavoriteRecipes(id)
}

View File

@ -6,6 +6,7 @@ type RecipeRepository interface {
SearchRecipes(filters SearchFilters) ([]Recipe, error)
CreateRecipeTags(recipe Recipe, tags []string) error
GetUserRecipes(id int) ([]Recipe, error)
GetUserFavoriteRecipes(id int) ([]Recipe, error)
GetRecipeTags(recipe *Recipe) error
GetRecipeFavorite(recipe *Recipe, userId int) error
}

View File

@ -7,4 +7,5 @@ type RecipeService interface {
GetRecipe(id int, userId *int) (*Recipe, error)
SearchRecipes(filters SearchFilters) ([]Recipe, error)
GetUserRecipes(id int) ([]Recipe, error)
GetUserFavoriteRecipes(id int) ([]Recipe, error)
}

View File

@ -548,6 +548,94 @@ func (r *RecipeRepository) GetUserRecipes(id int) ([]domain.Recipe, error) {
return recipes, nil
}
func (r *RecipeRepository) GetUserFavoriteRecipes(id int) ([]domain.Recipe, error) {
tx, err := r.db.Begin()
if err != nil {
tx.Rollback()
return nil, err
}
query := `
SELECT r.id, r.title, r.description, r.instructions, r.serves, r.difficulty, r.duration, r.category, r.ingredients, r.
userid, r.modified, r.created
FROM favorites f
JOIN recipes r ON r.id = f.recipeid
WHERE f.userid = $1
ORDER BY f.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()
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
if err := r.GetRecipeTags(&recipe); err != nil {
fmt.Printf("ERROR getting recipe tags. %s\n", err.Error())
}
// Set favorite status (they're always true!)
recipe.Favorite = true
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.

View File

@ -44,7 +44,7 @@ templ userDetailsSection(user domainUser.User, recipeCount int) {
} else {
<img
class="w-24 md:w-32 border-2 border-blue-500 rounded-full shadow-blue-500 shadow select-none"
src={ fmt.Sprintf("https://ui-avatars.com/api/?name=%s+%s&size=150", strings.Split(user.Name, " " )[0], strings.Split(user.Name, " " )[1]) }
src={ fmt.Sprintf("https://ui-avatars.com/api/?name=%s+%s&size=150", strings.Split(user.Name, " ")[0], strings.Split(user.Name, " ")[1]) }
/>
}
<div class="flex flex-col gap-y-4">
@ -74,7 +74,7 @@ templ recipesSection(recipes []domainRecipe.Recipe) {
@recipeListItem(recipe)
}
}
<a href="/" class="bg-red-500">
<a href="/">
<li
class="w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center"
>
@ -88,7 +88,24 @@ templ recipesSection(recipes []domainRecipe.Recipe) {
templ favoritesSection(recipes []domainRecipe.Recipe) {
<section class="p-8">
<h2 class="text-2xl font-semibold text-gray-800">My Favorites</h2>
<p class="text-sm my-2">Favorites section is under construction!</p>
<ul class="w-full my-2">
if len(recipes) <= 4 {
for _, recipe := range recipes {
@recipeListItem(recipe)
}
} else {
for _, recipe := range recipes[:4] {
@recipeListItem(recipe)
}
}
<a href="/">
<li
class="w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center"
>
See all...
</li>
</a>
</ul>
</section>
}
@ -113,13 +130,13 @@ templ activitySection(engagement []domainEngagement.Engagement) {
templ recipeListItem(recipe domainRecipe.Recipe) {
<li class="w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150">
<p
hx-post={ fmt.Sprintf(domain.API_ENGAGEMENT_VIEW, recipe.Id) }
hx-trigger="click"
hx-swap="none"
class="text-base md:text-lg hover:text-blue-600 duration-100 cursor-pointer"
>
{ recipe.Title }
<p
hx-post={ fmt.Sprintf(domain.API_ENGAGEMENT_VIEW, recipe.Id) }
hx-trigger="click"
hx-swap="none"
class="text-base md:text-lg hover:text-blue-600 duration-100 cursor-pointer"
>
{ recipe.Title }
</p>
<p class="hidden md:block text-sm text-gray-700 my-1.5">
Difficulty: <span class="font-semibold">{ displayDifficulty(recipe.Difficulty) }</span>
@ -167,13 +184,13 @@ templ logoutSection() {
</section>
}
templ ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe, engagement []domainEngagement.Engagement) {
templ ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe, favorites []domainRecipe.Recipe, engagement []domainEngagement.Engagement) {
@components.Navbar(" profile")
<div class="w-full h-fit flex justify-center">
<div class="mx-2 md:mx-0 w-full md:w-1/2 md:pt-14 border-l border-r border-gray-300 bg-white flex flex-col">
@userDetailsSection(user, len(recipes))
@recipesSection(recipes)
@favoritesSection(recipes)
@favoritesSection(favorites)
@activitySection(engagement)
@logoutSection()
</div>

View File

@ -92,7 +92,7 @@ func userDetailsSection(user domainUser.User, recipeCount int) templ.Component {
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("https://ui-avatars.com/api/?name=%s+%s&size=150", strings.Split(user.Name, " ")[0], strings.Split(user.Name, " ")[1]))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 47, Col: 143}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 47, Col: 141}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@ -190,7 +190,7 @@ func recipesSection(recipes []domainRecipe.Recipe) templ.Component {
}
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<a href=\"/\" class=\"bg-red-500\"><li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center\">See all...</li></a></ul></section>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<a href=\"/\"><li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center\">See all...</li></a></ul></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -219,7 +219,26 @@ func favoritesSection(recipes []domainRecipe.Recipe) templ.Component {
templ_7745c5c3_Var8 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<section class=\"p-8\"><h2 class=\"text-2xl font-semibold text-gray-800\">My Favorites</h2><p class=\"text-sm my-2\">Favorites section is under construction!</p></section>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<section class=\"p-8\"><h2 class=\"text-2xl font-semibold text-gray-800\">My Favorites</h2><ul class=\"w-full my-2\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(recipes) <= 4 {
for _, recipe := range recipes {
templ_7745c5c3_Err = recipeListItem(recipe).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
} else {
for _, recipe := range recipes[:4] {
templ_7745c5c3_Err = recipeListItem(recipe).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<a href=\"/\"><li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center\">See all...</li></a></ul></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -248,7 +267,7 @@ func activitySection(engagement []domainEngagement.Engagement) templ.Component {
templ_7745c5c3_Var9 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<section class=\"p-8\"><h2 class=\"text-2xl font-semibold text-gray-800\">Recent Activity</h2><p class=\"text-sm my-2\">Activity section is under construction!</p><ul class=\"w-full my-2\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<section class=\"p-8\"><h2 class=\"text-2xl font-semibold text-gray-800\">Recent Activity</h2><p class=\"text-sm my-2\">Activity section is under construction!</p><ul class=\"w-full my-2\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -258,7 +277,7 @@ func activitySection(engagement []domainEngagement.Engagement) templ.Component {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<a href=\"/\" class=\"bg-red-500\"><li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center\">See all...</li></a></ul></section>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<a href=\"/\" class=\"bg-red-500\"><li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 hover:text-blue-600 duration-150 text-center\">See all...</li></a></ul></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -287,134 +306,134 @@ func recipeListItem(recipe domainRecipe.Recipe) templ.Component {
templ_7745c5c3_Var10 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150\"><p hx-post=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150\"><p hx-post=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(domain.API_ENGAGEMENT_VIEW, recipe.Id))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 117, Col: 66}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 134, Col: 63}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "\" hx-trigger=\"click\" hx-swap=\"none\" class=\"text-base md:text-lg hover:text-blue-600 duration-100 cursor-pointer\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\" 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_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: 122, Col: 18}
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, 17, "</p><p class=\"hidden md:block text-sm text-gray-700 my-1.5\">Difficulty: <span class=\"font-semibold\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</p><p class=\"hidden md:block text-sm text-gray-700 my-1.5\">Difficulty: <span class=\"font-semibold\">")
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: 125, Col: 81}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 142, 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, 18, "</span> | Duration: <span class=\"font-semibold\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</span> | Duration: <span class=\"font-semibold\">")
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: 126, Col: 66}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 143, 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, 19, " min</span> | Category: <span class=\"font-semibold\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, " min</span> | Category: <span class=\"font-semibold\">")
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: 127, Col: 60}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 144, 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, 20, "</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Difficulty: <span class=\"font-semibold\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Difficulty: <span class=\"font-semibold\">")
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: 130, Col: 81}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 147, 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, 21, "</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Duration: <span class=\"font-semibold\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Duration: <span class=\"font-semibold\">")
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: 133, Col: 64}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 150, 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, 22, " min</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Category: <span class=\"font-semibold\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, " min</span></p><p class=\"md:hidden text-xs md:text-sm text-gray-700 my-1\">Category: <span class=\"font-semibold\">")
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: 136, Col: 58}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 153, 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, 23, "</span></p>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</span></p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(recipe.Tags) > 0 {
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "<p class=\"text-xs italic text-gray-500\">Tags: ")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "<p class=\"text-xs italic text-gray-500\">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: 140, Col: 36}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 157, 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, 25, "</p>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "</li>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -443,33 +462,33 @@ func activityListItem(engagement domainEngagement.Engagement) templ.Component {
templ_7745c5c3_Var20 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "<li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150 flex justify-between items-center\"><p class=\"text-sm md:text-base text-gray-800\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<li class=\"w-full border-b border-gray-300 px-2 py-4 even:bg-gray-50 hover:bg-gray-100 duration-150 flex justify-between items-center\"><p class=\"text-sm md:text-base text-gray-800\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var21 string
templ_7745c5c3_Var21, 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: 151, Col: 23}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 168, Col: 23}
}
_, 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, 28, "</p><p class=\"text-xs md:text-sm text-gray-600 w-fit shrink-0\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</p><p class=\"text-xs md:text-sm text-gray-600 w-fit shrink-0\">")
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"))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 154, Col: 44}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/templates/pages/profile.templ`, Line: 171, Col: 44}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</p></li>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</p></li>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -498,7 +517,7 @@ func logoutSection() templ.Component {
templ_7745c5c3_Var23 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<section class=\"w-full flex flex-col justify-center items-center py-8 border-t border-gray-300 mt-auto\"><a href=\"")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<section class=\"w-full flex flex-col justify-center items-center py-8 border-t border-gray-300 mt-auto\"><a href=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -507,7 +526,7 @@ func logoutSection() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\" 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</a></section>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "\" 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</a></section>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -515,7 +534,7 @@ func logoutSection() templ.Component {
})
}
func ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe, engagement []domainEngagement.Engagement) templ.Component {
func ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe, favorites []domainRecipe.Recipe, engagement []domainEngagement.Engagement) 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 {
@ -540,7 +559,7 @@ func ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe, engagement
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "<div class=\"w-full h-fit flex justify-center\"><div class=\"mx-2 md:mx-0 w-full md:w-1/2 md:pt-14 border-l border-r border-gray-300 bg-white flex flex-col\">")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "<div class=\"w-full h-fit flex justify-center\"><div class=\"mx-2 md:mx-0 w-full md:w-1/2 md:pt-14 border-l border-r border-gray-300 bg-white flex flex-col\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -552,7 +571,7 @@ func ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe, engagement
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = favoritesSection(recipes).Render(ctx, templ_7745c5c3_Buffer)
templ_7745c5c3_Err = favoritesSection(favorites).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -564,7 +583,7 @@ func ProfilePage(user domainUser.User, recipes []domainRecipe.Recipe, engagement
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</div></div>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</div></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -9,7 +9,6 @@
monospace;
--color-red-100: oklch(93.6% 0.032 17.717);
--color-red-500: oklch(63.7% 0.237 25.331);
--color-green-300: oklch(87.1% 0.15 154.449);
--color-green-500: oklch(72.3% 0.219 149.579);
--color-blue-50: oklch(97% 0.014 254.604);
--color-blue-100: oklch(93.2% 0.032 255.585);