This commit is contained in:
@ -197,6 +197,9 @@ function renderClientTableBody() {
|
||||
body.querySelectorAll('.delete-client-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => deleteClient(btn.dataset.code));
|
||||
});
|
||||
body.querySelectorAll('.reset-client-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => resetClient(btn.dataset.code));
|
||||
});
|
||||
body.querySelectorAll('.archive-client-btn').forEach(btn => {
|
||||
btn.addEventListener('click', () => setClientArchived(btn.dataset.code, true));
|
||||
});
|
||||
@ -413,6 +416,9 @@ function profileScoreBlockHTML(p, clientCode = '') {
|
||||
<span class="client-profile-score-label">Counselor</span>
|
||||
${coachControl}
|
||||
${coachDiffers ? '<span class="client-profile-override-hint">override</span>' : ''}
|
||||
${coachDiffers && p.coachReviewedByUsername
|
||||
? `<span class="client-profile-override-meta">by ${esc(p.coachReviewedByUsername)}${p.coachReviewedAt ? ` · ${esc(p.coachReviewedAt)}` : ''}</span>`
|
||||
: ''}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
@ -431,7 +437,10 @@ function renderClientScoringProfiles(profiles, clientCode = '') {
|
||||
const coachPending = p.pendingReview !== false && !p.coachBand;
|
||||
const computedAt = p.computedAt ? `Last computed ${esc(p.computedAt)}` : '';
|
||||
const reviewedAt = p.coachReviewedAt ? `Counselor reviewed ${esc(p.coachReviewedAt)}` : '';
|
||||
const meta = [computedAt, reviewedAt].filter(Boolean).join(' · ');
|
||||
const overrideMeta = p.coachOverride && p.coachReviewedByUsername
|
||||
? `Overridden by ${esc(p.coachReviewedByUsername)}${p.coachReviewedAt ? ` · ${esc(p.coachReviewedAt)}` : ''}`
|
||||
: '';
|
||||
const meta = [computedAt, reviewedAt, overrideMeta].filter(Boolean).join(' · ');
|
||||
return `
|
||||
<div class="scoring-profile-detail-card">
|
||||
${profileScoreBlockHTML(p, clientCode)}
|
||||
@ -732,6 +741,7 @@ function clientRowHTML(c) {
|
||||
clientCode: esc(c.clientCode),
|
||||
archived,
|
||||
showDelete: true,
|
||||
showReset: clientHasResponseData(c),
|
||||
});
|
||||
|
||||
return `
|
||||
@ -818,6 +828,44 @@ async function setClientArchived(clientCode, archived) {
|
||||
else renderClientTableBody();
|
||||
}
|
||||
|
||||
async function resetClient(clientCode) {
|
||||
if (!(await confirmAction({
|
||||
title: 'Reset client',
|
||||
message: `Reset client "${clientCode}"? This clears all questionnaire answers, upload history, and scoring results. The client code and counselor assignment are kept.`,
|
||||
confirmLabel: 'Reset',
|
||||
variant: 'danger',
|
||||
}))) return;
|
||||
try {
|
||||
await apiPost('clients.php', { action: 'reset', clientCode });
|
||||
const row = clientsList.find(c => c.clientCode === clientCode);
|
||||
if (row) {
|
||||
row.hasResponseData = 0;
|
||||
row.scoringProfiles = (row.scoringProfiles || []).map(p => ({
|
||||
...p,
|
||||
band: null,
|
||||
calculatedBand: null,
|
||||
coachBand: null,
|
||||
effectiveBand: null,
|
||||
pendingReview: false,
|
||||
coachOverride: false,
|
||||
coachReviewedAt: '',
|
||||
coachReviewedByUsername: '',
|
||||
weightedTotal: null,
|
||||
}));
|
||||
}
|
||||
delete detailByClient[clientCode];
|
||||
if (expandedClientCode === clientCode) {
|
||||
expandedClientCode = null;
|
||||
expandedQnKey = null;
|
||||
expandedVersionKey = null;
|
||||
}
|
||||
showToast(`Client "${clientCode}" reset`, 'success');
|
||||
renderClientTableBody();
|
||||
} catch (e) {
|
||||
showToast(e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteClient(clientCode) {
|
||||
if (!(await confirmAction({
|
||||
title: 'Delete client',
|
||||
|
||||
Reference in New Issue
Block a user