Files
breadcrumb-the-shire/web/js/pages/app-users-list.js

157 lines
5.3 KiB
JavaScript
Raw Normal View History

2026-03-06 00:44:52 +01:00
import { confirmDialog } from '../core/app-confirm-dialog.js';
import { warnOnce } from '../core/app-dom.js';
import { postForm } from '../core/app-http.js';
2026-03-06 00:44:52 +01:00
2026-02-04 23:31:53 +01:00
export function initUsersListPage(options = {}) {
const {
gridConfig,
appBase,
csrf,
labels = {},
selectors = {},
bulkDownloadForms = {},
2026-02-04 23:31:53 +01:00
exportPath = 'admin/users/export',
listPath = 'admin/users',
2026-03-04 15:56:58 +01:00
resetOptions = {},
2026-02-04 23:31:53 +01:00
buildBulkUrl,
showFlash,
withLoading
} = options;
if (!gridConfig) {return;}
2026-02-04 23:31:53 +01:00
const exportSelector = selectors.exportButton || '[data-users-export]';
const resetSelector = selectors.resetButton || '[data-users-reset]';
const bulkSelector = selectors.bulkButtons || '[data-users-bulk]';
const resolveBulkUrl = buildBulkUrl
? buildBulkUrl
: (action) => new URL(`admin/users/bulk/${action}`, appBase).toString();
const postAction = async (url, data = {}) => {
const body = new URLSearchParams({ ...data, [csrf.key]: csrf.token });
return postForm(url, body);
2026-02-04 23:31:53 +01:00
};
const exportButton = document.querySelector(exportSelector);
if (exportButton) {
exportButton.addEventListener('click', () => {
const exportUrl = new URL(exportPath, appBase);
const dataUrl = new URL(gridConfig.baseUrl());
dataUrl.searchParams.forEach((value, key) => exportUrl.searchParams.set(key, value));
const sortParams = gridConfig.getSortParams ? gridConfig.getSortParams() : null;
if (sortParams && sortParams.order) {
exportUrl.searchParams.set('order', sortParams.order);
exportUrl.searchParams.set('dir', sortParams.dir || 'asc');
}
window.location.href = exportUrl.toString();
});
}
const resetButton = document.querySelector(resetSelector);
if (resetButton) {
resetButton.addEventListener('click', () => {
if (typeof gridConfig.resetFilters === 'function') {
2026-03-04 15:56:58 +01:00
gridConfig.resetFilters(resetOptions);
2026-02-04 23:31:53 +01:00
} else {
2026-03-04 15:56:58 +01:00
gridConfig.updateGrid(resetOptions);
2026-02-04 23:31:53 +01:00
}
2026-03-04 15:56:58 +01:00
document.dispatchEvent(new CustomEvent('app:filters-updated'));
2026-02-04 23:31:53 +01:00
});
}
const bulkButtons = Array.from(document.querySelectorAll(bulkSelector));
if (bulkButtons.length) {
bulkButtons.forEach((button) => {
button.addEventListener('click', async () => {
const action = button.getAttribute('data-users-bulk') || '';
const ids = gridConfig.selection?.getSelectedIds?.() || [];
const validActions = ['activate', 'deactivate', 'delete', 'send-access', 'access-pdf'];
2026-02-04 23:31:53 +01:00
if (!ids.length || !validActions.includes(action)) {
if (action && !validActions.includes(action)) {
2026-03-06 00:44:52 +01:00
warnOnce('UI_ACTION_UNSUPPORTED', `Unsupported users bulk action: ${action}`, {
module: 'users-list',
component: 'bulk-action',
});
}
2026-02-04 23:31:53 +01:00
return;
}
const confirmTexts = {
'activate': labels.bulkActivateConfirm,
'deactivate': labels.bulkDeactivateConfirm,
'delete': labels.bulkDeleteConfirm,
'send-access': labels.bulkSendAccessConfirm,
'access-pdf': labels.bulkAccessPdfConfirm
2026-02-04 23:31:53 +01:00
};
const confirmText = confirmTexts[action];
2026-03-06 00:44:52 +01:00
if (confirmText) {
const approved = await confirmDialog.confirm({
message: confirmText,
actionKind: action,
});
if (!approved) {
return;
}
2026-02-04 23:31:53 +01:00
}
const downloadFormSelector = bulkDownloadForms?.[action];
if (downloadFormSelector) {
const downloadForm = document.querySelector(downloadFormSelector);
if (!downloadForm) {
window.location.href = new URL(listPath, appBase).toString();
return;
}
const uuidsInput = downloadForm.querySelector('input[name="uuids"]');
if (uuidsInput) {
uuidsInput.value = ids.join(',');
}
downloadForm.submit();
return;
}
2026-02-04 23:31:53 +01:00
const executeBulk = async () => {
const url = resolveBulkUrl(action);
try {
const data = await postAction(url, { uuids: ids.join(',') });
if (!data || data.ok !== true) {
throw new Error('Bulk action failed');
}
2026-02-04 23:31:53 +01:00
gridConfig.selection?.clear?.();
gridConfig.grid?.forceRender();
if (showFlash && labels.bulkMessages) {
const msg = labels.bulkMessages[action];
if (msg) {
const count = data.count ?? 0;
const failed = data.failed ?? 0;
let text = msg.success.replace('%d', count);
if (failed > 0 && msg.partial) {
text = msg.partial.replace('%d', count).replace('%f', failed);
}
showFlash('success', text);
}
}
} catch {
2026-02-04 23:31:53 +01:00
if (showFlash && labels.bulkMessages) {
const msg = labels.bulkMessages[action];
if (msg?.error) {
showFlash('error', msg.error);
} else {
window.location.href = new URL(listPath, appBase).toString();
}
} else {
window.location.href = new URL(listPath, appBase).toString();
}
}
};
if (withLoading) {
await withLoading(executeBulk);
} else {
await executeBulk();
}
});
});
}
}