// Test script for the new suggestMealName and shortItemName functions const NEVO_DESC = new Set([ 'rauw','rauwe','gekookt','gekookte','onbereid','onbereide','bereid','bereide', 'vers','verse','diepvries','diepgevroren','gedroogd','gedroogde', 'gem','gemixt','gesneden','gebakken','gebraden','gegrild','gestoofd','gefrituurd', 'ongezouten','gezouten','gerookt','gepekeld', 'gekonserveerd','geconserveerd','gezeefd','uitgesmolten', 'gepaneerd','gevuld','voorgekookt','koelvers', 'halfvolle','magere','volle','halfvol', 'scharrel','biologisch','biologische','mais', 'witte','bruine','zwarte','rode','groene','groen','gele','oranje', 'zoete','zure','bittere','zoute', 'schil','vliesje','vel','niet','panklaar', 'kruimig','vastkokend','eigen','mnd','ongekookt','gt','kippen','naturel', ]); function shortItemName(naam) { if (!naam) return ''; let name = naam.replace(/^\d+\s+/, ''); const dsi = name.indexOf(' '); if (dsi > 0) name = name.substring(dsi).trim(); name = name.split('/')[0].trim(); name = name.replace(/\([^)]*\)/g, '').trim(); name = name.split(',')[0].trim(); name = name.replace(/\b\d+[%+]?\b/g, '').trim(); name = name.replace(/>/g, '').trim(); name = name.replace(/\s+/g, ' ').trim(); if (!name) return ''; const words = name.split(/\s+/); let keep = words.slice(0, 2); if (keep.length >= 2 && keep[1].endsWith('-') && keep[0].toLowerCase() !== 'ei') { const mod = keep[1].slice(0, -1); const base = keep[0]; const comp = mod.toLowerCase() + base.toLowerCase(); keep = [comp.charAt(0).toUpperCase() + comp.slice(1)]; } keep = keep.map(w => w.replace(/-$/, '')); const result = []; const seen = new Set(); for (const w of keep) { if (w.length <= 1) continue; const wl = w.toLowerCase(); if (NEVO_DESC.has(wl)) continue; if (seen.has(wl)) continue; seen.add(wl); result.push(w); } return result.join(' '); } function nevoDinerType(nevoCat) { const map = { 'Aardappelen en knolgewassen': 'aardappel', 'Groente': 'groente', 'Vlees en gevogelte': 'vlees', 'Vis, schaal- en schelpdieren': 'vlees', 'Vleeswaren': 'vlees', 'Eieren': 'vlees', 'Brood': 'brood', 'Kaas': 'kaas', 'Melk en melkproducten': 'zuivel', 'Fruit': 'fruit', }; return map[nevoCat] || 'overig'; } const CATEGORY_MAP = { 'Brood': 'Brood', 'Melk en melkproducten': 'Zuivel', 'Kaas': 'Zuivel', 'Fruit': 'Fruit', 'Groente': 'Groente', 'Aardappelen en knolgewassen': 'Groente', 'Peulvruchten': 'Groente', 'Vlees en gevogelte': 'Vlees/Vis', 'Vis, schaal- en schelpdieren': 'Vlees/Vis', 'Vleeswaren': 'Vlees/Vis', 'Eieren': 'Vlees/Vis', 'Alcoholische dranken': 'Dranken', 'Niet-alcoholische dranken': 'Dranken', 'Hartige snacks en zoutjes': 'Tussendoortjes', 'Noten en zaden': 'Tussendoortjes', 'Gebak en koek': 'Snoep/Koek', 'Suiker, snoep, zoet beleg en zoete sauzen': 'Snoep/Koek', 'Graanproducten en meelsoorten': 'Overig', 'Vleesvervangers en zuivelvervangers': 'Overig', 'Samengestelde gerechten': 'Overig', 'Soepen': 'Overig', 'Hartige sauzen': 'Overig', 'Kruiden en specerijen': 'Overig', 'Vetten en oliƫn': 'Overig', 'Diversen': 'Overig', 'Flesvoeding en preparaten': 'Overig', 'Hartig broodbeleg': 'Overig' }; function mapCategory(itemCat) { return CATEGORY_MAP[itemCat] || 'Overig'; } function suggestMealName(items) { if (!items || items.length === 0) return ''; if (items.length === 1) return shortItemName(items[0].item.naam); const enriched = items.map(e => ({ name: shortItemName(e.item.naam), cat: mapCategory(e.item.cat || 'Overig'), nevoCat: e.item.cat || 'Overig', type: nevoDinerType(e.item.cat || 'Overig'), })); const byCat = {}; enriched.forEach(info => { if (!byCat[info.cat]) byCat[info.cat] = []; byCat[info.cat].push(info); }); const cats = Object.keys(byCat); const hasAardappel = enriched.some(e => e.type === 'aardappel'); const hasGroente = enriched.some(e => e.type === 'groente'); const hasVlees = enriched.some(e => e.type === 'vlees'); if (hasAardappel && (hasGroente || hasVlees)) { const groenteNamen = enriched .filter(e => e.type === 'groente') .map(e => e.name); const vleesNamen = enriched .filter(e => e.type === 'vlees') .map(e => e.name); const groente = groenteNamen[0] || ''; const vlees = vleesNamen[0] || ''; if (hasGroente && hasVlees && groente && vlees) { return 'AVG ' + groente + ' en ' + vlees; } if (hasGroente && groente) { return 'Prakkie ' + groente + (vlees ? ' met ' + vlees : ''); } const other = enriched.find(e => e.type !== 'aardappel'); if (other) return 'Aardappel met ' + other.name; } if (hasGroente && hasVlees) { const gr = enriched.filter(e => e.type === 'groente').map(e => e.name)[0] || ''; const vl = enriched.filter(e => e.type === 'vlees').map(e => e.name)[0] || ''; if (gr && vl) return gr + ' met ' + vl; if (gr) return 'Groente met ' + vl; } if (cats.includes('Brood')) { const beleg = enriched.filter(e => e.cat !== 'Brood').map(e => e.name); if (beleg.length === 1) return 'Broodje ' + beleg[0]; if (beleg.length === 2) return 'Broodje ' + beleg[0] + ' en ' + beleg[1]; if (beleg.length <= 4) return 'Brood met ' + beleg.slice(0, -1).join(', ') + ' en ' + beleg[beleg.length - 1]; return 'Brood met beleg'; } if (cats.length === 1) { const cat = cats[0]; const catNamen = byCat[cat].map(i => i.name); if (catNamen.length <= 3) { if (catNamen.length === 2) return catNamen[0] + ' en ' + catNamen[1]; if (catNamen.length === 3) return catNamen[0] + ', ' + catNamen[1] + ' en ' + catNamen[2]; return catNamen[0]; } return cat + ' (' + catNamen.length + ' stuks)'; } if (cats.length === 2) { const [a, b] = cats; const na = byCat[a].map(i => i.name); const nb = byCat[b].map(i => i.name); if (na.length === 1 && nb.length === 1) return na[0] + ' & ' + nb[0]; const parts = cats.map(c => { const n = byCat[c].map(i => i.name); if (n.length <= 2) return n.join(' & '); return n[0] + ' (+' + (n.length - 1) + ')'; }); return parts.join(' & '); } const sorted = cats.sort((a, b) => byCat[b].length - byCat[a].length); const [top1, top2] = sorted; const rest = enriched.length - byCat[top1].length - byCat[top2].length; let r = top1 + ' & ' + top2; if (rest > 0) r += ' +' + rest + ' meer'; return r; } // === TEST SCENARIOS === // Bug report: AVG dinner const bugItems = [ { item: { naam: '2747 Aardappelen kruimig z schil gekookt gem', cat: 'Aardappelen en knolgewassen', kh: '19' } }, { item: { naam: '1146 Spinazie gesneden diepvries onbereid', cat: 'Groente', kh: '1' } }, { item: { naam: '2769 Ei kippen- scharrel rauw Scharrelei/scharrelkippeneieren rauw', cat: 'Eieren', kh: '13' } }, { item: { naam: '3026 Speklap bereid in eigen vet', cat: 'Vlees en gevogelte', kh: '0' } }, ]; console.log('=== BUG REPORT: AVG dinner ==='); console.log('Items:', bugItems.map(i => shortItemName(i.item.naam)).join(', ')); console.log('Suggestion:', suggestMealName(bugItems)); console.log(); // Broodje kaas const broodjeKaas = [ { item: { naam: '533 Brood bruin volkoren', cat: 'Brood', kh: '40' } }, { item: { naam: '511 Kaas Edammer 40+', cat: 'Kaas', kh: '0' } }, ]; console.log('=== Broodje kaas ==='); console.log('Items:', broodjeKaas.map(i => i.item.naam).join(', ')); console.log('Suggestion:', suggestMealName(broodjeKaas)); console.log(); // Prakkie: aardappel + groente const prakkie = [ { item: { naam: '1 Aardappelen rauw', cat: 'Aardappelen en knolgewassen', kh: '19' } }, { item: { naam: '8 Andijvie gekookt', cat: 'Groente', kh: '1' } }, ]; console.log('=== Prakkie: aardappel + groente ==='); console.log('Items:', prakkie.map(i => shortItemName(i.item.naam)).join(', ')); console.log('Suggestion:', suggestMealName(prakkie)); console.log(); // Prakkie met vlees const prakkieVlees = [ { item: { naam: '1 Aardappelen rauw', cat: 'Aardappelen en knolgewassen', kh: '19' } }, { item: { naam: '8 Andijvie gekookt', cat: 'Groente', kh: '1' } }, { item: { naam: '1432 Speklap rauw', cat: 'Vlees en gevogelte', kh: '0' } }, ]; console.log('=== Prakkie met vlees ==='); console.log('Items:', prakkieVlees.map(i => shortItemName(i.item.naam)).join(', ')); console.log('Suggestion:', suggestMealName(prakkieVlees)); console.log(); // Brood met ham const broodHam = [ { item: { naam: '533 Brood bruin volkoren', cat: 'Brood', kh: '40' } }, { item: { naam: '328 Ham rauwe', cat: 'Vleeswaren', kh: '0' } }, ]; console.log('=== Broodje ham ==='); console.log('Suggestion:', suggestMealName(broodHam)); console.log(); // Yoghurt + fruit (ontbijt) const ontbijt = [ { item: { naam: '270 Melk rauwe', cat: 'Melk en melkproducten', kh: '5' } }, { item: { naam: '148 Aardbeien', cat: 'Fruit', kh: '5' } }, { item: { naam: '209 Ontbijtproduct Cornflakes', cat: 'Graanproducten en meelsoorten', kh: '75' } }, ]; console.log('=== Ontbijt (generic) ==='); console.log('Items:', ontbijt.map(i => shortItemName(i.item.naam)).join(', ')); console.log('Suggestion:', suggestMealName(ontbijt)); console.log(); // Groente + vlees dinner const groenteVlees = [ { item: { naam: '51 Spinazie rauw', cat: 'Groente', kh: '1' } }, { item: { naam: '1432 Speklap rauw', cat: 'Vlees en gevogelte', kh: '0' } }, ]; console.log('=== Groente + vlees ==='); console.log('Suggestion:', suggestMealName(groenteVlees)); console.log(); // Brood met 2 beleg const broodDubbel = [ { item: { naam: '533 Brood bruin volkoren', cat: 'Brood', kh: '40' } }, { item: { naam: '511 Kaas Edammer 40+', cat: 'Kaas', kh: '0' } }, { item: { naam: '328 Ham rauwe', cat: 'Vleeswaren', kh: '0' } }, ]; console.log('=== Broodje kaas en ham ==='); console.log('Suggestion:', suggestMealName(broodDubbel)); console.log(); // Single category, multiple items (Fruit) const fruitMand = [ { item: { naam: '147 Appel z schil gem', cat: 'Fruit', kh: '13' } }, { item: { naam: '148 Aardbeien', cat: 'Fruit', kh: '5' } }, { item: { naam: '33 Rozijnen gedroogd', cat: 'Fruit', kh: '67' } }, ]; console.log('=== Fruitmand (3 items) ==='); console.log('Suggestion:', suggestMealName(fruitMand)); console.log(); // Kip + groente const kipGroente = [ { item: { naam: '51 Spinazie rauw', cat: 'Groente', kh: '1' } }, { item: { naam: '95 Paardenvlees rauw', cat: 'Vlees en gevogelte', kh: '0' } }, ]; console.log('=== Kip + groente (vlees + groente) ==='); console.log('Suggestion:', suggestMealName(kipGroente));