From 90937b1f5f16ac5fb45c08afc488db0ce96305e6 Mon Sep 17 00:00:00 2001 From: Rene Fernandez Date: Tue, 9 Jul 2024 18:20:01 +0200 Subject: [PATCH] Add sides support on the client --- client/src/MainRouter.tsx | 12 + .../NavigationLinks/NavigationLinks.tsx | 8 +- client/src/components/PageTitle/PageTitle.tsx | 6 - .../RecipeDetails/RecipeDetails.tsx | 229 -------- client/src/hooks/recipes/use-recipes.tsx | 11 + client/src/locales/es/translation.json | 6 + .../WeeklyMenusList/WeeklyMenusList.tsx | 102 ++-- .../DayMenuDetailsPage/DayMenuDetailsPage.tsx | 12 +- .../menus/MenuDetailsPage/MenuDetailsPage.tsx | 115 ++-- .../AddProductButton/AddProductButton.tsx | 5 +- .../components/ProductList/ProductList.tsx | 62 +- .../AddRecipeForm/AddRecipeForm.tsx | 37 +- .../recipes/EditRecipePage/EditRecipePage.tsx | 43 +- .../EditRecipeForm/EditRecipeForm.tsx | 74 ++- .../RecipeDetails/RecipeDetails.tsx | 65 +++ .../RecipeExtraInfo/RecipeExtraInfo.tsx | 105 ++++ .../components/RecipeHeader/RecipeHeader.tsx | 38 ++ .../RecipeInstructions/RecipeInstructions.tsx | 67 +++ .../RecipeDetailsPage/RecipeDetailsPage.tsx | 55 +- .../components/RecipeList/RecipeList.tsx | 164 +++--- .../pages/sides/AddSidePage/AddSidePage.tsx | 34 ++ .../components/AddSideForm/AddSideForm.tsx | 536 +++++++++++++++++ .../pages/sides/EditSidePage/EditSidePage.tsx | 55 ++ .../components/EditSideForm/EditSideForm.tsx | 541 ++++++++++++++++++ client/src/pages/sides/SidesMain.tsx | 5 + .../src/pages/sides/SidesPage/SidesPage.tsx | 24 + .../components/SideList/SideList.tsx | 195 +++++++ client/src/routes.ts | 4 + client/src/types/recipes.d.ts | 3 +- 29 files changed, 2073 insertions(+), 540 deletions(-) delete mode 100644 client/src/components/RecipeDetails/RecipeDetails.tsx create mode 100644 client/src/pages/recipes/RecipeDetailsPage/RecipeDetails/RecipeDetails.tsx create mode 100644 client/src/pages/recipes/RecipeDetailsPage/RecipeDetails/components/RecipeExtraInfo/RecipeExtraInfo.tsx create mode 100644 client/src/pages/recipes/RecipeDetailsPage/RecipeDetails/components/RecipeHeader/RecipeHeader.tsx create mode 100644 client/src/pages/recipes/RecipeDetailsPage/RecipeDetails/components/RecipeInstructions/RecipeInstructions.tsx create mode 100644 client/src/pages/sides/AddSidePage/AddSidePage.tsx create mode 100644 client/src/pages/sides/AddSidePage/components/AddSideForm/AddSideForm.tsx create mode 100644 client/src/pages/sides/EditSidePage/EditSidePage.tsx create mode 100644 client/src/pages/sides/EditSidePage/components/EditSideForm/EditSideForm.tsx create mode 100644 client/src/pages/sides/SidesMain.tsx create mode 100644 client/src/pages/sides/SidesPage/SidesPage.tsx create mode 100644 client/src/pages/sides/SidesPage/components/SideList/SideList.tsx diff --git a/client/src/MainRouter.tsx b/client/src/MainRouter.tsx index 79c7e8c..d8cbb6f 100644 --- a/client/src/MainRouter.tsx +++ b/client/src/MainRouter.tsx @@ -13,6 +13,10 @@ import EditRecipePage from "pages/recipes/EditRecipePage/EditRecipePage"; import RecipeDetailsPage from "pages/recipes/RecipeDetailsPage/RecipeDetailsPage"; import RecipesMain from "pages/recipes/RecipesMain"; import RecipesPage from "pages/recipes/RecipesPage/RecipesPage"; +import AddSidePage from "pages/sides/AddSidePage/AddSidePage"; +import EditSidePage from "pages/sides/EditSidePage/EditSidePage"; +import SidesMain from "pages/sides/SidesMain"; +import SidesPage from "pages/sides/SidesPage/SidesPage"; import routes from "routes"; export default function Main(): ReactElement { @@ -32,6 +36,14 @@ export default function Main(): ReactElement { element={} /> + + }> + } /> + } /> + } /> + } /> + + }> } /> } /> diff --git a/client/src/components/NavigationLinks/NavigationLinks.tsx b/client/src/components/NavigationLinks/NavigationLinks.tsx index 0d5b95b..c3e2e33 100644 --- a/client/src/components/NavigationLinks/NavigationLinks.tsx +++ b/client/src/components/NavigationLinks/NavigationLinks.tsx @@ -1,5 +1,5 @@ /* eslint-disable react/jsx-props-no-spreading */ -import { IconBaguette, IconChefHat } from "@tabler/icons-react"; +import { IconBaguette, IconChefHat, IconCooker } from "@tabler/icons-react"; import NavigationLink from "./NavigationLink"; import routes from "routes"; @@ -22,6 +22,12 @@ const data = [ label: "Recipes", route: routes.recipesRoute, }, + { + icon: , + color: "orange", + label: "Sides", + route: routes.sidesRoute, + }, ]; export default function NavigationLinks() { diff --git a/client/src/components/PageTitle/PageTitle.tsx b/client/src/components/PageTitle/PageTitle.tsx index f1e262a..2a34c86 100644 --- a/client/src/components/PageTitle/PageTitle.tsx +++ b/client/src/components/PageTitle/PageTitle.tsx @@ -36,10 +36,4 @@ function PageTitle({ ); } -PageTitle.defaultProps = { - icon: null, - subHeader: null, - withBackButton: false, -}; - export default PageTitle; diff --git a/client/src/components/RecipeDetails/RecipeDetails.tsx b/client/src/components/RecipeDetails/RecipeDetails.tsx deleted file mode 100644 index 5408e2d..0000000 --- a/client/src/components/RecipeDetails/RecipeDetails.tsx +++ /dev/null @@ -1,229 +0,0 @@ -/* eslint-disable react/no-danger */ -import React, { useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; -import { - Badge, - Grid, - Group, - List, - Paper, - Rating, - Stack, - Text, - Title, - Image, -} from "@mantine/core"; -import { IconClock, IconEdit, IconFlame, IconUsers } from "@tabler/icons-react"; -import { generateHTML } from "@tiptap/core"; -import { IIngredient } from "types/ingredients"; -import { IRecipe } from "types/recipes"; -import { editorExtensions, renderExtensions } from "utils/editor"; - -interface Props { - recipe: IRecipe; -} - -export default function RecipeDetails({ recipe }: Props) { - const { t } = useTranslation(); - const description = useMemo(() => { - if (recipe && recipe.description) { - let descr = recipe.description; - // Get the type of descr - if (typeof descr === "string") { - descr = JSON.parse(descr); - } - return generateHTML(descr, renderExtensions); - } - return ""; - }, [recipe]); - - const instructions = useMemo(() => { - if (recipe && recipe.instructions) { - let instr = recipe.instructions; - // Get the type of descr - if (typeof instr === "string") { - instr = JSON.parse(instr); - } - return generateHTML(instr, editorExtensions); - } - return ""; - }, [recipe]); - - const notes = useMemo(() => { - if (recipe && recipe.notes) { - let notesParsed = recipe.notes; - // Get the type of descr - if (typeof notesParsed === "string") { - notesParsed = JSON.parse(notesParsed); - } - return generateHTML(notesParsed, editorExtensions); - } - return ""; - }, [recipe]); - - const getRecipeDaysOfWeek = (daysOfWeek: string) => { - switch (daysOfWeek) { - case "ALL": - return t("Todos los días"); - case "WEEKDAYS": - return t("Entre semana"); - case "WEEKENDS": - return t("Fin de semana"); - default: - return t("Todos"); - } - }; - - return ( - <> - - - - - - / - - } - fullSymbol={} - /> - - / - - <IconClock /> - - / - {recipe.preparationTime} - / - - <IconUsers /> - - {recipe.servings} - - - - - - - - {recipe.active ? ( - {t("Activa")} - ) : ( - {t("Inactiva")} - )} - - - - - - - - - - -
- - {t("Ingredientes")} - - {recipe.ingredients.map((ingredient: IIngredient) => ( - - {ingredient.product.name}: {ingredient.quantity} - - ))} - - Instrucciones -
- {recipe.sides && recipe.sides.length > 0 && ( - <> - {t("Acompañamientos")} - - {recipe.sides.map((side: IIngredient) => ( - - {side.product.name}: {side.quantity} - - ))} - - - )} - - - - {t<string("Imagen de la receta")} - /> - - - - - - - {t("Detalles")} - {recipe.meal === "LUNCH" && ( - <> - - {recipe.preferedMeal === "LUNCH" - ? t("Preferida para comer") - : t("Preferida para cenar")} - - - {recipe.isOnlyLunch - ? t("Sólo para comer") - : t("Para comer y cenar")} - - - )} - {recipe.meal === "DINNER" && ( - - {recipe.isOnlyDinner - ? t("Sólo para cenar") - : t("Para comer y cenar")} - - )} - - {t("Días")} - {getRecipeDaysOfWeek(recipe.daysOfWeek)} - - {t("Estaciones")} - - - {t("Primavera")} - - - {t("Verano")} - - - {t("Otoño")} - - - {t("Invierno")} - - - - {t("Temperatura")} - - {recipe.mealTemp === "WARM" ? ( - {t("Caliente")} - ) : ( - {t("Fría")} - )} - - {notes && ( - <> - {t("Notas")} - -
- - - )} - - - - ); -} diff --git a/client/src/hooks/recipes/use-recipes.tsx b/client/src/hooks/recipes/use-recipes.tsx index 6ca9b48..4305adc 100644 --- a/client/src/hooks/recipes/use-recipes.tsx +++ b/client/src/hooks/recipes/use-recipes.tsx @@ -17,6 +17,17 @@ export function useRecipes(options = {}) { }); } +export const fetchSides = async () => { + const { data } = await apiClient.get(`/recipes/?isSidePlate=true`); + return data; +}; + +export function useSides(options = {}) { + return useQuery(["recipes", "sides"], () => fetchSides(), { + ...options, + }); +} + export const useAddrecipe = () => { const { t } = useTranslation(); return useMutation( diff --git a/client/src/locales/es/translation.json b/client/src/locales/es/translation.json index d8c19ef..33dfc75 100644 --- a/client/src/locales/es/translation.json +++ b/client/src/locales/es/translation.json @@ -3,10 +3,12 @@ "Active": "Activa", "Add new product": "Añadir nuevo producto", "Add new recipe": "Añadir nueva receta", + "Add new side": "Añadir nuevo acompañamiento", "Add product": "Añadir producto", "Create weekly menu": "Crear menu semanal", "Choose a recipe for lunch": "Elije una receta para la comida", "Choose the lunch of the day": "Elige la comida del día", + "Choos the meal of the day": "Elige la comida del día", "Credits": "Créditos", "Dinner": "Cena", "Enabled": "Activada", @@ -17,6 +19,7 @@ "Initialize recipes": "Inicializar recetas", "Loading...": "Cargando...", "Loading products...": "Cargando productos...", + "Loading products and side meals...": "Cargando productos y acompañamientos...", "Lunch": "Comida", "Lunch of the day": "Comida del día", "Monday": "Lunes", @@ -30,12 +33,15 @@ "FRUITS": "Frutas", "GRAIN_NUTS_BAKING": "Cereales, frutos secos y panadería", "LEGUMES": "Legumbres", + "Meal": "Comida", + "Meal of the day": "Comida del día", "MEAT_SASUAGE": "Carne y embutido", "PASTA_RICE": "Pasta y arroz", "Products": "Productos", "PRODUCT_FORM_HELP_TEXT": "Añade un producto a tu lista de productos utilizando este formulario. Puedes establecer un nombre y un tipo.", "Recipes": "Recetas", "Seasons": "Estaciones", + "Sides": "Acompañamientos", "Type": "Tipo", "VEGETABLES": "Verduras", "Version": "Versión", diff --git a/client/src/pages/home/components/WeeklyMenusList/WeeklyMenusList.tsx b/client/src/pages/home/components/WeeklyMenusList/WeeklyMenusList.tsx index 9de6830..4255e0a 100644 --- a/client/src/pages/home/components/WeeklyMenusList/WeeklyMenusList.tsx +++ b/client/src/pages/home/components/WeeklyMenusList/WeeklyMenusList.tsx @@ -4,6 +4,7 @@ import { Link } from "react-router-dom"; import { ActionIcon, Anchor, + Box, Button, Group, LoadingOverlay, @@ -81,53 +82,68 @@ export default function WeeklyMenusList() { return ( - - - - - - - - - - - {data && - data.map((menu: IWeeklyMenu) => ( - - - {dayjs(menu.dateCreated).format("DD/MM/YYYY HH:mm")} - - - - {menu.name} - - - - - - handleOpenModal(menu.id, menu.name)} - /> - - handleOpenEditModal(menu.id, menu.name)} - title={t("Cambiar nombre")} - > - - - - + + + +
{t("Fecha")}{t("Name")}{t("Acciones")}
+ + + + + - ))} - -
{t("Fecha")}{t("Name")}{t("Acciones")}
+ + + {data && + data.map((menu: IWeeklyMenu) => ( + + + {dayjs(menu.dateCreated).format("DD/MM/YYYY HH:mm")} + + + + {menu.name} + + + + + + handleOpenModal(menu.id, menu.name)} + /> + + + handleOpenEditModal(menu.id, menu.name) + } + title={t("Cambiar nombre")} + > + + + + + + ))} + + + + diff --git a/client/src/pages/menus/DayMenuDetailsPage/DayMenuDetailsPage.tsx b/client/src/pages/menus/DayMenuDetailsPage/DayMenuDetailsPage.tsx index aa6c37a..7ff6526 100644 --- a/client/src/pages/menus/DayMenuDetailsPage/DayMenuDetailsPage.tsx +++ b/client/src/pages/menus/DayMenuDetailsPage/DayMenuDetailsPage.tsx @@ -10,9 +10,9 @@ import { } from "@mantine/core"; import { Footer } from "components/Footer/Footer"; import PageTitle from "components/PageTitle/PageTitle"; -import RecipeDetails from "components/RecipeDetails/RecipeDetails"; import { useRecipe } from "hooks/recipes/use-recipes"; import { useWeeklyMenu } from "hooks/weekly-menus/use-weekly-menus"; +import RecipeDetails from "pages/recipes/RecipeDetailsPage/RecipeDetails/RecipeDetails"; import { IDailyMenu } from "types/weekly-menus"; export default function DayMenuDetailsPage() { @@ -68,31 +68,31 @@ export default function DayMenuDetailsPage() { }, [data, dayName]); return ( - + - + {items} - + {t("Comida")} {lunchRecipe?.name} {lunchRecipe && } - + Cena {dinnerRecipe?.name} {dinnerRecipe && } - +