import { useEffect, useMemo, useState } from "react"; import { useParams } from "react-router-dom"; import styled from "styled-components"; import { useChildren } from "../state/ChildrenContext"; import { apiClient } from "../services/api-client"; import { TimeGridMulti } from "../components/TimeGridMulti"; import { Link } from "react-router-dom"; const Container = styled.div` display: flex; flex-direction: column; gap: 16px; `; const Title = styled.h1` margin: 0; font-size: 1.6rem; `; const Toggle = styled.div` display: inline-flex; gap: 8px; `; const ToggleBtn = styled.button<{ $active?: boolean }>` padding: 8px 12px; border-radius: 10px; border: 1px solid rgba(126, 136, 180, 0.25); background: ${({ $active }) => ($active ? "rgba(85,98,255,0.2)" : "transparent")}; color: #e9ebff; cursor: pointer; `; type Act = { title: string; startDateTime: string; endDateTime: string; notes?: string }; export const ChildPlanningScreen = () => { const { childId } = useParams(); const { children } = useChildren(); const [mode, setMode] = useState<"day" | "week">("week"); const [dayEvents, setDayEvents] = useState([]); const [weekDays, setWeekDays] = useState>({}); const [timeZone, setTimeZone] = useState(null); const [lastSchedule, setLastSchedule] = useState<{ sourceFileUrl?: string; exportCsvUrl?: string } | null>(null); const child = children.find((c) => c.id === childId); const color = child?.colorHex ?? "#5562ff"; const today = useMemo(() => new Date(), []); useEffect(() => { const saved = localStorage.getItem("fp:view:timeZone"); if (!saved || saved === "auto") { setTimeZone(Intl.DateTimeFormat().resolvedOptions().timeZone); } else { setTimeZone(saved); } }, []); useEffect(() => { const loadLast = async () => { const items = await apiClient.get>("/schedules"); const forChild = items.filter((i) => i.childId === childId); forChild.sort((a, b) => b.createdAt.localeCompare(a.createdAt)); if (forChild.length > 0) { setLastSchedule({ sourceFileUrl: forChild[0].sourceFileUrl, exportCsvUrl: (forChild[0] as any).exportCsvUrl }); // Reload planning data when we detect a new schedule void loadPlanningData(); } }; if (childId) void loadLast(); }, [childId]); // Reload last schedule periodically to detect new uploads useEffect(() => { if (!childId) return; const interval = setInterval(async () => { const items = await apiClient.get>("/schedules"); const forChild = items.filter((i) => i.childId === childId); forChild.sort((a, b) => b.createdAt.localeCompare(a.createdAt)); if (forChild.length > 0) { const newSchedule = { sourceFileUrl: forChild[0].sourceFileUrl, exportCsvUrl: (forChild[0] as any).exportCsvUrl }; // Only reload if schedule changed if (newSchedule.sourceFileUrl !== lastSchedule?.sourceFileUrl) { setLastSchedule(newSchedule); void loadPlanningData(); } } }, 5000); // Check every 5 seconds return () => clearInterval(interval); }, [childId, lastSchedule]); // Load planning data const loadPlanningData = async () => { if (!childId) return; const y = today.getFullYear(); const m = String(today.getMonth() + 1).padStart(2, "0"); const d = String(today.getDate()).padStart(2, "0"); const date = `${y}-${m}-${d}`; // local date const day = await apiClient.get<{ date: string; items: Array<{ childId: string; activities: Act[] }> }>(`/schedules/day/activities?date=${date}&childId=${childId}`); setDayEvents(day.items?.[0]?.activities ?? []); const start = new Date(today); const weekday = (start.getDay() + 6) % 7; // 0=Mon start.setDate(start.getDate() - weekday); const sy = start.getFullYear(); const sm = String(start.getMonth() + 1).padStart(2, "0"); const sd = String(start.getDate()).padStart(2, "0"); const startISO = `${sy}-${sm}-${sd}`; const week = await apiClient.get<{ start: string; items: Array<{ childId: string; days: Record }> }>(`/schedules/week/activities?start=${startISO}&childId=${childId}`); setWeekDays(week.items?.[0]?.days ?? {}); }; useEffect(() => { void loadPlanningData(); }, [childId, today]); // Auto-reload when user returns to the tab useEffect(() => { const handleVisibilityChange = () => { if (!document.hidden) { void loadPlanningData(); } }; document.addEventListener("visibilitychange", handleVisibilityChange); return () => document.removeEventListener("visibilitychange", handleVisibilityChange); }, [childId, today]); const dayColumns = useMemo(() => { return [ { id: childId || "child", title: child?.fullName ?? "Enfant", color, events: dayEvents, dateISO: today.toISOString().slice(0, 10) } ]; }, [childId, child?.fullName, color, dayEvents]); const weekColumns = useMemo(() => { // Build 7 days columns Mon..Sun const start = new Date(today); const weekday = (start.getDay() + 6) % 7; // 0=Mon start.setDate(start.getDate() - weekday); const cols = [] as { id: string; title: string; color: string; events: Act[]; dateISO?: string }[]; for (let i = 0; i < 7; i++) { const d = new Date(start); d.setDate(start.getDate() + i); const dISO = d.toISOString().slice(0, 10); const label = d.toLocaleDateString("fr-FR", { weekday: "short", day: "2-digit", month: "2-digit" }); cols.push({ id: dISO, title: label, color, events: weekDays[dISO] ?? [], dateISO: dISO }); } return cols; }, [today, weekDays, color]); return ( Planning — {child?.fullName ?? "Enfant"} setMode("day")}>Jour setMode("week")}>Semaine {mode === "day" ? ( ) : ( )} ); };