@@ -168,18 +185,57 @@ export default function WeekEditor({ monday }: { monday: string }) {
})}
{isAdding ? (
-
+ {selectedDishObj ? (
+
+
+ {localized(selectedDishObj, locale)} (
+ {formatPrice(selectedDishObj.price)})
+
+
+
+ ) : (
+ <>
+
setDishSearch(e.target.value)}
+ />
+
+ {filteredDishes.map((dish) => (
+ -
+
+
+ ))}
+ {filteredDishes.length === 0 && (
+ -
+ {formatMessage(dict.dishManager.noResults, {
+ query: dishSearch,
+ })}
+
+ )}
+
+ >
+ )}
@@ -205,10 +258,7 @@ export default function WeekEditor({ monday }: { monday: string }) {
diff --git a/db/seed-demo.mjs b/db/seed-demo.mjs
new file mode 100644
index 0000000..3c1a072
--- /dev/null
+++ b/db/seed-demo.mjs
@@ -0,0 +1,30 @@
+#!/usr/bin/env node
+// Spielt db/seed-demo.sql ein: ersetzt Essenszeiten/Gerichte/Allergene/
+// Zusatzstoffe/Wochenplan durch den Beispieldatensatz. Nur für lokale
+// Entwicklung/Demos gedacht, läuft nicht automatisch beim Start.
+
+import { readFileSync } from "node:fs";
+import { dirname, join } from "node:path";
+import { fileURLToPath } from "node:url";
+import pg from "pg";
+
+const sql = readFileSync(
+ join(dirname(fileURLToPath(import.meta.url)), "seed-demo.sql"),
+ "utf8"
+);
+
+async function main() {
+ const client = new pg.Client({ connectionString: process.env.DATABASE_URL });
+ await client.connect();
+ try {
+ await client.query(sql);
+ console.log("db:seed-demo – Beispieldaten eingespielt.");
+ } finally {
+ await client.end();
+ }
+}
+
+main().catch((err) => {
+ console.error(err);
+ process.exit(1);
+});
diff --git a/db/seed-demo.sql b/db/seed-demo.sql
new file mode 100644
index 0000000..bddcf6d
--- /dev/null
+++ b/db/seed-demo.sql
@@ -0,0 +1,130 @@
+-- =============================================================
+-- Beispieldaten für die lokale Entwicklung/Demo (NICHT Teil der
+-- automatischen Migrationen – frische Deployments starten bewusst
+-- leer, s. db/migrations/0001_init.sql). Manuell anwendbar über
+-- "npm run db:seed-demo".
+--
+-- Ersetzt vorhandene Essenszeiten/Gerichte/Allergene/Zusatzstoffe/
+-- Wochenplan-Einträge durch den ursprünglichen Beispieldatensatz.
+-- =============================================================
+
+delete from menu_entries;
+delete from dish_suggestions;
+delete from dishes;
+delete from sections;
+delete from allergens;
+delete from additives;
+
+-- ---------- Essenszeiten ----------
+insert into sections (key, label, label_en, label_pl, time_range, sort) values
+ ('brotzeit', 'Brotzeit', 'Breakfast', 'Śniadanie', '09:00 - 10:00', 1),
+ ('mittagessen', 'Mittagessen', 'Lunch', 'Obiad', '11:30 - 13:30', 2),
+ ('mittagessen_veg', 'Mittagessen vegetarisch', 'Lunch (vegetarian)', 'Obiad (wegetariański)', '11:30 - 13:30', 3),
+ ('suppe', 'Suppe', 'Soup', 'Zupa', '11:30 - 13:30', 4);
+
+-- ---------- Allergene (EU-Kennzeichnung, Buchstaben) ----------
+insert into allergens (code, name, name_en, name_pl, sort) values
+ ('A', 'Glutenhaltiges Getreide', 'Cereals containing gluten', 'Zboża zawierające gluten', 1),
+ ('B', 'Krebstiere', 'Crustaceans', 'Skorupiaki', 2),
+ ('C', 'Eier', 'Eggs', 'Jaja', 3),
+ ('D', 'Fisch', 'Fish', 'Ryby', 4),
+ ('E', 'Erdnüsse', 'Peanuts', 'Orzeszki ziemne', 5),
+ ('F', 'Sojabohnen', 'Soybeans', 'Soja', 6),
+ ('G', 'Milch (einschließlich Laktose)', 'Milk (including lactose)', 'Mleko (w tym laktoza)', 7),
+ ('H', 'Schalenfrüchte (Nüsse)', 'Tree nuts', 'Orzechy', 8),
+ ('I', 'Sellerie', 'Celery', 'Seler', 9),
+ ('J', 'Senf', 'Mustard', 'Gorczyca', 10),
+ ('K', 'Sesamsamen', 'Sesame seeds', 'Nasiona sezamu', 11),
+ ('L', 'Schwefeldioxid und Sulfite', 'Sulphur dioxide and sulphites', 'Dwutlenek siarki i siarczyny', 12),
+ ('M', 'Lupinen', 'Lupin', 'Łubin', 13),
+ ('N', 'Weichtiere', 'Molluscs', 'Mięczaki', 14);
+
+-- ---------- Zusatzstoffe (Ziffern) ----------
+insert into additives (code, name, name_en, name_pl, sort) values
+ ('1', 'mit Farbstoff', 'with colouring', 'z barwnikiem', 1),
+ ('2', 'mit Konservierungsstoff', 'with preservative', 'z konserwantem', 2),
+ ('3', 'mit Antioxidationsmittel', 'with antioxidant', 'z przeciwutleniaczem', 3),
+ ('4', 'mit Geschmacksverstärker', 'with flavour enhancer', 'ze wzmacniaczem smaku', 4),
+ ('5', 'geschwefelt', 'sulphured', 'siarkowany', 5),
+ ('6', 'geschwärzt', 'blackened', 'barwiony na czarno', 6),
+ ('7', 'gewachst', 'waxed', 'woskowany', 7),
+ ('8', 'mit Phosphat', 'with phosphate', 'z fosforanem', 8),
+ ('9', 'mit Süßungsmittel(n)', 'with sweetener(s)', 'ze słodzikiem/słodzikami', 9),
+ ('10', 'enthält eine Phenylalaninquelle', 'contains a source of phenylalanine', 'zawiera źródło fenyloalaniny', 10),
+ ('11', 'koffeinhaltig', 'caffeinated', 'zawiera kofeinę', 11);
+
+-- ---------- Testgerichte ----------
+insert into dishes (name, price) values
+ -- Brotzeit
+ ('1 Stk. Rindskäsewurst mit Brötchen', 2.30),
+ ('Hackfleischbaguette', 3.20),
+ ('Knusperhähnchen Wrap', 3.70),
+ ('Leberkäse im Brötchen', 2.30),
+ ('Chili con Carne mit Brötchen', 3.90),
+ -- Mittagessen
+ ('Schnitzel Baguette', 3.50),
+ ('Penne mit Grünen Spargel und Garnelenspieße', 5.90),
+ ('Bratkartoffel Gemüse Pfanne mit Hähnchenbrust und Dip', 5.90),
+ ('Schweinefilet im Speckmantel dazu Rahmsoße und Butterspätzle', 5.90),
+ -- Mittagessen vegetarisch
+ ('Penne mit Grünen Spargel, get. Tomaten und Cherrytomaten', 5.30),
+ ('Spaghetti mit fruchtiger Tomatensauce und Parmesan', 5.30),
+ ('Gebackener Feta mit griechischen Bauernsalat und Baguette', 5.30),
+ ('Gemüse-Curry mit Basmatireis', 4.90),
+ -- Suppen
+ ('Kartoffelcremesuppe', 1.50),
+ ('Gulaschsuppe', 2.50),
+ ('Tomatensuppe mit Croutons', 1.80),
+ ('Kürbiscremesuppe', 1.80),
+ ('Linseneintopf mit Würstchen', 2.20);
+
+-- ---------- Beispielwoche 13.–17. Juli 2026 ----------
+with d as (select id, name from dishes)
+insert into menu_entries (menu_date, section_key, dish_id)
+select x.menu_date::date, x.section_key, d.id
+from (values
+ ('2026-07-13', 'brotzeit', '1 Stk. Rindskäsewurst mit Brötchen'),
+ ('2026-07-14', 'brotzeit', 'Hackfleischbaguette'),
+ ('2026-07-15', 'brotzeit', 'Knusperhähnchen Wrap'),
+ ('2026-07-16', 'brotzeit', 'Leberkäse im Brötchen'),
+ ('2026-07-17', 'brotzeit', 'Chili con Carne mit Brötchen'),
+ ('2026-07-13', 'mittagessen', 'Schnitzel Baguette'),
+ ('2026-07-14', 'mittagessen', 'Penne mit Grünen Spargel und Garnelenspieße'),
+ ('2026-07-15', 'mittagessen', 'Bratkartoffel Gemüse Pfanne mit Hähnchenbrust und Dip'),
+ ('2026-07-16', 'mittagessen', 'Schweinefilet im Speckmantel dazu Rahmsoße und Butterspätzle'),
+ ('2026-07-14', 'mittagessen_veg', 'Penne mit Grünen Spargel, get. Tomaten und Cherrytomaten'),
+ ('2026-07-15', 'mittagessen_veg', 'Spaghetti mit fruchtiger Tomatensauce und Parmesan'),
+ ('2026-07-16', 'mittagessen_veg', 'Gebackener Feta mit griechischen Bauernsalat und Baguette'),
+ ('2026-07-13', 'suppe', 'Kartoffelcremesuppe'),
+ ('2026-07-14', 'suppe', 'Gulaschsuppe'),
+ ('2026-07-15', 'suppe', 'Tomatensuppe mit Croutons'),
+ ('2026-07-16', 'suppe', 'Kürbiscremesuppe'),
+ ('2026-07-17', 'suppe', 'Linseneintopf mit Würstchen')
+) as x (menu_date, section_key, name)
+join d on d.name = x.name;
+
+-- ---------- Beispielwoche 20.–24. Juli 2026 ("Nächste Woche") ----------
+with d as (select id, name from dishes)
+insert into menu_entries (menu_date, section_key, dish_id)
+select x.menu_date::date, x.section_key, d.id
+from (values
+ ('2026-07-20', 'brotzeit', 'Leberkäse im Brötchen'),
+ ('2026-07-21', 'brotzeit', 'Knusperhähnchen Wrap'),
+ ('2026-07-22', 'brotzeit', '1 Stk. Rindskäsewurst mit Brötchen'),
+ ('2026-07-23', 'brotzeit', 'Hackfleischbaguette'),
+ ('2026-07-24', 'brotzeit', 'Chili con Carne mit Brötchen'),
+ ('2026-07-20', 'mittagessen', 'Bratkartoffel Gemüse Pfanne mit Hähnchenbrust und Dip'),
+ ('2026-07-21', 'mittagessen', 'Schweinefilet im Speckmantel dazu Rahmsoße und Butterspätzle'),
+ ('2026-07-22', 'mittagessen', 'Schnitzel Baguette'),
+ ('2026-07-23', 'mittagessen', 'Penne mit Grünen Spargel und Garnelenspieße'),
+ ('2026-07-20', 'mittagessen_veg', 'Gemüse-Curry mit Basmatireis'),
+ ('2026-07-21', 'mittagessen_veg', 'Spaghetti mit fruchtiger Tomatensauce und Parmesan'),
+ ('2026-07-22', 'mittagessen_veg', 'Gebackener Feta mit griechischen Bauernsalat und Baguette'),
+ ('2026-07-23', 'mittagessen_veg', 'Penne mit Grünen Spargel, get. Tomaten und Cherrytomaten'),
+ ('2026-07-20', 'suppe', 'Gulaschsuppe'),
+ ('2026-07-21', 'suppe', 'Kartoffelcremesuppe'),
+ ('2026-07-22', 'suppe', 'Linseneintopf mit Würstchen'),
+ ('2026-07-23', 'suppe', 'Tomatensuppe mit Croutons'),
+ ('2026-07-24', 'suppe', 'Kürbiscremesuppe')
+) as x (menu_date, section_key, name)
+join d on d.name = x.name;
diff --git a/lib/i18n/dictionaries.ts b/lib/i18n/dictionaries.ts
index d5fd1ec..d8c81a9 100644
--- a/lib/i18n/dictionaries.ts
+++ b/lib/i18n/dictionaries.ts
@@ -68,7 +68,7 @@ const de = {
weekEditor: {
title: "Wochenplan",
loading: "Lade Wochenplan…",
- selectDish: "– Gericht wählen –",
+ changeDish: "Anderes Gericht wählen",
addMeal: "Mahlzeit hinzufügen",
newDishesHint: "Neue Gerichte legst du unter {link} an.",
newDishesLinkLabel: "Gerichte",
@@ -322,7 +322,7 @@ const en: Dict = {
weekEditor: {
title: "Weekly plan",
loading: "Loading weekly plan…",
- selectDish: "– Select dish –",
+ changeDish: "Choose a different dish",
addMeal: "Add meal",
newDishesHint: "Add new dishes under {link}.",
newDishesLinkLabel: "Dishes",
@@ -574,7 +574,7 @@ const pl: Dict = {
weekEditor: {
title: "Plan tygodnia",
loading: "Wczytywanie planu tygodnia…",
- selectDish: "– Wybierz danie –",
+ changeDish: "Wybierz inne danie",
addMeal: "Dodaj posiłek",
newDishesHint: "Nowe dania możesz dodać w zakładce {link}.",
newDishesLinkLabel: "Dania",
diff --git a/package.json b/package.json
index 4fce37d..99e1cee 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,8 @@
"prestart": "node --env-file-if-exists=.env.local db/migrate.mjs && node --env-file-if-exists=.env.local scripts/bootstrap-admin.mjs",
"start": "next start -H 0.0.0.0",
"lint": "eslint",
- "db:migrate": "node --env-file-if-exists=.env.local db/migrate.mjs"
+ "db:migrate": "node --env-file-if-exists=.env.local db/migrate.mjs",
+ "db:seed-demo": "node --env-file-if-exists=.env.local db/seed-demo.mjs"
},
"dependencies": {
"@simplewebauthn/browser": "^13.3.0",