registerPage('sites', async (content, params = {}) => { document.getElementById('topbar-title').textContent = 'Client Sites'; let clients = []; async function loadClients() { const r = await api('clients.php', { action: 'list' }); if (r.success) clients = r.clients; } async function render(search = '', clientFilter = '') { const r = await api('sites.php', { action: 'list', search, clients_id: clientFilter }); if (!r.success) { document.getElementById('sites-table').innerHTML = emptyHTML('Error: ' + (r.error || 'unknown')); return; } const rows = r.sites; document.getElementById('sites-table').innerHTML = rows.length === 0 ? emptyHTML('No sites found') : `
${rows.map(s => ``).join('')}
Site NameClientActions
${s.client_sites_name} ${s.clients_name || '—'}
`; } content.innerHTML = `
${loadingHTML()}
`; await loadClients(); const filterSel = document.getElementById('site-client-filter'); const modalSel = document.getElementById('sf-client'); clients.forEach(c => { filterSel.innerHTML += ``; modalSel.innerHTML += ``; }); const go = () => render( document.getElementById('site-search').value, document.getElementById('site-client-filter').value ); document.getElementById('site-search').addEventListener('input', go); document.getElementById('site-client-filter').addEventListener('change', go); render(); window.siteAdd = () => { document.getElementById('site-modal-title').textContent = 'Add Site'; document.getElementById('sf-id').value = ''; document.getElementById('sf-name').value = ''; document.getElementById('sf-client').value = ''; openModal('site-modal'); }; window.siteEdit = async (id) => { const r = await api('sites.php', { action: 'get', id }); if (!r.success) { toast('Failed to load site', 'error'); return; } const s = r.site; document.getElementById('site-modal-title').textContent = 'Edit Site'; document.getElementById('sf-id').value = s.record_id; document.getElementById('sf-name').value = s.client_sites_name; document.getElementById('sf-client').value = s.clients_id; openModal('site-modal'); }; window.siteSave = async () => { const id = document.getElementById('sf-id').value; const r = await api('sites.php', { action: id ? 'update' : 'create', id, client_sites_name: document.getElementById('sf-name').value, clients_id: document.getElementById('sf-client').value, }, 'POST'); if (r.success) { toast(r.message, 'success'); closeModal('site-modal'); go(); } else toast(r.error, 'error'); }; window.siteDelete = async (id, name) => { if (!confirm(`Delete site "${name}"?`)) return; const r = await api('sites.php', { action: 'delete', id }, 'POST'); if (r.success) { toast('Site deleted', 'success'); go(); } else toast(r.error, 'error'); }; // ── Export ───────────────────────────────────────────────────────────────── const _getExportRows = async (filter) => { const clientId = document.getElementById('site-client-filter').value || ''; const r = await api('sites.php', { action: 'list', clients_id: clientId }); if (!r.success) { toast('Export failed', 'error'); return null; } return r.sites.map(s => [s.client_sites_name || '', s.clients_name || '']); }; const _exportHeaders = ['Site Name', 'Client']; const _exportTitle = 'Client Sites'; 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, 'Sites'); XLSX.writeFile(wb, _exportTitle.toLowerCase().replace(/ /g, '_') + '_' + new Date().toISOString().slice(0, 10) + '.xlsx'); }; });