Wochenplan: Gerichtsuche statt langer Dropdown-Liste, Beispieldaten zurück

WeekEditor: "Mahlzeit hinzufügen" zeigt jetzt ein Suchfeld mit
gefilterter Trefferliste (wie die Live-Suche bei Gerichten) statt einer
langen Dropdown-Liste zum Durchscrollen. Ausgewähltes Gericht lässt sich
per ×-Button wieder ändern.

Neues Skript db/seed-demo.sql (+ db/seed-demo.mjs, "npm run
db:seed-demo"): spielt den ursprünglichen Beispieldatensatz ein
(4 Essenszeiten, 14 Allergene, 11 Zusatzstoffe, 18 Testgerichte, zwei
Beispielwochen) – nur für lokale Entwicklung/Demos, kein Teil der
automatischen Migrationen, da frische Deployments weiterhin leer
starten sollen.
This commit is contained in:
2026-07-18 11:35:13 +02:00
parent c60f481aec
commit 3d13ba88f4
5 changed files with 237 additions and 26 deletions
+72 -22
View File
@@ -35,6 +35,19 @@ export default function WeekEditor({ monday }: { monday: string }) {
null
);
const [selectedDish, setSelectedDish] = useState("");
const [dishSearch, setDishSearch] = useState("");
function startAdding(iso: string, section: string) {
setAdding({ iso, section });
setSelectedDish("");
setDishSearch("");
}
function cancelAdding() {
setAdding(null);
setSelectedDish("");
setDishSearch("");
}
const load = useCallback(async () => {
setError(null);
@@ -77,8 +90,7 @@ export default function WeekEditor({ monday }: { monday: string }) {
: formatMessage(dict.weekEditor.saveError, { message: data.error ?? String(res.status) })
);
}
setAdding(null);
setSelectedDish("");
cancelAdding();
await load();
}
@@ -90,6 +102,11 @@ export default function WeekEditor({ monday }: { monday: string }) {
}
const [hintBefore, hintAfter] = dict.weekEditor.newDishesHint.split("{link}");
const selectedDishObj = dishes.find((d) => d.id === selectedDish) ?? null;
const query = dishSearch.trim().toLowerCase();
const filteredDishes = query
? dishes.filter((d) => localized(d, locale).toLowerCase().includes(query))
: dishes;
return (
<div>
@@ -168,18 +185,57 @@ export default function WeekEditor({ monday }: { monday: string }) {
})}
{isAdding ? (
<div className="mt-2 space-y-1 text-left">
<select
className="input"
value={selectedDish}
onChange={(e) => setSelectedDish(e.target.value)}
>
<option value="">{dict.weekEditor.selectDish}</option>
{dishes.map((dish) => (
<option key={dish.id} value={dish.id}>
{localized(dish, locale)} ({formatPrice(dish.price)})
</option>
))}
</select>
{selectedDishObj ? (
<div className="flex items-center gap-1 text-sm">
<span className="mr-auto">
{localized(selectedDishObj, locale)} (
{formatPrice(selectedDishObj.price)})
</span>
<button
type="button"
className="text-gray-400 hover:text-[var(--c-primary)]"
onClick={() => {
setSelectedDish("");
setDishSearch("");
}}
aria-label={dict.weekEditor.changeDish}
title={dict.weekEditor.changeDish}
>
×
</button>
</div>
) : (
<>
<input
type="search"
className="input"
autoFocus
placeholder={dict.dishManager.searchPlaceholder}
value={dishSearch}
onChange={(e) => setDishSearch(e.target.value)}
/>
<ul className="max-h-32 overflow-y-auto border border-gray-200 rounded-md bg-white divide-y divide-gray-100">
{filteredDishes.map((dish) => (
<li key={dish.id}>
<button
type="button"
className="w-full text-left px-2 py-1 text-sm hover:bg-[var(--c-row-bg-alt)]"
onClick={() => setSelectedDish(dish.id)}
>
{localized(dish, locale)} ({formatPrice(dish.price)})
</button>
</li>
))}
{filteredDishes.length === 0 && (
<li className="px-2 py-1 text-sm text-gray-500">
{formatMessage(dict.dishManager.noResults, {
query: dishSearch,
})}
</li>
)}
</ul>
</>
)}
<div className="flex gap-1 justify-center">
<button
type="button"
@@ -192,10 +248,7 @@ export default function WeekEditor({ monday }: { monday: string }) {
<button
type="button"
className="btn btn-neutral"
onClick={() => {
setAdding(null);
setSelectedDish("");
}}
onClick={cancelAdding}
>
{dict.common.cancel}
</button>
@@ -205,10 +258,7 @@ export default function WeekEditor({ monday }: { monday: string }) {
<button
type="button"
className="btn btn-add mt-1"
onClick={() => {
setAdding({ iso: d.iso, section: s.key });
setSelectedDish("");
}}
onClick={() => startAdding(d.iso, s.key)}
>
{dict.weekEditor.addMeal}
</button>