diff --git a/internal/app/server/recipe_handler_v2.go b/internal/app/server/recipe_handler_v2.go index 46f90c1..f7b8148 100644 --- a/internal/app/server/recipe_handler_v2.go +++ b/internal/app/server/recipe_handler_v2.go @@ -6,6 +6,7 @@ import ( "strconv" "github.com/gin-gonic/gin" + domain "github.com/haydenhargreaves/Potion/internal/domain/recipe" ) // GetRecipeOfTheWeekHandler fetchs the current recipe of the week and returns it. @@ -32,7 +33,7 @@ func (s *Server) GetRecipeOfTheWeekHandlerV2(ctx *gin.Context) { }) } -func (s *Server) GetRecipeV2(ctx *gin.Context) { +func (s *Server) GetRecipeHandlerV2(ctx *gin.Context) { id := ctx.Param("id") parsedId, err := strconv.Atoi(id) if err != nil { @@ -59,3 +60,36 @@ func (s *Server) GetRecipeV2(ctx *gin.Context) { "recipe": recipe, }) } + +func (s *Server) SearchRecipeHandlerV2(ctx *gin.Context) { + var filters domain.SearchFilters + + // Parse filters + if err := ctx.ShouldBindJSON(&filters); err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{ + "status": http.StatusBadRequest, + "message": fmt.Sprintf("[ERROR] Failed to parse filters. %s", err.Error()), + }) + return + } + + // This is optional, so we can do this + userId := getUserId(ctx) + + // Did I really have two APIs...? + // TODO: Fix service at some point, no need to accept the favorites (bool) param + recipes, err := s.deps.RecipeService.SearchRecipes(filters, userId, filters.Favorites) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{ + "status": http.StatusBadRequest, + "message": fmt.Sprintf("[ERROR] Failed to get searched recipes. %s", err.Error()), + }) + return + } + + ctx.JSON(http.StatusOK, gin.H{ + "status": http.StatusOK, + "message": "[OK] Successfully retrieved recipes based on provided filters.", + "recipes": recipes, + }) +} diff --git a/internal/app/server/server.go b/internal/app/server/server.go index b141f6e..67ac926 100644 --- a/internal/app/server/server.go +++ b/internal/app/server/server.go @@ -201,8 +201,9 @@ func (s *Server) Setup() *Server { // ---- VERSION 2 ROUTES ---- // router_api_v2 := router_v2.Group(domain.API) - router_api_v2.GET("/recipe/:id", JwtOptionalAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.GetRecipeV2) + router_api_v2.GET("/recipe/:id", JwtOptionalAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.GetRecipeHandlerV2) router_api_v2.GET("/recipe/of-the-week", JwtOptionalAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.GetRecipeOfTheWeekHandlerV2) + router_api_v2.POST("/recipe/search", JwtOptionalAuthMiddlewareV2([]byte(cfg.JwtSecret)), s.SearchRecipeHandlerV2) router_api_v2.GET("/auth/login", s.GetGoogleAuthUrlHandlerV2) router_api_v2.GET("/auth/callback", s.GoogleCallbackHandlerV2) diff --git a/internal/domain/recipe/recipe.go b/internal/domain/recipe/recipe.go index 56419fa..d73585b 100644 --- a/internal/domain/recipe/recipe.go +++ b/internal/domain/recipe/recipe.go @@ -78,11 +78,12 @@ type Recipe struct { // The integer values should be provided as bits and used to parse out individual flags. More // details can be found in the SearchRecipes service function. type SearchFilters struct { - Search string - MealType int - Time int - Difficulty int - ServingSize int + Search string `json:"Search"` + MealType int `json:"MealType"` + Time int `json:"Time"` + Difficulty int `json:"Difficulty"` + ServingSize int `json:"ServingSize"` + Favorites bool `json:"Favorites"` } // Tag is a model which represents a single tag in the Tags table. A tag is mapped to a recipe diff --git a/web/src/App.tsx b/web/src/App.tsx index ba64894..a4ef3b0 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -12,6 +12,7 @@ import LoginPage from './pages/Login'; import { use, type ReactNode } from 'react'; import { AuthContext } from './context/AuthContext'; import RecipePage from './pages/Recipe'; +import SearchPage from './pages/Search'; function ProtectedRoute({ children }: { children: ReactNode }) { const { isLoggedIn } = use(AuthContext) @@ -39,6 +40,7 @@ function App() { }> } /> } /> + } /> } /> } /> } /> diff --git a/web/src/components/buttons/DropdownButton.tsx b/web/src/components/buttons/DropdownButton.tsx index 266678a..f1de8b3 100644 --- a/web/src/components/buttons/DropdownButton.tsx +++ b/web/src/components/buttons/DropdownButton.tsx @@ -4,13 +4,13 @@ interface DropdownButtonProps { name: string; value: string; selected: boolean; + changeHandler: (e: React.ChangeEvent) => void; } -export default function DropdownButton({ content, name, value, selected }: DropdownButtonProps) { - +export default function DropdownButton({ content, name, value, selected, changeHandler }: DropdownButtonProps) { return (