"use client"; import { RiDownload2Line, RiArrowDownSLine as ChevronDown, RiResetLeftLine as RotateCcw, RiShuffleLine as Shuffle, RiEqualizerLine as SlidersHorizontal, RiMagicLine as Wand2 } from "@remixicon/react"; import { useState, type Dispatch } from "react"; import { APPLIANCES, CUISINES, STYLES, activeRecipeIds, mealLabel, visibleMeals } from "@/app/lib/plan"; import { buildPlanModel, renderPlanPdf } from "@/app/lib/exportPlan"; import type { PlanAction } from "@/app/lib/usePlanState"; import type { FillMode, MealPlanState } from "@/app/types"; import { Chip } from "./Chip"; import { ApplianceIcon, StyleIcon } from "./Icons"; import { RadioGroup } from "./RadioGroup"; import { Button } from "@/components/base/buttons/button"; interface ConfigPanelProps { state: MealPlanState; dispatch: Dispatch; onGenerate: (mode: FillMode) => void; onClear: () => void; isGenerating: boolean; } const MEALS_OPTIONS = [ { value: 1, label: "1" }, { value: 2, label: "2" }, { value: 3, label: "3" }, ] as const; const PEOPLE_OPTIONS = [ { value: 1, label: "1" }, { value: 2, label: "2" }, { value: 3, label: "3" }, { value: 4, label: "4" }, { value: 5, label: "5" }, { value: 6, label: "6" }, ] as const; export function ConfigPanel({ state, dispatch, onGenerate, onClear, isGenerating }: ConfigPanelProps) { const [filtersOpen, setFiltersOpen] = useState(false); const filledCount = activeRecipeIds(state).length; const [isExporting, setIsExporting] = useState(false); async function downloadPlan() { setIsExporting(true); try { // Loaded on demand so jsPDF stays out of the planner's initial bundle. const { jsPDF } = await import("jspdf"); renderPlanPdf(buildPlanModel(state), jsPDF).save("meal-plan.pdf"); } finally { setIsExporting(false); } } const mealNames = visibleMeals(state.mealsPerDay).map(mealLabel).join(" · "); const activeFilterCount = (APPLIANCES.length - state.selectedAppliances.length > 0 ? 1 : 0) + state.preferredCuisines.length + state.preferredStyles.length; const filterSummary = [ `${state.selectedAppliances.length}/${APPLIANCES.length} appliances`, state.preferredCuisines.length > 0 ? `${state.preferredCuisines.length} cuisines` : "Any cuisine", state.preferredStyles.length > 0 ? `${state.preferredStyles.length} styles` : null, ] .filter(Boolean) .join(" · "); return (

Plan parameters

{/* --- Compact Top Strip: Core Week Parameters ---------------------- */}
{/* Budget */}
At checkout
dispatch({ type: "setBudget", value: Number(e.target.value) })} className="min-w-0 flex-1" aria-label="Weekly budget slider" />
$ dispatch({ type: "setBudget", value: Math.max(0, Number(e.target.value) || 0) })} className="min-h-9 w-22 rounded-lg border border-line-strong py-1 pr-2.5 pl-6 text-right font-mono text-sm font-semibold tabular-nums" />
{/* Days */}
{state.daysCount} {state.daysCount === 1 ? "day" : "days"}
dispatch({ type: "setDays", value: Number(e.target.value) })} className="w-full" />
{/* Meals per day */}
Meals / day {mealNames}
dispatch({ type: "setMealsPerDay", value })} fullWidth />
{/* Household size */}
Household Scales amounts
dispatch({ type: "setHouseholdSize", value })} fullWidth />
{/* --- Action Toolbar + Progressive Disclosure Toggle --------------- */}
{/* --- Collapsible Appliances, Cuisines & Styles -------------------- */} {filtersOpen && (
Appliances you own · recipes needing anything else stay hidden
{APPLIANCES.map((a) => ( dispatch({ type: "toggleAppliance", value: a.id })} > {a.label} ))}
Preferred cuisines · none selected = any
{CUISINES.map((c) => ( dispatch({ type: "toggleCuisine", value: c.id })} > {c.label} ))}
Cooking style · matches any selected
{STYLES.map((s) => ( dispatch({ type: "toggleStyle", value: s.id })} > {s.label} ))}
)}
); }