88 lines
3.3 KiB
JavaScript
88 lines
3.3 KiB
JavaScript
const STATUS_LABELS = {
|
|
upcoming: "Noch nicht",
|
|
pending: "Jetzt!",
|
|
overdue: "Überfällig",
|
|
snoozed: "Snoozed",
|
|
taken: "Genommen ✓",
|
|
missed: "Verpasst",
|
|
};
|
|
|
|
export function showToast(msg, ms = 3000) {
|
|
const el = document.getElementById("toast");
|
|
el.textContent = msg;
|
|
el.hidden = false;
|
|
clearTimeout(el._timer);
|
|
el._timer = setTimeout(() => { el.hidden = true; }, ms);
|
|
}
|
|
|
|
export function showConfetti() {
|
|
const el = document.getElementById("confetti");
|
|
el.hidden = false;
|
|
el.classList.add("show");
|
|
setTimeout(() => { el.hidden = true; el.classList.remove("show"); }, 650);
|
|
}
|
|
|
|
export function showEasterEgg(title, text) {
|
|
const overlay = document.getElementById("easterEgg");
|
|
overlay.innerHTML = `
|
|
<div class="easterEggInner">
|
|
<h2>🏆 ${title}</h2>
|
|
<p>${text}</p>
|
|
<button type="button" class="btn btn-primary" id="easterClose">Nice</button>
|
|
</div>`;
|
|
overlay.hidden = false;
|
|
overlay.querySelector("#easterClose").addEventListener("click", () => {
|
|
overlay.hidden = true;
|
|
overlay.innerHTML = "";
|
|
});
|
|
}
|
|
|
|
export function renderSlots(slots, onTake, onSnooze) {
|
|
const container = document.getElementById("slotCards");
|
|
container.innerHTML = slots.map((slot) => {
|
|
const taken = slot.status === "taken";
|
|
const canTake = ["pending", "overdue", "snoozed", "upcoming"].includes(slot.status);
|
|
return `
|
|
<div class="slotCard status-${slot.status}" data-slot="${slot.id}">
|
|
<div class="slotHeader">
|
|
<span class="slotLabel">${slot.label}</span>
|
|
<span class="slotTime">${slot.time}</span>
|
|
</div>
|
|
<div class="slotMeds">${slot.meds.map((m) => `${m.name} ${m.dose}`).join(", ")}</div>
|
|
<span class="slotStatus">${STATUS_LABELS[slot.status] || slot.status}</span>
|
|
${canTake && !taken ? `
|
|
<div class="slotActions">
|
|
<button type="button" class="btn btn-primary" data-action="take" data-slot="${slot.id}">Genommen ✓</button>
|
|
<button type="button" class="btn btn-snooze" data-action="snooze15" data-slot="${slot.id}">+15 Min</button>
|
|
<button type="button" class="btn btn-snooze" data-action="snooze30" data-slot="${slot.id}">+30 Min</button>
|
|
</div>` : ""}
|
|
</div>`;
|
|
}).join("");
|
|
|
|
container.querySelectorAll("[data-action]").forEach((btn) => {
|
|
btn.addEventListener("click", () => {
|
|
const slotId = btn.dataset.slot;
|
|
const action = btn.dataset.action;
|
|
if (action === "take") onTake(slotId);
|
|
else if (action === "snooze15") onSnooze(slotId, 15);
|
|
else if (action === "snooze30") onSnooze(slotId, 30);
|
|
});
|
|
});
|
|
}
|
|
|
|
export function renderHeatmap(days) {
|
|
const container = document.getElementById("heatmap");
|
|
container.innerHTML = days.map((d) =>
|
|
`<div class="heatCell ${d.level}" title="${d.day}"></div>`
|
|
).join("");
|
|
}
|
|
|
|
export function updateStats(stats) {
|
|
document.getElementById("statStreak").textContent = stats.streak;
|
|
document.getElementById("statCompliance").textContent = `${stats.compliance_percent}%`;
|
|
const windowDays = stats.compliance_window_days ?? 90;
|
|
document.getElementById("statComplianceLabel").textContent = windowDays === 1 ? "1 Tag" : `${windowDays} Tage`;
|
|
document.getElementById("statTaken").textContent = stats.total_taken;
|
|
document.getElementById("streakBadge").textContent = `🔥 ${stats.streak}`;
|
|
}
|