fix: event-delegatie voor meal-group acties (move/delete/toggle werken nu) + dialog-knoppen gebruiken bestaande Karby-classes (btn-cancel, btn-save, btn-danger-outline) + e2e test voor confirm modal
This commit is contained in:
parent
423977e397
commit
4925169ac9
3 changed files with 90 additions and 76 deletions
|
|
@ -2913,40 +2913,32 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
});
|
||||
});
|
||||
|
||||
// Meal group toggle collaps/expand
|
||||
listEl.querySelectorAll('[data-action="toggle-meal"]').forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
const group = el.closest('.eetmoment-meal-group');
|
||||
// === Unified meal-group action delegation ===
|
||||
listEl.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('[data-action]');
|
||||
if (!btn) return;
|
||||
const action = btn.dataset.action;
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = btn.dataset.entry != null ? parseInt(btn.dataset.entry) : null;
|
||||
|
||||
if (action === 'toggle-meal') {
|
||||
const group = btn.closest('.eetmoment-meal-group');
|
||||
if (!group) return;
|
||||
const wrap = group.querySelector('.eetmoment-meal-items-wrap');
|
||||
const actions = group.querySelector('.eetmoment-meal-actions');
|
||||
if (wrap) {
|
||||
wrap.classList.toggle('hidden');
|
||||
if (actions) actions.classList.toggle('hidden');
|
||||
const arrow = el.querySelector('span:last-child i');
|
||||
const arrow = btn.querySelector('span:last-child i');
|
||||
if (arrow) {
|
||||
arrow.className = wrap.classList.contains('hidden') ? 'fas fa-chevron-down' : 'fas fa-chevron-up';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Meal group bulk edit button
|
||||
listEl.querySelectorAll('[data-action="edit-porties"]').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = parseInt(btn.dataset.entry);
|
||||
}
|
||||
else if (action === 'edit-porties') {
|
||||
showBulkPortieEdit(activeDate, momentId, entryIdx);
|
||||
});
|
||||
});
|
||||
|
||||
// Delete meal group from diary
|
||||
listEl.querySelectorAll('[data-action="delete-meal"]').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = parseInt(btn.dataset.entry);
|
||||
}
|
||||
else if (action === 'delete-meal') {
|
||||
const dayData = getOrCreateDay(activeDate);
|
||||
const entry = (dayData[momentId] || [])[entryIdx];
|
||||
const mealName = (entry && entry.mealNaam) || 'maaltijd';
|
||||
|
|
@ -2957,15 +2949,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
saveDagboek();
|
||||
renderDagboek();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Move meal group to different eetmoment
|
||||
listEl.querySelectorAll('[data-action="move-meal"]').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = parseInt(btn.dataset.entry);
|
||||
}
|
||||
else if (action === 'move-meal') {
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'modal-overlay';
|
||||
overlay.style.zIndex = '500';
|
||||
|
|
@ -2979,8 +2964,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
<div class="modal-body" style="padding:0 20px 20px;">
|
||||
<select class="add-meal-select" id="moveTarget">${options}</select>
|
||||
<div style="display:flex;gap:10px;margin-top:16px;">
|
||||
<button class="btn btn-outline" style="flex:1;" id="moveCancel">Annuleren</button>
|
||||
<button class="btn" style="flex:1;" id="moveOk">Verplaatsen</button>
|
||||
<button class="btn-cancel" id="moveCancel">Annuleren</button>
|
||||
<button class="btn-save" id="moveOk" style="flex:1;">Verplaatsen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -3003,8 +2988,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
close();
|
||||
renderDagboek();
|
||||
});
|
||||
overlay.addEventListener('click', (e) => { if (e.target === overlay) close(); });
|
||||
});
|
||||
overlay.addEventListener('click', (ev) => { if (ev.target === overlay) close(); });
|
||||
}
|
||||
});
|
||||
|
||||
listEl.querySelectorAll('.eetmoment-add-btn').forEach(btn => {
|
||||
|
|
@ -4255,8 +4240,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
<p style="color:var(--text-muted);font-size:var(--font-base);margin:0;">${escapeHtml(message)}</p>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;padding:0 20px 20px;">
|
||||
<button class="btn btn-outline" style="flex:1;" id="confirmCancel">Annuleren</button>
|
||||
<button class="btn" style="flex:1;background:var(--danger, #e74c3c);color:white;" id="confirmOk">Verwijderen</button>
|
||||
<button class="btn-cancel" style="flex:1;" id="confirmCancel">Annuleren</button>
|
||||
<button class="btn-danger-outline" style="flex:1;" id="confirmOk">Verwijderen</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
61
index.html
61
index.html
|
|
@ -2913,40 +2913,32 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
});
|
||||
});
|
||||
|
||||
// Meal group toggle collaps/expand
|
||||
listEl.querySelectorAll('[data-action="toggle-meal"]').forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
const group = el.closest('.eetmoment-meal-group');
|
||||
// === Unified meal-group action delegation ===
|
||||
listEl.addEventListener('click', (e) => {
|
||||
const btn = e.target.closest('[data-action]');
|
||||
if (!btn) return;
|
||||
const action = btn.dataset.action;
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = btn.dataset.entry != null ? parseInt(btn.dataset.entry) : null;
|
||||
|
||||
if (action === 'toggle-meal') {
|
||||
const group = btn.closest('.eetmoment-meal-group');
|
||||
if (!group) return;
|
||||
const wrap = group.querySelector('.eetmoment-meal-items-wrap');
|
||||
const actions = group.querySelector('.eetmoment-meal-actions');
|
||||
if (wrap) {
|
||||
wrap.classList.toggle('hidden');
|
||||
if (actions) actions.classList.toggle('hidden');
|
||||
const arrow = el.querySelector('span:last-child i');
|
||||
const arrow = btn.querySelector('span:last-child i');
|
||||
if (arrow) {
|
||||
arrow.className = wrap.classList.contains('hidden') ? 'fas fa-chevron-down' : 'fas fa-chevron-up';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Meal group bulk edit button
|
||||
listEl.querySelectorAll('[data-action="edit-porties"]').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = parseInt(btn.dataset.entry);
|
||||
}
|
||||
else if (action === 'edit-porties') {
|
||||
showBulkPortieEdit(activeDate, momentId, entryIdx);
|
||||
});
|
||||
});
|
||||
|
||||
// Delete meal group from diary
|
||||
listEl.querySelectorAll('[data-action="delete-meal"]').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = parseInt(btn.dataset.entry);
|
||||
}
|
||||
else if (action === 'delete-meal') {
|
||||
const dayData = getOrCreateDay(activeDate);
|
||||
const entry = (dayData[momentId] || [])[entryIdx];
|
||||
const mealName = (entry && entry.mealNaam) || 'maaltijd';
|
||||
|
|
@ -2957,15 +2949,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
saveDagboek();
|
||||
renderDagboek();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Move meal group to different eetmoment
|
||||
listEl.querySelectorAll('[data-action="move-meal"]').forEach(btn => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const momentId = btn.dataset.moment;
|
||||
const entryIdx = parseInt(btn.dataset.entry);
|
||||
}
|
||||
else if (action === 'move-meal') {
|
||||
const overlay = document.createElement('div');
|
||||
overlay.className = 'modal-overlay';
|
||||
overlay.style.zIndex = '500';
|
||||
|
|
@ -2979,8 +2964,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
<div class="modal-body" style="padding:0 20px 20px;">
|
||||
<select class="add-meal-select" id="moveTarget">${options}</select>
|
||||
<div style="display:flex;gap:10px;margin-top:16px;">
|
||||
<button class="btn btn-outline" style="flex:1;" id="moveCancel">Annuleren</button>
|
||||
<button class="btn" style="flex:1;" id="moveOk">Verplaatsen</button>
|
||||
<button class="btn-cancel" id="moveCancel">Annuleren</button>
|
||||
<button class="btn-save" id="moveOk" style="flex:1;">Verplaatsen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -3003,8 +2988,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
close();
|
||||
renderDagboek();
|
||||
});
|
||||
overlay.addEventListener('click', (e) => { if (e.target === overlay) close(); });
|
||||
});
|
||||
overlay.addEventListener('click', (ev) => { if (ev.target === overlay) close(); });
|
||||
}
|
||||
});
|
||||
|
||||
listEl.querySelectorAll('.eetmoment-add-btn').forEach(btn => {
|
||||
|
|
@ -4255,8 +4240,8 @@ button:active, .btn:active, .meal-card-main:active, .dagboek-item:active, .food-
|
|||
<p style="color:var(--text-muted);font-size:var(--font-base);margin:0;">${escapeHtml(message)}</p>
|
||||
</div>
|
||||
<div style="display:flex;gap:10px;padding:0 20px 20px;">
|
||||
<button class="btn btn-outline" style="flex:1;" id="confirmCancel">Annuleren</button>
|
||||
<button class="btn" style="flex:1;background:var(--danger, #e74c3c);color:white;" id="confirmOk">Verwijderen</button>
|
||||
<button class="btn-cancel" style="flex:1;" id="confirmCancel">Annuleren</button>
|
||||
<button class="btn-danger-outline" style="flex:1;" id="confirmOk">Verwijderen</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -354,4 +354,48 @@ test.describe('Karby Eetdagboek', () => {
|
|||
await expect(chevronUp).toBeVisible();
|
||||
});
|
||||
|
||||
// ---------- Confirm + delete dialogs ----------
|
||||
|
||||
test('confirm modal: deletion dialog shows design-conforme buttons', async ({ page }) => {
|
||||
await page.goto(BASE);
|
||||
// Go to maaltijden tab
|
||||
await page.locator('#navMaaltijden').click();
|
||||
await page.waitForTimeout(600);
|
||||
// Quick-save a meal first if none exist (via search)
|
||||
await page.locator('.search-input').fill('brood');
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator('.food-item').first().click();
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator('#detailAddBtn').click();
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator('#addMealSubmit').click();
|
||||
await page.waitForTimeout(600);
|
||||
// Navigate to diary, save as meal
|
||||
await page.locator('#navDagboek').click();
|
||||
await page.waitForTimeout(600);
|
||||
const saveBtn = page.locator('.save-meal-btn');
|
||||
if (await saveBtn.count() === 0) { test.skip(); return; }
|
||||
await saveBtn.first().click();
|
||||
await page.waitForTimeout(500);
|
||||
await page.locator('#mealNameInput').fill('Test');
|
||||
await page.locator('#mealNameSave').click();
|
||||
await page.waitForTimeout(600);
|
||||
// Now go to maaltijden and delete
|
||||
await page.locator('#navMaaltijden').click();
|
||||
await page.waitForTimeout(600);
|
||||
// Open first meal edit
|
||||
await page.locator('.meal-card-main').first().click();
|
||||
await page.waitForTimeout(500);
|
||||
// Click delete
|
||||
const deleteBtn = page.locator('#mealEditDelete');
|
||||
if (await deleteBtn.isVisible().catch(() => false)) {
|
||||
await deleteBtn.click();
|
||||
await page.waitForTimeout(300);
|
||||
// Confirm modal should show
|
||||
await expect(page.locator('#confirmOk')).toBeVisible({ timeout: 3000 });
|
||||
await expect(page.locator('#confirmCancel')).toBeVisible();
|
||||
await page.locator('#confirmCancel').click();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue