import { confirmDialog } from '../core/app-confirm-dialog.js'; import { warnOnce } from '../core/app-dom.js'; import { postForm } from '../core/app-http.js'; import { initListExport } from '../core/app-list-export.js'; export function initUsersListPage(options = {}) { const { gridConfig, appBase, csrf, labels = {}, selectors = {}, bulkDownloadForms = {}, exportUrl, listPath = 'admin/users', resetOptions = {}, buildBulkUrl, showFlash, withLoading } = options; if (!gridConfig) {return;} 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); }; if (exportUrl) { initListExport({ gridConfig, exportUrl }); } const resetButton = document.querySelector(resetSelector); if (resetButton) { resetButton.addEventListener('click', () => { if (typeof gridConfig.resetFilters === 'function') { gridConfig.resetFilters(resetOptions); } else { gridConfig.updateGrid(resetOptions); } document.dispatchEvent(new CustomEvent('app:filters-updated')); }); } 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']; if (!ids.length || !validActions.includes(action)) { if (action && !validActions.includes(action)) { warnOnce('UI_ACTION_UNSUPPORTED', `Unsupported users bulk action: ${action}`, { module: 'users-list', component: 'bulk-action', }); } return; } const confirmTexts = { 'activate': labels.bulkActivateConfirm, 'deactivate': labels.bulkDeactivateConfirm, 'delete': labels.bulkDeleteConfirm, 'send-access': labels.bulkSendAccessConfirm, 'access-pdf': labels.bulkAccessPdfConfirm }; const confirmText = confirmTexts[action]; if (confirmText) { const approved = await confirmDialog.confirm({ message: confirmText, actionKind: action, }); if (!approved) { return; } } 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; } 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'); } 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 { 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(); } }); }); } }