import type { RecipeTab } from "@batch-cooking/shared"; import type { LucideIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; import { AccountIcon, FavoriteIcon, HouseholdIcon, PublicIcon, SourcesIcon, } from "../../layouts/nav-icons"; import "./recipes.scss"; /** * A tab of the recipe catalog — either a real {@link RecipeTab} (`GET * /recipes?tab=`, `recipe.service.ts`'s `listRecipes`) or `"sources"`, a * web-only mode that doesn't query the recipe table at all: it browses a * household-enabled external source's own catalog live * (`GET /sources/:sourceKey/browse`, `RecipeSourcesPanel`) instead of * listing saved `Recipe` rows. Kept out of the shared `RecipeTab` type on * purpose — the API has no `tab=sources` to validate. */ export type RecipesPageTab = RecipeTab | "sources"; /** Every possible tab, in display order, with its icon — reuses `AccountIcon`/`HouseholdIcon` from the sidebar's own icon set (see nav-icons.tsx) rather than a second "person"/"house" glyph. */ const ALL_TABS: Array<{ value: RecipesPageTab; Icon: LucideIcon }> = [ { value: "favoris", Icon: FavoriteIcon }, { value: "perso", Icon: AccountIcon }, { value: "foyer", Icon: HouseholdIcon }, { value: "publique", Icon: PublicIcon }, { value: "sources", Icon: SourcesIcon }, ]; /** * Catalog tab bar — Favoris / Perso / Foyer / Publique / Sources by * default (`/recettes`, `RecipesPage`). `tabs` narrows which of those * show — `RecipePickerDialog` (picking a recipe for a planning slot) * passes just the four real ones: browsing external sources mid-dialog, * without the review/import flow, doesn't make sense there yet (its * `onChange` narrows the result back to `RecipeTab` itself, safe exactly * because `tabs` guarantees `"sources"` is never clickable there). No * "toutes" tab among the real ones: every recipe a viewer can see falls * under exactly one of perso/foyer/publique (its own visibility) — see * `recipe.service.ts`'s `listRecipes`. */ export function RecipeTabs({ active, onChange, tabs = ALL_TABS.map((tab) => tab.value), }: { active: RecipesPageTab; onChange: (tab: RecipesPageTab) => void; tabs?: readonly RecipesPageTab[]; }) { const { t } = useTranslation(); return (