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 = `
`;
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 => (c.clientCode || '').toLowerCase().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 = `
`;
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;
}