20 fichiers à plat -> badges/ (DietTagSelect, DietBadges, AllergenBadges, ReproducibleBadge, FavoriteStarButton), ingredients/ (IngredientPicker, IngredientRow, ingredient-icons), steps/ (StepListEditor, StepDescription, highlight-tech-steps), sources/ (RecipeSourcesPanel, SourceItemTable, RecipeImportForm, recipe-import-draft, useEnabledSources). RecipeTable/RecipeTabs/RecipeDetailPanel et recipes.scss restent à la racine (composants transverses aux sous-dossiers, partagés par plusieurs d'entre eux). Chemins relatifs corrigés dans les fichiers déplacés et chez tous leurs importeurs externes (pages/recipes/*, features/planning/ RecipePickerDialog.tsx, features/profile/DislikedIngredientsField.tsx), doc mise à jour (specs/frontend-architecture.md, specs/batch-cooking- modele.md). Vérifié : tsc --noEmit, biome check, build complet, 303 tests API, vérification live navigateur (planning, /recettes, /recettes/nouvelle). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
27 lines
931 B
TypeScript
27 lines
931 B
TypeScript
import type { AllergyView } from "@batch-cooking/shared";
|
|
import { useTranslation } from "react-i18next";
|
|
import "../recipes.scss";
|
|
|
|
/**
|
|
* A row of allergen pills — used both on {@link RecipeCard} (catalog list)
|
|
* and the recipe detail page, for a single ingredient's allergens as well
|
|
* as a recipe's aggregated set (`RecipeSummaryView.allergens`/
|
|
* `RecipeView.allergens`, already deduplicated server-side). Renders
|
|
* nothing for an empty list rather than an empty wrapper, so callers can
|
|
* mount it unconditionally.
|
|
*/
|
|
export function AllergenBadges({ allergens }: { allergens: AllergyView[] }) {
|
|
const { t } = useTranslation();
|
|
if (allergens.length === 0) {
|
|
return null;
|
|
}
|
|
return (
|
|
<ul className="allergen-badges">
|
|
{allergens.map((allergen) => (
|
|
<li key={allergen.id} className="allergen-badge">
|
|
{t(`catalog.allergens.${allergen.key}`)}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
);
|
|
}
|