import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { motion, AnimatePresence } from 'framer-motion' import { Plus, Check, Circle, Calendar, AlertTriangle, Undo2, Edit2 } from 'lucide-react' import { format, parseISO, isToday, isTomorrow, isPast } from 'date-fns' import { ru } from 'date-fns/locale' import { tasksApi } from '../api/tasks' import Navigation from '../components/Navigation' import CreateTaskModal from '../components/CreateTaskModal' import EditTaskModal from '../components/EditTaskModal' import clsx from 'clsx' const PRIORITY_LABELS = { 0: null, 1: { label: 'Низкий', class: 'bg-blue-100 text-blue-700' }, 2: { label: 'Средний', class: 'bg-yellow-100 text-yellow-700' }, 3: { label: 'Высокий', class: 'bg-red-100 text-red-700' }, } function formatDueDate(dateStr) { if (!dateStr) return null const date = parseISO(dateStr) if (isToday(date)) return 'Сегодня' if (isTomorrow(date)) return 'Завтра' return format(date, 'd MMM', { locale: ru }) } export default function Tasks() { const [showCreate, setShowCreate] = useState(false) const [editingTask, setEditingTask] = useState(null) const [filter, setFilter] = useState('active') // all, active, completed const queryClient = useQueryClient() const { data: tasks = [], isLoading } = useQuery({ queryKey: ['tasks', filter], queryFn: () => { if (filter === 'all') return tasksApi.list() return tasksApi.list(filter === 'completed') }, }) const completeMutation = useMutation({ mutationFn: (id) => tasksApi.complete(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tasks'] }) queryClient.invalidateQueries({ queryKey: ['tasks-today'] }) }, }) const uncompleteMutation = useMutation({ mutationFn: (id) => tasksApi.uncomplete(id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['tasks'] }) queryClient.invalidateQueries({ queryKey: ['tasks-today'] }) }, }) const handleToggle = (task) => { if (task.completed) { uncompleteMutation.mutate(task.id) } else { completeMutation.mutate(task.id) } } const activeTasks = tasks.filter(t => !t.completed) const completedTasks = tasks.filter(t => t.completed) return (

Задачи

{/* Фильтры */}
{[ { key: 'active', label: 'Активные' }, { key: 'completed', label: 'Выполненные' }, { key: 'all', label: 'Все' }, ].map(({ key, label }) => ( ))}
{isLoading ? (
{[1, 2, 3].map((i) => (
))}
) : tasks.length === 0 ? (

{filter === 'active' ? 'Нет активных задач' : filter === 'completed' ? 'Нет выполненных задач' : 'Нет задач'}

{filter === 'active' ? 'Добавь новую задачу или выбери другой фильтр' : 'Выполняй задачи и они появятся здесь'}

{filter === 'active' && ( )}
) : (
{tasks.map((task, index) => ( handleToggle(task)} onEdit={() => setEditingTask(task)} isLoading={completeMutation.isPending || uncompleteMutation.isPending} /> ))}
)}
setShowCreate(false)} /> setEditingTask(null)} task={editingTask} />
) } function TaskCard({ task, index, onToggle, onEdit, isLoading }) { const [showConfetti, setShowConfetti] = useState(false) const priorityInfo = PRIORITY_LABELS[task.priority] const dueDateLabel = formatDueDate(task.due_date) const isOverdue = task.due_date && isPast(parseISO(task.due_date)) && !isToday(parseISO(task.due_date)) && !task.completed const handleCheck = (e) => { e.stopPropagation() if (isLoading) return if (!task.completed) { setShowConfetti(true) setTimeout(() => setShowConfetti(false), 1000) } onToggle() } return ( {showConfetti && ( {[...Array(6)].map((_, i) => ( ))} )}
{task.completed ? ( ) : ( {task.icon || '📋'} )}

{task.title}

{task.description && (

{task.description}

)}
{dueDateLabel && ( {isOverdue && } {dueDateLabel} )} {priorityInfo && ( {priorityInfo.label} )}
{task.completed && ( )}
) }