// ── dayfocus.jsx — Smart daily focus widget ────────────────────────────────── // Synthesises priorities + urgency stage + day-of-week mode + energy level // → one clear "right now" action + one "then" — ADHD-friendly, revenue-first. // Email/calendar sections show placeholder until connectors are live. // ── Stage helper (mirrors priorities.jsx) ──────────────────────────────────── function dfStage(p) { if (p.extended || (p.rollovers || 0) >= 2) return 'final'; if ((p.rollovers || 0) === 1) return 'rolled'; return 'fresh'; } // ── Day-of-week working blocks ──────────────────────────────────────────────── const DF_BLOCKS = [ { short: 'SUN · PLAN', mode: 'plan', boost: ['admin','finance'], tip: 'Review targets. Set the week.' }, { short: 'MON · CEO HOUR', mode: 'ceo', boost: ['bdm','admin'], tip: 'Numbers, pipeline, one fix. No clients.' }, { short: 'TUE · DELIVERY', mode: 'delivery', boost: ['ops'], tip: 'Heads-down. Client work only.' }, { short: 'WED · DELIVERY', mode: 'delivery', boost: ['ops'], tip: 'Heads-down. Client work only.' }, { short: 'THU · DELIVERY', mode: 'delivery', boost: ['ops'], tip: 'Heads-down. Client work only.' }, { short: 'FRI · OUTREACH', mode: 'outreach', boost: ['bdm','marketing'], tip: 'Calls, proposals, follow-ups.' }, { short: 'SAT · SIMPLIFY', mode: 'simplify', boost: ['ops','admin'], tip: 'Kill one distraction. Close loops.' }, ]; // ── Revenue weights by category ─────────────────────────────────────────────── const DF_REV = { bdm: 60, marketing: 30, finance: 20, ops: 10, admin: 5 }; // ── Score + rank priorities ─────────────────────────────────────────────────── function dfRank(priorities, block, energy) { const isWeekend = [5, 6].includes(new Date().getDay()); return priorities .filter(p => !p.done) .map(p => { const stage = dfStage(p); const open = (p.tasks || []).filter(t => !t.done); const done = (p.tasks || []).filter(t => t.done); let score = 0; const why = []; // ── Urgency (stage) if (stage === 'final') { score += 110; why.push('final week'); } else if (stage === 'rolled') { score += 80; why.push('on borrowed time'); } else if (isWeekend) { score += 55; why.push('last chance'); } else score += 20; // ── Revenue const rev = DF_REV[p.tag] || 10; score += rev; if (rev >= 30) why.push('💰 revenue'); // ── Day-mode match — this type of work is RIGHT for today if (block.boost.includes(p.tag)) { score += 30; why.push('right time for this'); } // ── Momentum — started but not finished is easier to continue if (done.length > 0 && open.length > 0) score += 15; // ── No open tasks → deprioritise (probably needs completing, not focusing on) if ((p.tasks || []).length > 0 && open.length === 0) score -= 500; // ── Energy match — if spent, avoid deep/complex tasks if (energy === 'spent' && open.length > 4) score -= 25; return { p, score, why, open, stage }; }) .sort((a, b) => b.score - a.score); } // ── DayFocus component ──────────────────────────────────────────────────────── function DayFocus() { const { state } = useStore(); const [now, setNow] = React.useState(() => new Date()); React.useEffect(() => { const id = setInterval(() => setNow(new Date()), 60000); return () => clearInterval(id); }, []); const block = DF_BLOCKS[now.getDay()]; const timeStr = now.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }); const ranked = dfRank(state.priorities || [], block, state.energy); const focus = ranked[0]; const backup = ranked[1]; // Nothing to show if (!focus) return null; const focusStep = focus.open[0]; const backupStep = backup?.open[0]; // If focus priority has all tasks done, the nudge changes const allDone = focus.p.tasks.length > 0 && focus.open.length === 0; // Urgency colour on NOW badge const nowColor = focus.stage === 'final' ? 'var(--danger)' : focus.stage === 'rolled' ? 'var(--danger)' : 'var(--indigo-500)'; return (
{/* ── Header: time + day block ── */}
{timeStr} · {block.short} {block.tip}
{/* ── NOW ── */}
NOW
{focus.p.title} {allDone ? all tasks done — mark complete ✓ : focusStep && → {focusStep.label} }
{focus.why.slice(0, 2).map(w => ( {w} ))}
{/* ── THEN ── */} {backup && (
THEN
{backup.p.title} {backupStep && → {backupStep.label}}
{backup.why[0] && (
{backup.why[0]}
)}
)}
); } Object.assign(window, { DayFocus });