"use client"; import { useEffect, useState, useCallback, useMemo } from "react"; import { useRouter } from "next/navigation"; import { useAuth } from "@/lib/auth"; import { getTasks, getGroups, createTask, updateTask, Task, Group } from "@/lib/api"; import { useTranslation } from "@/lib/i18n"; import TaskCard from "@/components/TaskCard"; import TaskModal from "@/components/TaskModal"; import { useSwipeable } from "react-swipeable"; const STATUS_VALUES = ["pending", "in_progress", "done", "cancelled"] as const; type StatusValue = (typeof STATUS_VALUES)[number]; function statusColor(s: StatusValue | null): string { switch (s) { case "pending": return "#FBBF24"; case "in_progress": return "#60A5FA"; case "done": return "#34D399"; case "cancelled": return "#9CA3AF"; default: return "#7A7A9A"; } } export default function TasksPage() { const { token, user } = useAuth(); const { t } = useTranslation(); const router = useRouter(); const [tasks, setTasks] = useState([]); const [groups, setGroups] = useState([]); const [loading, setLoading] = useState(true); const [selectedGroup, setSelectedGroup] = useState(null); const [selectedStatus, setSelectedStatus] = useState(null); const [groupOpen, setGroupOpen] = useState(false); const [showForm, setShowForm] = useState(false); const [swipeDirection, setSwipeDirection] = useState<"left" | "right" | null>(null); const [swipeOverlay, setSwipeOverlay] = useState<{ name: string; icon: string | null } | null>(null); // Build group order: [null (all), group1.id, group2.id, ...] const groupOrder = useMemo(() => { return [null, ...groups.map((g) => g.id)]; }, [groups]); const currentGroupIndex = useMemo(() => { return groupOrder.indexOf(selectedGroup); }, [groupOrder, selectedGroup]); const selectedGroupObj = useMemo( () => (selectedGroup ? groups.find((g) => g.id === selectedGroup) ?? null : null), [selectedGroup, groups] ); const loadData = useCallback(async () => { if (!token) return; setLoading(true); try { const params: Record = {}; if (selectedGroup) params.group_id = selectedGroup; if (selectedStatus) params.status = selectedStatus; const [tasksRes, groupsRes] = await Promise.all([ getTasks(token, Object.keys(params).length > 0 ? params : undefined), getGroups(token), ]); setTasks(tasksRes.data || []); setGroups(groupsRes.data || []); } catch (err) { console.error("Load error:", err); } finally { setLoading(false); } }, [token, selectedGroup, selectedStatus]); useEffect(() => { if (!token) { router.replace("/login"); return; } loadData(); }, [token, router, loadData]); // Navigate to next/previous group via swipe const navigateGroup = useCallback( (direction: "left" | "right") => { if (groupOrder.length <= 1) return; const newIndex = direction === "left" ? (currentGroupIndex + 1) % groupOrder.length : (currentGroupIndex - 1 + groupOrder.length) % groupOrder.length; const newGroupId = groupOrder[newIndex]; if (newGroupId === null) { setSwipeOverlay({ name: t("tasks.all"), icon: null }); } else { const group = groups.find((g) => g.id === newGroupId); setSwipeOverlay({ name: group?.name || "", icon: group?.icon || null }); } setSwipeDirection(direction); setSelectedGroup(newGroupId); setTimeout(() => { setSwipeOverlay(null); setSwipeDirection(null); }, 600); }, [groupOrder, currentGroupIndex, groups, t] ); // Swipe handlers for cycling groups const swipeHandlers = useSwipeable({ onSwipedLeft: () => navigateGroup("left"), onSwipedRight: () => navigateGroup("right"), trackMouse: false, trackTouch: true, preventScrollOnSwipe: false, delta: 50, swipeDuration: 500, }); async function handleCreateTask(data: Partial) { if (!token) return; await createTask(token, data); setShowForm(false); loadData(); } async function handleCompleteTask(taskId: string) { if (!token) return; try { await updateTask(token, taskId, { status: "done" }); loadData(); } catch (err) { console.error("Complete error:", err); } } if (!token) return null; const userInitial = (user?.name || user?.email || "?").charAt(0).toUpperCase(); return (
{/* Single-row sticky filter header — group dropdown left, status pills right */}
{/* Groups dropdown — compact, left side */}
{groupOpen && ( <>
setGroupOpen(false)} style={{ position: "fixed", inset: 0, zIndex: 150 }} />
{groups.map(g => ( ))}
)}
{/* Status pills — horizontal scroll, right side */}
{/* "All" pill */} {STATUS_VALUES.map(s => ( ))}
{/* Swipeable task list area */}
{/* Swipe overlay */} {swipeOverlay && (
{swipeOverlay.icon && ( {swipeOverlay.icon} )} {swipeOverlay.name}
)} {/* Task list */}
{loading ? (
) : tasks.length === 0 ? (

{t("tasks.noTasks")}

{t("tasks.createFirst")}

) : (
{tasks.map((task) => ( ))}
)}
{/* Floating action button */} {/* Add task modal */} {showForm && ( setShowForm(false)} /> )}
); }