'use client'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; import { Button } from '@/components/ui/button'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { useCreateTask, useUpdateTask } from '@/lib/hooks/use-tasks'; import { useStories } from '@/lib/hooks/use-stories'; import type { Task, WorkItemPriority } from '@/types/project'; import { toast } from 'sonner'; import { Loader2 } from 'lucide-react'; const taskSchema = z.object({ storyId: z.string().min(1, 'Parent Story is required'), title: z .string() .min(1, 'Title is required') .max(200, 'Title must be less than 200 characters'), description: z .string() .max(2000, 'Description must be less than 2000 characters') .optional(), priority: z.enum(['Low', 'Medium', 'High', 'Critical']), estimatedHours: z .number() .min(0, 'Estimated hours must be positive') .optional() .or(z.literal('')), }); type TaskFormValues = z.infer; interface TaskFormProps { task?: Task; storyId?: string; epicId?: string; onSuccess?: () => void; onCancel?: () => void; } export function TaskForm({ task, storyId, epicId, onSuccess, onCancel, }: TaskFormProps) { const isEditing = !!task; const createTask = useCreateTask(); const updateTask = useUpdateTask(); // Fetch stories for parent story selection const { data: stories = [], isLoading: storiesLoading } = useStories(epicId); const form = useForm({ resolver: zodResolver(taskSchema), defaultValues: { storyId: task?.storyId || storyId || '', title: task?.title || '', description: task?.description || '', priority: task?.priority || 'Medium', estimatedHours: task?.estimatedHours || ('' as any), }, }); async function onSubmit(data: TaskFormValues) { try { if (isEditing && task) { await updateTask.mutateAsync({ id: task.id, data: { title: data.title, description: data.description, priority: data.priority, estimatedHours: typeof data.estimatedHours === 'number' ? data.estimatedHours : undefined, }, }); toast.success('Task updated successfully'); } else { await createTask.mutateAsync({ storyId: data.storyId, title: data.title, description: data.description, priority: data.priority, estimatedHours: typeof data.estimatedHours === 'number' ? data.estimatedHours : undefined, }); toast.success('Task created successfully'); } onSuccess?.(); } catch (error) { const message = error instanceof Error ? error.message : 'Operation failed'; toast.error(message); } } const isLoading = createTask.isPending || updateTask.isPending; return (
( Parent Story * {isEditing ? 'Parent story cannot be changed' : 'Select the parent story'} )} /> ( Task Title * A clear, concise title for this task )} /> ( Description