/* ───────────────────────────────────────────── REMINDERS — daily study reminder Two channels: on the website (banner + optional browser notification) or by email (members). Exposes: window.ReminderCard, window.DueReminderBanner ───────────────────────────────────────────── */ const REM_TIMES = ['08:00','12:30','17:00','19:00','21:00']; function remDefaults() { return { on:false, channel:'site', time:'19:00', browserNotif:false, dismissedOn:null, notifiedOn:null }; } function remIsDue(rem) { if (!rem || !rem.on) return false; const [h, m] = (rem.time || '19:00').split(':').map(Number); const now = new Date(); return now.getHours() > h || (now.getHours() === h && now.getMinutes() >= m); } function remTasksLeft(state) { const plan = state.plan && (window.LEARN_PLANS || []).find(p => p.id === state.plan.id); const today = (state.history || {})[window.todayKey ? window.todayKey() : ''] || {}; if (!plan) return Object.values(today).reduce((a,b)=>a+b,0) === 0 ? 1 : 0; // no plan: remind if nothing done return Object.entries(plan.targets).filter(([k, n]) => (today[k] || 0) < n).length; } /* ── Settings card (Learning home) ── */ function ReminderCard({ state, setState, t, lang, member, onNeedMember }) { const rem = { ...remDefaults(), ...(state.reminder || {}) }; const isAr = lang === 'ar'; const upd = (patch) => setState(s => ({ ...s, reminder: { ...remDefaults(), ...(s.reminder || {}), ...patch } })); const pickChannel = (ch) => { if (ch === 'email' && !member) { if (onNeedMember) onNeedMember(); return; } upd({ channel: ch }); }; const askBrowserNotif = async () => { if (!('Notification' in window)) return; if (Notification.permission === 'default') { const p = await Notification.requestPermission(); upd({ browserNotif: p === 'granted' }); } else { upd({ browserNotif: Notification.permission === 'granted' && !rem.browserNotif }); } }; return (
⏰ {t('Daily reminder','تذكير يومي','Günlük hatırlatıcı')}
{rem.on ? t('We\u2019ll nudge you if your daily plan isn\u2019t done yet.','سنذكّرك إذا لم تُكمل خطتك اليومية بعد.','Günlük planın bitmediyse sana hatırlatırız.') : t('Turn it on so you never miss a study day.','فعّله حتى لا يفوتك يوم دراسة.','Aç ki hiçbir çalışma gününü kaçırma.')}
{rem.on && (
{t('How should we remind you?','كيف نذكّرك؟','Nasıl hatırlatalım?')}
{t('Reminder time','وقت التذكير','Hatırlatma saati')}
{REM_TIMES.map(tm => ( ))} e.target.value && upd({ time: e.target.value })} />
{rem.channel === 'site' && ('Notification' in window) && ( )} {rem.channel === 'email' && member && (
✓ {t('Email reminders are set. You\u2019ll get one at','تم ضبط تذكير البريد. سيصلك عند الساعة','E-posta hatırlatıcısı ayarlandı. Saat')} {rem.time} {t('every day you haven\u2019t studied yet.','كل يوم لم تدرس فيه بعد.','henüz çalışmadığın her gün.')}
)}
)}
); } /* ── Due banner (shown on every tab) ── */ function DueReminderBanner({ state, setState, t, setMode }) { const rem = { ...remDefaults(), ...(state.reminder || {}) }; const tk = window.todayKey ? window.todayKey() : ''; const left = remTasksLeft(state); const due = rem.channel === 'site' && remIsDue(rem) && left > 0 && rem.dismissedOn !== tk; // one browser notification per day, if enabled React.useEffect(() => { if (!due || !rem.browserNotif || rem.notifiedOn === tk) return; if (!('Notification' in window) || Notification.permission !== 'granted') return; try { new Notification('The Fluent Engineer', { body: t('Time to study — your daily plan is waiting!','حان وقت الدراسة — خطتك اليومية بانتظارك!','Çalışma zamanı — günlük planın seni bekliyor!') }); setState(s => ({ ...s, reminder: { ...remDefaults(), ...(s.reminder || {}), notifiedOn: tk } })); } catch {} }, [due]); if (!due) return null; return (
{t('Study reminder — ','تذكير بالدراسة — ','Çalışma hatırlatması — ')} {state.plan ? left + ' ' + t('tasks left on today\u2019s plan.','مهام متبقية في خطة اليوم.','görev bugünkü planında kaldı.') : t('you haven\u2019t studied yet today.','لم تدرس اليوم بعد.','bugün henüz çalışmadın.')}
); } Object.assign(window, { ReminderCard, DueReminderBanner });