diff --git a/website/css/style.css b/website/css/style.css index d981c15..a470467 100644 --- a/website/css/style.css +++ b/website/css/style.css @@ -3498,16 +3498,14 @@ body.logged-in .insights-chart-card.card:hover { } .client-note-cell { + min-width: 200px; max-width: 280px; vertical-align: middle; } -.client-note-text { - white-space: pre-wrap; - word-break: break-word; - font-size: 0.9rem; - line-height: 1.35; - color: var(--text-primary); +.client-note-cell .client-note-input { + width: 100%; + margin-bottom: 8px; } .client-note-empty { diff --git a/website/js/pages/clients.js b/website/js/pages/clients.js index 6b1ea43..7d43e9e 100644 --- a/website/js/pages/clients.js +++ b/website/js/pages/clients.js @@ -204,6 +204,13 @@ function renderClientTableBody() { body.querySelectorAll('.restore-client-btn').forEach(btn => { btn.addEventListener('click', () => setClientArchived(btn.dataset.code, false)); }); + body.querySelectorAll('.save-client-note-btn').forEach(btn => { + btn.addEventListener('click', () => { + const tr = btn.closest('tr'); + const ta = tr?.querySelector('.client-note-input'); + saveClientNote(btn.dataset.client, ta); + }); + }); bindCoachBandPickerEvents(body); } @@ -740,13 +747,20 @@ function clientRowHTML(c) { archived, showDelete: true, }); - const note = String(c.note || '').trim(); - const noteCell = note - ? `${esc(note)}` - : `—`; + const note = String(c.note || ''); + const noteCell = ` + + +
+ +
+ `; return ` - + ${expandControl}${esc(c.clientCode)}${clientArchivedLabel(c)} @@ -806,6 +820,25 @@ function toggleVersion(clientCode, questionnaireID, submissionID) { renderClientTableBody(); } +async function saveClientNote(clientCode, ta) { + if (!ta || !clientCode) return; + const note = ta.value.trim(); + if (note.length > 200) { + showToast('Note must be at most 200 characters', 'error'); + return; + } + try { + const res = await apiPut('analytics.php', { clientCode, note }); + const saved = res?.note ?? note; + ta.value = saved; + const row = clientsList.find(c => c.clientCode === clientCode); + if (row) row.note = saved; + showToast('Note saved', 'success'); + } catch (e) { + showToast(e.message, 'error'); + } +} + async function setClientArchived(clientCode, archived) { const ok = await confirmAndPatchClientArchive(clientCode, archived); if (!ok) return;