editable client note on website
Some checks failed
PHPUnit / test (push) Has been cancelled

This commit is contained in:
2026-07-17 17:36:10 +02:00
parent 4d7be68080
commit 497246cd57
2 changed files with 42 additions and 11 deletions

View File

@ -3498,16 +3498,14 @@ body.logged-in .insights-chart-card.card:hover {
} }
.client-note-cell { .client-note-cell {
min-width: 200px;
max-width: 280px; max-width: 280px;
vertical-align: middle; vertical-align: middle;
} }
.client-note-text { .client-note-cell .client-note-input {
white-space: pre-wrap; width: 100%;
word-break: break-word; margin-bottom: 8px;
font-size: 0.9rem;
line-height: 1.35;
color: var(--text-primary);
} }
.client-note-empty { .client-note-empty {

View File

@ -204,6 +204,13 @@ function renderClientTableBody() {
body.querySelectorAll('.restore-client-btn').forEach(btn => { body.querySelectorAll('.restore-client-btn').forEach(btn => {
btn.addEventListener('click', () => setClientArchived(btn.dataset.code, false)); 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); bindCoachBandPickerEvents(body);
} }
@ -740,13 +747,20 @@ function clientRowHTML(c) {
archived, archived,
showDelete: true, showDelete: true,
}); });
const note = String(c.note || '').trim(); const note = String(c.note || '');
const noteCell = note const noteCell = `
? `<td class="client-note-cell"><span class="client-note-text">${esc(note)}</span></td>` <td class="followup-note-cell client-note-cell">
: `<td class="client-note-cell client-note-empty">—</td>`; <textarea class="followup-note-input client-note-input" rows="2"
data-client="${esc(c.clientCode)}" maxlength="200"
placeholder="Client note…">${esc(note)}</textarea>
<div class="followup-note-actions">
<button type="button" class="btn btn-sm btn-primary save-client-note-btn"
data-client="${esc(c.clientCode)}">Save note</button>
</div>
</td>`;
return ` return `
<tr class="${archived ? 'client-row-archived' : ''}"> <tr class="${archived ? 'client-row-archived' : ''}" data-client="${esc(c.clientCode)}">
<td> <td>
${expandControl}<strong>${esc(c.clientCode)}</strong>${clientArchivedLabel(c)} ${expandControl}<strong>${esc(c.clientCode)}</strong>${clientArchivedLabel(c)}
</td> </td>
@ -806,6 +820,25 @@ function toggleVersion(clientCode, questionnaireID, submissionID) {
renderClientTableBody(); 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) { async function setClientArchived(clientCode, archived) {
const ok = await confirmAndPatchClientArchive(clientCode, archived); const ok = await confirmAndPatchClientArchive(clientCode, archived);
if (!ok) return; if (!ok) return;