update frontend routes

This commit is contained in:
Arthur Barre 2025-03-13 22:04:04 +01:00
parent 45a26e269d
commit bd5891ff1b
8 changed files with 272 additions and 180 deletions

View File

@ -1,4 +1,4 @@
import { BrowserRouter, Routes, Route } from 'react-router-dom' import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'
import './App.css' import './App.css'
import Register from './pages/Auth/Register' import Register from './pages/Auth/Register'
import Login from './pages/Auth/Login' import Login from './pages/Auth/Login'
@ -9,25 +9,37 @@ import Profile from './pages/Profile'
import Home from './pages/Home' import Home from './pages/Home'
import { MainLayout } from './layouts/MainLayout' import { MainLayout } from './layouts/MainLayout'
import RecipeForm from "@/pages/Recipes/RecipeForm" import RecipeForm from "@/pages/Recipes/RecipeForm"
import useAuth from '@/hooks/useAuth'
import { ProtectedRoute, AuthRoute } from '@/components/RouteGuards'
function App() { function App() {
const { isAuthenticated, isLoading } = useAuth();
if (isLoading) {
return <div>Chargement de l'application...</div>;
}
return ( return (
<BrowserRouter> <BrowserRouter>
<MainLayout> <MainLayout>
<Routes> <Routes>
{/* Pages d'authentification */} {/* Routes d'authentification */}
<Route path="/auth/register" element={<Register />} /> <Route path="/auth/register" element={<AuthRoute><Register /></AuthRoute>} />
<Route path="/auth/login" element={<Login />} /> <Route path="/auth/login" element={<AuthRoute><Login /></AuthRoute>} />
{/* Pages de recettes */} {/* Routes publiques */}
<Route path="/recipes" element={<RecipeList />} /> <Route path="/recipes" element={<ProtectedRoute><RecipeList /></ProtectedRoute>} />
<Route path="/recipes/:id" element={<RecipeDetail />} /> <Route path="/recipes/:id" element={<ProtectedRoute><RecipeDetail /></ProtectedRoute>} />
<Route path="/recipes/new" element={<RecipeForm />} />
{/* <Route path="/favorites" element={<Favorites />} /> */}
{/* Autres pages */} {/* Routes protégées */}
<Route path="/profile" element={<Profile />} /> <Route path="/recipes/new" element={<ProtectedRoute><RecipeForm /></ProtectedRoute>} />
<Route path="/" element={<Home />} /> <Route path="/profile" element={<ProtectedRoute><Profile /></ProtectedRoute>} />
{/* Route racine avec redirection conditionnelle */}
<Route path="/" element={isAuthenticated ? <Navigate to="/recipes" replace /> : <Home />} />
{/* Route de fallback pour les URLs non trouvées */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes> </Routes>
</MainLayout> </MainLayout>
</BrowserRouter> </BrowserRouter>

View File

@ -3,10 +3,11 @@ import axios from 'axios';
export interface Recipe { export interface Recipe {
id: string; id: string;
title: string; title?: string;
ingredients: string; instructions: string[];
generatedRecipe: string; ingredients?: string;
createdAt: string; generatedRecipe?: string;
createdAt?: string;
audioUrl?: string; audioUrl?: string;
} }

View File

@ -0,0 +1,52 @@
import { Navigate } from 'react-router-dom';
import useAuth from '@/hooks/useAuth';
interface RouteGuardProps {
children: JSX.Element;
}
/**
* Protège les routes qui nécessitent une authentification
*
* Règles:
* 1. Si l'utilisateur n'est pas authentifié, redirection vers /auth/login
* 2. Si l'utilisateur est authentifié, affiche le composant enfant
*/
export const ProtectedRoute = ({ children }: RouteGuardProps): JSX.Element => {
const { isAuthenticated, isLoading } = useAuth();
// Afficher un loader pendant la vérification
if (isLoading) {
return <div>Chargement...</div>;
}
// Rediriger vers login si non authentifié
if (!isAuthenticated) {
return <Navigate to="/auth/login" replace />;
}
return children;
};
/**
* Protège les routes d'authentification (login, register)
*
* Règles:
* 1. Si l'utilisateur est déjà authentifié, redirection vers /recipes
* 2. Si l'utilisateur n'est pas authentifié, affiche le composant enfant
*/
export const AuthRoute = ({ children }: RouteGuardProps): JSX.Element => {
const { isAuthenticated, isLoading } = useAuth();
// Afficher un loader pendant la vérification
if (isLoading) {
return <div>Chargement...</div>;
}
// Rediriger vers recipes si déjà authentifié
if (isAuthenticated) {
return <Navigate to="/recipes" replace />;
}
return children;
};

View File

@ -7,20 +7,13 @@ import { Menu, X, LogOut, User, Heart, Home, BookOpen } from "lucide-react"
import { cn } from "@/lib/utils" import { cn } from "@/lib/utils"
import { motion, AnimatePresence } from "framer-motion" import { motion, AnimatePresence } from "framer-motion"
import { Logo } from "@/components/illustrations/Logo" import { Logo } from "@/components/illustrations/Logo"
import useAuth from "@/hooks/useAuth"
export function Header() { export function Header() {
const [isAuthenticated, setIsAuthenticated] = useState(false) const { isAuthenticated } = useAuth()
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false) const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
const location = useLocation() const location = useLocation()
useEffect(() => {
// Vérifier si l'utilisateur est authentifié
const token = localStorage.getItem("token")
setIsAuthenticated(!!token)
// Fermer le menu mobile lors d'un changement de route
setIsMobileMenuOpen(false)
}, [location])
const toggleMobileMenu = () => { const toggleMobileMenu = () => {
setIsMobileMenuOpen(!isMobileMenuOpen) setIsMobileMenuOpen(!isMobileMenuOpen)
@ -28,7 +21,6 @@ export function Header() {
const handleLogout = () => { const handleLogout = () => {
localStorage.removeItem("token") localStorage.removeItem("token")
setIsAuthenticated(false)
setIsMobileMenuOpen(false) setIsMobileMenuOpen(false)
window.location.href = "/auth/login" window.location.href = "/auth/login"
} }
@ -36,9 +28,9 @@ export function Header() {
const navItems = [ const navItems = [
{ name: "Accueil", path: "/", icon: Home, public: true }, { name: "Accueil", path: "/", icon: Home, public: true },
{ name: "Recettes", path: "/recipes", icon: BookOpen, public: true }, { name: "Recettes", path: "/recipes", icon: BookOpen, public: true },
// { name: "Mes recettes", path: "/my-recipes", icon: BookOpen, public: false }, { name: "Mes recettes", path: "/recipes", icon: BookOpen, public: false },
// { name: "Favoris", path: "/favorites", icon: Heart, public: false }, { name: "Favoris", path: "/favorites", icon: Heart, public: false },
// { name: "Profil", path: "/profile", icon: User, public: false }, { name: "Profil", path: "/profile", icon: User, public: false },
] ]
const filteredNavItems = navItems.filter((item) => item.public || isAuthenticated) const filteredNavItems = navItems.filter((item) => item.public || isAuthenticated)
@ -54,21 +46,25 @@ export function Header() {
</div> </div>
{/* Navigation desktop */} {/* Navigation desktop */}
<nav className="hidden md:flex items-center gap-10"> {
{filteredNavItems.map((item) => ( isAuthenticated && (
<Link <nav className="hidden md:flex items-center gap-10">
key={item.path} {filteredNavItems.map((item) => (
to={item.path} <Link
className={cn( key={item.path}
"text-sm font-medium transition-colors hover:text-orange-500 flex items-center gap-1.5", to={item.path}
location.pathname === item.path ? "text-orange-500" : "text-muted-foreground", className={cn(
)} "text-sm font-medium transition-colors hover:text-orange-500 flex items-center gap-1.5",
> location.pathname === item.path ? "text-orange-500" : "text-muted-foreground",
<item.icon className="h-4 w-4" /> )}
{item.name} >
</Link> <item.icon className="h-4 w-4" />
))} {item.name}
</nav> </Link>
))}
</nav>
)
}
{/* Boutons d'authentification */} {/* Boutons d'authentification */}
<div className="hidden md:flex items-center gap-4"> <div className="hidden md:flex items-center gap-4">
@ -98,80 +94,84 @@ export function Header() {
</div> </div>
{/* Bouton menu mobile */} {/* Bouton menu mobile */}
<Button variant="ghost" size="icon" className="md:hidden rounded-full" onClick={toggleMobileMenu}> {isAuthenticated && (
{isMobileMenuOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />} <Button variant="ghost" size="icon" className="md:hidden rounded-full" onClick={toggleMobileMenu}>
</Button> {isMobileMenuOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />}
</Button>
)}
</div> </div>
</div> </div>
{/* Menu mobile */} {/* Menu mobile */}
<AnimatePresence> {isAuthenticated && (
{isMobileMenuOpen && ( <AnimatePresence>
<motion.div {isMobileMenuOpen && (
className="md:hidden border-b" <motion.div
initial={{ opacity: 0, height: 0 }} className="md:hidden border-b"
animate={{ opacity: 1, height: "auto" }} initial={{ opacity: 0, height: 0 }}
exit={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: "auto" }}
transition={{ duration: 0.2 }} exit={{ opacity: 0, height: 0 }}
> transition={{ duration: 0.2 }}
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-4 pb-6"> >
<nav className="flex flex-col space-y-4"> <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-4 pb-6">
{filteredNavItems.map((item, index) => ( <nav className="flex flex-col space-y-4">
{filteredNavItems.map((item, index) => (
<motion.div
key={item.path}
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.05 }}
>
<Link
to={item.path}
className={cn(
"flex items-center gap-3 py-2 text-sm font-medium transition-colors hover:text-orange-500",
location.pathname === item.path ? "text-orange-500" : "text-muted-foreground",
)}
onClick={() => setIsMobileMenuOpen(false)}
>
<item.icon className="h-5 w-5" />
{item.name}
</Link>
</motion.div>
))}
<motion.div <motion.div
key={item.path}
initial={{ opacity: 0, x: -10 }} initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.05 }} transition={{ delay: filteredNavItems.length * 0.05 }}
className="pt-2"
> >
<Link {isAuthenticated ? (
to={item.path} <Button
className={cn( variant="outline"
"flex items-center gap-3 py-2 text-sm font-medium transition-colors hover:text-orange-500", onClick={handleLogout}
location.pathname === item.path ? "text-orange-500" : "text-muted-foreground", className="w-full border-orange-200 hover:bg-orange-50 hover:text-orange-600 dark:border-orange-800 dark:hover:bg-orange-900/20 dark:hover:text-orange-400"
)} >
onClick={() => setIsMobileMenuOpen(false)} <LogOut className="mr-2 h-4 w-4" />
> Déconnexion
<item.icon className="h-5 w-5" /> </Button>
{item.name} ) : (
</Link> <div className="flex flex-col space-y-2">
<Link to="/auth/login" onClick={() => setIsMobileMenuOpen(false)}>
<Button variant="ghost" className="w-full hover:text-orange-500">
Connexion
</Button>
</Link>
<Link to="/auth/register" onClick={() => setIsMobileMenuOpen(false)}>
<Button className="w-full bg-gradient-to-r from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600 text-white">
S'inscrire
</Button>
</Link>
</div>
)}
</motion.div> </motion.div>
))} </nav>
</div>
<motion.div </motion.div>
initial={{ opacity: 0, x: -10 }} )}
animate={{ opacity: 1, x: 0 }} </AnimatePresence>
transition={{ delay: filteredNavItems.length * 0.05 }} )}
className="pt-2"
>
{isAuthenticated ? (
<Button
variant="outline"
onClick={handleLogout}
className="w-full border-orange-200 hover:bg-orange-50 hover:text-orange-600 dark:border-orange-800 dark:hover:bg-orange-900/20 dark:hover:text-orange-400"
>
<LogOut className="mr-2 h-4 w-4" />
Déconnexion
</Button>
) : (
<div className="flex flex-col space-y-2">
<Link to="/auth/login" onClick={() => setIsMobileMenuOpen(false)}>
<Button variant="ghost" className="w-full hover:text-orange-500">
Connexion
</Button>
</Link>
<Link to="/auth/register" onClick={() => setIsMobileMenuOpen(false)}>
<Button className="w-full bg-gradient-to-r from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600 text-white">
S'inscrire
</Button>
</Link>
</div>
)}
</motion.div>
</nav>
</div>
</motion.div>
)}
</AnimatePresence>
</header> </header>
) )
} }

View File

@ -29,7 +29,7 @@ export function LoginForm({
throw new Error("Échec de la connexion") throw new Error("Échec de la connexion")
} }
navigate("/") navigate("/recipes")
} catch (err) { } catch (err) {
console.error("Erreur de connexion:", err); console.error("Erreur de connexion:", err);
setError(err instanceof Error ? err.message : "Une erreur est survenue") setError(err instanceof Error ? err.message : "Une erreur est survenue")
@ -52,7 +52,7 @@ export function LoginForm({
localStorage.setItem("token", response.token) localStorage.setItem("token", response.token)
navigate("/") navigate("/recipes")
} catch (err) { } catch (err) {
console.error("Erreur de connexion Google:", err) console.error("Erreur de connexion Google:", err)
setError(err instanceof Error ? err.message : "Une erreur est survenue") setError(err instanceof Error ? err.message : "Une erreur est survenue")

View File

@ -0,0 +1,41 @@
import { useState, useEffect } from 'react';
interface AuthHook {
isAuthenticated: boolean;
isLoading: boolean;
checkAuth: () => boolean;
}
/**
* Hook pour gérer l'authentification
*
* Règles:
* 1. Un utilisateur est considéré comme authentifié s'il a un token valide dans localStorage
* 2. Le hook vérifie l'authentification au chargement et fournit un état de chargement
* 3. Expose une méthode pour vérifier l'authentification à la demande
*/
const useAuth = (): AuthHook => {
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(true);
// Fonction pour vérifier l'authentification
const checkAuth = (): boolean => {
const token = localStorage.getItem('token');
// On pourrait ajouter une vérification de validité du token ici
return !!token;
};
useEffect(() => {
// Vérifier l'authentification au chargement
setIsAuthenticated(checkAuth());
setIsLoading(false);
}, []);
return {
isAuthenticated,
isLoading,
checkAuth
};
};
export default useAuth;

View File

@ -13,7 +13,6 @@ import PastaVongole from "@/assets/pasta-alla-vongole-home.jpeg"
export default function Home() { export default function Home() {
return ( return (
<div className="md:space-y-24 space-y-4 pb-16"> <div className="md:space-y-24 space-y-4 pb-16">
222
<section className="py-12 md:py-20 flex justify-center"> <section className="py-12 md:py-20 flex justify-center">
<div className="container px-4 md:px-6"> <div className="container px-4 md:px-6">
<div className="grid gap-6 lg:grid-cols-2 lg:gap-12 items-center"> <div className="grid gap-6 lg:grid-cols-2 lg:gap-12 items-center">
@ -37,20 +36,20 @@ export default function Home() {
secondes. Fini le gaspillage alimentaire ! secondes. Fini le gaspillage alimentaire !
</p> </p>
<div className="flex flex-col gap-3 min-[400px]:flex-row"> <div className="flex flex-col gap-3 min-[400px]:flex-row">
<Link to="/recipes"> <Link to="/auth/register">
<Button className="bg-gradient-to-r from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600 text-white"> <Button className="bg-gradient-to-r from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600 text-white">
Commencer maintenant Commencer maintenant
<ArrowRight className="ml-2 h-4 w-4" /> <ArrowRight className="ml-2 h-4 w-4" />
</Button> </Button>
</Link> </Link>
<Link to="/auth/register"> {/* <Link to="/auth/register">
<Button <Button
variant="outline" variant="outline"
className="border-orange-200 hover:bg-orange-50 hover:text-orange-600 dark:border-orange-800 dark:hover:bg-orange-900/20 dark:hover:text-orange-400" className="border-orange-200 hover:bg-orange-50 hover:text-orange-600 dark:border-orange-800 dark:hover:bg-orange-900/20 dark:hover:text-orange-400"
> >
Créer un compte Créer un compte
</Button> </Button>
</Link> </Link> */}
</div> </div>
</motion.div> </motion.div>
<motion.div <motion.div
@ -429,11 +428,11 @@ export default function Home() {
<ArrowRight className="ml-2 h-4 w-4" /> <ArrowRight className="ml-2 h-4 w-4" />
</Button> </Button>
</Link> </Link>
<Link to="/recipes"> {/* <Link to="/recipes">
<Button variant="outline" className="border-white text-white hover:bg-white/20"> <Button variant="outline" className="border-white text-white hover:bg-white/20">
Explorer les recettes Explorer les recettes
</Button> </Button>
</Link> </Link> */}
</div> </div>
</div> </div>
</motion.div> </motion.div>

View File

@ -11,8 +11,6 @@ import {
Heart, Heart,
Share2, Share2,
ArrowLeft, ArrowLeft,
Trash2,
Edit,
Printer, Printer,
CheckCircle2, CheckCircle2,
Timer, Timer,
@ -32,8 +30,8 @@ export default function RecipeDetail() {
const [recipe, setRecipe] = useState<Recipe | null>(null) const [recipe, setRecipe] = useState<Recipe | null>(null)
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [error, setError] = useState("") const [error, setError] = useState("")
const [isFavorite, setIsFavorite] = useState(false) // const [isFavorite, setIsFavorite] = useState(false)
const [addingToFavorites, setAddingToFavorites] = useState(false) // const [addingToFavorites, setAddingToFavorites] = useState(false)
const [checkedIngredients, setCheckedIngredients] = useState<Set<number>>(new Set()) const [checkedIngredients, setCheckedIngredients] = useState<Set<number>>(new Set())
const [checkedSteps, setCheckedSteps] = useState<Set<number>>(new Set()) const [checkedSteps, setCheckedSteps] = useState<Set<number>>(new Set())
const [showScrollTop, setShowScrollTop] = useState(false) const [showScrollTop, setShowScrollTop] = useState(false)
@ -68,8 +66,8 @@ export default function RecipeDetail() {
// ✅ GET FAVORITE RECIPES & CHECK IF FAVORITE // ✅ GET FAVORITE RECIPES & CHECK IF FAVORITE
try { try {
const favorites = await recipeService.getFavoriteRecipes() // const favorites = await recipeService.getFavoriteRecipes()
setIsFavorite(favorites.some((fav) => fav.id === id)) // setIsFavorite(favorites.some((fav) => fav.id === id))
} catch (favError) { } catch (favError) {
// Ignorer les erreurs de favoris pour ne pas bloquer l'affichage // Ignorer les erreurs de favoris pour ne pas bloquer l'affichage
console.log("Impossible de vérifier les favoris:", favError) console.log("Impossible de vérifier les favoris:", favError)
@ -97,42 +95,42 @@ export default function RecipeDetail() {
return () => window.removeEventListener("scroll", handleScroll) return () => window.removeEventListener("scroll", handleScroll)
}, [id]) }, [id])
const handleToggleFavorite = async () => { // const handleToggleFavorite = async () => {
if (!id || !recipe) return // if (!id || !recipe) return
try { // try {
setAddingToFavorites(true) // setAddingToFavorites(true)
if (isFavorite) { // if (isFavorite) {
// ✅ REMOVE FROM FAVORITES // // ✅ REMOVE FROM FAVORITES
await recipeService.removeFromFavorites(id) // await recipeService.removeFromFavorites(id)
setIsFavorite(false) // setIsFavorite(false)
} else { // } else {
// ✅ ADD TO FAVORITES // // ✅ ADD TO FAVORITES
await recipeService.addToFavorites(id) // await recipeService.addToFavorites(id)
setIsFavorite(true) // setIsFavorite(true)
} // }
} catch (err) { // } catch (err) {
console.error("Erreur lors de la modification des favoris:", err) // console.error("Erreur lors de la modification des favoris:", err)
// Ne pas afficher d'erreur à l'utilisateur pour cette fonctionnalité // // Ne pas afficher d'erreur à l'utilisateur pour cette fonctionnalité
} finally { // } finally {
setAddingToFavorites(false) // setAddingToFavorites(false)
} // }
} // }
const handleDeleteRecipe = async () => { // const handleDeleteRecipe = async () => {
if (!id) return // if (!id) return
if (!window.confirm("Êtes-vous sûr de vouloir supprimer cette recette ?")) return // if (!window.confirm("Êtes-vous sûr de vouloir supprimer cette recette ?")) return
try { // try {
// ✅ DELETE RECIPE // // ✅ DELETE RECIPE
await recipeService.deleteRecipe(id) // await recipeService.deleteRecipe(id)
navigate("/recipes") // navigate("/recipes")
} catch (err) { // } catch (err) {
console.error("Erreur lors de la suppression:", err) // console.error("Erreur lors de la suppression:", err)
// Optionnel: afficher un message d'erreur à l'utilisateur // // Optionnel: afficher un message d'erreur à l'utilisateur
} // }
} // }
const handleShare = () => { const handleShare = () => {
if (!recipe) return if (!recipe) return
@ -177,9 +175,6 @@ export default function RecipeDetail() {
window.scrollTo({ top: 0, behavior: "smooth" }) window.scrollTo({ top: 0, behavior: "smooth" })
} }
// ========================================
// === LOADING & ERROR STATES ============
// ========================================
if (loading) { if (loading) {
return <RecipeDetailLoader /> return <RecipeDetailLoader />
} }
@ -222,7 +217,7 @@ export default function RecipeDetail() {
<Button variant="ghost" size="icon" className="rounded-full" onClick={handleShare}> <Button variant="ghost" size="icon" className="rounded-full" onClick={handleShare}>
<Share2 className="h-4 w-4" /> <Share2 className="h-4 w-4" />
</Button> </Button>
{/*
<Button <Button
variant={isFavorite ? "default" : "ghost"} variant={isFavorite ? "default" : "ghost"}
size="icon" size="icon"
@ -231,7 +226,7 @@ export default function RecipeDetail() {
disabled={addingToFavorites} disabled={addingToFavorites}
> >
<Heart className="h-4 w-4" /> <Heart className="h-4 w-4" />
</Button> </Button> */}
</div> </div>
</div> </div>
</div> </div>
@ -371,41 +366,33 @@ export default function RecipeDetail() {
{recipe.instructions && recipe.instructions.length > 0 ? ( {recipe.instructions && recipe.instructions.length > 0 ? (
recipe.instructions.map((instruction, index) => ( recipe.instructions.map((instruction, index) => (
<li key={index} className="flex"> <li key={index} className="flex">
<Checkbox {/* <Checkbox
id={`step-${index}`} id={`step-${index}`}
checked={checkedSteps.has(index)} checked={checkedSteps.has(index)}
onCheckedChange={() => toggleStep(index)} onCheckedChange={() => toggleStep(index)}
className="mr-3 mt-1 data-[state=checked]:bg-orange-500 data-[state=checked]:border-orange-500" className="mr-3 mt-1 data-[state=checked]:bg-orange-500 data-[state=checked]:border-orange-500"
/> /> */}
<div className="flex-1"> <div className="flex-1">
<label <p className={checkedSteps.has(index) ? "text-muted-foreground" : ""}>
htmlFor={`step-${index}`} {instruction}
className={`flex items-center font-medium mb-2 cursor-pointer ${checkedSteps.has(index) ? "line-through text-muted-foreground" : ""}`} {checkedSteps.has(index) && <CheckCircle2 className="ml-2 h-4 w-4 text-green-500 inline" />}
> </p>
Étape {index + 1}
{checkedSteps.has(index) && <CheckCircle2 className="ml-2 h-4 w-4 text-green-500" />}
</label>
<p className={checkedSteps.has(index) ? "text-muted-foreground" : ""}>{instruction}</p>
</div> </div>
</li> </li>
)) ))
) : ( ) : (
<li className="flex"> <li className="flex">
<Checkbox {/* <Checkbox
id="step-single" id="step-single"
checked={checkedSteps.has(0)} checked={checkedSteps.has(0)}
onCheckedChange={() => toggleStep(0)} onCheckedChange={() => toggleStep(0)}
className="mr-3 mt-1 data-[state=checked]:bg-orange-500 data-[state=checked]:border-orange-500" className="mr-3 mt-1 data-[state=checked]:bg-orange-500 data-[state=checked]:border-orange-500"
/> /> */}
<div className="flex-1"> <div className="flex-1">
<label <p className={checkedSteps.has(0) ? "text-muted-foreground" : ""}>
htmlFor="step-single" {recipe.generatedRecipe}
className={`flex items-center font-medium mb-2 cursor-pointer ${checkedSteps.has(0) ? "line-through text-muted-foreground" : ""}`} {checkedSteps.has(0) && <CheckCircle2 className="ml-2 h-4 w-4 text-green-500 inline" />}
> </p>
Instructions
{checkedSteps.has(0) && <CheckCircle2 className="ml-2 h-4 w-4 text-green-500" />}
</label>
<p className={checkedSteps.has(0) ? "text-muted-foreground" : ""}>{recipe.generatedRecipe}</p>
</div> </div>
</li> </li>
)} )}