This commit is contained in:
@ -62,7 +62,7 @@ function renderExport() {
|
||||
<th>Version</th>
|
||||
<th>State</th>
|
||||
<th>Questions</th>
|
||||
<th>Completed</th>
|
||||
<th>Uploaded responses</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -133,7 +133,7 @@ function exportRowHTML(q) {
|
||||
<td>${esc(q.version || '—')}</td>
|
||||
<td><span class="badge badge-${(q.state || 'draft').toLowerCase()}">${esc(q.state || 'draft')}</span></td>
|
||||
<td>${q.questionCount || 0}</td>
|
||||
<td>${q.completedCount ?? 0}</td>
|
||||
<td>${q.submissionCount ?? 0}</td>
|
||||
<td class="export-actions-cell">
|
||||
<button class="btn btn-sm btn-primary export-btn" data-id="${esc(q.questionnaireID)}" data-name="${esc(q.name)}" data-version="${esc(q.version)}" data-all="0">
|
||||
Export current
|
||||
|
||||
108
website/js/pages/schedule.js
Normal file
108
website/js/pages/schedule.js
Normal file
@ -0,0 +1,108 @@
|
||||
import { apiGet } from '../api.js';
|
||||
import { pageHeaderHTML, showToast } from '../app.js';
|
||||
|
||||
export async function schedulePage() {
|
||||
const app = document.getElementById('app');
|
||||
app.innerHTML = `
|
||||
${pageHeaderHTML('Schedule', '', {
|
||||
subtitle: 'Upcoming session appointments set by counselors in the app',
|
||||
})}
|
||||
<div id="scheduleContent"><div class="spinner"></div></div>
|
||||
`;
|
||||
|
||||
try {
|
||||
const data = await apiGet('schedule');
|
||||
renderSchedule(data.entries || [], data.byDate || {});
|
||||
} catch (e) {
|
||||
showToast(e.message, 'error');
|
||||
document.getElementById('scheduleContent').innerHTML =
|
||||
`<p class="error-text">${esc(e.message)}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
function renderSchedule(entries, byDate) {
|
||||
const el = document.getElementById('scheduleContent');
|
||||
const todayStart = new Date();
|
||||
todayStart.setHours(0, 0, 0, 0);
|
||||
const futureEntries = entries.filter(e => parseDdMmYyyy(e.scheduledDate) > todayStart.getTime());
|
||||
const futureByDate = {};
|
||||
futureEntries.forEach(e => {
|
||||
(futureByDate[e.scheduledDate] ||= []).push(e);
|
||||
});
|
||||
|
||||
if (!futureEntries.length) {
|
||||
el.innerHTML = `
|
||||
<div class="card">
|
||||
<p class="scoring-empty-hint" style="margin:0">No upcoming session appointments.</p>
|
||||
</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const dates = Object.keys(futureByDate).sort((a, b) => parseDdMmYyyy(a) - parseDdMmYyyy(b));
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="card" style="margin-bottom:16px">
|
||||
<p class="data-toolbar-hint" style="margin:0">
|
||||
${futureEntries.length} scheduled client${futureEntries.length === 1 ? '' : 's'} across ${dates.length} date${dates.length === 1 ? '' : 's'}.
|
||||
Counselors set dates in the mobile app.
|
||||
</p>
|
||||
</div>
|
||||
${dates.map(date => dateGroupHTML(date, futureByDate[date] || [])).join('')}
|
||||
`;
|
||||
}
|
||||
|
||||
function dateGroupHTML(scheduledDate, rows) {
|
||||
const sorted = [...rows].sort((a, b) =>
|
||||
String(a.coachUsername || '').localeCompare(String(b.coachUsername || ''))
|
||||
|| String(a.clientCode).localeCompare(String(b.clientCode)),
|
||||
);
|
||||
return `
|
||||
<div class="card scoring-profiles-card" style="margin-bottom:16px">
|
||||
<div class="scoring-profile-header">
|
||||
<div>
|
||||
<h3 class="scoring-section-title">${esc(scheduledDate)}</h3>
|
||||
<p class="scoring-section-desc">
|
||||
${sorted.length} client${sorted.length === 1 ? '' : 's'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Client</th>
|
||||
<th>Cycle</th>
|
||||
<th>Session</th>
|
||||
<th>Counselor</th>
|
||||
<th>Supervisor</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${sorted.map(row => `
|
||||
<tr>
|
||||
<td>${esc(row.clientCode)}</td>
|
||||
<td>${esc(String(row.programCycleNumber))}</td>
|
||||
<td>${esc(String(row.programSessionNumber))}</td>
|
||||
<td>${esc(row.coachUsername || row.coachID || '—')}</td>
|
||||
<td>${esc(row.supervisorUsername || '—')}</td>
|
||||
</tr>
|
||||
`).join('')}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function parseDdMmYyyy(date) {
|
||||
const m = /^(\d{2})-(\d{2})-(\d{4})$/.exec(String(date));
|
||||
if (!m) return 0;
|
||||
return new Date(Number(m[3]), Number(m[2]) - 1, Number(m[1])).getTime();
|
||||
}
|
||||
|
||||
function esc(value) {
|
||||
return String(value ?? '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
Reference in New Issue
Block a user