registerPage('clients', async (content, params = {}) => { document.getElementById('topbar-title').textContent = 'Clients'; let provinces = []; async function loadProvinces() { if (provinces.length) return; const r = await api('clients.php', { action: 'provinces' }); if (r.success) provinces = r.provinces; } async function render(search = '') { const r = await api('clients.php', { action: 'list', search }); if (!r.success) { content.innerHTML = emptyHTML('Failed to load clients'); return; } const rows = r.clients; const tableHtml = rows.length === 0 ? emptyHTML('No clients found') : `
${rows.map(c => ` `).join('')}
CodeNameProvinceEmailPhoneActions
${c.client_code || '—'} ${c.clients_name} ${c.provinces_name || '—'} ${c.email || '—'} ${c.phone || '—'}
`; document.getElementById('clients-table').innerHTML = tableHtml; } content.innerHTML = `
${loadingHTML()}
`; await loadProvinces(); const sel = document.getElementById('cf-province'); provinces.forEach(p => sel.innerHTML += ``); document.getElementById('client-search').addEventListener('input', e => render(e.target.value)); render(); window.clientAdd = async () => { document.getElementById('client-modal-title').textContent = 'Add Client'; document.getElementById('client-form').reset(); document.getElementById('cf-id').value = ''; openModal('client-modal'); }; window.clientEdit = async (id) => { const r = await api('clients.php', { action: 'get', id }); if (!r.success) { toast('Failed to load client', 'error'); return; } const c = r.client; document.getElementById('client-modal-title').textContent = 'Edit Client'; document.getElementById('cf-id').value = c.record_id; document.getElementById('cf-name').value = c.clients_name; document.getElementById('cf-code').value = c.client_code || ''; document.getElementById('cf-province').value = c.provinces_id || 0; document.getElementById('cf-email').value = c.email || ''; document.getElementById('cf-phone').value = c.phone || ''; document.getElementById('cf-address').value = c.address || ''; openModal('client-modal'); }; window.clientSave = async () => { const id = document.getElementById('cf-id').value; const params = { action: id ? 'update' : 'create', id, clients_name: document.getElementById('cf-name').value, client_code: document.getElementById('cf-code').value, provinces_id: document.getElementById('cf-province').value, email: document.getElementById('cf-email').value, phone: document.getElementById('cf-phone').value, address: document.getElementById('cf-address').value, }; const r = await api('clients.php', params, 'POST'); if (r.success) { toast(r.message, 'success'); closeModal('client-modal'); render(); } else toast(r.error, 'error'); }; window.clientDelete = async (id, name) => { if (!confirm(`Delete client "${name}"? This cannot be undone.`)) return; const r = await api('clients.php', { action: 'delete', id }, 'POST'); if (r.success) { toast('Client deleted', 'success'); render(); } else toast(r.error, 'error'); }; // ── Export ───────────────────────────────────────────────────────────────── const _getExportRows = async (filter) => { const r = await api('clients.php', { action: 'list', search: '' }); if (!r.success) { toast('Export failed', 'error'); return null; } return r.clients.map(c => [c.client_code || '', c.clients_name || '', c.provinces_name || '', c.email || '', c.phone || '', c.address || '']); }; const _exportHeaders = ['Code', 'Name', 'Province', 'Email', 'Phone', 'Address']; const _exportTitle = 'Clients'; function printExport(title, headers, rows) { const headHtml = headers.map(h => '' + h + '').join(''); const bodyHtml = rows.map((row, i) => '' + row.map(v => '' + (v ?? '') + '').join('') + '' ).join(''); const date = new Date().toLocaleDateString('en-ZA', { day: 'numeric', month: 'short', year: 'numeric' }); const html = '' + title + '' + '
' + '
SafeSure
' + title + '
' + '
Date: ' + date + '
Records: ' + rows.length + '
' + '' + headHtml + '' + bodyHtml + '
' + '
SafeSure Competency Assessment SystemConfidential — ' + title + ' ' + date + '
' + 'window.onload=function(){window.print();}' + ''; const w = window.open('', '_blank'); w.document.write(html); w.document.close(); } window.doExportPDF = async () => { const rows = await _getExportRows(); if (rows) printExport(_exportTitle, _exportHeaders, rows); }; window.doExportCSV = async () => { const rows = await _getExportRows(); if (!rows) return; const wb = XLSX.utils.book_new(); const ws = XLSX.utils.aoa_to_sheet([_exportHeaders, ...rows]); XLSX.utils.book_append_sheet(wb, ws, 'Clients'); XLSX.writeFile(wb, _exportTitle.toLowerCase().replace(/ /g, '_') + '_' + new Date().toISOString().slice(0, 10) + '.xlsx'); }; });