diff --git a/public/pages/meals.js b/public/pages/meals.js
index 1e5a0bf..3f3bfa6 100644
--- a/public/pages/meals.js
+++ b/public/pages/meals.js
@@ -9,6 +9,7 @@ import { openModal as openSharedModal, closeModal as closeSharedModal, selectMod
import { stagger } from '/utils/ux.js';
import { t, formatDate } from '/i18n.js';
import { esc } from '/utils/html.js';
+import { DEFAULT_CATEGORY_NAME, categoryLabel } from '/utils/shopping-categories.js';
// --------------------------------------------------------
// Konstanten
@@ -26,6 +27,8 @@ const DAY_NAMES = () => [
t('meals.dayFr'), t('meals.daySa'), t('meals.daySo'),
];
+const EXCLUDED_MEAL_CATEGORY_NAMES = new Set(['Haushalt', 'Drogerie', 'Sonstiges']);
+
// --------------------------------------------------------
// State
// --------------------------------------------------------
@@ -73,6 +76,10 @@ function formatDayDate(dateStr) {
return formatDate(dateStr);
}
+function mealCategories() {
+ return state.categories.filter((c) => !EXCLUDED_MEAL_CATEGORY_NAMES.has(c.name));
+}
+
// --------------------------------------------------------
// API-Wrapper
// --------------------------------------------------------
@@ -564,7 +571,7 @@ function buildModalContent({ mode, date, mealType, meal }) {
: ``;
const ingRows = isEdit && meal.ingredients?.length
- ? meal.ingredients.map((ing) => ingredientRowHTML(ing.name, ing.quantity ?? '', ing.id, ing.category ?? 'Sonstiges')).join('')
+ ? meal.ingredients.map((ing) => ingredientRowHTML(ing.name, ing.quantity ?? '', ing.id, ing.category ?? DEFAULT_CATEGORY_NAME)).join('')
: '';
const hasIngOpen = isEdit && meal.ingredients?.some((i) => !i.on_shopping_list);
@@ -630,10 +637,14 @@ function buildModalContent({ mode, date, mealType, meal }) {
`;
}
-function ingredientRowHTML(name, qty, id, category = 'Sonstiges') {
- const catOptions = state.categories.length
- ? state.categories.map((c) => ``).join('')
- : ``;
+function ingredientRowHTML(name, qty, id, category = DEFAULT_CATEGORY_NAME) {
+ const availableCategories = mealCategories();
+ const resolvedCategory = availableCategories.some((c) => c.name === category)
+ ? category
+ : (availableCategories[0]?.name ?? DEFAULT_CATEGORY_NAME);
+ const catOptions = availableCategories.length
+ ? availableCategories.map((c) => ``).join('')
+ : ``;
return `
@@ -669,7 +680,7 @@ async function saveModal(overlay) {
overlay.querySelectorAll('.ingredient-row').forEach((row) => {
const name = row.querySelector('.ingredient-row__name').value.trim();
const qty = row.querySelector('.ingredient-row__qty').value.trim() || null;
- const category = row.querySelector('.ingredient-row__cat')?.value || 'Sonstiges';
+ const category = row.querySelector('.ingredient-row__cat')?.value || DEFAULT_CATEGORY_NAME;
if (name) ingredients.push({ name, quantity: qty, category, id: row.dataset.ingId || null });
});
diff --git a/public/pages/shopping.js b/public/pages/shopping.js
index 1cd43b3..4c7379b 100644
--- a/public/pages/shopping.js
+++ b/public/pages/shopping.js
@@ -9,6 +9,7 @@ import { stagger, vibrate } from '/utils/ux.js';
import { t } from '/i18n.js';
import { esc } from '/utils/html.js';
import { promptModal, confirmModal } from '/components/modal.js';
+import { DEFAULT_CATEGORY_NAME, categoryLabel } from '/utils/shopping-categories.js';
// --------------------------------------------------------
// Konstanten
@@ -19,25 +20,6 @@ const SWIPE_THRESHOLD = 80; // px - Mindestweg für Aktion
const SWIPE_MAX_VERT = 12; // px - vertikaler Toleranzbereich
const SWIPE_LOCK_VERT = 30; // px - ab diesem Weg gilt es als Scroll
-// Übersetzungs-Map für die Standard-Kategorien (DB-Name → i18n-Key)
-const DEFAULT_CATEGORY_I18N = {
- 'Obst & Gemüse': 'shopping.catFruitVeg',
- 'Backwaren': 'shopping.catBakery',
- 'Milchprodukte': 'shopping.catDairy',
- 'Fleisch & Fisch': 'shopping.catMeatFish',
- 'Tiefkühl': 'shopping.catFrozen',
- 'Getränke': 'shopping.catDrinks',
- 'Haushalt': 'shopping.catHousehold',
- 'Drogerie': 'shopping.catDrugstore',
- 'Sonstiges': 'shopping.catMisc',
-};
-
-/** Übersetzten Label für eine Kategorie zurückgeben. */
-function catLabel(name) {
- const key = DEFAULT_CATEGORY_I18N[name];
- return key ? t(key) : name;
-}
-
/** Icon für eine Kategorie (aus state.categories, Fallback 'tag'). */
function catIcon(name) {
return state.categories.find((c) => c.name === name)?.icon ?? 'tag';
@@ -67,7 +49,7 @@ const state = {
function groupItemsByCategory(items) {
const grouped = {};
for (const item of items) {
- const cat = item.category || (state.categories[0]?.name ?? 'Sonstiges');
+ const cat = item.category || (state.categories[0]?.name ?? DEFAULT_CATEGORY_NAME);
(grouped[cat] = grouped[cat] || []).push(item);
}
// In DB-Reihenfolge zurückgeben; unbekannte Kategorien ans Ende
@@ -157,7 +139,7 @@ function renderListContent(container) {