fix(ui): replace native alert/confirm with showConfirm/showToast helpers
Daniel flagged the native browser confirm() dialogs in Extensions as ugly
and incompatible with the app's design. There was also a stray alert()
in calculators.js resus-meds weight validation.
Replaced:
- extensions.js: confirmDelete → showConfirm(..., {confirmText: 'Move to trash'})
- extensions.js: confirmPurge → showConfirm(..., {danger: true, confirmText: 'Delete permanently'})
- calculators.js:2060 alert() → showToast(..., 'error')
All three helpers (showConfirm, showToast) are already defined as globals
in public/js/app.js. The design already had a modal — I should have used
it from the start.
Audit confirmation: `grep -rnE '\b(alert|confirm|prompt)\s*\(' public/`
now returns only comment references and the showConfirm definition
itself. No native dialogs remain anywhere in the frontend.
Playwright test updated to click the in-app modal's #confirm-modal-ok
and #confirm-modal-cancel buttons instead of intercepting page.on('dialog').
This commit is contained in:
parent
8ea79c7f30
commit
b37c565cf0
3 changed files with 36 additions and 26 deletions
|
|
@ -149,9 +149,9 @@ test.describe('Extensions — CRUD', () => {
|
|||
await openTab(page);
|
||||
await fillForm(page, { location: 'Loc', name: 'To delete', number: '9999', type: 'extension' });
|
||||
|
||||
// Auto-accept the confirm() dialog
|
||||
page.once('dialog', d => d.accept());
|
||||
await page.locator('.ext-card button[data-ext-action="delete"]').first().click();
|
||||
// In-app modal — click confirm
|
||||
await page.click('#confirm-modal-ok');
|
||||
|
||||
// Gone from active list
|
||||
await expect(page.locator('#ext-list')).toContainText(/No entries yet/i, { timeout: 5000 });
|
||||
|
|
@ -188,8 +188,8 @@ test.describe('Extensions — CRUD', () => {
|
|||
await page.click('#ext-trash-btn');
|
||||
await expect(page.locator('.ext-card')).toContainText('Gone forever');
|
||||
|
||||
page.once('dialog', d => d.accept());
|
||||
await page.locator('.ext-card button[data-ext-action="purge"]').first().click();
|
||||
await page.click('#confirm-modal-ok');
|
||||
|
||||
// Trash is empty
|
||||
await expect(page.locator('#ext-list')).toContainText(/Trash is empty/i, { timeout: 5000 });
|
||||
|
|
@ -203,9 +203,9 @@ test.describe('Extensions — CRUD', () => {
|
|||
await openTab(page);
|
||||
await fillForm(page, { location: 'Loc', name: 'Stays', number: '8888', type: 'extension' });
|
||||
|
||||
// User cancels the confirm dialog
|
||||
page.once('dialog', d => d.dismiss());
|
||||
// User cancels the modal
|
||||
await page.locator('.ext-card button[data-ext-action="delete"]').first().click();
|
||||
await page.click('#confirm-modal-cancel');
|
||||
|
||||
// Still there
|
||||
await expect(page.locator('.ext-card')).toContainText('Stays');
|
||||
|
|
|
|||
|
|
@ -2057,7 +2057,7 @@
|
|||
var weightEl = document.getElementById('resus-weight');
|
||||
var resultDiv = document.getElementById('resus-result');
|
||||
var w = parseFloat(weightEl.value);
|
||||
if (!w || w <= 0) { alert('Please enter a valid weight.'); return; }
|
||||
if (!w || w <= 0) { showToast('Please enter a valid weight.', 'error'); return; }
|
||||
|
||||
var html = '<div style="margin-bottom:12px;font-size:14px;font-weight:700;color:var(--g800);">Doses for ' + w + ' kg patient</div>';
|
||||
html += '<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:14px;font-size:11px;">';
|
||||
|
|
|
|||
|
|
@ -228,16 +228,21 @@
|
|||
function confirmDelete(id) {
|
||||
var item = _items.filter(function (x) { return x.id === id; })[0];
|
||||
if (!item) return;
|
||||
if (!confirm('Move "' + item.name + ' (' + item.number + ')" to trash?\n\nYou can restore it later from the trash view.')) return;
|
||||
fetch('/api/extensions/' + id, { method: 'DELETE', headers: getAuthHeaders() })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
if (!d.success) { showToast(d.error || 'Delete failed', 'error'); return; }
|
||||
showToast('Moved to trash', 'success');
|
||||
load();
|
||||
loadTrashCount();
|
||||
})
|
||||
.catch(function () { showToast('Delete failed', 'error'); });
|
||||
showConfirm(
|
||||
'Move "' + item.name + ' (' + item.number + ')" to trash? You can restore it later from the trash view.',
|
||||
function () {
|
||||
fetch('/api/extensions/' + id, { method: 'DELETE', headers: getAuthHeaders() })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
if (!d.success) { showToast(d.error || 'Delete failed', 'error'); return; }
|
||||
showToast('Moved to trash', 'success');
|
||||
load();
|
||||
loadTrashCount();
|
||||
})
|
||||
.catch(function () { showToast('Delete failed', 'error'); });
|
||||
},
|
||||
{ confirmText: 'Move to trash' }
|
||||
);
|
||||
}
|
||||
|
||||
function restoreItem(id) {
|
||||
|
|
@ -255,16 +260,21 @@
|
|||
function confirmPurge(id) {
|
||||
var item = _items.filter(function (x) { return x.id === id; })[0];
|
||||
if (!item) return;
|
||||
if (!confirm('Permanently delete "' + item.name + ' (' + item.number + ')"?\n\nThis cannot be undone.')) return;
|
||||
fetch('/api/extensions/' + id + '/purge', { method: 'DELETE', headers: getAuthHeaders() })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
if (!d.success) { showToast(d.error || 'Delete failed', 'error'); return; }
|
||||
showToast('Permanently deleted', 'success');
|
||||
load();
|
||||
loadTrashCount();
|
||||
})
|
||||
.catch(function () { showToast('Delete failed', 'error'); });
|
||||
showConfirm(
|
||||
'Permanently delete "' + item.name + ' (' + item.number + ')"? This cannot be undone.',
|
||||
function () {
|
||||
fetch('/api/extensions/' + id + '/purge', { method: 'DELETE', headers: getAuthHeaders() })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
if (!d.success) { showToast(d.error || 'Delete failed', 'error'); return; }
|
||||
showToast('Permanently deleted', 'success');
|
||||
load();
|
||||
loadTrashCount();
|
||||
})
|
||||
.catch(function () { showToast('Delete failed', 'error'); });
|
||||
},
|
||||
{ danger: true, confirmText: 'Delete permanently' }
|
||||
);
|
||||
}
|
||||
|
||||
function toggleTrashMode() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue