// Habits screen — streaks, calendar grid, IA insights const HabitsScreen = ({ state, setState, navigate, showToast }) => { const { habits } = state; const [selected, setSelected] = React.useState(null); const [showNew, setShowNew] = React.useState(false); const totalStreak = Math.max(...habits.map(h => h.streak)); const done = habits.filter(h => h.done).length; const toggleHabit = (id) => { setState(s => ({ ...s, habits: s.habits.map(h => h.id === id ? { ...h, done: !h.done, current: h.done ? Math.max(0, h.current - 1) : Math.min(h.target, h.current + 1) } : h) })); showToast('Hábito marcado'); }; // Intent: abrir modal de novo hábito via evento global React.useEffect(() => { const handler = () => setShowNew(true); window.addEventListener('cdv:open-new-habit', handler); return () => window.removeEventListener('cdv:open-new-habit', handler); }, []); if (selected) { return h.id === selected)} onBack={() => setSelected(null)} onToggle={toggleHabit} />; } return (
setShowNew(true)} style={{ background: CDV.brandGrad, border: 'none', width: 38, height: 38, borderRadius: 99, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff', }}> } /> {/* Streak hero */}
🔥
Sua maior sequência
{totalStreak} dias
Treinar — não pare agora!
{/* Habits list */}
{habits.map(h => ( setSelected(h.id)} /> ))}
{/* AI insight */}
Sofia detectou
Você mantém hábitos por mais tempo quando começa antes das 8h. Quer reagendar "Meditar" para 7h?
setShowNew(false)} title="Novo hábito"> { setState(s => ({ ...s, habits: [...s.habits, { ...habit, id: 'h' + Date.now(), streak: 0, target: 1, current: 0, unit: 'sessão', done: false, history: [], }] })); setShowNew(false); showToast('Hábito criado'); }} />
); }; const MiniStat = ({ val, label, color }) => (
{val}
{label}
); const HabitRow = ({ habit, onToggle, onClick }) => { const pct = (habit.current / habit.target) * 100; return (
{habit.name}
{habit.streak}
{habit.current}/{habit.target} {habit.unit}
{habit.history.slice(-7).map((d, i) => (
))}
); }; // ── Habit detail view ─────────────────────────────────────── const HabitDetail = ({ habit, onBack, onToggle }) => { const totalDone = habit.history.filter(Boolean).length; const successRate = Math.round((totalDone / habit.history.length) * 100); return (
{habit.streak}
dias seguidos
Próximo marco: 30 dias em {30 - habit.streak} dias
{habit.history.map((d, i) => (
))}
30 dias atrás Hoje
{[ { name: '7 dias', icon: 'flame', unlocked: true }, { name: '30 dias', icon: 'star', unlocked: habit.streak >= 30 }, { name: '100 dias', icon: 'crown', unlocked: false }, { name: 'Marco anual', icon: 'trophy', unlocked: false }, ].map((m, i) => (
{m.name}
))}
); }; const NewHabitForm = ({ onSubmit, onDone }) => { const [name, setName] = React.useState(''); const [icon, setIcon] = React.useState('drop'); const [freq, setFreq] = React.useState('todo-dia'); const [weekdays, setWeekdays] = React.useState([1, 2, 3, 4, 5]); // seg-sex default const colors = [CDV.brand, CDV.mint, CDV.coral, CDV.sky, CDV.amber, CDV.flame]; const [color, setColor] = React.useState(colors[0]); const iconOpts = ['drop', 'book', 'dumbbell', 'meditate', 'cup', 'pomodoro', 'sun', 'flame']; const weekdaysValid = freq !== 'semana' || weekdays.length > 0; const canSave = name.trim().length > 0 && weekdaysValid; const toggleWeekday = (i) => setWeekdays(arr => arr.includes(i) ? arr.filter(d => d !== i) : [...arr, i].sort()); const submit = () => { if (!canSave) return; if (typeof onSubmit === 'function') { onSubmit({ name: name.trim(), icon, color, freq, ...(freq === 'semana' ? { weekdays } : {}), }); } else if (typeof onDone === 'function') onDone(); }; return (
setName(e.target.value)} placeholder="Ex: Beber 2L de água" style={{ width: '100%', height: 54, borderRadius: 16, border: `1px solid ${CDV.stroke}`, background: CDV.surfaceHi, color: CDV.text, padding: '0 18px', fontSize: 15, outline: 'none', fontFamily: 'inherit', }} />
Ícone
{iconOpts.map(i => ( ))}
Cor
{colors.map(c => (
Frequência
{[{ id: 'todo-dia', label: 'Todo dia' }, { id: 'semana', label: 'Dias da semana' }, { id: 'x-semana', label: '3x semana' }].map(f => ( ))}
{freq === 'semana' && (
Selecione os dias
{['D', 'S', 'T', 'Q', 'Q', 'S', 'S'].map((label, i) => { const active = weekdays.includes(i); return ( ); })}
{weekdays.length === 0 && (
Selecione ao menos 1 dia.
)}
)}
); }; Object.assign(window, { HabitsScreen });