debug line test
This commit is contained in:
+173
@@ -0,0 +1,173 @@
|
||||
import { api } from "./lib/api.js";
|
||||
import { getToken, setToken, clearToken, isLoggedIn } from "./lib/auth.js";
|
||||
import { setStreakBadge } from "./lib/badge.js";
|
||||
import { enqueue, flushQueue } from "./lib/offlineQueue.js";
|
||||
import { registerPwa, wirePwaInstall, subscribePush } from "./lib/pwa.js";
|
||||
import { renderSlots, renderHeatmap, updateStats, showToast, showConfetti, showEasterEgg } from "./lib/ui.js";
|
||||
|
||||
let pinBuffer = "";
|
||||
|
||||
const STATUS = { upcoming: "Noch nicht", pending: "Jetzt!", overdue: "Überfällig", snoozed: "Snoozed", taken: "Genommen", missed: "Verpasst" };
|
||||
|
||||
function showScreen(id) {
|
||||
document.querySelectorAll(".screen").forEach((s) => { s.hidden = s.id !== id; });
|
||||
}
|
||||
|
||||
function wirePinPad() {
|
||||
const pad = document.getElementById("pinPad");
|
||||
const keys = ["1","2","3","4","5","6","7","8","9","⌫","0","✓"];
|
||||
pad.innerHTML = keys.map((k) =>
|
||||
`<button type="button" class="pinKey${k.length > 1 ? " wide" : ""}" data-key="${k}">${k}</button>`
|
||||
).join("");
|
||||
|
||||
pad.addEventListener("click", async (e) => {
|
||||
const btn = e.target.closest("[data-key]");
|
||||
if (!btn) return;
|
||||
const key = btn.dataset.key;
|
||||
const errEl = document.getElementById("loginError");
|
||||
errEl.hidden = true;
|
||||
|
||||
if (key === "⌫") { pinBuffer = pinBuffer.slice(0, -1); }
|
||||
else if (key === "✓") {
|
||||
if (pinBuffer.length < 4) return;
|
||||
try {
|
||||
const { token } = await api.login(pinBuffer);
|
||||
setToken(token);
|
||||
pinBuffer = "";
|
||||
await initApp();
|
||||
} catch {
|
||||
errEl.textContent = "Falscher PIN. Dein Gehirn auch.";
|
||||
errEl.hidden = false;
|
||||
pinBuffer = "";
|
||||
}
|
||||
} else if (pinBuffer.length < 6) {
|
||||
pinBuffer += key;
|
||||
}
|
||||
document.getElementById("pinDisplay").textContent = "•".repeat(pinBuffer.length) || "••••";
|
||||
});
|
||||
}
|
||||
|
||||
function wireTabs() {
|
||||
document.querySelectorAll(".tab").forEach((tab) => {
|
||||
tab.addEventListener("click", () => {
|
||||
document.querySelectorAll(".tab").forEach((t) => t.classList.remove("active"));
|
||||
document.querySelectorAll(".tabPanel").forEach((p) => p.hidden = true);
|
||||
tab.classList.add("active");
|
||||
const panel = document.getElementById(`tab-${tab.dataset.tab}`);
|
||||
panel.hidden = false;
|
||||
if (tab.dataset.tab === "history") loadHistory();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function handleTake(slotId) {
|
||||
const card = document.querySelector(`[data-slot="${slotId}"]`);
|
||||
try {
|
||||
if (!navigator.onLine) {
|
||||
await enqueue({ slot_id: slotId, status: "taken" });
|
||||
showToast("Offline gespeichert — wird synchronisiert.");
|
||||
return;
|
||||
}
|
||||
const result = await api.log({ slot_id: slotId, status: "taken" });
|
||||
card?.classList.add("dopamin");
|
||||
showConfetti();
|
||||
showToast(result.message);
|
||||
if (result.new_milestones?.length) {
|
||||
for (const m of result.new_milestones) {
|
||||
showEasterEgg(m.title, "Achievement freigeschaltet!");
|
||||
}
|
||||
}
|
||||
await refreshDashboard(result.stats);
|
||||
} catch (e) {
|
||||
await enqueue({ slot_id: slotId, status: "taken" });
|
||||
showToast("Gespeichert — Sync folgt.");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSnooze(slotId, minutes) {
|
||||
try {
|
||||
const result = await api.snooze(slotId, minutes);
|
||||
showToast(result.message || `Snooze +${minutes} Min`);
|
||||
await refreshDashboard();
|
||||
} catch (e) {
|
||||
showToast("Snooze fehlgeschlagen.");
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshDashboard(stats) {
|
||||
const [today, roast] = await Promise.all([
|
||||
api.today(),
|
||||
api.roast().catch(() => ({ text: "Dein Gebrain wartet auf Koffein und Medis." })),
|
||||
]);
|
||||
renderSlots(today.slots, handleTake, handleSnooze);
|
||||
document.getElementById("roastText").textContent = roast.text;
|
||||
|
||||
const s = stats || await api.stats();
|
||||
updateStats(s);
|
||||
await setStreakBadge(s.streak);
|
||||
}
|
||||
|
||||
async function loadHistory() {
|
||||
const data = await api.history(90);
|
||||
renderHeatmap(data.days);
|
||||
updateStats(data.stats);
|
||||
const oracle = await api.oracle().catch(() => ({ text: "Das Orakel schweigt. Wahrscheinlich enttäuscht." }));
|
||||
document.getElementById("oracleText").textContent = oracle.text;
|
||||
}
|
||||
|
||||
async function handleDeepLink() {
|
||||
const params = new URLSearchParams(location.search);
|
||||
const slot = params.get("slot");
|
||||
if (params.get("action") === "take" && slot) {
|
||||
await handleTake(slot);
|
||||
history.replaceState({}, "", "/");
|
||||
} else if (params.get("action") === "snooze" && slot) {
|
||||
const minutes = parseInt(params.get("minutes") || "15", 10);
|
||||
await handleSnooze(slot, minutes);
|
||||
history.replaceState({}, "", "/");
|
||||
}
|
||||
}
|
||||
|
||||
async function initApp() {
|
||||
showScreen("mainScreen");
|
||||
wireTabs();
|
||||
wirePwaInstall();
|
||||
document.getElementById("logoutBtn").addEventListener("click", () => {
|
||||
clearToken();
|
||||
location.reload();
|
||||
});
|
||||
|
||||
document.getElementById("enablePush").addEventListener("click", async () => {
|
||||
const statusEl = document.getElementById("pushStatus");
|
||||
try {
|
||||
const perm = await Notification.requestPermission();
|
||||
if (perm !== "granted") { statusEl.textContent = "Permission verweigert."; return; }
|
||||
const { key } = await api.vapidKey();
|
||||
if (!key) { statusEl.textContent = "VAPID keys nicht konfiguriert."; return; }
|
||||
const sub = await subscribePush(key);
|
||||
await api.pushSubscribe(sub);
|
||||
statusEl.textContent = "Push aktiv! Du wirst dezent erinnert.";
|
||||
} catch (e) {
|
||||
statusEl.textContent = e.message || "Push-Setup fehlgeschlagen.";
|
||||
}
|
||||
});
|
||||
|
||||
await flushQueue((data) => api.log(data));
|
||||
await refreshDashboard();
|
||||
await handleDeepLink();
|
||||
}
|
||||
|
||||
navigator.serviceWorker?.addEventListener("message", (event) => {
|
||||
if (event.data?.type === "SYNC_QUEUE") flushQueue((data) => api.log(data));
|
||||
});
|
||||
|
||||
async function boot() {
|
||||
registerPwa();
|
||||
if (isLoggedIn()) {
|
||||
try { await initApp(); return; } catch { clearToken(); }
|
||||
}
|
||||
showScreen("loginScreen");
|
||||
wirePinPad();
|
||||
}
|
||||
|
||||
boot();
|
||||
Reference in New Issue
Block a user