Potion/internal/app/server/page_handler.go
2025-10-30 11:58:17 -07:00

301 lines
9.4 KiB
Go

package server
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"github.com/a-h/templ"
"github.com/gin-gonic/gin"
domainRecipe "github.com/haydenhargreaves/Potion/internal/domain/recipe"
domain "github.com/haydenhargreaves/Potion/internal/domain/server"
"github.com/haydenhargreaves/Potion/internal/templates/components"
layouts "github.com/haydenhargreaves/Potion/internal/templates/layouts"
pages "github.com/haydenhargreaves/Potion/internal/templates/pages"
)
func (s *Server) LoginPageHandler(ctx *gin.Context) {
title := "Potion - Login"
page := pages.LoginPage()
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) HomePageHandler(ctx *gin.Context) {
loggedIn := domain.IsLoggedIn(ctx)
// Ensure user is logged in with a valid account
if loggedIn {
if user := s.deps.UserService.GetAuthenicatedUser(ctx); user == nil {
// Log (stale) user out
s.SetCookie(ctx, "jwt_token", "", -1)
s.SetCookie(ctx, "search-filters", "", -1)
loggedIn = false
}
}
var page templ.Component
if loggedIn {
userId := ctx.MustGet("userId").(int)
madeRecipes, err := s.deps.RecipeService.GetUserMadeRecipes(userId, 6)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting made recipes. %s\n", err.Error()))
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": fmt.Sprintf("Error getting made recipes. %s\n", err.Error()),
})
return
}
viewedRecipes, err := s.deps.RecipeService.GetUserViewedRecipes(userId, 6)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()))
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": fmt.Sprintf("Error getting viewed recipes. %s\n", err.Error()),
})
return
}
// Get the recipe of the week
recipeOfTheWeek, err := s.deps.RecipeService.GetRecipeOfTheWeek(&userId)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
})
return
}
if bytes, err := ctx.Cookie("search-filters"); err != nil {
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
page = pages.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
} 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.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, nil)
} else {
page = pages.HomePage(true, viewedRecipes, madeRecipes, recipeOfTheWeek, &filters)
}
}
} else {
// Get the recipe of the week
recipeOfTheWeek, err := s.deps.RecipeService.GetRecipeOfTheWeek(nil)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()))
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": fmt.Sprintf("Error getting recipe of the week. %s\n", err.Error()),
})
return
}
if bytes, err := ctx.Cookie("search-filters"); err != nil {
fmt.Printf("ERROR: Failed to get search-filter cookie. %s\n", err.Error())
page = pages.HomePage(false, nil, nil, recipeOfTheWeek, nil)
} 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.HomePage(false, nil, nil, recipeOfTheWeek, nil)
} else {
page = pages.HomePage(false, nil, nil, recipeOfTheWeek, &filters)
}
}
}
title := "Potion - Home"
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) FavoritesPageHandler(ctx *gin.Context) {
// If not logged in, direct to the login page
if !domain.IsLoggedIn(ctx) {
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
return
}
title := "Potion - Favorites"
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(nil)
} 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(nil)
} else {
page = pages.FavoritesPage(&filters)
}
}
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) CreatePageHandler(ctx *gin.Context) {
// If not logged in, direct to the login page
if !domain.IsLoggedIn(ctx) {
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
return
}
// Ensure user is logged in with a valid account
if user := s.deps.UserService.GetAuthenicatedUser(ctx); user == nil {
// Log (stale) user out
s.SetCookie(ctx, "jwt_token", "", -1)
s.SetCookie(ctx, "search-filters", "", -1)
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
return
}
title := "Potion - Create"
page := pages.CreatePage()
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) ProfilePageHandler(ctx *gin.Context) {
// If not logged in, direct to the login page
if !domain.IsLoggedIn(ctx) {
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
return
}
// Else, get the user data
user := s.deps.UserService.GetAuthenicatedUser(ctx)
if user == nil {
// User is failing to be found, direct to the login page
ctx.Redirect(http.StatusSeeOther, domain.WEB_LOGIN)
return
}
recipes, err := s.deps.RecipeService.GetUserRecipes(user.Id)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("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
}
favorites, err := s.deps.RecipeService.GetUserFavoriteRecipes(user.Id)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()))
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": fmt.Sprintf("Error getting favorite recipes. %s\n", err.Error()),
})
return
}
// Get the engagement data, not sure what will happen when errors occur
engagements, err := s.deps.EngagementService.GetUserEngagement(user.Id, 6)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("Error getting user engagements. %s\n", err.Error()))
ctx.JSON(http.StatusInternalServerError, gin.H{
"status": http.StatusInternalServerError,
"message": fmt.Sprintf("Error getting user engagements. %s\n", err.Error()),
})
return
}
title := "Potion - Profile"
page := pages.ProfilePage(*user, recipes, favorites, engagements)
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) ListPageHandler(ctx *gin.Context) {
title := "Potion - Shopping List"
page := pages.ListPage()
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) RecipePageHandler(ctx *gin.Context) {
// Call recipe service to get via ID
id := ctx.Param("id")
// Parse ID
parsed, err := strconv.Atoi(id)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
ctx.JSON(400, err.Error())
return
}
// Get signed in user, if they exist
var userId *int = nil
var loggedIn = domain.IsLoggedIn(ctx)
// Ensure user is logged in with a valid account
if user := s.deps.UserService.GetAuthenicatedUser(ctx); user == nil {
// Log (stale) user out
s.SetCookie(ctx, "jwt_token", "", -1)
s.SetCookie(ctx, "search-filters", "", -1)
loggedIn = false
}
if loggedIn {
storeId := ctx.MustGet("userId").(int)
userId = &storeId
}
// Get recipe
recipe, err := s.deps.RecipeService.GetRecipe(parsed, userId)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
ctx.JSON(400, err.Error())
return
}
// Get user (owner)
user, err := s.deps.UserService.GetUser(recipe.UserId)
if err != nil {
components.RenderErrorBanner(ctx, fmt.Sprintf("ERROR: %s", err.Error()))
ctx.JSON(400, err.Error())
return
}
title := "Potion - View Recipe"
page := pages.RecipePage(*recipe, *user, loggedIn, s.deps.EnvironmentConfig.Domain)
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) SearchPageHandler(ctx *gin.Context) {
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(nil, false)
} 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(nil, false)
} else {
page = pages.SearchPage(&filters, true)
}
}
title := "Potion - Recipe Search"
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}
func (s *Server) NotFoundPageHandler(ctx *gin.Context) {
title := "Potion - Not Found"
page := pages.NotFoundPage()
ctx.HTML(http.StatusOK, "", layouts.AppLayout(title, page))
}