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:
parent
24136595b7
commit
9de414fefe
111
index.html
111
index.html
@ -121,6 +121,18 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 0.88rem;
|
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 {
|
button.link:hover {
|
||||||
background: var(--accent-soft);
|
background: var(--accent-soft);
|
||||||
transform: none;
|
transform: none;
|
||||||
@ -338,11 +350,12 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="reminders">
|
<section id="reminders">
|
||||||
<h2>🔔 Напоминания</h2>
|
<h2>🔔 Напоминания в WhatsApp</h2>
|
||||||
<p>Шаги (будни 5 000, выходные 10 000) — в 12:00.<br/>Instagram — раз в неделю, воскресенье 11:00.</p>
|
<p class="muted small">Жми кнопку — откроется WhatsApp с готовым текстом, отправь себе.</p>
|
||||||
<button id="enable-notifications">Включить уведомления</button>
|
<div style="display:flex; flex-direction:column; gap:10px; margin-top:12px;">
|
||||||
<span id="notif-status" class="muted"></span>
|
<a id="wa-steps" class="wa-btn" target="_blank" rel="noopener">👟 <span id="wa-steps-label">Шаги сегодня</span></a>
|
||||||
<p class="muted small">⚠️ Уведомления приходят только пока вкладка открыта. Для пуша когда сайт закрыт нужен Service Worker — это следующий шаг.</p>
|
<a id="wa-ig" class="wa-btn" target="_blank" rel="noopener">📷 Опубликовать историю в Instagram</a>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="checklist">
|
<section id="checklist">
|
||||||
@ -464,11 +477,13 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
const REMINDERS = {
|
const REMINDERS = {
|
||||||
weekdaySteps: { time: "12:00", text: "Пройти 5 000 шагов сегодня" },
|
weekdaySteps: { text: "Пройти 5 000 шагов сегодня 👟" },
|
||||||
weekendSteps: { time: "12:00", text: "Пройти 10 000 шагов сегодня" },
|
weekendSteps: { text: "Пройти 10 000 шагов сегодня 👟" },
|
||||||
instagram: { day: 0, time: "11:00", text: "Опубликовать одну историю в Instagram (@zhanara2964)" }
|
instagram: { text: "Опубликовать одну историю в Instagram (@zhanara2964) 📷" }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const WHATSAPP_NUMBER = "77477854246";
|
||||||
|
|
||||||
const PASSWORD = "zhanar2026";
|
const PASSWORD = "zhanar2026";
|
||||||
|
|
||||||
/* ===== AUTH ===== */
|
/* ===== AUTH ===== */
|
||||||
@ -615,77 +630,27 @@
|
|||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/* ===== REMINDERS ===== */
|
/* ===== REMINDERS (WhatsApp manual) ===== */
|
||||||
(function () {
|
(function () {
|
||||||
const btn = document.getElementById("enable-notifications");
|
const stepsBtn = document.getElementById("wa-steps");
|
||||||
const status = document.getElementById("notif-status");
|
const stepsLabel = document.getElementById("wa-steps-label");
|
||||||
const FIRED_KEY = "reminders-fired";
|
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) {
|
function refresh() {
|
||||||
try {
|
const dow = new Date().getDay();
|
||||||
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();
|
|
||||||
const isWeekend = dow === 0 || dow === 6;
|
const isWeekend = dow === 0 || dow === 6;
|
||||||
|
|
||||||
const steps = isWeekend ? REMINDERS.weekendSteps : REMINDERS.weekdaySteps;
|
const steps = isWeekend ? REMINDERS.weekendSteps : REMINDERS.weekdaySteps;
|
||||||
if (hhmm === steps.time && !firedToday("steps")) {
|
stepsBtn.href = waLink(steps.text);
|
||||||
new Notification("Шаги", { body: steps.text });
|
stepsLabel.textContent = steps.text;
|
||||||
markFired("steps");
|
igBtn.href = waLink(REMINDERS.instagram.text);
|
||||||
}
|
|
||||||
const ig = REMINDERS.instagram;
|
|
||||||
if (dow === ig.day && hhmm === ig.time && !firedToday("ig")) {
|
|
||||||
new Notification("Instagram", { body: ig.text });
|
|
||||||
markFired("ig");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
btn.addEventListener("click", function () {
|
|
||||||
if (!("Notification" in window)) return;
|
refresh();
|
||||||
Notification.requestPermission().then(function (p) {
|
setInterval(refresh, 60 * 60 * 1000);
|
||||||
updateStatus();
|
|
||||||
if (p === "granted") {
|
|
||||||
new Notification("Уведомления включены", { body: "Я буду напоминать о шагах и Instagram." });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
updateStatus();
|
|
||||||
setInterval(checkAndFire, 60_000);
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/* ===== APP (render) ===== */
|
/* ===== APP (render) ===== */
|
||||||
|
|||||||
Reference in New Issue
Block a user