"use client"; import { useState } from "react"; import { toast } from "sonner"; import { motion } from "framer-motion"; import { useTodos, useCreateTodo, useUpdateTodo, useDeleteTodo, } from "@/hooks/use-todos"; import { useTags } from "@/hooks/use-tags"; import { TodoCard } from "@/components/todo-card"; import { TodoRow } from "@/components/todo-row"; import { TodoForm } from "@/components/todo-form"; import { Button } from "@/components/ui/button"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Icons } from "@/components/icons"; import type { Tag, Todo } from "@/services/api-types"; export default function TodoListPage() { const [status, setStatus] = useState(undefined); const [tagFilter, setTagFilter] = useState(undefined); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(""); const [viewMode, setViewMode] = useState<"grid" | "list">("grid"); const { data: todos = [], isLoading, isError, } = useTodos({ status, tagId: tagFilter }); const { data: tags = [] } = useTags(); const createTodoMutation = useCreateTodo(); const updateTodoMutation = useUpdateTodo(); const deleteTodoMutation = useDeleteTodo(); const handleCreateTodo = async (todo: Partial) => { try { await createTodoMutation.mutateAsync(todo); setIsCreateDialogOpen(false); toast.success("Todo created successfully"); } catch { toast.error("Failed to create todo"); } }; const handleUpdateTodo = async (id: string, todo: Partial) => { try { await updateTodoMutation.mutateAsync({ id, todo }); toast.success("Todo updated successfully"); } catch { toast.error("Failed to update todo"); } }; const handleDeleteTodo = async (id: string) => { try { await deleteTodoMutation.mutateAsync(id); toast.success("Todo deleted successfully"); } catch { toast.error("Failed to delete todo"); } }; const filteredTodos = todos.filter( (todo) => todo.title.toLowerCase().includes(searchQuery.toLowerCase()) || (todo.description && todo.description.toLowerCase().includes(searchQuery.toLowerCase())) ); if (isError) { return (

Error loading todos

Please try again later

); } return (

Todos

Create New Todo Add a new task to your todo list
setSearchQuery(e.target.value)} className="max-w-md" />
setStatus(value === "all" ? undefined : value) } > All Pending In Progress todo.status === "pending")} tags={tags} isLoading={isLoading} onUpdate={handleUpdateTodo} onDelete={handleDeleteTodo} viewMode={viewMode} /> todo.status === "in-progress" )} tags={tags} isLoading={isLoading} onUpdate={handleUpdateTodo} onDelete={handleDeleteTodo} viewMode={viewMode} />
); } function TodoList({ todos, tags, isLoading, onUpdate, onDelete, viewMode, }: { todos: Todo[]; tags: Tag[]; isLoading: boolean; onUpdate: (id: string, todo: Partial) => void; onDelete: (id: string) => void; viewMode: "grid" | "list"; }) { const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.05, }, }, }; const item = { hidden: { opacity: 0, y: 20 }, show: { opacity: 1, y: 0 }, }; if (isLoading) { if (viewMode === "grid") { return (
{[1, 2, 3, 4, 5, 6].map((i) => (
))}
); } else { return (
{[1, 2, 3, 4, 5, 6].map((i) => (
))}
); } } if (todos.length === 0) { return (

No todos found

Create one to get started!

); } if (viewMode === "grid") { return ( {todos.map((todo) => ( onUpdate(todo.id, updatedTodo)} onDelete={() => onDelete(todo.id)} /> ))} ); } else { return ( {todos.map((todo) => ( onUpdate(todo.id, updatedTodo)} onDelete={() => onDelete(todo.id)} /> ))} ); } }