import { apiGet, apiPost, apiDelete } from '../api.js'; import { showToast } from '../app.js'; import { isDevTestClientCode, testDataRowClassForClient } from '../test-data.js'; const PAGE_SIZE = 50; let clientsList = []; let coachesList = []; let filterSearch = ''; let filterTestData = ''; let page = 0; export async function clientsPage() { const app = document.getElementById('app'); app.innerHTML = `
`; document.getElementById('showCreateFormBtn').addEventListener('click', () => { const wrapper = document.getElementById('createClientWrapper'); if (wrapper.style.display === 'none') { showCreateForm(); } else { hideCreateForm(); } }); await loadClients(); } async function loadClients() { try { const [clientsData, assignData] = await Promise.all([ apiGet('clients.php'), apiGet('assignments.php'), ]); clientsList = clientsData.clients || []; coachesList = assignData.coaches || []; renderClients(); } catch (e) { showToast(e.message, 'error'); document.getElementById('clientsContent').innerHTML = `

${esc(e.message)}

`; } } function renderClients() { const container = document.getElementById('clientsContent'); if (!clientsList.length) { container.innerHTML = `

No clients found

Create the first client above.

`; return; } container.innerHTML = `
Client Code Current Coach Actions
`; document.getElementById('clientListSearch').addEventListener('input', (e) => { filterSearch = e.target.value.trim(); page = 0; renderClientTableBody(); }); document.getElementById('clientTestFilter').addEventListener('change', (e) => { filterTestData = e.target.value; page = 0; renderClientTableBody(); }); renderClientTableBody(); } function getFilteredClientsList() { let list = clientsList; if (filterSearch) { const q = filterSearch.toLowerCase(); list = list.filter(c => { const hay = `${c.clientCode || ''} ${c.coachUsername || ''}`.toLowerCase(); return hay.includes(q); }); } if (filterTestData === 'test') { list = list.filter(c => isDevTestClientCode(c.clientCode)); } else if (filterTestData === 'hide-test') { list = list.filter(c => !isDevTestClientCode(c.clientCode)); } return list; } function renderClientTableBody() { const body = document.getElementById('clientsTableBody'); const countEl = document.getElementById('clientListCount'); const filtered = getFilteredClientsList(); const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE)); if (page >= totalPages) page = totalPages - 1; const slice = filtered.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE); if (countEl) { countEl.textContent = `${filtered.length} client${filtered.length === 1 ? '' : 's'}`; } if (!slice.length) { body.innerHTML = `No clients match`; } else { body.innerHTML = slice.map(c => clientRowHTML(c)).join(''); body.querySelectorAll('.delete-client-btn').forEach(btn => { btn.addEventListener('click', () => deleteClient(btn.dataset.code)); }); } const pag = document.getElementById('clientsPagination'); if (!pag) return; if (filtered.length <= PAGE_SIZE) { pag.innerHTML = ''; return; } const from = page * PAGE_SIZE + 1; const to = Math.min((page + 1) * PAGE_SIZE, filtered.length); pag.innerHTML = ` Rows ${from}–${to} of ${filtered.length} `; document.getElementById('clientsPagePrev')?.addEventListener('click', () => { page--; renderClientTableBody(); }); document.getElementById('clientsPageNext')?.addEventListener('click', () => { page++; renderClientTableBody(); }); } function clientRowHTML(c) { const coach = c.coachUsername ? `${esc(c.coachUsername)}` : `Unassigned`; return ` ${esc(c.clientCode)} ${coach} `; } async function deleteClient(clientCode) { if (!confirm(`Delete client "${clientCode}"? This will also remove all their answers and results. This cannot be undone.`)) return; try { await apiDelete('clients.php', { clientCode }); clientsList = clientsList.filter(c => c.clientCode !== clientCode); showToast(`Client "${clientCode}" deleted`, 'success'); if (!clientsList.length) renderClients(); else renderClientTableBody(); } catch (e) { showToast(e.message, 'error'); } } function showCreateForm() { if (!coachesList.length) { showToast('No coaches available. Create a coach first.', 'error'); return; } const wrapper = document.getElementById('createClientWrapper'); wrapper.style.display = ''; wrapper.innerHTML = `

Create New Client

`; const input = document.getElementById('cc_code'); input.focus(); wrapper.querySelectorAll('input').forEach(inp => { inp.addEventListener('keydown', (e) => { if (e.key === 'Enter') submitCreateClient(); if (e.key === 'Escape') hideCreateForm(); }); }); document.getElementById('cc_submit').addEventListener('click', submitCreateClient); document.getElementById('cc_cancel').addEventListener('click', hideCreateForm); } function hideCreateForm() { const wrapper = document.getElementById('createClientWrapper'); if (wrapper) { wrapper.style.display = 'none'; wrapper.innerHTML = ''; } } async function submitCreateClient() { const errEl = document.getElementById('cc_error'); errEl.style.display = 'none'; const clientCode = document.getElementById('cc_code').value.trim(); const coachID = document.getElementById('cc_coach').value; if (!clientCode) { showError(errEl, 'Client code is required'); return; } if (!coachID) { showError(errEl, 'Please select a coach'); return; } const btn = document.getElementById('cc_submit'); btn.disabled = true; btn.textContent = 'Creating...'; try { const data = await apiPost('clients.php', { clientCode, coachID }); const coach = coachesList.find(c => c.coachID === coachID); clientsList.push({ clientCode: data.clientCode, coachID: coachID, coachUsername: coach?.username ?? null, }); showToast(`Client "${data.clientCode}" created`, 'success'); hideCreateForm(); renderClients(); } catch (e) { showError(errEl, e.message); btn.disabled = false; btn.textContent = 'Create Client'; } } function showError(el, msg) { el.textContent = msg; el.style.display = ''; } function esc(s) { const d = document.createElement('div'); d.textContent = s ?? ''; return d.innerHTML; }