Control: add 'Add applicant' form to Applicants tab
Owner can add a tester directly (email/label) via the existing POST /api/control/admin/applicants proxy route, instead of relying on the not-yet-built public /register page. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -75,6 +75,23 @@ async function renderApplicants(panel) {
|
||||
try { rows = await api.get(`${A}/applicants?status=pending`); }
|
||||
catch (e) { return mount(panel, errBox(e)); }
|
||||
|
||||
// Add-applicant form (owner adds a tester directly; the public /register page
|
||||
// is a later addition). Posts to POST /admin/applicants {email,label}.
|
||||
const emailI = el('input', { class: 'lk-url', type: 'email', placeholder: 'email (optional)' });
|
||||
const labelI = el('input', { class: 'lk-url', placeholder: 'label / name' });
|
||||
const addMsg = el('span', { class: 'muted', style: { fontSize: '0.78rem' } }, '');
|
||||
const addBtn = btn('Add applicant', async () => {
|
||||
if (!emailI.value.trim() && !labelI.value.trim()) return notify(addMsg, 'email or label required', false);
|
||||
try {
|
||||
await api.post(`${A}/applicants`, { email: emailI.value.trim(), label: labelI.value.trim() });
|
||||
emailI.value = ''; labelI.value = '';
|
||||
renderApplicants(panel);
|
||||
} catch (e) { notify(addMsg, e.message || 'add failed', false); }
|
||||
}, 'primary');
|
||||
const addCard = el('div', { class: 'card', style: { display: 'grid', gap: '0.5rem', marginBottom: '0.9rem', gridTemplateColumns: 'repeat(auto-fit, minmax(160px, 1fr))', alignItems: 'end' } },
|
||||
field('Email', emailI), field('Label', labelI),
|
||||
el('div', { style: { display: 'flex', alignItems: 'center', gap: '0.5rem' } }, addBtn, addMsg));
|
||||
|
||||
const body = rows.map(a => {
|
||||
const msg = el('span', { class: 'muted', style: { fontSize: '0.75rem' } }, '');
|
||||
const groupSel = select([{ value: '', label: '(default group)' }, ...groupsCache.map(g => ({ value: g.id, label: g.name }))]);
|
||||
@@ -104,6 +121,7 @@ async function renderApplicants(panel) {
|
||||
mount(panel,
|
||||
el('div', { class: 'term-bar' }, el('span', { class: 'term-title' }, '◆ Pending applicants'),
|
||||
btn('Refresh', () => renderApplicants(panel), 'ghost')),
|
||||
addCard,
|
||||
rows.length ? table(['Applicant', 'Note', 'Status', 'Action', ''], body)
|
||||
: el('p', { class: 'muted' }, 'No pending applicants.'));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user