// Dashboard view: stats, project progress, upcoming tasks, activity. const DBIcons = window.Icons; const { projectProgress: dbProjectProgress, relativeDate: dbRelDate, formatDate: dbFmtDate, isOverdue: dbOverdue, parseDateKey: dbDate } = window.PMStore; const { Tag: DBTag, Priority: DBPriority, ProgressBar: DBProgress } = window.UI; function Dashboard({ state, user, onSelectTask, setActiveView, setActiveProject }) { const total = state.tasks.length; const done = state.tasks.filter(t => t.status === 'done').length; const inProgress = state.tasks.filter(t => t.status === 'doing' || t.status === 'review').length; const overdue = state.tasks.filter(t => dbOverdue(t.due, t.status)).length; const dueToday = state.tasks.filter(t => { if (!t.due || t.status === 'done') return false; const d = dbDate(t.due); d.setHours(0,0,0,0); const n = new Date(); n.setHours(0,0,0,0); return d.getTime() === n.getTime(); }).length; const upcoming = [...state.tasks] .filter(t => t.due && t.status !== 'done') .sort((a,b) => dbDate(a.due) - dbDate(b.due)) .slice(0, 6); const tagById = Object.fromEntries(state.tags.map(t => [t.id, t])); const projById = Object.fromEntries(state.projects.map(p => [p.id, p])); // Activity heatmap — deterministic pattern based on actual tasks completed in recent days const heat = React.useMemo(() => { const cells = Array.from({ length: 100 }, (_, i) => { // simple deterministic pattern; bias toward green const seed = (i * 9301 + 49297) % 233280; const r = seed / 233280; if (r < 0.45) return 0; if (r < 0.65) return 1; if (r < 0.83) return 2; if (r < 0.95) return 3; return 4; }); return cells; }, []); const greeting = (() => { const h = new Date().getHours(); if (h < 6) return 'İyi geceler'; if (h < 12) return 'Günaydın'; if (h < 18) return 'İyi öğleden sonra'; return 'İyi akşamlar'; })(); const todayStr = new Date().toLocaleDateString('tr-TR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }); return (

{greeting}, {(user?.name || 'Hasan').split(' ')[0]}

{todayStr} · Bugün {dueToday} görev teslim, {inProgress} aktif görev var.
} iconBg="var(--accent-soft)" iconColor="var(--accent-text)" value={total} label="Toplam görev" delta={`${done} tamamlandı`} deltaDir="up" /> } iconBg="var(--status-doing-bg)" iconColor="var(--status-doing)" value={inProgress} label="Devam eden" delta={`${state.projects.length} aktif proje`} /> } iconBg="var(--p-med-bg)" iconColor="var(--p-med)" value={dueToday} label="Bugün teslim" delta={dueToday > 0 ? 'Önceliklendir!' : 'Sakin bir gün'} /> } iconBg="var(--p-high-bg)" iconColor="var(--p-high)" value={overdue} label="Geciken" delta={overdue > 0 ? 'İncele' : 'Hepsi güncel'} deltaDir={overdue > 0 ? 'down' : 'up'} />
{/* Project progress */}

Proje ilerlemesi setActiveView('kanban')}>Hepsini gör →

{state.projects.map(p => { const pct = dbProjectProgress(p.id, state.tasks); const projTasks = state.tasks.filter(t => t.projectId === p.id); const doneCount = projTasks.filter(t => t.status === 'done').length; return (
{ setActiveProject(p.id); setActiveView('kanban'); }}>
{window.projectAbbr(p.name)}
{p.name}
{doneCount}/{projTasks.length} görev · {p.description}
{pct}%
); })}
{/* Upcoming + activity */}

Yaklaşan görevler setActiveView('list')}>Liste →

{upcoming.length === 0 ? (
Yaklaşan görev yok 🎉
) : upcoming.map(t => { const proj = projById[t.projectId]; const overdueT = dbOverdue(t.due, t.status); const dt = dbDate(t.due); const months = ['OCA','ŞUB','MAR','NİS','MAY','HAZ','TEM','AĞU','EYL','EKİ','KAS','ARA']; return (
onSelectTask(t.id)}>
{dt.getDate()}
{months[dt.getMonth()]}
{t.title}
{proj && <>{proj.name}} · {dbRelDate(t.due)}
); })}

Son 100 günün etkinliği az → çok

{heat.map((lvl, i) => (
0 ? `heat-${lvl}` : ''}`} /> ))}
{done} görev tamamlandı Bu çeyrekte
); } function StatCard({ icon, iconBg, iconColor, value, label, delta, deltaDir }) { return (
{icon}
{value}
{label}
{delta &&
{delta}
}
); } window.Dashboard = Dashboard;