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')
: `
| Site Name | Client | Actions |
${rows.map(s => `
| ${s.client_sites_name} |
${s.clients_name || '—'} |
|
`).join('')}
`;
}
content.innerHTML = `
`;
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 + '' +
'' +
'' + headHtml + '
' + bodyHtml + '
' +
'' +
'window.onload=function(){window.print();}' + 'script>' +
'';
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');
};
});