diff --git a/frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx b/frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx new file mode 100644 index 00000000..04bfd690 --- /dev/null +++ b/frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx @@ -0,0 +1,248 @@ +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { DatePicker } from '@/components/ui/date-picker'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Key } from '@/components/ui/key-button'; +import { Label } from '@/components/ui/label'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { AddTaskDialogProps } from '@/components/utils/types'; +import { format } from 'date-fns'; + +export const AddTaskdialog = ({ + isOpen, + setIsOpen, + newTask, + setNewTask, + tagInput, + setTagInput, + onSubmit, + isCreatingNewProject, + setIsCreatingNewProject, + uniqueProjects = [], +}: AddTaskDialogProps) => { + const handleAddTag = () => { + if (tagInput && !newTask.tags.includes(tagInput, 0)) { + setNewTask({ ...newTask, tags: [...newTask.tags, tagInput] }); + setTagInput(''); + } + }; + + const handleRemoveTag = (tagToRemove: string) => { + setNewTask({ + ...newTask, + tags: newTask.tags.filter((tag) => tag !== tagToRemove), + }); + }; + + return ( + + + + + + + + + + Add a{' '} + + new task + + + + Fill in the details below to add a new task. + + +
+
+ + + setNewTask({ + ...newTask, + description: e.target.value, + }) + } + required + className="col-span-3" + /> +
+
+ +
+ +
+
+ +
+ +
+ + + {isCreatingNewProject && ( + + setNewTask({ ...newTask, project: e.target.value }) + } + /> + )} +
+
+
+ +
+ { + setNewTask({ + ...newTask, + due: date ? format(date, 'yyyy-MM-dd') : '', + }); + }} + placeholder="Select a due date" + /> +
+
+
+ + setTagInput(e.target.value)} + onKeyDown={(e) => e.key === 'Enter' && handleAddTag()} + required + className="col-span-3" + /> +
+ +
+ {newTask.tags.length > 0 && ( +
+
+
+ {newTask.tags.map((tag, index) => ( + + {tag} + + + ))} +
+
+ )} +
+
+ + + + +
+
+ ); +}; diff --git a/frontend/src/components/HomeComponents/Tasks/TaskDialog.tsx b/frontend/src/components/HomeComponents/Tasks/TaskDialog.tsx new file mode 100644 index 00000000..80a0c500 --- /dev/null +++ b/frontend/src/components/HomeComponents/Tasks/TaskDialog.tsx @@ -0,0 +1,1319 @@ +import { EditTaskDialogProps } from '../../utils/types'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { DatePicker } from '@/components/ui/date-picker'; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Key } from '@/components/ui/key-button'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from '@/components/ui/select'; +import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table'; +import { format } from 'date-fns'; +import { + CheckIcon, + CopyIcon, + Folder, + PencilIcon, + Tag, + Trash2Icon, + XIcon, +} from 'lucide-react'; +import CopyToClipboard from 'react-copy-to-clipboard'; +import { formattedDate, handleCopy } from './tasks-utils'; + +export const TaskDialog = ({ + index, + task, + isOpen, + selectedIndex, + onOpenChange, + onSelectTask, + editState, + onUpdateState, + allTasks, + onSaveDescription, + onSaveTags, + onSavePriority, + onSaveProject, + onSaveWaitDate, + onSaveStartDate, + onSaveEntryDate, + onSaveEndDate, + onSaveDueDate, + onSaveDepends, + onSaveRecur, + onMarkComplete, + onMarkDeleted, + isOverdue, +}: EditTaskDialogProps) => { + const handleDialogOpenChange = (open: boolean) => { + if (open) { + onSelectTask(task, index); // Notify parent that this task is selected + } + onOpenChange(open); + }; + + const handleCancelClick = () => { + onUpdateState({ + editedDescription: task.description, + editedPriority: task.priority, + editedProject: task.project, + editedTags: task.tags, + isEditing: false, + }); + }; + + const handleEditClick = (description: string) => { + onUpdateState({ + isEditing: true, + editedDescription: description, + }); + }; + + return ( + + + { + onSelectTask(task, index); + }} + > + {/* Display task details */} + + + {task.id} + + + + {task.priority === 'H' && ( +
+ )} + {task.priority === 'M' && ( +
+ )} + {task.priority != 'H' && task.priority != 'M' && ( +
+ )} + {task.description} + {task.project != '' && ( + + + {task.project === '' ? '' : task.project} + + )} +
+ + + {task.status === 'pending' && isOverdue(task.due) + ? 'O' + : task.status === 'completed' + ? 'C' + : task.status === 'deleted' + ? 'D' + : 'P'} + + +
+
+ + + + + + Task{' '} + + Details + + + + + {/* Scrollable content */} +
+ + + + + ID: + + {task.id} + {task.status === 'pending' && isOverdue(task.due) && ( + + Overdue + + )} + + + + Description: + + {editState.isEditing ? ( + <> +
+ + onUpdateState({ + editedDescription: e.target.value, + }) + } + className="flex-grow mr-2" + /> + + +
+ + ) : ( + <> + {task.description} + + + )} +
+
+ + Due: + + {editState.isEditingDueDate ? ( +
+ { + try { + const dateStr = + editState.editedDueDate.includes('T') + ? editState.editedDueDate.split('T')[0] + : editState.editedDueDate; + const parsed = new Date( + dateStr + 'T00:00:00' + ); + return isNaN(parsed.getTime()) + ? undefined + : parsed; + } catch { + return undefined; + } + })() + : undefined + } + onDateChange={(date) => + onUpdateState({ + editedDueDate: date + ? format(date, 'yyyy-MM-dd') + : '', + }) + } + placeholder="Select due date" + /> + + +
+ ) : ( + <> + {formattedDate(task.due)} + + + )} +
+
+ + Start: + + {editState.isEditingStartDate ? ( +
+ { + try { + // Handle YYYY-MM-DD format + const dateStr = + editState.editedStartDate.includes('T') + ? editState.editedStartDate.split( + 'T' + )[0] + : editState.editedStartDate; + const parsed = new Date( + dateStr + 'T00:00:00' + ); + return isNaN(parsed.getTime()) + ? undefined + : parsed; + } catch { + return undefined; + } + })() + : undefined + } + onDateChange={(date) => + onUpdateState({ + editedStartDate: date + ? format(date, 'yyyy-MM-dd') + : '', + }) + } + /> + + + + +
+ ) : ( + <> + {formattedDate(task.start)} + + + )} +
+
+ + End: + + {editState.isEditingEndDate ? ( +
+ { + try { + const dateStr = + editState.editedEndDate.includes('T') + ? editState.editedEndDate.split('T')[0] + : editState.editedEndDate; + const parsed = new Date( + dateStr + 'T00:00:00' + ); + return isNaN(parsed.getTime()) + ? undefined + : parsed; + } catch { + return undefined; + } + })() + : undefined + } + onDateChange={(date) => + onUpdateState({ + editedEndDate: date + ? format(date, 'yyyy-MM-dd') + : '', + }) + } + placeholder="Select end date" + /> + + +
+ ) : ( +
+ {formattedDate(task.end)} + +
+ )} +
+
+ + Wait: + + {editState.isEditingWaitDate ? ( +
+ { + try { + const dateStr = + editState.editedWaitDate.includes('T') + ? editState.editedWaitDate.split('T')[0] + : editState.editedWaitDate; + const parsed = new Date( + dateStr + 'T00:00:00' + ); + return isNaN(parsed.getTime()) + ? undefined + : parsed; + } catch { + return undefined; + } + })() + : undefined + } + onDateChange={(date) => + onUpdateState({ + editedWaitDate: date + ? format(date, 'yyyy-MM-dd') + : '', + }) + } + /> + + + + +
+ ) : ( + <> + {formattedDate(task.wait)} + + + )} +
+
+ + Depends: + + {!editState.isEditingDepends ? ( +
+ {(task.depends || []).map((depUuid) => { + const depTask = allTasks.find( + (t) => t.uuid === depUuid + ); + return ( + { + if (depTask) { + onOpenChange(false); + setTimeout(() => { + const depIndex = allTasks.findIndex( + (t) => t.uuid === depTask?.uuid + ); + onSelectTask(depTask!, depIndex); + onOpenChange(true); + }, 100); + } + }} + > + {depTask?.description || depUuid.substring(0, 8)} + + ); + })} + +
+ ) : ( +
+
+ {editState.editedDepends.map((depUuid) => { + const depTask = allTasks.find( + (t) => t.uuid === depUuid + ); + return ( + + + {depTask?.description || + depUuid.substring(0, 8)} + + + + ); + })} +
+
+
+ + {editState.dependsDropdownOpen && ( +
+ + onUpdateState({ + dependsSearchTerm: e.target.value, + }) + } + className="m-2 w-[calc(100%-1rem)]" + /> + {allTasks + .filter( + (t) => + t.uuid !== task.uuid && + t.status === 'pending' && + !editState.editedDepends.includes( + t.uuid + ) && + t.description + .toLowerCase() + .includes( + editState.dependsSearchTerm.toLowerCase() + ) + ) + .map((t) => ( +
{ + onUpdateState({ + editedDepends: [ + ...editState.editedDepends, + t.uuid, + ], + dependsSearchTerm: '', + }); + }} + > + + + {t.description} + +
+ ))} +
+ )} +
+ + +
+
+ )} +
+
+ + Priority: + + {editState.isEditingPriority ? ( +
+ + + +
+ ) : ( +
+ + {task.priority + ? task.priority === 'H' + ? 'High (H)' + : task.priority === 'M' + ? 'Medium (M)' + : task.priority === 'L' + ? 'Low (L)' + : task.priority + : 'None'} + + +
+ )} +
+
+ + Project: + + {editState.isEditingProject ? ( + <> +
+ + onUpdateState({ + editedProject: e.target.value, + }) + } + className="flex-grow mr-2" + /> + + +
+ + ) : ( + <> + {task.project} + + + )} +
+
+ + Status: + {task.status} + + + Tags: + + {editState.isEditingTags ? ( +
+
+ { + // For allowing only alphanumeric characters + if (e.target.value.length > 1) { + /^[a-zA-Z0-9]*$/.test(e.target.value.trim()) + ? onUpdateState({ + editTagInput: e.target.value.trim(), + }) + : ''; + } else { + /^[a-zA-Z]*$/.test(e.target.value.trim()) + ? onUpdateState({ + editTagInput: e.target.value.trim(), + }) + : ''; + } + }} + placeholder="Add a tag (press enter to add)" + className="flex-grow mr-2" + onKeyDown={(e) => { + if ( + e.key === 'Enter' && + editState.editTagInput.trim() + ) { + onUpdateState({ + editedTags: [ + ...editState.editedTags, + editState.editTagInput.trim(), + ], + editTagInput: '', + }); + } + }} + /> + + +
+
+ {editState.editedTags != null && + editState.editedTags.length > 0 && ( +
+
+ {editState.editedTags.map((tag, index) => ( + + {tag} + + + ))} +
+
+ )} +
+
+ ) : ( +
+ {task.tags !== null && task.tags.length >= 1 ? ( + task.tags.map((tag, index) => ( + + + {tag} + + )) + ) : ( + No Tags + )} + +
+ )} +
+
+ + Entry: + + {editState.isEditingEntryDate ? ( +
+ { + try { + // Handle YYYY-MM-DD format + const dateStr = + editState.editedEntryDate.includes('T') + ? editState.editedEntryDate.split( + 'T' + )[0] + : editState.editedEntryDate; + const parsed = new Date( + dateStr + 'T00:00:00' + ); + return isNaN(parsed.getTime()) + ? undefined + : parsed; + } catch { + return undefined; + } + })() + : undefined + } + onDateChange={(date) => + onUpdateState({ + editedEntryDate: date + ? format(date, 'yyyy-MM-dd') + : '', + }) + } + /> + + + + +
+ ) : ( + <> + {formattedDate(task.entry)} + + + )} +
+
+ + Recur: + + {editState.isEditingRecur ? ( +
+ + + +
+ ) : ( +
+ {task.recur || 'None'} + +
+ )} +
+
+ + RType: + + {task.rtype || 'None'} + {!task.rtype && ( + + (Auto-set by recur) + + )} + + + + Urgency: + {task.urgency} + + + UUID: + + {task.uuid} + handleCopy('Task UUID')} + > + + + + +
+
+
+
+ + {/* Non-scrollable footer */} + + {task.status == 'pending' ? ( + + + + + + + + + Are you{' '} + + sure? + + + + + + + + + + + + + ) : null} + + {task.status != 'deleted' ? ( + + + + + + + + + Are you{' '} + + sure? + + + + + + + + + + + + + ) : null} + + + + +
+
+ ); +}; diff --git a/frontend/src/components/HomeComponents/Tasks/Tasks.tsx b/frontend/src/components/HomeComponents/Tasks/Tasks.tsx index e482644f..d9bf20e5 100644 --- a/frontend/src/components/HomeComponents/Tasks/Tasks.tsx +++ b/frontend/src/components/HomeComponents/Tasks/Tasks.tsx @@ -1,4 +1,5 @@ import { useEffect, useState, useCallback, useRef } from 'react'; +import { useEditTask } from './UseEditTask'; import { Task } from '../../utils/types'; import { ReportsView } from './ReportsView'; import Fuse from 'fuse.js'; @@ -13,42 +14,11 @@ import { } from '@/components/ui/table'; import { Button } from '@/components/ui/button'; import { toast } from 'react-toastify'; -import { Badge } from '@/components/ui/badge'; -import { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from '../../ui/dialog'; -import { - ArrowUpDown, - CheckIcon, - CopyIcon, - Folder, - Loader2, - PencilIcon, - Tag, - Trash2Icon, - XIcon, -} from 'lucide-react'; +import { ArrowUpDown, Loader2 } from 'lucide-react'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; -import CopyToClipboard from 'react-copy-to-clipboard'; -import { - formattedDate, getDisplayedPages, - handleCopy, handleDate, markTaskAsCompleted, markTaskAsDeleted, @@ -70,10 +40,11 @@ import { TasksDatabase, } from './hooks'; import { debounce } from '@/components/utils/utils'; -import { DatePicker } from '@/components/ui/date-picker'; -import { format } from 'date-fns'; import { Taskskeleton } from './TaskSkeleton'; import { Key } from '@/components/ui/key-button'; +import { AddTaskdialog } from './AddTaskDialog'; +import { TaskDialog } from './TaskDialog'; +import { TaskFormData } from '../../utils/types'; const db = new TasksDatabase(); export let syncTasksWithTwAndDb: () => any; @@ -108,44 +79,23 @@ export const Tasks = ( const [isAddTaskOpen, setIsAddTaskOpen] = useState(false); const [_isDialogOpen, setIsDialogOpen] = useState(false); const [tagInput, setTagInput] = useState(''); - - const [isEditing, setIsEditing] = useState(false); - const [editedDescription, setEditedDescription] = useState(''); const [_selectedTask, setSelectedTask] = useState(null); const [editedTags, setEditedTags] = useState( _selectedTask?.tags || [] ); - const [editTagInput, setEditTagInput] = useState(''); - const [isEditingTags, setIsEditingTags] = useState(false); - const [isEditingPriority, setIsEditingPriority] = useState(false); - const [editedPriority, setEditedPriority] = useState('NONE'); - const [isEditingProject, setIsEditingProject] = useState(false); - const [editedProject, setEditedProject] = useState( - _selectedTask?.project || '' - ); - const [isEditingWaitDate, setIsEditingWaitDate] = useState(false); - const [editedWaitDate, setEditedWaitDate] = useState(''); - const [isEditingStartDate, setIsEditingStartDate] = useState(false); - const [editedStartDate, setEditedStartDate] = useState(''); - const [isEditingEntryDate, setIsEditingEntryDate] = useState(false); - const [editedEntryDate, setEditedEntryDate] = useState(''); - const [isEditingEndDate, setIsEditingEndDate] = useState(false); - const [editedEndDate, setEditedEndDate] = useState(''); - const [isEditingDueDate, setIsEditingDueDate] = useState(false); - const [editedDueDate, setEditedDueDate] = useState(''); - const [isEditingDepends, setIsEditingDepends] = useState(false); - const [editedDepends, setEditedDepends] = useState([]); - const [dependsDropdownOpen, setDependsDropdownOpen] = useState(false); - const [dependsSearchTerm, setDependsSearchTerm] = useState(''); - const [isEditingRecur, setIsEditingRecur] = useState(false); - const [editedRecur, setEditedRecur] = useState(''); - const [originalRecur, setOriginalRecur] = useState(''); const [searchTerm, setSearchTerm] = useState(''); const [debouncedTerm, setDebouncedTerm] = useState(''); const [lastSyncTime, setLastSyncTime] = useState(null); const tableRef = useRef(null); const [hotkeysEnabled, setHotkeysEnabled] = useState(false); const [selectedIndex, setSelectedIndex] = useState(0); + const { + state: editState, + updateState: updateEditState, + resetState: resetEditState, + } = useEditTask(_selectedTask); + + // Handler for dialog open/close const isOverdue = (due?: string) => { if (!due) return false; @@ -345,27 +295,18 @@ export const Tasks = ( } }, [props.email, props.encryptionSecret, props.UUID]); // Add dependencies - async function handleAddTask( - email: string, - encryptionSecret: string, - UUID: string, - description: string, - project: string, - priority: string, - due: string, - tags: string[] - ) { + async function handleAddTask(task: TaskFormData) { if (handleDate(newTask.due)) { try { await addTaskToBackend({ - email, - encryptionSecret, - UUID, - description, - project, - priority, - due, - tags, + email: props.email, + encryptionSecret: props.encryptionSecret, + UUID: props.UUID, + description: task.description, + project: task.project, + priority: task.priority, + due: task.due, + tags: task.tags, backendURL: url.backendURL, }); @@ -444,13 +385,32 @@ export const Tasks = ( setCurrentPage(1); }; - const handleEditClick = (description: string) => { - setIsEditing(true); - setEditedDescription(description); + const handleMarkComplete = async (taskuuid: string) => { + await markTaskAsCompleted( + props.email, + props.encryptionSecret, + props.UUID, + taskuuid + ); + }; + + const handleMarkDelete = async (taskuuid: string) => { + await markTaskAsDeleted( + props.email, + props.encryptionSecret, + props.UUID, + taskuuid + ); + }; + + const handleSelectTask = (task: Task, index: number) => { + setSelectedTask(task); + setSelectedIndex(index); + resetEditState(); // as before }; - const handleSaveClick = (task: Task) => { - task.description = editedDescription; + const handleSaveDescription = (task: Task, description: string) => { + task.description = description; handleEditTaskOnBackend( props.email, props.encryptionSecret, @@ -467,11 +427,10 @@ export const Tasks = ( task.due || '', task.recur || '' ); - setIsEditing(false); }; - const handleProjectSaveClick = (task: Task) => { - task.project = editedProject; + const handleProjectSaveClick = (task: Task, project: string) => { + task.project = project; handleEditTaskOnBackend( props.email, props.encryptionSecret, @@ -488,11 +447,10 @@ export const Tasks = ( task.due || '', task.recur || '' ); - setIsEditingProject(false); }; - const handleWaitDateSaveClick = (task: Task) => { - task.wait = editedWaitDate; + const handleWaitDateSaveClick = (task: Task, waitDate: string) => { + task.wait = waitDate; handleEditTaskOnBackend( props.email, @@ -510,12 +468,10 @@ export const Tasks = ( task.due || '', task.recur || '' ); - - setIsEditingWaitDate(false); }; - const handleStartDateSaveClick = (task: Task) => { - task.start = editedStartDate; + const handleStartDateSaveClick = (task: Task, startDate: string) => { + task.start = startDate; handleEditTaskOnBackend( props.email, @@ -533,12 +489,10 @@ export const Tasks = ( task.due || '', task.recur || '' ); - - setIsEditingStartDate(false); }; - const handleEntryDateSaveClick = (task: Task) => { - task.entry = editedEntryDate; + const handleEntryDateSaveClick = (task: Task, entryDate: string) => { + task.entry = entryDate; handleEditTaskOnBackend( props.email, @@ -556,12 +510,10 @@ export const Tasks = ( task.due || '', task.recur || '' ); - - setIsEditingEntryDate(false); }; - const handleEndDateSaveClick = (task: Task) => { - task.end = editedEndDate; + const handleEndDateSaveClick = (task: Task, endDate: string) => { + task.end = endDate; handleEditTaskOnBackend( props.email, @@ -579,12 +531,10 @@ export const Tasks = ( task.due || '', task.recur || '' ); - - setIsEditingEndDate(false); }; - const handleDueDateSaveClick = (task: Task) => { - task.due = editedDueDate; + const handleDueDateSaveClick = (task: Task, dueDate: string) => { + task.due = dueDate; handleEditTaskOnBackend( props.email, @@ -602,12 +552,10 @@ export const Tasks = ( task.due, task.recur || '' ); - - setIsEditingDueDate(false); }; - const handleDependsSaveClick = (task: Task) => { - task.depends = editedDepends; + const handleDependsSaveClick = (task: Task, depends: string[]) => { + task.depends = depends; handleEditTaskOnBackend( props.email, @@ -625,23 +573,20 @@ export const Tasks = ( task.due || '', task.recur || '' ); - - setIsEditingDepends(false); - setDependsDropdownOpen(false); }; - const handleRecurSaveClick = (task: Task) => { - if (editedRecur === 'none') { - setIsEditingRecur(false); + const handleRecurSaveClick = (task: Task, recur: string) => { + if (editState.editedRecur === 'none') { + updateEditState({ isEditingRecur: false }); return; } - if (!editedRecur || editedRecur === '') { - setIsEditingRecur(false); + if (!editState.editedRecur || editState.editedRecur === '') { + updateEditState({ isEditingRecur: false }); return; } - task.recur = editedRecur; + task.recur = recur; handleEditTaskOnBackend( props.email, @@ -659,84 +604,18 @@ export const Tasks = ( task.due || '', task.recur ); - - setIsEditingRecur(false); }; - const handleAddDependency = (uuid: string) => { - if (!editedDepends.includes(uuid)) { - setEditedDepends([...editedDepends, uuid]); - } - }; - - const handleRemoveDependency = (uuid: string) => { - setEditedDepends(editedDepends.filter((dep) => dep !== uuid)); - }; - - const handleCancelClick = () => { - setIsEditing(false); - }; - - const handleDialogOpenChange = (_isDialogOpen: boolean, task: any) => { - setIsDialogOpen(_isDialogOpen); - if (!_isDialogOpen) { - setIsEditing(false); - setEditedDescription(''); - setIsEditingTags(false); - setEditedTags([]); - setIsEditingPriority(false); - setEditedPriority('NONE'); - setIsEditingStartDate(false); - setEditedStartDate(''); - setIsEditingEntryDate(false); - setEditedEntryDate(''); - setIsEditingEndDate(false); - setEditedEndDate(''); - setIsEditingDueDate(false); - setEditedDueDate(''); - setIsEditingDepends(false); - setEditedDepends([]); - setDependsDropdownOpen(false); - setDependsSearchTerm(''); - setIsEditingRecur(false); - setEditedRecur(''); - setOriginalRecur(''); - } else { + const handleDialogOpenChange = (isOpen: boolean, task?: Task) => { + setIsDialogOpen(isOpen); + if (!isOpen) { + resetEditState(); + setSelectedTask(null); + } else if (task) { setSelectedTask(task); - setEditedDescription(task?.description || ''); - setEditedPriority(task?.priority || 'NONE'); } }; - // Handle adding a tag - const handleAddTag = () => { - if (tagInput && !newTask.tags.includes(tagInput, 0)) { - setNewTask({ ...newTask, tags: [...newTask.tags, tagInput] }); - setTagInput(''); // Clear the input field - } - }; - - // Handle adding a tag while editing - const handleAddEditTag = () => { - if (editTagInput && !editedTags.includes(editTagInput, 0)) { - setEditedTags([...editedTags, editTagInput]); - setEditTagInput(''); - } - }; - - // Handle removing a tag - const handleRemoveTag = (tagToRemove: string) => { - setNewTask({ - ...newTask, - tags: newTask.tags.filter((tag) => tag !== tagToRemove), - }); - }; - - // Handle removing a tag while editing task - const handleRemoveEditTag = (tagToRemove: string) => { - setEditedTags(editedTags.filter((tag) => tag !== tagToRemove)); - }; - const sortWithOverdueOnTop = (tasks: Task[]) => { return [...tasks].sort((a, b) => { const aOverdue = a.status === 'pending' && isOverdue(a.due); @@ -801,16 +680,11 @@ export const Tasks = ( setTempTasks(filteredTasks); }, [selectedProjects, selectedTags, selectedStatuses, tasks, debouncedTerm]); - const handleEditTagsClick = (task: Task) => { - setEditedTags(task.tags || []); - setIsEditingTags(true); - }; - - const handleSaveTags = (task: Task) => { - const currentTags = task.tags || []; + const handleSaveTags = (task: Task, tags: string[]) => { + const currentTags = tags || []; const removedTags = currentTags.filter((tag) => !editedTags.includes(tag)); const updatedTags = editedTags.filter((tag) => tag.trim() !== ''); - const tagsToRemove = removedTags.map((tag) => `-${tag}`); + const tagsToRemove = removedTags.map((tag) => `${tag}`); const finalTags = [...updatedTags, ...tagsToRemove]; console.log(finalTags); handleEditTaskOnBackend( @@ -829,23 +703,11 @@ export const Tasks = ( task.due || '', task.recur || '' ); - - setIsEditingTags(false); - setEditTagInput(''); - }; - - const handleCancelTags = () => { - setIsEditingTags(false); - setEditedTags([]); - }; - const handleEditPriorityClick = (task: Task) => { - setEditedPriority(task.priority || 'NONE'); - setIsEditingPriority(true); }; - const handleSavePriority = async (task: Task) => { + const handleSavePriority = async (task: Task, priority: string) => { try { - const priorityValue = editedPriority === 'NONE' ? '' : editedPriority; + const priorityValue = priority === 'NONE' ? '' : priority; await modifyTaskOnBackend({ email: props.email, @@ -863,20 +725,12 @@ export const Tasks = ( console.log('Priority updated successfully!'); toast.success('Priority updated successfully!'); - setIsEditingPriority(false); } catch (error) { console.error('Failed to update priority:', error); toast.error('Failed to update priority. Please try again.'); } }; - const handleCancelPriority = () => { - setIsEditingPriority(false); - if (_selectedTask) { - setEditedPriority(_selectedTask.priority || 'NONE'); - } - }; - useHotkeys(['f'], () => { if (!showReports) { document.getElementById('search')?.focus(); @@ -1064,251 +918,18 @@ export const Tasks = ( icon={} />
- - - - - - - - - - Add a{' '} - - new task - - - - Fill in the details below to add a new task. - - -
-
- - - setNewTask({ - ...newTask, - description: e.target.value, - }) - } - required - className="col-span-3" - /> -
-
- -
- -
-
- -
- -
- - {isCreatingNewProject && ( - - ) => - setNewTask({ - ...newTask, - project: e.target.value, - }) - } - /> - )} -
-
-
- -
- { - setNewTask({ - ...newTask, - due: date - ? format(date, 'yyyy-MM-dd') - : '', - }); - }} - placeholder="Select a due date" - /> -
-
-
- - setTagInput(e.target.value)} - onKeyDown={(e) => - e.key === 'Enter' && handleAddTag() - } // Allow adding tag on pressing Enter - required - className="col-span-3" - /> -
- -
- {newTask.tags.length > 0 && ( -
-
-
- {newTask.tags.map((tag, index) => ( - - {tag} - - - ))} -
-
- )} -
-
- - - - -
-
+
- - - - - - Are you{' '} - - sure? - - - - - - - - - - - - - ) : null} - - {task.status != 'deleted' ? ( - - - - - - - - - Are you{' '} - - sure? - - - - - - - - - - - - - ) : null} - - - - - - + onOpenChange={handleDialogOpenChange} + editState={editState} + onUpdateState={updateEditState} + allTasks={tasks} + onSaveDescription={handleSaveDescription} + onSaveTags={handleSaveTags} + onSavePriority={handleSavePriority} + onSaveProject={handleProjectSaveClick} + onSaveWaitDate={handleWaitDateSaveClick} + onSaveStartDate={handleStartDateSaveClick} + onSaveEntryDate={handleEntryDateSaveClick} + onSaveEndDate={handleEndDateSaveClick} + onSaveDueDate={handleDueDateSaveClick} + onSaveDepends={handleDependsSaveClick} + onSaveRecur={handleRecurSaveClick} + onMarkComplete={handleMarkComplete} + onMarkDeleted={handleMarkDelete} + isOverdue={isOverdue} + /> )) )} @@ -2715,151 +1083,18 @@ export const Tasks = (
- - - - - - - - - - Add a{' '} - - new task - - - - Fill in the details below to add a new task. - - -
-
- - - setNewTask({ - ...newTask, - description: e.target.value, - }) - } - className="col-span-3" - /> -
-
- -
- -
-
- -
- - - setNewTask({ - ...newTask, - project: e.target.value, - }) - } - className="col-span-3" - /> -
-
- -
- { - setNewTask({ - ...newTask, - due: date - ? format(date, 'yyyy-MM-dd') - : '', - }); - }} - placeholder="Select a due date" - /> -
-
-
- - - - -
-
+