"use client"; import React, { useState, useMemo, useCallback, useEffect } from "react"; import { AlertTriangle, Target, Clock, Trash2, ChevronDown, ChevronUp, User, Sparkles, X, Check, Circle, Star, ListOrdered, BarChart2, Grid, SlidersHorizontal, UserCheck, SendHorizonal, Tag, CalendarDays, FolderOpen, List, Pencil, FileText, Link2, ExternalLink, } from "lucide-react"; import { LinkifiedText } from "./weekly/LinkifiedText"; export interface PriorityTask { id: string; title: string; completed: boolean; urgency?: boolean | null; importance?: boolean | null; priority?: string | null; // A | B | C | D | E delegatedTo?: string | null; delegationNote?: string | null; scheduledDate?: string | null; somedayListId?: string | null; projectId?: string | null; project?: { id: string; name: string; icon?: string | null; color?: string | null } | null; subTasks?: PriorityTask[]; dayOfWeek?: number | null; markdownContent?: string | null; startTime?: string | null; url?: string | null; } export interface PrioritySomedayList { id: string; title: string; } export interface PriorityProject { id: string; name: string; color?: string | null; } type PriorityMethod = "eisenhower" | "abcde" | "ivylee" | "pareto"; interface PriorityViewProps { tasks: PriorityTask[]; somedayLists: PrioritySomedayList[]; projects: PriorityProject[]; darkMode: boolean; language?: string; onUpdateTask: (id: string, fields: Partial) => Promise; initialMethod?: PriorityMethod; onMethodChange?: (m: PriorityMethod) => void; } const ABCDE_LABELS: Record = { A: { label: "A — Critical", desc: "Must do. Serious consequences if not done.", color: "#ef4444", bg: "#fef2f2" }, B: { label: "B — Should do", desc: "Mild consequences if not done.", color: "#f97316", bg: "#fff7ed" }, C: { label: "C — Nice to do", desc: "No consequences if not done.", color: "#eab308", bg: "#fefce8" }, D: { label: "D — Delegate", desc: "Someone else can do this.", color: "#3b82f6", bg: "#eff6ff" }, E: { label: "E — Eliminate", desc: "Delete — no real value.", color: "#6b7280", bg: "#f9fafb" }, }; const ABCDE_LABELS_DARK: Record = { A: { bg: "#450a0a" }, B: { bg: "#431407" }, C: { bg: "#422006" }, D: { bg: "#1e3a5f" }, E: { bg: "#1f2937" }, }; const ABCDE_LABELS_DE: Record = { A: { label: "A — Kritisch", desc: "Muss erledigt werden. Ernste Konsequenzen." }, B: { label: "B — Sollte erledigt werden", desc: "Leichte Konsequenzen wenn nicht erledigt." }, C: { label: "C — Schön wenn erledigt", desc: "Keine Konsequenzen wenn nicht erledigt." }, D: { label: "D — Delegieren", desc: "Kann von jemand anderem erledigt werden." }, E: { label: "E — Eliminieren", desc: "Streichen — kein echter Mehrwert." }, }; function today(): string { return new Date().toISOString().split("T")[0]; } function getWeekRange(offsetWeeks = 0): [string, string] { const now = new Date(); const day = now.getDay(); const mon = new Date(now); mon.setDate(now.getDate() - day + (day === 0 ? -6 : 1) + offsetWeeks * 7); const sun = new Date(mon); sun.setDate(mon.getDate() + 6); return [mon.toISOString().split("T")[0], sun.toISOString().split("T")[0]]; } function formatDate(dateStr: string | null | undefined): string { if (!dateStr) return ""; const d = new Date(dateStr); return d.toLocaleDateString("default", { month: "short", day: "numeric" }); } export default function PriorityView({ tasks, somedayLists, projects, darkMode, language = "en", onUpdateTask, initialMethod, onMethodChange, }: PriorityViewProps) { const [method, setMethodState] = useState(initialMethod || "eisenhower"); const setMethod = useCallback((m: PriorityMethod) => { setMethodState(m); onMethodChange?.(m); }, [onMethodChange]); const [filterProject, setFilterProject] = useState(""); const [filterList, setFilterList] = useState(""); const [filterTimespan, setFilterTimespan] = useState("all"); // Optimistic set: tasks marked complete inside this view disappear immediately, // without waiting for the API round-trip + parent re-render. const [locallyDone, setLocallyDone] = useState>(new Set()); const [delegateModal, setDelegateModal] = useState(null); const [delegateTo, setDelegateTo] = useState(""); const [delegateNote, setDelegateNote] = useState(""); const [delegateType, setDelegateType] = useState<"person" | "ai">("person"); const [ivyLeeSelected, setIvyLeeSelected] = useState>(() => { // Hydrate from any task that already has a numeric priority "1"-"6" const init = new Set(); const ranked = tasks .filter((t) => t.priority && /^[1-6]$/.test(t.priority)) .sort((a, b) => Number(a.priority) - Number(b.priority)); for (const t of ranked) init.add(t.id); return init; }); const [showFilters, setShowFilters] = useState(false); const [isMobile, setIsMobile] = useState(false); const de = language === "de"; useEffect(() => { const check = () => setIsMobile(window.innerWidth < 768); check(); window.addEventListener("resize", check); return () => window.removeEventListener("resize", check); }, []); // --- Filter tasks --- const filteredTasks = useMemo(() => { let result = tasks.filter((t) => !t.id.startsWith("virtual-")); // Priority view is "what to do next" — always hide completed tasks. result = result.filter((t) => !t.completed && !locallyDone.has(t.id)); if (filterProject) result = result.filter((t) => t.projectId === filterProject); if (filterList) { if (filterList === "__scheduled__") { result = result.filter((t) => t.scheduledDate || t.dayOfWeek != null); } else if (filterList === "__unscheduled__") { result = result.filter((t) => !t.scheduledDate && t.dayOfWeek == null && !t.somedayListId); } else { result = result.filter((t) => t.somedayListId === filterList); } } if (filterTimespan !== "all") { const todayStr = today(); const [thisWeekStart, thisWeekEnd] = getWeekRange(0); const [nextWeekStart, nextWeekEnd] = getWeekRange(1); result = result.filter((t) => { const d = t.scheduledDate?.split("T")[0]; if (filterTimespan === "today") return d === todayStr; if (filterTimespan === "this-week") return d && d >= thisWeekStart && d <= thisWeekEnd; if (filterTimespan === "next-week") return d && d >= nextWeekStart && d <= nextWeekEnd; if (filterTimespan === "unscheduled") return !t.scheduledDate && t.dayOfWeek == null; return true; }); } return result; }, [tasks, locallyDone, filterProject, filterList, filterTimespan]); // --- Eisenhower quadrants --- const eisenhowerQuadrants = useMemo(() => { const q1: PriorityTask[] = []; // Urgent + Important → Do const q2: PriorityTask[] = []; // Not Urgent + Important → Schedule const q3: PriorityTask[] = []; // Urgent + Not Important → Delegate const q4: PriorityTask[] = []; // Not Urgent + Not Important → Delete const unset: PriorityTask[] = []; for (const t of filteredTasks) { if (t.urgency == null && t.importance == null) { unset.push(t); continue; } if (t.urgency && t.importance) q1.push(t); else if (!t.urgency && t.importance) q2.push(t); else if (t.urgency && !t.importance) q3.push(t); else q4.push(t); } return { q1, q2, q3, q4, unset }; }, [filteredTasks]); // --- ABCDE groups --- const abcdeGroups = useMemo(() => { const groups: Record = { A: [], B: [], C: [], D: [], E: [], none: [] }; for (const t of filteredTasks) { if (t.priority && groups[t.priority]) groups[t.priority].push(t); else groups.none.push(t); } return groups; }, [filteredTasks]); // --- Pareto: top 20% by importance --- const paretoSplit = useMemo(() => { const important = filteredTasks.filter((t) => t.importance === true || t.priority === "A" || t.priority === "B"); const rest = filteredTasks.filter((t) => !(t.importance === true || t.priority === "A" || t.priority === "B")); return { important, rest }; }, [filteredTasks]); // --- Handlers --- const setEisenhower = useCallback(async (task: PriorityTask, urgency: boolean, importance: boolean) => { await onUpdateTask(task.id, { urgency, importance }); }, [onUpdateTask]); const clearEisenhower = useCallback(async (task: PriorityTask) => { await onUpdateTask(task.id, { urgency: null, importance: null }); }, [onUpdateTask]); const setAbcde = useCallback(async (task: PriorityTask, grade: string | null) => { await onUpdateTask(task.id, { priority: grade }); }, [onUpdateTask]); const handleDelegate = useCallback(async () => { if (!delegateModal) return; await onUpdateTask(delegateModal.id, { delegatedTo: delegateTo || (delegateType === "ai" ? "AI" : undefined), delegationNote: delegateNote || undefined, }); setDelegateModal(null); setDelegateTo(""); setDelegateNote(""); }, [delegateModal, delegateTo, delegateNote, delegateType, onUpdateTask]); const toggleComplete = useCallback(async (task: PriorityTask) => { if (!task.completed) { // Optimistically hide immediately so the task doesn't linger // while the API call + parent re-render cycle completes. setLocallyDone((prev) => new Set([...prev, task.id])); } else { setLocallyDone((prev) => { const n = new Set(prev); n.delete(task.id); return n; }); } await onUpdateTask(task.id, { completed: !task.completed }); }, [onUpdateTask]); const toggleIvyLee = useCallback((id: string) => { setIvyLeeSelected((prev) => { const next = new Set(prev); const removing = next.has(id); if (removing) { next.delete(id); onUpdateTask(id, { priority: null }); } else { if (next.size >= 6) return prev; next.add(id); } // Re-rank all selected tasks 1..N so cross-view badges stay consistent Array.from(next).forEach((tid, idx) => { onUpdateTask(tid, { priority: String(idx + 1) }); }); return next; }); }, [onUpdateTask]); const openDelegate = useCallback((task: PriorityTask) => { setDelegateModal(task); setDelegateTo(task.delegatedTo || ""); setDelegateNote(task.delegationNote || ""); setDelegateType(task.delegatedTo === "AI" ? "ai" : "person"); }, []); // ---------- STYLES ---------- const bg = darkMode ? "#111827" : "#f9fafb"; const cardBg = darkMode ? "#1f2937" : "#ffffff"; const border = darkMode ? "#374151" : "#e5e7eb"; const textPrimary = darkMode ? "#f9fafb" : "#111827"; const textSecondary = darkMode ? "#9ca3af" : "#6b7280"; const accentColor = "#6366f1"; const methodButtons: { key: PriorityMethod; label: string; icon: React.ReactNode }[] = [ { key: "eisenhower", label: "Eisenhower", icon: }, { key: "abcde", label: "ABCDE", icon: }, { key: "ivylee", label: "Ivy Lee", icon: }, { key: "pareto", label: "80/20", icon: }, ]; // Filter panel — always rendered in the right column of every mode const filterPanel = (
{filteredTasks.length} {de ? "Aufgaben" : "tasks"}
); return (
{/* ─── Header ─── */}
{de ? "Prioritäten" : "Priority View"}
{/* Filter active indicator — filters are always in the right column */} {(filterProject || filterList || filterTimespan !== "all") && ( {de ? "Filter aktiv" : "Filter active"} )}
{/* ─── Method Tabs ─── */}
{methodButtons.map((m) => ( ))}
{/* ─── METHOD: EISENHOWER ─── */} {method === "eisenhower" && ( )} {/* ─── METHOD: ABCDE ─── */} {method === "abcde" && ( )} {/* ─── METHOD: IVY LEE ─── */} {method === "ivylee" && ( )} {/* ─── METHOD: PARETO ─── */} {method === "pareto" && ( )} {/* ─── Delegate Modal ─── */} {delegateModal && (
setDelegateModal(null)} >
e.stopPropagation()} >
{de ? "Aufgabe delegieren" : "Delegate task"}

“{delegateModal.title}”

{/* Type toggle */}
{delegateType === "person" ? ( <> setDelegateTo(e.target.value)} placeholder={de ? "z.B. Max Mustermann" : "e.g. John Doe"} style={{ width: "100%", padding: "8px 10px", borderRadius: "7px", border: `1px solid ${border}`, background: darkMode ? "#374151" : "#f9fafb", color: textPrimary, fontSize: "0.9rem", boxSizing: "border-box", marginBottom: "12px", outline: "none" }} /> ) : (

{de ? "Die KI übernimmt diese Aufgabe. Füge eine Notiz hinzu, was sie wissen muss." : "Assign this task to AI. Add a note about what it needs to know."}

)}