From 2f5dd0dbc4af2b0d7e8d8ab118ac98b456b23bd6 Mon Sep 17 00:00:00 2001 From: Hayden Hargreaves Date: Wed, 19 Nov 2025 12:30:56 -0700 Subject: [PATCH] (FEAT): UI is complete, just need the actions to be implemented. --- web/src/components/Spinner.tsx | 12 ++++++ web/src/components/buttons/MadeButton.tsx | 4 +- web/src/components/buttons/ShareButton.tsx | 4 +- web/src/components/items/IngredientList.tsx | 34 ++++++++++++++++ web/src/components/items/InstructionList.tsx | 24 +++++++++++ web/src/components/items/TagList.tsx | 43 ++++++++++++++++++++ web/src/pages/Recipe.tsx | 40 +++++++++--------- 7 files changed, 138 insertions(+), 23 deletions(-) create mode 100644 web/src/components/Spinner.tsx create mode 100644 web/src/components/items/IngredientList.tsx create mode 100644 web/src/components/items/InstructionList.tsx create mode 100644 web/src/components/items/TagList.tsx diff --git a/web/src/components/Spinner.tsx b/web/src/components/Spinner.tsx new file mode 100644 index 0000000..14b509b --- /dev/null +++ b/web/src/components/Spinner.tsx @@ -0,0 +1,12 @@ +interface SpinnerProps { + content: string; +} + +export default function Spinner({ content }: SpinnerProps) { + return ( + <> +
+

{ content }

+ + ); +} diff --git a/web/src/components/buttons/MadeButton.tsx b/web/src/components/buttons/MadeButton.tsx index 29fcf49..41a10c5 100644 --- a/web/src/components/buttons/MadeButton.tsx +++ b/web/src/components/buttons/MadeButton.tsx @@ -2,14 +2,14 @@ import { useState } from "react"; interface MadeButtonProps { - id: number | undefined; + id: number; } export default function MadeButton({ id }: MadeButtonProps) { const [clicked, setClicked] = useState(false); const clickHandler = () => { - if (!id || clicked) return; + if (clicked) return; // TODO: Implement actions diff --git a/web/src/components/buttons/ShareButton.tsx b/web/src/components/buttons/ShareButton.tsx index 18759ee..ced9381 100644 --- a/web/src/components/buttons/ShareButton.tsx +++ b/web/src/components/buttons/ShareButton.tsx @@ -2,14 +2,14 @@ import { useState } from "react"; interface ShareButtonProps { - id: number | undefined; + id: number; } export default function ShareButton({ id }: ShareButtonProps) { const [clicked, setClicked] = useState(false); const clickHandler = () => { - if (!id || clicked) return; + if (clicked) return; // TODO: Implement action here diff --git a/web/src/components/items/IngredientList.tsx b/web/src/components/items/IngredientList.tsx new file mode 100644 index 0000000..6e9c337 --- /dev/null +++ b/web/src/components/items/IngredientList.tsx @@ -0,0 +1,34 @@ +import type { RecipeIngredient } from "../../types/recipe"; + +interface IngredientListProps { + ingredients: RecipeIngredient[]; +} + +export default function IngredientList({ ingredients }: IngredientListProps) { + return ( + <> +
+

Ingredients

+
+
    + {ingredients?.map(ingredient => ( +
  • + + + + + + {ingredient.Quantity}: {ingredient.Name} +
  • + ))} +
+
+ + ); +} diff --git a/web/src/components/items/InstructionList.tsx b/web/src/components/items/InstructionList.tsx new file mode 100644 index 0000000..9aef668 --- /dev/null +++ b/web/src/components/items/InstructionList.tsx @@ -0,0 +1,24 @@ +interface InstructionListProps { + instructions: string[]; +} +export default function InstructionList({ instructions }: InstructionListProps) { + return ( + <> +
+

Instructions

+
+
    + {instructions?.map((instruction, i) => ( +
  • +
    +

    { i + 1}

    +
    +

    { instruction }

    +
  • + ))} +
+
+ + + ); +} diff --git a/web/src/components/items/TagList.tsx b/web/src/components/items/TagList.tsx new file mode 100644 index 0000000..51c0060 --- /dev/null +++ b/web/src/components/items/TagList.tsx @@ -0,0 +1,43 @@ +import type { Tag } from "../../types/recipe"; + +interface TagListProps { + tags: Tag[] + created: Date + modified: Date | null; +} + +function FormatDate(date: Date): string { + return new Intl.DateTimeFormat("en-US", { + year: "numeric", + month: "2-digit", + day: "2-digit" + }).format(date); +} + +export default function TagList({ tags, created, modified }: TagListProps) { + + + return ( +
+ {tags && ( + <> +

Tags

+
+
    + {tags.map(tag => ( +
  • + {tag.Name} +
  • + + ))} +
+ + )} +
+

Created: {FormatDate(new Date(created))}

+ {modified && ( +

Last Modified: {FormatDate(new Date(modified))}

+ )} +
+ ); +} diff --git a/web/src/pages/Recipe.tsx b/web/src/pages/Recipe.tsx index db6461a..97089d6 100644 --- a/web/src/pages/Recipe.tsx +++ b/web/src/pages/Recipe.tsx @@ -1,22 +1,20 @@ -import { use, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; import { isApiError, type ApiError } from "../types/api/error"; import { GetRecipe } from "../services/RecipeService"; import type { Recipe } from "../types/recipe"; -import { AuthContext } from "../context/AuthContext"; import { useParams } from "react-router-dom"; import RecipePlaceholder from "../assets/images/recipe_placeholder_wide.jpg" -import TimeIcon from "../components/icons/TimeIcon"; -import StarIcon from "../components/icons/StarIcon"; import RecipeMetaData from "../components/display/RecipeMetaData"; import MadeButton from "../components/buttons/MadeButton"; import ShareButton from "../components/buttons/ShareButton"; import FavoriteButton from "../components/buttons/FavoriteButton"; +import TagList from "../components/items/TagList"; +import IngredientList from "../components/items/IngredientList"; +import InstructionList from "../components/items/InstructionList"; +import Spinner from "../components/Spinner"; export default function RecipePage() { - // Context - const { isLoggedIn } = use(AuthContext); - // Url params const { id } = useParams(); @@ -42,28 +40,32 @@ export default function RecipePage() { console.error(error); }, [error]); - return ( + return recipe ? ( <>
-

{recipe?.Title ?? "Loading..."}

+

{recipe.Title}

Author: loading...

-

Category: {recipe?.Category ?? "loading..."}

+

Category: {recipe.Category}

- - - + + +

About this recipe

-

{recipe?.Description ?? "loading..."}

+

{recipe.Description}

- @ingredientList(recipe.Ingredients) - @instructionList(recipe.Instructions) - @tagList(recipe.Tags, recipe.Created, recipe.Modified) - + + + - ) + ) : ( + /* TODO: Implement a loading page! */ +
+ +
+ ); }