import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { CheckSquare, Square, UtensilsCrossed } from "lucide-react"; import { useRecipes } from "@/hooks/useRecipes"; import { useDebouncedValue } from "@/hooks/useDebouncedValue"; import { RecipeCard } from "@/components/recipes/RecipeCard"; import { RecipeFilters, type CategoryFilter } from "@/components/recipes/RecipeFilters"; import { PdfGenerator } from "@/components/pdf/PdfGenerator"; import { GridSkeleton } from "@/components/ui/Skeleton"; import { EmptyState } from "@/components/ui/EmptyState"; import { ErrorState } from "@/components/ui/ErrorState"; import { extractApiError } from "@/api/axiosInstance"; import { nextSort, sortBy, sortIndicator, type SortDirection } from "@/utils/sort.util"; type RecipeSortColumn = "name" | "calories" | "prepTime"; const RECIPE_SORT_COLUMNS: { id: RecipeSortColumn; labelKey: string }[] = [ { id: "name", labelKey: "manage.recipeName" }, { id: "calories", labelKey: "recipes.calories" }, { id: "prepTime", labelKey: "manage.prepTimeMin" }, ]; export function AllMealsPage() { const { t } = useTranslation(); const [filter, setFilter] = useState("all"); const [search, setSearch] = useState(""); const [searchByIngredient, setSearchByIngredient] = useState(false); const [selected, setSelected] = useState>(new Set()); const [recipeSort, setRecipeSort] = useState<{ column: RecipeSortColumn; direction: SortDirection }>({ column: "name", direction: "asc", }); const debouncedSearch = useDebouncedValue(search.trim(), 350); const ingredientTerm = searchByIngredient && debouncedSearch ? debouncedSearch : undefined; const { data: recipes, isLoading, isError, error, refetch } = useRecipes( undefined, undefined, ingredientTerm, ); const visible = useMemo(() => { if (!recipes) return []; const term = search.trim().toLowerCase(); return recipes.filter((r) => { const matchesCategory = filter === "all" || r.mealCategory === filter; const matchesSearch = searchByIngredient || term === "" || r.name.toLowerCase().includes(term); return matchesCategory && matchesSearch; }); }, [recipes, filter, search, searchByIngredient]); const sortedVisible = useMemo(() => { const { column, direction } = recipeSort; return sortBy(visible, direction, (recipe) => { switch (column) { case "name": return recipe.name; case "calories": return recipe.calories; case "prepTime": return recipe.prepTimeMinutes; } }); }, [visible, recipeSort]); const toggleRecipeSort = (column: RecipeSortColumn) => { setRecipeSort((current) => nextSort(current, column)); }; const toggleSelected = (id: number) => { setSelected((prev) => { const next = new Set(prev); if (next.has(id)) { next.delete(id); } else { next.add(id); } return next; }); }; const selectAllVisible = () => { setSelected((prev) => { const next = new Set(prev); visible.forEach((r) => next.add(r.id)); return next; }); }; const deselectAll = () => setSelected(new Set()); const selectedIds = useMemo(() => Array.from(selected), [selected]); return (

{t("recipes.allMealsTitle")}

{t("recipes.allMealsSubtitle")}

{t("common.selectedCount", { count: selected.size })}
{isLoading && } {isError && ( void refetch()} /> )} {!isLoading && !isError && visible.length === 0 && ( )} {!isLoading && !isError && visible.length > 0 && ( <>
{RECIPE_SORT_COLUMNS.map(({ id, labelKey }) => ( ))}
{sortedVisible.map((recipe) => ( ))}
)}
); }