Files
Daily-review-page/templates/history.html
2026-04-12 18:55:00 +03:00

199 lines
6.4 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>History — Daily Check-in</title>
<link rel="stylesheet" href="/static/css/style.css">
<script src="/static/js/theme.js"></script>
</head>
<body>
<nav class="topbar">
<span class="topbar-title">Daily Check-in</span>
<div class="topbar-nav">
<a href="/">Form</a>
<a href="/history" class="active">History</a>
</div>
<button class="theme-toggle" id="theme-toggle" title="Toggle theme"></button>
</nav>
<div class="page-wide">
<div class="cal-header">
<button class="cal-nav-btn" id="prev-btn"></button>
<h2 id="month-label"></h2>
<button class="cal-nav-btn" id="next-btn"></button>
</div>
<div class="cal-grid" id="cal-grid"></div>
</div>
<!-- Overlay -->
<div class="overlay" id="overlay" onclick="closePanel()"></div>
<!-- Snapshot panel -->
<div class="snapshot-panel" id="snapshot-panel">
<div class="snapshot-panel-header">
<span class="snapshot-panel-title" id="panel-title"></span>
<button class="panel-close-btn" onclick="closePanel()"></button>
</div>
<div class="snapshot-panel-body" id="panel-body">
<p style="color:var(--text3);font-size:13px">Select a day to view answers.</p>
</div>
</div>
<script>
const QUESTIONS = {{ questions | tojson }};
let snapshots = {}; // date string → snapshot doc
let curYear, curMonth;
const DAYS = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
const MONTHS = ['January','February','March','April','May','June','July','August','September','October','November','December'];
async function loadSnapshots() {
const res = await fetch('/api/snapshots?limit=365');
const list = await res.json();
snapshots = {};
list.forEach(s => { snapshots[s.date] = s; });
renderCalendar();
}
function renderCalendar() {
const label = document.getElementById('month-label');
label.textContent = MONTHS[curMonth] + ' ' + curYear;
const grid = document.getElementById('cal-grid');
grid.innerHTML = '';
// Day of week headers
DAYS.forEach(d => {
const el = document.createElement('div');
el.className = 'cal-dow';
el.textContent = d;
grid.appendChild(el);
});
const today = new Date();
const todayStr = fmtDate(today);
// First day of month — Monday-based offset
const firstDay = new Date(curYear, curMonth, 1);
let offset = firstDay.getDay(); // 0=Sun
offset = offset === 0 ? 6 : offset - 1; // convert to Mon=0
for (let i = 0; i < offset; i++) {
const el = document.createElement('div');
el.className = 'cal-cell empty';
grid.appendChild(el);
}
const daysInMonth = new Date(curYear, curMonth + 1, 0).getDate();
for (let d = 1; d <= daysInMonth; d++) {
const dateStr = `${curYear}-${String(curMonth+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
const snap = snapshots[dateStr];
const isToday = dateStr === todayStr;
const isDone = snap && snap.answers && snap.answers.__done__;
const hasSnap = !!snap;
const el = document.createElement('div');
el.className = 'cal-cell' +
(hasSnap ? ' has-snapshot' : '') +
(isDone ? ' done' : '') +
(isToday ? ' today' : '');
el.innerHTML = `<span class="cal-day-num">${d}</span>`;
if (hasSnap && !isDone) el.innerHTML += `<span class="cal-dot"></span>`;
if (isDone) el.innerHTML += `<span class="cal-done-dot"></span>`;
if (hasSnap) el.addEventListener('click', () => openPanel(dateStr, snap));
grid.appendChild(el);
}
}
function fmtDate(d) {
return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
}
function openPanel(dateStr, snap) {
document.getElementById('panel-title').textContent = formatDateNice(dateStr);
const body = document.getElementById('panel-body');
// Download button
let html = `<a class="download-btn" href="/api/snapshots/${dateStr}/md" download="checkin-${dateStr}.md">⬇ Download .md</a>`;
// Done badge
if (snap.answers && snap.answers.__done__) {
const at = snap.answers.__done_at__ ? new Date(snap.answers.__done_at__).toLocaleTimeString('en-GB', {hour:'2-digit',minute:'2-digit'}) : '';
html += `<div style="display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--success-bg);border:1px solid var(--success);border-radius:100px;font-size:12px;color:var(--success);margin-bottom:20px;margin-left:8px;">✓ Filled ${at ? 'at ' + at : ''}</div>`;
}
html += `<div style="border-top:1px solid var(--border);padding-top:20px;">`;
QUESTIONS.forEach(q => {
const val = snap.answers ? snap.answers[q.id] : null;
html += `<div class="snapshot-qa">
<div class="snapshot-q">${escHtml(q.label)}</div>
<div class="snapshot-a">${formatVal(q, val)}</div>
</div>`;
});
html += `</div>`;
body.innerHTML = html;
document.getElementById('snapshot-panel').classList.add('open');
document.getElementById('overlay').classList.add('visible');
}
function closePanel() {
document.getElementById('snapshot-panel').classList.remove('open');
document.getElementById('overlay').classList.remove('visible');
}
function formatVal(q, val) {
if (val == null) return `<span style="color:var(--text3)">—</span>`;
switch(q.type) {
case 'yesno': return val ? '✅ Yes' : '❌ No';
case 'duration': {
const h = Math.floor(val/60), m = val%60;
return `${h}h ${String(m).padStart(2,'0')}m`;
}
case 'time': {
const h = Math.floor(val/60), m = val%60;
return `${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')}`;
}
case 'multichoice': return Array.isArray(val) ? val.join(', ') : String(val);
default: return escHtml(String(val));
}
}
function formatDateNice(dateStr) {
const d = new Date(dateStr + 'T12:00:00');
return d.toLocaleDateString('en-GB', {weekday:'long', day:'numeric', month:'long', year:'numeric'});
}
function escHtml(s) {
return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
// Nav
const now = new Date();
curYear = now.getFullYear();
curMonth = now.getMonth();
document.getElementById('prev-btn').addEventListener('click', () => {
curMonth--;
if (curMonth < 0) { curMonth = 11; curYear--; }
renderCalendar();
});
document.getElementById('next-btn').addEventListener('click', () => {
curMonth++;
if (curMonth > 11) { curMonth = 0; curYear++; }
renderCalendar();
});
loadSnapshots();
initThemeToggle();
</script>
</body>
</html>