diff --git a/src/components/NewTaskModal.tsx b/src/components/NewTaskModal.tsx new file mode 100644 index 0000000..51aedc8 --- /dev/null +++ b/src/components/NewTaskModal.tsx @@ -0,0 +1,234 @@ +'use client'; + +import { useApp } from './AppProvider'; +import { useState, useEffect, useRef } from 'react'; +import { format } from 'date-fns'; + +export default function NewTaskModal() { + const { + showNewTaskModal, setShowNewTaskModal, + projects, selectedProject, refreshTasks, + } = useApp(); + + const [title, setTitle] = useState(''); + const [description, setDescription] = useState(''); + const [projectId, setProjectId] = useState(selectedProject || ''); + const [priority, setPriority] = useState<'low' | 'medium' | 'high' | 'urgent'>('medium'); + const [dueDate, setDueDate] = useState(''); + const [status, setStatus] = useState<'todo' | 'in_progress'>('todo'); + const [showRecurrence, setShowRecurrence] = useState(false); + const [recurrenceRule, setRecurrenceRule] = useState<'none' | 'daily' | 'weekly' | 'biweekly' | 'monthly' | 'yearly'>('none'); + const [recurrenceInterval, setRecurrenceInterval] = useState(1); + + const modalRef = useRef(null); + const titleInputRef = useRef(null); + + useEffect(() => { + if (showNewTaskModal && titleInputRef.current) { + titleInputRef.current.focus(); + } + }, [showNewTaskModal]); + + useEffect(() => { + if (showNewTaskModal) { + setProjectId(selectedProject || ''); + } + }, [showNewTaskModal, selectedProject]); + + const handleCreate = async () => { + if (!title.trim()) return; + + try { + await fetch('/api/tasks', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + title: title.trim(), + description: description.trim(), + projectId: projectId || null, + priority, + dueDate: dueDate || null, + status, + recurrenceRule, + recurrenceInterval, + }), + }); + + setTitle(''); + setDescription(''); + setPriority('medium'); + setDueDate(''); + setStatus('todo'); + setShowRecurrence(false); + setRecurrenceRule('none'); + setRecurrenceInterval(1); + setShowNewTaskModal(false); + refreshTasks(); + } catch (error) { + console.error('Failed to create task:', error); + } + }; + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Escape') { + setShowNewTaskModal(false); + } + if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) { + handleCreate(); + } + }; + + if (!showNewTaskModal) return null; + + return ( +
{ if (e.target === e.currentTarget) setShowNewTaskModal(false); }} + > +
+ {/* Header */} +
+

New Task

+ +
+ + {/* Body */} +
+ {/* Title */} + setTitle(e.target.value)} + placeholder="Task title" + className="w-full bg-content border border-border rounded-lg px-3 py-2.5 text-sm focus:outline-none focus:border-accent focus:ring-1 focus:ring-accent/20 transition-colors" + /> + + {/* Description */} +