// Dashboard view: hero + today + overdue + upcoming events function StatCard({ icon, label, value, hint, accent = "var(--terracotta)", bg = "var(--terracotta-tint)" }) { return (
{label}
{value}
{hint &&
{hint}
}
); } function DashboardHero({ items, openForm, user }) { const userInfo = (typeof USERS !== "undefined" && USERS[user]) || { name: user || "vous" }; const today = TODAY; const greeting = (() => { const h = today.getHours(); if (h < 12) return "Bonjour"; if (h < 18) return "Bon après-midi"; return "Bonsoir"; })(); const todayItems = itemsOnDate(items, today); const tasksToday = todayItems.filter(x => x.kind === "task"); const remaining = tasksToday.filter(x => { const s = statusOn(x, today); return s === "todo" || s === "progress"; }).length; const done = tasksToday.filter(x => statusOn(x, today) === "done").length; const total = tasksToday.length; return (
{/* Decorative arc */}
{fmtFull(today)}

{greeting}, {userInfo.name}.
{remaining > 0 ? `${remaining} chose${remaining > 1 ? "s" : ""} à faire` : total > 0 ? "tout est sous contrôle." : "rien de prévu aujourd'hui."}

{done}/{total}
Aujourd'hui
{total === 0 ? "Aucune tâche" : `${done} terminée${done > 1 ? "s" : ""} sur ${total}`}
); } function TaskRow({ item, date, onStatusChange, onEdit, dense }) { const isTask = item.kind === "task"; const status = statusOn(item, date); const s = STATES[status]; const k = KINDS[item.kind]; const cycleStatus = () => { if (!isTask) return; const order = ["todo", "progress", "done"]; const i = order.indexOf(status); const next = i === -1 || i === order.length - 1 ? "todo" : order[i + 1]; onStatusChange(item.id, ymd(date), next); }; return (
{/* Checkbox or dot */} {/* Title + meta */}
{item.title}
{!isTask && } {item.recurrence?.kind && item.recurrence.kind !== "none" && ( {recurrenceLabel(item.recurrence)} )} {item.notify && ( rappel )} {item.assignee && ( {(USERS[item.assignee]?.avatar || item.assignee[0].toUpperCase())} {USERS[item.assignee]?.name || item.assignee} )} {item.notes && {item.notes}}
{/* Right side */}
{isTask && } onEdit(item)} />
); } function recurrenceLabel(r) { if (!r || r.kind === "none") return "Une fois"; if (r.kind === "daily") return "Tous les jours"; if (r.kind === "weekly") return "Chaque semaine"; if (r.kind === "monthly") return "Chaque mois"; if (r.kind === "custom") return `${(r.days || []).length} dates`; return ""; } function DashboardView({ items, openForm, onStatusChange, onEdit, navigate, user }) { const today = TODAY; const todayItems = itemsOnDate(items, today); const todayTasks = todayItems.filter(x => x.kind === "task"); const todayEvents = todayItems.filter(x => x.kind !== "task"); // Overdue: non-recurring tasks before today, not done/cancelled const overdue = items.filter(x => { if (x.kind !== "task") return false; if ((x.recurrence?.kind || "none") !== "none") return false; if (!isBefore(fromYmd(x.date), today)) return false; return !["done", "cancelled"].includes(x.status); }).sort((a, b) => a.date.localeCompare(b.date)); // Upcoming events (next 14 days, not today) const upcoming = []; for (let i = 1; i <= 14; i++) { const d = addDays(today, i); const its = itemsOnDate(items, d).filter(x => x.kind !== "task"); its.forEach(it => upcoming.push({ item: it, date: d })); } // Counts const remainingToday = todayTasks.filter(x => ["todo", "progress"].includes(statusOn(x, today))).length; const doneToday = todayTasks.filter(x => statusOn(x, today) === "done").length; return (
{/* Stats grid */}
(x.recurrence?.kind || "none") !== "none").length} hint="actives" accent="var(--done)" bg="var(--done-bg)" />
{/* Today's tasks */}
navigate("tasks")}>Tout voir} />
{todayTasks.length === 0 ? ( Nouvelle tâche} /> ) : ( todayTasks.map(it => ) )}
{overdue.length > 0 && ( <>
{overdue.slice(0, 4).map(it => )}
)}
{/* Right column */}
{todayEvents.length === 0 ? (
Aucun événement aujourd'hui
) : ( todayEvents.map(it => ) )}
{upcoming.length === 0 ? (
Pas d'événement prévu
) : ( upcoming.slice(0, 6).map(({ item, date }, i) => { const k = KINDS[item.kind]; return (
{DAYS_SHORT[date.getDay()].replace(".", "")}
{date.getDate()}
{item.title}
{item.notes &&
{item.notes}
}
onEdit(item)} />
); }) )}
); } Object.assign(window, { DashboardView, TaskRow, recurrenceLabel });