Replace browser notifications with manual WhatsApp reminders

Drop Notification API (only fires when tab open). Instead render two
wa.me deep-link buttons that pre-fill reminder text to the user's own
WhatsApp number (77477854246). Steps button auto-picks 5k (weekday)
or 10k (weekend) based on current day.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
kuzbaeva 2026-05-22 13:08:51 +05:00
parent 24136595b7
commit 9de414fefe

View File

@ -121,6 +121,18 @@
font-weight: 500;
font-size: 0.88rem;
}
.wa-btn {
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
background: linear-gradient(135deg, #25d366, #128c7e);
color: white; text-decoration: none;
padding: 12px 18px;
border-radius: 12px;
font-weight: 600; font-size: 0.95rem;
box-shadow: 0 4px 14px rgba(37, 211, 102, 0.3);
transition: transform .15s ease, box-shadow .2s ease;
}
.wa-btn:hover { transform: translateY(-1px); box-shadow: 0 6px 20px rgba(37, 211, 102, 0.45); }
.wa-btn:active { transform: translateY(0); }
button.link:hover {
background: var(--accent-soft);
transform: none;
@ -338,11 +350,12 @@
</section>
<section id="reminders">
<h2>🔔 Напоминания</h2>
<p>Шаги (будни 5 000, выходные 10 000) — в 12:00.<br/>Instagram — раз в неделю, воскресенье 11:00.</p>
<button id="enable-notifications">Включить уведомления</button>
<span id="notif-status" class="muted"></span>
<p class="muted small">⚠️ Уведомления приходят только пока вкладка открыта. Для пуша когда сайт закрыт нужен Service Worker — это следующий шаг.</p>
<h2>🔔 Напоминания в WhatsApp</h2>
<p class="muted small">Жми кнопку — откроется WhatsApp с готовым текстом, отправь себе.</p>
<div style="display:flex; flex-direction:column; gap:10px; margin-top:12px;">
<a id="wa-steps" class="wa-btn" target="_blank" rel="noopener">👟 <span id="wa-steps-label">Шаги сегодня</span></a>
<a id="wa-ig" class="wa-btn" target="_blank" rel="noopener">📷 Опубликовать историю в Instagram</a>
</div>
</section>
<section id="checklist">
@ -464,11 +477,13 @@
];
const REMINDERS = {
weekdaySteps: { time: "12:00", text: "Пройти 5 000 шагов сегодня" },
weekendSteps: { time: "12:00", text: "Пройти 10 000 шагов сегодня" },
instagram: { day: 0, time: "11:00", text: "Опубликовать одну историю в Instagram (@zhanara2964)" }
weekdaySteps: { text: "Пройти 5 000 шагов сегодня 👟" },
weekendSteps: { text: "Пройти 10 000 шагов сегодня 👟" },
instagram: { text: "Опубликовать одну историю в Instagram (@zhanara2964) 📷" }
};
const WHATSAPP_NUMBER = "77477854246";
const PASSWORD = "zhanar2026";
/* ===== AUTH ===== */
@ -615,77 +630,27 @@
});
})();
/* ===== REMINDERS ===== */
/* ===== REMINDERS (WhatsApp manual) ===== */
(function () {
const btn = document.getElementById("enable-notifications");
const status = document.getElementById("notif-status");
const FIRED_KEY = "reminders-fired";
const stepsBtn = document.getElementById("wa-steps");
const stepsLabel = document.getElementById("wa-steps-label");
const igBtn = document.getElementById("wa-ig");
function todayKey() { return new Date().toISOString().slice(0, 10); }
function waLink(text) {
return "https://wa.me/" + WHATSAPP_NUMBER + "?text=" + encodeURIComponent(text);
}
function firedToday(tag) {
try {
const data = JSON.parse(localStorage.getItem(FIRED_KEY) || "{}");
return data[todayKey()] && data[todayKey()][tag];
} catch (e) { return false; }
}
function markFired(tag) {
let data;
try { data = JSON.parse(localStorage.getItem(FIRED_KEY) || "{}"); }
catch (e) { data = {}; }
const k = todayKey();
Object.keys(data).forEach(function (d) { if (d !== k) delete data[d]; });
data[k] = data[k] || {};
data[k][tag] = true;
localStorage.setItem(FIRED_KEY, JSON.stringify(data));
}
function updateStatus() {
if (!("Notification" in window)) {
status.textContent = "не поддерживается в этом браузере";
btn.disabled = true;
return;
}
const p = Notification.permission;
if (p === "granted") {
status.textContent = "✅ включены";
btn.textContent = "Уведомления включены";
btn.disabled = true;
} else if (p === "denied") {
status.textContent = "❌ заблокированы в браузере";
btn.disabled = true;
} else {
status.textContent = "не запрошены";
}
}
function checkAndFire() {
if (Notification.permission !== "granted") return;
const now = new Date();
const hhmm = now.toTimeString().slice(0, 5);
const dow = now.getDay();
function refresh() {
const dow = new Date().getDay();
const isWeekend = dow === 0 || dow === 6;
const steps = isWeekend ? REMINDERS.weekendSteps : REMINDERS.weekdaySteps;
if (hhmm === steps.time && !firedToday("steps")) {
new Notification("Шаги", { body: steps.text });
markFired("steps");
}
const ig = REMINDERS.instagram;
if (dow === ig.day && hhmm === ig.time && !firedToday("ig")) {
new Notification("Instagram", { body: ig.text });
markFired("ig");
}
stepsBtn.href = waLink(steps.text);
stepsLabel.textContent = steps.text;
igBtn.href = waLink(REMINDERS.instagram.text);
}
btn.addEventListener("click", function () {
if (!("Notification" in window)) return;
Notification.requestPermission().then(function (p) {
updateStatus();
if (p === "granted") {
new Notification("Уведомления включены", { body: "Я буду напоминать о шагах и Instagram." });
}
});
});
updateStatus();
setInterval(checkAndFire, 60_000);
refresh();
setInterval(refresh, 60 * 60 * 1000);
})();
/* ===== APP (render) ===== */