import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { X, Send, Pencil, Calendar, User as UserIcon, Users, FolderOpen, CheckCircle2, ArrowLeft, Check, Clock } from 'lucide-react'; import { tasksApi } from '@/services/tasks.api'; import { settingsApi } from '@/services/settings.api'; import { useAuthStore } from '@/store/authStore'; import { useNotificationStore } from '@/store/notificationStore'; import { useSnoozeOptions, calculateSnoozeMinutes } from '@/hooks/useSnoozeOptions'; import type { Task } from '@/types'; import { Button, Badge, Textarea, Select } from '@/components/ui'; import { TaskForm } from './TaskForm'; import { formatDate, formatDateTime } from '@/lib/utils'; import toast from 'react-hot-toast'; interface Comment { id: string; content: string; userId: string; user?: { id: string; name: string }; createdAt: string; } interface TaskDetailProps { taskId: string; onClose: () => void; onEdit?: (task: Task) => void; // Optional - ak nie je, použije sa interný edit mód notificationId?: string; // Ak je detail otvorený z notifikácie } export function TaskDetail({ taskId, onClose, notificationId }: TaskDetailProps) { const queryClient = useQueryClient(); const { user } = useAuthStore(); const [newComment, setNewComment] = useState(''); const [isEditing, setIsEditing] = useState(false); const [snoozeOpen, setSnoozeOpen] = useState(false); // Notifikácie - len ak bol detail otvorený z notifikácie const { notifications, markAsRead, snooze } = useNotificationStore(); const snoozeOptions = useSnoozeOptions(); // Konkrétna notifikácia ak existuje const notification = notificationId ? notifications.find((n) => n.id === notificationId && !n.isRead) : null; const { data: taskData, isLoading } = useQuery({ queryKey: ['task', taskId], queryFn: () => tasksApi.getById(taskId), }); const { data: commentsData, isLoading: commentsLoading } = useQuery({ queryKey: ['task-comments', taskId], queryFn: () => tasksApi.getComments(taskId), }); const { data: statusesData } = useQuery({ queryKey: ['task-statuses'], queryFn: () => settingsApi.getTaskStatuses(), }); const { data: prioritiesData } = useQuery({ queryKey: ['priorities'], queryFn: () => settingsApi.getPriorities(), }); const addCommentMutation = useMutation({ mutationFn: (content: string) => tasksApi.addComment(taskId, content), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['task-comments', taskId] }); setNewComment(''); toast.success('Komentár bol pridaný'); // Označiť notifikáciu ako prečítanú ak existuje if (notificationId) { markAsRead(notificationId); } }, onError: (error: unknown) => { const axiosError = error as { response?: { data?: { message?: string } } }; toast.error(axiosError.response?.data?.message || 'Chyba pri pridávaní komentára'); }, }); const updateTaskMutation = useMutation({ mutationFn: (data: { statusId?: string; priorityId?: string }) => tasksApi.update(taskId, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['task', taskId] }); queryClient.invalidateQueries({ queryKey: ['tasks'] }); queryClient.invalidateQueries({ queryKey: ['dashboard-today'] }); toast.success('Úloha bola aktualizovaná'); // Označiť notifikáciu ako prečítanú ak existuje if (notificationId) { markAsRead(notificationId); } }, onError: () => { toast.error('Chyba pri aktualizácii úlohy'); }, }); const task = taskData?.data; const comments = (commentsData?.data || []) as Comment[]; const statuses = statusesData?.data || []; const priorities = prioritiesData?.data || []; // Kontrola oprávnení - môže komentovať/meniť autor alebo priradený const isCreator = user && task && ( task.createdById === user.id || task.createdBy?.id === user.id ); const isAssignee = user && task && task.assignees?.some(a => a.userId === user.id || a.user?.id === user.id ); const canComment = isCreator || isAssignee; const canChangeStatus = isCreator || isAssignee; // Stav môže meniť autor + priradený const canChangePriority = isCreator; // Prioritu môže meniť len zadávateľ const canEdit = isCreator; // Len zadávateľ môže editovať úlohu const handleSubmitComment = () => { if (!newComment.trim()) return; addCommentMutation.mutate(newComment.trim()); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) { handleSubmitComment(); } }; const handleStatusChange = (statusId: string) => { if (statusId && statusId !== task?.statusId) { updateTaskMutation.mutate({ statusId }); } }; const handlePriorityChange = (priorityId: string) => { if (priorityId && priorityId !== task?.priorityId) { updateTaskMutation.mutate({ priorityId }); } }; const handleEditComplete = () => { setIsEditing(false); queryClient.invalidateQueries({ queryKey: ['task', taskId] }); queryClient.invalidateQueries({ queryKey: ['tasks'] }); queryClient.invalidateQueries({ queryKey: ['dashboard-today'] }); }; if (isLoading) { return (
); } if (!task) { return null; } const statusOptions = statuses.map(s => ({ value: s.id, label: s.name })); const priorityOptions = priorities.map(p => ({ value: p.id, label: p.name })); // Edit mód - zobrazí formulár if (isEditing) { return (
e.stopPropagation()}> {/* Header */}

Upraviť úlohu

{/* Form */}
); } // View mód - zobrazí detail return (
e.stopPropagation()}> {/* Header */}

{task.title}

{task.status.name} {task.priority.name} {task.status.isFinal && ( Dokončená )}
{/* Tlačidlá pre notifikáciu */} {notification && ( <>
{snoozeOpen && (
{snoozeOptions.map((option) => ( ))}
)}
)} {canEdit && ( )}
{/* Content */}
{/* Quick actions - zmena statusu a priority */} {(canChangeStatus || canChangePriority) && (
{canChangeStatus && (
handlePriorityChange(e.target.value)} disabled={updateTaskMutation.isPending} />
)}
)} {/* Info grid */}
Zadal: {task.createdBy?.name || '-'}
{task.project && (
Projekt: {task.project.name}
)} {task.deadline && (
Termín: {formatDate(task.deadline)} {new Date(task.deadline) < new Date() && ' (po termíne!)'}
)} {task.assignees && task.assignees.length > 0 && (
Priradení: {task.assignees.map(a => a.user?.name || a.userId).join(', ')}
)}
{/* Description */} {task.description ? (

Popis

{task.description}

) : (
Bez popisu
)} {/* Comments */}

Komentáre ({comments.length})

{/* Add comment - na vrchu */} {canComment && (