"use client"; import React, { useState, useEffect } from "react"; import { ChevronRight, ChevronLeft, X, Sun, Moon, Check } from "lucide-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faGoogle, faApple, faMicrosoft, faNotion } from "@fortawesome/free-brands-svg-icons"; import { faServer } from "@fortawesome/free-solid-svg-icons"; import FontPicker from "./FontPicker"; interface OnboardingWizardProps { profile: any; darkMode: boolean; language: string; connections: any[]; onComplete: () => void; onSkip: () => void; saveSetting: (key: string, value: any) => Promise; onLanguageChange: (lang: string) => void; onDarkModeToggle: () => void; onConnectProvider?: (provider: string) => void; } const STEPS = ["welcome", "language", "connect", "header", "tasks", "display"] as const; const translations: Record> = { en: { welcomeTitle: "Welcome to My Weekly ToDo List", welcomeSubtitle: "Let's set up your workspace in under a minute", getStarted: "Get Started", skipSetup: "Skip setup", next: "Next", back: "Back", finish: "Start Using My Weekly ToDo List", langTitle: "Language & Region", langSubtitle: "Choose your language, formats and week start", timezone: "Timezone", dateFormat: "Date Format", timeFormat: "Time Format", weekStartLabel: "Start week on", monday: "Monday", sunday: "Sunday", connectTitle: "Connect Your Services", connectSubtitle: "Sync calendars and tasks from your favorite services", connectGoogle: "Google Calendar & Tasks", connectApple: "Apple Calendar (events only)", connectOutlook: "Microsoft Outlook", connectSynology: "Synology Calendar", connectNotion: "Notion", connected: "Connected", connect: "Connect", skipConnect: "Skip for now — you can connect later in Settings", // Header step headerTitle: "Day Headers", headerSubtitle: "Style the weekday names and dates at the top of each column", weekdayFont: "Weekday Font", dateSection: "Date", datePosition: "Position", dateAlignment: "Alignment", datePositionRight: "Right", datePositionLeft: "Left", datePositionAbove: "Above", datePositionBelow: "Below", datePositionHidden: "Hidden", alignLeft: "Left", alignCenter: "Center", alignRight: "Right", alignTight: "Tight", weekdayFormat: "Weekday Format", weekdayFull: "Full (Monday)", weekdayShort: "Short (Mon)", weekdayNarrow: "Narrow (M)", // Tasks step tasksTitle: "Tasks & Events", tasksSubtitle: "Choose how your tasks and calendar events look", taskFont: "Task Font", eventFont: "Calendar Event Font", fontSize: "Base Font Size", // Display step displayTitle: "Display Options", displaySubtitle: "Toggle which areas to show and pick your theme", showAllDay: "All-Day Events", showSomeday: "Someday Area", showTimeGrid: "Time Grid", showCheckboxes: "Task Checkboxes", darkMode: "Dark Mode", somedayLabel: "Someday", color: "Color", }, de: { welcomeTitle: "Willkommen bei My Weekly ToDo List", welcomeSubtitle: "Richte deinen Arbeitsbereich in unter einer Minute ein", getStarted: "Los geht's", skipSetup: "Setup überspringen", next: "Weiter", back: "Zurück", finish: "My Weekly ToDo List starten", langTitle: "Sprache & Region", langSubtitle: "Wähle Sprache, Formate und Wochenstart", timezone: "Zeitzone", dateFormat: "Datumsformat", timeFormat: "Zeitformat", weekStartLabel: "Woche beginnt am", monday: "Montag", sunday: "Sonntag", connectTitle: "Dienste verbinden", connectSubtitle: "Synchronisiere Kalender und Aufgaben", connectGoogle: "Google Kalender & Aufgaben", connectApple: "Apple Kalender (nur Ereignisse)", connectOutlook: "Microsoft Outlook", connectSynology: "Synology Kalender", connectNotion: "Notion", connected: "Verbunden", connect: "Verbinden", skipConnect: "Jetzt überspringen — du kannst später in den Einstellungen verbinden", headerTitle: "Tagesüberschriften", headerSubtitle: "Gestalte die Wochentage und Datumsanzeige über den Spalten", weekdayFont: "Wochentag-Schrift", dateSection: "Datum", datePosition: "Position", dateAlignment: "Ausrichtung", datePositionRight: "Rechts", datePositionLeft: "Links", datePositionAbove: "Darüber", datePositionBelow: "Darunter", datePositionHidden: "Ausblenden", alignLeft: "Links", alignCenter: "Zentriert", alignRight: "Rechts", alignTight: "Eng", weekdayFormat: "Wochentag-Format", weekdayFull: "Voll (Montag)", weekdayShort: "Kurz (Mo)", weekdayNarrow: "Schmal (M)", tasksTitle: "Aufgaben & Termine", tasksSubtitle: "Wähle das Aussehen deiner Aufgaben und Kalendereinträge", taskFont: "Aufgaben-Schrift", eventFont: "Kalenderevent-Schrift", fontSize: "Basis-Schriftgröße", displayTitle: "Anzeige-Optionen", displaySubtitle: "Wähle welche Bereiche sichtbar sein sollen und dein Farbschema", showAllDay: "Ganztags-Termine", showSomeday: "Someday-Bereich", showTimeGrid: "Zeitraster", showCheckboxes: "Aufgaben-Checkboxen", darkMode: "Dunkler Modus", somedayLabel: "Someday", color: "Farbe", }, fr: { welcomeTitle: "Bienvenue sur My Weekly ToDo List", welcomeSubtitle: "Configurez votre espace en moins d'une minute", getStarted: "Commencer", skipSetup: "Passer la configuration", next: "Suivant", back: "Retour", finish: "Commencer à utiliser My Weekly ToDo List", langTitle: "Langue & Région", langSubtitle: "Choisissez langue, formats et début de semaine", timezone: "Fuseau horaire", dateFormat: "Format de date", timeFormat: "Format d'heure", weekStartLabel: "Semaine commence le", monday: "Lundi", sunday: "Dimanche", connectTitle: "Connectez vos services", connectSubtitle: "Synchronisez calendriers et tâches", connectGoogle: "Google Agenda & Tâches", connectApple: "Calendrier Apple (événements uniquement)", connectOutlook: "Microsoft Outlook", connectSynology: "Calendrier Synology", connectNotion: "Notion", connected: "Connecté", connect: "Connecter", skipConnect: "Passer pour l'instant — vous pourrez connecter plus tard", headerTitle: "En-têtes de jour", headerSubtitle: "Personnalisez les noms et dates en haut de chaque colonne", weekdayFont: "Police jour", dateSection: "Date", datePosition: "Position", dateAlignment: "Alignement", datePositionRight: "Droite", datePositionLeft: "Gauche", datePositionAbove: "Au-dessus", datePositionBelow: "En-dessous", datePositionHidden: "Masqué", alignLeft: "Gauche", alignCenter: "Centre", alignRight: "Droite", alignTight: "Serré", weekdayFormat: "Format jour", weekdayFull: "Complet (Lundi)", weekdayShort: "Court (Lun)", weekdayNarrow: "Étroit (L)", tasksTitle: "Tâches & Événements", tasksSubtitle: "Choisissez l'apparence de vos tâches et événements", taskFont: "Police tâches", eventFont: "Police événements", fontSize: "Taille de base", displayTitle: "Options d'affichage", displaySubtitle: "Activez les zones à afficher et choisissez votre thème", showAllDay: "Événements journée entière", showSomeday: "Zone Someday", showTimeGrid: "Grille horaire", showCheckboxes: "Cases à cocher", darkMode: "Mode sombre", somedayLabel: "Someday", color: "Couleur", }, es: { welcomeTitle: "Bienvenido a My Weekly ToDo List", welcomeSubtitle: "Configura tu espacio en menos de un minuto", getStarted: "Empezar", skipSetup: "Omitir configuración", next: "Siguiente", back: "Atrás", finish: "Empezar a usar My Weekly ToDo List", langTitle: "Idioma y Región", langSubtitle: "Elige idioma, formatos e inicio de semana", timezone: "Zona horaria", dateFormat: "Formato de fecha", timeFormat: "Formato de hora", weekStartLabel: "Semana empieza el", monday: "Lunes", sunday: "Domingo", connectTitle: "Conecta tus servicios", connectSubtitle: "Sincroniza calendarios y tareas", connectGoogle: "Google Calendar y Tareas", connectApple: "Calendario Apple (solo eventos)", connectOutlook: "Microsoft Outlook", connectSynology: "Calendario Synology", connectNotion: "Notion", connected: "Conectado", connect: "Conectar", skipConnect: "Omitir por ahora — puedes conectar después en Ajustes", headerTitle: "Encabezados de día", headerSubtitle: "Personaliza los nombres y fechas de cada columna", weekdayFont: "Fuente día", dateSection: "Fecha", datePosition: "Posición", dateAlignment: "Alineación", datePositionRight: "Derecha", datePositionLeft: "Izquierda", datePositionAbove: "Arriba", datePositionBelow: "Abajo", datePositionHidden: "Oculta", alignLeft: "Izquierda", alignCenter: "Centro", alignRight: "Derecha", alignTight: "Ajustado", weekdayFormat: "Formato día", weekdayFull: "Completo (Lunes)", weekdayShort: "Corto (Lun)", weekdayNarrow: "Estrecho (L)", tasksTitle: "Tareas y Eventos", tasksSubtitle: "Elige cómo se ven tus tareas y eventos del calendario", taskFont: "Fuente tareas", eventFont: "Fuente eventos", fontSize: "Tamaño base", displayTitle: "Opciones de pantalla", displaySubtitle: "Elige qué áreas mostrar y tu tema de color", showAllDay: "Eventos de todo el día", showSomeday: "Área Someday", showTimeGrid: "Rejilla horaria", showCheckboxes: "Casillas de verificación", darkMode: "Modo oscuro", somedayLabel: "Someday", color: "Color", }, }; const COMMON_TIMEZONES = [ "Europe/Berlin", "Europe/London", "Europe/Paris", "Europe/Madrid", "Europe/Rome", "Europe/Amsterdam", "Europe/Zurich", "Europe/Vienna", "America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Toronto", "America/Sao_Paulo", "America/Mexico_City", "Asia/Tokyo", "Asia/Shanghai", "Asia/Kolkata", "Asia/Singapore", "Asia/Dubai", "Australia/Sydney", "Pacific/Auckland", "UTC" ]; const DATE_FORMATS = [ { value: "DD.MM.YYYY", example: "25.03.2026" }, { value: "MM/DD/YYYY", example: "03/25/2026" }, { value: "YYYY-MM-DD", example: "2026-03-25" }, { value: "DD/MM/YYYY", example: "25/03/2026" }, ]; const LANGUAGES = [ { code: "de", label: "Deutsch", flag: "DE" }, { code: "en", label: "English", flag: "EN" }, { code: "fr", label: "Français", flag: "FR" }, { code: "es", label: "Español", flag: "ES" }, ]; const WEIGHT_OPTS = [ { value: "300", label: "Light" }, { value: "400", label: "Normal" }, { value: "500", label: "Medium" }, { value: "600", label: "Semi" }, { value: "700", label: "Bold" }, { value: "900", label: "Black" }, ]; export default function OnboardingWizard({ profile, darkMode, language, connections, onComplete, onSkip, saveSetting, onLanguageChange, onDarkModeToggle, onConnectProvider, }: OnboardingWizardProps) { const [currentStep, setCurrentStep] = useState(0); const [direction, setDirection] = useState<"forward" | "backward">("forward"); const [animKey, setAnimKey] = useState(0); // Language step const [selectedLang, setSelectedLang] = useState(language || "de"); const [selectedTimezone, setSelectedTimezone] = useState(profile.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC"); const [selectedDateFormat, setSelectedDateFormat] = useState(profile.dateFormat || "DD.MM.YYYY"); const [selectedTimeFormat, setSelectedTimeFormat] = useState(profile.timeFormat || "24H"); const [selectedWeekStart, setSelectedWeekStart] = useState(profile.weekStartDay ?? 1); // Header step const [selectedHeadlineFont, setSelectedHeadlineFont] = useState(profile.headlineFont || "Oswald"); const [selectedHeadlineFontSize, setSelectedHeadlineFontSize] = useState(profile.headlineFontSize || "1.25rem"); const [selectedHeadlineFontWeight, setSelectedHeadlineFontWeight] = useState(profile.headlineFontWeight || "900"); const [selectedWeekdayColor, setSelectedWeekdayColor] = useState(profile.weekdayColor || (darkMode ? "#d1d5db" : "#555555")); const [selectedDateFontSize, setSelectedDateFontSize] = useState(profile.dateFontSize || "0.65rem"); const [selectedDateFontWeight, setSelectedDateFontWeight] = useState(profile.dateFontWeight || "400"); const [selectedDateColor, setSelectedDateColor] = useState(profile.dateColor || (darkMode ? "#9ca3af" : "#888888")); const [selectedDateLayout, setSelectedDateLayout] = useState(profile.dateLayout || "right"); const [selectedDateAlignment, setSelectedDateAlignment] = useState(profile.dateAlignment || "center"); const [selectedWeekdayFormat, setSelectedWeekdayFormat] = useState(profile.weekdayFormat || "full"); // Tasks step const [selectedBodyFont, setSelectedBodyFont] = useState(profile.bodyFont || "Inter"); const [selectedTaskFontSize, setSelectedTaskFontSize] = useState(profile.taskFontSize || "0.9rem"); const [selectedTaskFontWeight, setSelectedTaskFontWeight] = useState(profile.taskFontWeight || "400"); const [selectedTaskColor, setSelectedTaskColor] = useState(profile.taskColor || (darkMode ? "#e5e7eb" : "#333333")); const [selectedEventFont, setSelectedEventFont] = useState(profile.eventFontFamily || "Inter"); const [selectedEventFontSize, setSelectedEventFontSize] = useState(profile.eventFontSize || "0.85rem"); const [selectedEventFontWeight, setSelectedEventFontWeight] = useState(profile.eventFontWeight || "400"); const [selectedFontSize, setSelectedFontSize] = useState(profile.fontSize || "M"); // Display step const [selectedShowSomeday, setSelectedShowSomeday] = useState(profile.showSomeday !== false); const [selectedShowAllDay, setSelectedShowAllDay] = useState(profile.showAllDayEvents !== false); const [selectedShowTimeGrid, setSelectedShowTimeGrid] = useState(profile.showTimeGrid !== false); const [selectedShowCheckboxes, setSelectedShowCheckboxes] = useState(profile.showTaskCheckboxes === true); useEffect(() => { const savedStep = localStorage.getItem("onboarding_step"); if (savedStep) { const step = parseInt(savedStep, 10); setCurrentStep(Math.min(step, STEPS.length - 1)); localStorage.removeItem("onboarding_step"); } }, []); const t = translations[selectedLang] || translations.en; const goNext = async () => { await saveCurrentStep(); setDirection("forward"); setAnimKey((k) => k + 1); setCurrentStep((s) => Math.min(s + 1, STEPS.length - 1)); }; const goBack = () => { setDirection("backward"); setAnimKey((k) => k + 1); setCurrentStep((s) => Math.max(s - 1, 0)); }; const saveCurrentStep = async () => { const step = STEPS[currentStep]; if (step === "language") { await saveSetting("language", selectedLang); await saveSetting("timezone", selectedTimezone); await saveSetting("dateFormat", selectedDateFormat); await saveSetting("timeFormat", selectedTimeFormat); await saveSetting("weekStartDay", selectedWeekStart); onLanguageChange(selectedLang); } else if (step === "header") { await saveSetting("headlineFont", selectedHeadlineFont); await saveSetting("headlineFontSize", selectedHeadlineFontSize); await saveSetting("headlineFontWeight", selectedHeadlineFontWeight); await saveSetting("weekdayColor", selectedWeekdayColor); await saveSetting("dateFontSize", selectedDateFontSize); await saveSetting("dateFontWeight", selectedDateFontWeight); await saveSetting("dateColor", selectedDateColor); await saveSetting("dateLayout", selectedDateLayout); await saveSetting("dateAlignment", selectedDateAlignment); await saveSetting("weekdayFormat", selectedWeekdayFormat); } else if (step === "tasks") { await saveSetting("bodyFont", selectedBodyFont); await saveSetting("taskFontFamily", selectedBodyFont); await saveSetting("timeTaskFontFamily", selectedBodyFont); await saveSetting("taskFontSize", selectedTaskFontSize); await saveSetting("timeTaskFontSize", selectedTaskFontSize); await saveSetting("taskFontWeight", selectedTaskFontWeight); await saveSetting("timeTaskFontWeight", selectedTaskFontWeight); await saveSetting("taskColor", selectedTaskColor); await saveSetting("eventFontFamily", selectedEventFont); await saveSetting("eventFontSize", selectedEventFontSize); await saveSetting("eventFontWeight", selectedEventFontWeight); await saveSetting("fontSize", selectedFontSize); } else if (step === "display") { await saveSetting("showSomeday", selectedShowSomeday); await saveSetting("showAllDayEvents", selectedShowAllDay); await saveSetting("showTimeGrid", selectedShowTimeGrid); await saveSetting("showTaskCheckboxes", selectedShowCheckboxes); } }; const handleFinish = async () => { await saveCurrentStep(); onComplete(); }; const connectedProviders = new Set(connections.map((c: any) => c.provider)); const handleOAuthConnect = (url: string) => { localStorage.setItem("onboarding_step", String(currentStep)); window.location.href = url; }; const handleProviderConnect = (provider: string) => { if (onConnectProvider) { localStorage.setItem("onboarding_step", String(currentStep)); onConnectProvider(provider); } }; const bg = darkMode ? "#1f2937" : "#ffffff"; const textColor = darkMode ? "#e5e7eb" : "#333333"; const mutedColor = darkMode ? "#9ca3af" : "#6b7280"; const borderColor = darkMode ? "#374151" : "#e5e7eb"; const accentColor = "#0d9488"; const inputBg = darkMode ? "#111827" : "#fff"; const itemBg = darkMode ? "#111827" : "#f9fafb"; const btnStyle: React.CSSProperties = { display: "inline-flex", alignItems: "center", gap: "6px", padding: "10px 24px", borderRadius: "10px", border: "none", fontSize: "0.95rem", fontWeight: 600, cursor: "pointer", transition: "all 0.15s", }; const primaryBtn: React.CSSProperties = { ...btnStyle, background: accentColor, color: "#fff" }; const secondaryBtn: React.CSSProperties = { ...btnStyle, background: darkMode ? "#374151" : "#f3f4f6", color: textColor }; const labelStyle: React.CSSProperties = { display: "block", fontSize: "0.78rem", fontWeight: 600, color: textColor, marginBottom: "3px" }; const selectStyle: React.CSSProperties = { width: "100%", padding: "5px 8px", borderRadius: "6px", border: `1px solid ${borderColor}`, background: inputBg, color: textColor, fontSize: "0.8rem", }; const smallInputStyle: React.CSSProperties = { ...selectStyle, padding: "5px 8px" }; const colorPickerStyle: React.CSSProperties = { width: "26px", height: "26px", border: `1px solid ${borderColor}`, borderRadius: "4px", cursor: "pointer", padding: 0, flexShrink: 0, }; const isLastStep = currentStep === STEPS.length - 1; const isWideStep = ["header", "tasks", "display"].includes(STEPS[currentStep]); // ─── Preview ─── const renderPreview = () => { const sizeScale = selectedFontSize === "S" ? 0.85 : selectedFontSize === "L" ? 1.15 : 1.0; const pvBg = darkMode ? "#1a1a2e" : "#ffffff"; const pvBorder = darkMode ? "#334155" : "#eee"; const pvMuted = darkMode ? "#64748b" : "#a6a6a7"; const pvTodayBg = darkMode ? "rgba(13,148,136,0.06)" : "rgba(13,148,136,0.03)"; const dayNamesMap: Record> = { full: { en: ["SUNDAY", "MONDAY"], de: ["SONNTAG", "MONTAG"], fr: ["DIMANCHE", "LUNDI"], es: ["DOMINGO", "LUNES"] }, short: { en: ["SUN", "MON"], de: ["SO", "MO"], fr: ["DIM", "LUN"], es: ["DOM", "LUN"] }, narrow: { en: ["S", "M"], de: ["S", "M"], fr: ["D", "L"], es: ["D", "L"] }, }; const cols = (dayNamesMap[selectedWeekdayFormat] || dayNamesMap.full)[selectedLang] || dayNamesMap.full.en; const colDates = ["22. MÄR", "23. MÄR"]; if (selectedLang === "en") { colDates[0] = "MAR 22"; colDates[1] = "MAR 23"; } if (selectedLang === "fr") { colDates[0] = "22 MARS"; colDates[1] = "23 MARS"; } if (selectedLang === "es") { colDates[0] = "22 MAR"; colDates[1] = "23 MAR"; } const allDayEvents = [ [ { title: selectedLang === "de" ? "Omas Geburtstag" : "Grandma's Birthday", color: "#ec4899" }, { title: selectedLang === "de" ? "Pizza-Abend" : "Pizza Night", color: "#f59e0b" }, ], [ { title: selectedLang === "de" ? "Netflix & Snacks" : "Netflix & Snacks", color: "#6366f1" }, ], ]; const taskLists = [ [ { title: selectedLang === "de" ? "Endlich den Keller aufräumen" : "Finally clean the basement", color: "#8b5cf6" }, { title: selectedLang === "de" ? "Herausfinden warum die Pflanze traurig aussieht" : "Figure out why the plant looks sad", color: "#10b981" }, { title: "", color: "" }, { title: selectedLang === "de" ? "Steuererklärung (diesmal wirklich)" : "Tax return (for real this time)", color: "#ef4444" }, { title: selectedLang === "de" ? "Geburtstagsgeschenk für Mama besorgen" : "Get birthday gift for Mom", color: "#f59e0b" }, ], [ { title: selectedLang === "de" ? "Arzttermin nicht vergessen!" : "Don't forget doctor appointment!", color: "#3b82f6" }, { title: "", color: "" }, { title: selectedLang === "de" ? "Kühlschrank ausmisten (riecht komisch)" : "Clean out fridge (smells weird)", color: "#ef4444" }, { title: selectedLang === "de" ? "10 Min joggen (oder 10 Min drüber nachdenken)" : "10 min jog (or 10 min thinking about it)", color: "#8b5cf6" }, { title: "", color: "" }, { title: selectedLang === "de" ? "WLAN-Passwort endlich aufschreiben" : "Finally write down the WiFi password", color: "#f59e0b" }, ], ]; const somedayLists = [ { name: selectedLang === "de" ? "Irgendwann" : "Someday", count: 5, active: true }, { name: selectedLang === "de" ? "Träume" : "Dreams", count: 2, active: false }, ]; const somedayTasks = [ selectedLang === "de" ? "Buch schreiben" : "Write a book", selectedLang === "de" ? "Spanisch lernen" : "Learn Spanish", ]; const headerAlign = selectedDateAlignment === "left" ? "flex-start" : selectedDateAlignment === "right" ? "flex-end" : "center"; const renderDayHeader = (dayName: string, date: string, isToday: boolean) => { const dayStyle: React.CSSProperties = { fontFamily: `'${selectedHeadlineFont}', sans-serif`, fontSize: `calc(${selectedHeadlineFontSize} * ${sizeScale})`, fontWeight: parseInt(selectedHeadlineFontWeight) as any, color: isToday ? accentColor : selectedWeekdayColor, letterSpacing: "-0.02em", lineHeight: 1.2, margin: 0, }; const dStyle: React.CSSProperties = { fontFamily: `'${selectedBodyFont}', sans-serif`, fontSize: `calc(${selectedDateFontSize} * ${sizeScale})`, fontWeight: parseInt(selectedDateFontWeight) as any, color: selectedDateColor, textTransform: "uppercase" as const, letterSpacing: "0.1em", lineHeight: 1.2, }; const isVertical = selectedDateLayout === "above" || selectedDateLayout === "below"; const pad: React.CSSProperties = { padding: "12px 12px 8px" }; if (selectedDateLayout === "hidden") return
{dayName}
; if (isVertical) return (
{dayName} {date}
); if (selectedDateLayout === "left") return
{date}{dayName}
; return
{dayName}{date}
; }; return (
{/* All-day events */} {selectedShowAllDay && (
{allDayEvents.map((evts, colIdx) => (
0 ? `1px solid ${pvBorder}` : "none", }}> {evts.map((ev) => (
{ev.title}
))}
))}
)} {/* Day headers */}
{cols.map((day, i) => (
0 ? `1px solid ${pvBorder}` : "none" }}> {renderDayHeader(day, colDates[i], i === 0)}
))}
{/* Task columns */}
{[0, 1].map((colIdx) => (
0 ? `1px solid ${pvBorder}` : "none", background: colIdx === 0 ? pvTodayBg : "transparent", position: "relative", }}> {taskLists[colIdx].map((task, tIdx) => ( task.title ? (
{selectedShowCheckboxes && (
)}
{task.title}
) : (
) ))} {Array.from({ length: 4 }).map((_, i) => (
))} {colIdx === 0 && (
19:21
)}
))}
{/* Someday area */} {selectedShowSomeday && (
{somedayLists.map((list) => (
{list.name} {list.count}
))}
{somedayTasks.map((task) => (
{task}
{selectedLang === "de" ? "Aufgabe hinzufügen..." : "Add task..."}
))}
)}
); }; // ─── Render Steps ─── const renderStep = () => { const step = STEPS[currentStep]; if (step === "welcome") { return (

{t.welcomeTitle}

{t.welcomeSubtitle}

); } if (step === "language") { return (

{t.langTitle}

{t.langSubtitle}

{LANGUAGES.map((lang) => ( ))}
{(["24H", "12H"] as const).map((fmt) => ( ))}
{([{ value: 1, label: t.monday }, { value: 0, label: t.sunday }] as const).map((opt) => ( ))}
); } if (step === "connect") { const providers = [ { key: "google", label: t.connectGoogle, icon: faGoogle, color: "#4285F4", action: () => handleOAuthConnect("/api/calendar/google/start") }, { key: "apple", label: t.connectApple, icon: faApple, color: darkMode ? "#ccc" : "#333", action: () => handleProviderConnect("apple") }, { key: "outlook", label: t.connectOutlook, icon: faMicrosoft, color: "#0078D4", action: () => handleOAuthConnect("/api/calendar/outlook/start") }, { key: "synology", label: t.connectSynology, icon: faServer, color: "#007AFF", action: () => handleProviderConnect("synology") }, { key: "notion", label: t.connectNotion, icon: faNotion, color: darkMode ? "#fff" : "#000", action: () => handleOAuthConnect("/api/calendar/notion/start") }, ]; return (

{t.connectTitle}

{t.connectSubtitle}

{providers.map((p) => { const isConnected = connectedProviders.has(p.key); return (
{p.label} {isConnected ? ( {t.connected} ) : ( )}
); })}

{t.skipConnect}

); } // ─── HEADER step ─── if (step === "header") { return (

{t.headerTitle}

{t.headerSubtitle}

{/* Weekday Font */}
setSelectedWeekdayColor(e.target.value)} style={colorPickerStyle} />
setSelectedHeadlineFontSize(e.target.value)} placeholder="1.25rem" style={smallInputStyle} />
{/* Weekday Format */}
{([ { value: "full", label: t.weekdayFull }, { value: "short", label: t.weekdayShort }, { value: "narrow", label: t.weekdayNarrow }, ] as const).map((opt) => ( ))}
{/* Date */}
setSelectedDateColor(e.target.value)} style={colorPickerStyle} /> setSelectedDateFontSize(e.target.value)} placeholder="0.65rem" style={{ ...smallInputStyle, flex: 1 }} />
{/* Preview */}
{renderPreview()}
); } // ─── TASKS step ─── if (step === "tasks") { return (

{t.tasksTitle}

{t.tasksSubtitle}

{/* Task Font */}
setSelectedTaskColor(e.target.value)} style={colorPickerStyle} />
setSelectedTaskFontSize(e.target.value)} placeholder="0.9rem" style={smallInputStyle} />
{/* Event Font */}
setSelectedEventFontSize(e.target.value)} placeholder="0.85rem" style={smallInputStyle} />
{/* Font size S/M/L */}
{(["S", "M", "L"] as const).map((size) => ( ))}
{/* Preview */}
{renderPreview()}
); } // ─── DISPLAY step ─── if (step === "display") { const toggles = [ { label: t.showAllDay, value: selectedShowAllDay, setter: setSelectedShowAllDay }, { label: t.showSomeday, value: selectedShowSomeday, setter: setSelectedShowSomeday }, { label: t.showTimeGrid, value: selectedShowTimeGrid, setter: setSelectedShowTimeGrid }, { label: t.showCheckboxes, value: selectedShowCheckboxes, setter: setSelectedShowCheckboxes }, { label: t.darkMode, value: darkMode, setter: () => {}, isDarkMode: true }, ]; return (

{t.displayTitle}

{t.displaySubtitle}

{toggles.map((toggle) => (
{toggle.label}
))}
{/* Preview */}
{renderPreview()}
); } return null; }; return (
{/* Close button */} {currentStep > 0 && ( )} {/* Step content with animation */}
{renderStep()}
{/* Footer with progress + nav (not on welcome) */} {currentStep > 0 && (
{/* Progress dots */}
{STEPS.map((_, i) => (
))}
{isLastStep ? ( ) : ( )}
)}
); }