Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion backend/controllers/add_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,44 @@ func AddTaskHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, fmt.Sprintf("Invalid dependencies: %v", err), http.StatusBadRequest)
return
}

// Convert all date fields to Taskwarrior format
dueDateStr, err := utils.ConvertOptionalISOToTaskwarriorFormat(dueDate)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid due date format: %v", err), http.StatusBadRequest)
return
}

startStr, err := utils.ConvertISOToTaskwarriorFormat(start)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid start date format: %v", err), http.StatusBadRequest)
return
}

entryDateStr, err := utils.ConvertISOToTaskwarriorFormat(entryDate)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid entry date format: %v", err), http.StatusBadRequest)
return
}

waitDateStr, err := utils.ConvertISOToTaskwarriorFormat(waitDate)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid wait date format: %v", err), http.StatusBadRequest)
return
}

endStr, err := utils.ConvertISOToTaskwarriorFormat(end)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid end date format: %v", err), http.StatusBadRequest)
return
}

logStore := models.GetLogStore()
job := Job{
Name: "Add Task",
Execute: func() error {
logStore.AddLog("INFO", fmt.Sprintf("Adding task: %s", description), uuid, "Add Task")
err := tw.AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDateStr, start, entryDate, waitDate, end, recur, tags, annotations, depends)
err := tw.AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDateStr, startStr, entryDateStr, waitDateStr, endStr, recur, tags, annotations, depends)
if err != nil {
logStore.AddLog("ERROR", fmt.Sprintf("Failed to add task: %v", err), uuid, "Add Task")
return err
Expand Down
33 changes: 32 additions & 1 deletion backend/controllers/edit_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,43 @@ func EditTaskHandler(w http.ResponseWriter, r *http.Request) {
return
}

// Convert all date fields to Taskwarrior format
startStr, err := utils.ConvertISOToTaskwarriorFormat(start)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid start date format: %v", err), http.StatusBadRequest)
return
}

entryStr, err := utils.ConvertISOToTaskwarriorFormat(entry)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid entry date format: %v", err), http.StatusBadRequest)
return
}

waitStr, err := utils.ConvertISOToTaskwarriorFormat(wait)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid wait date format: %v", err), http.StatusBadRequest)
return
}

endStr, err := utils.ConvertISOToTaskwarriorFormat(end)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid end date format: %v", err), http.StatusBadRequest)
return
}

dueStr, err := utils.ConvertISOToTaskwarriorFormat(due)
if err != nil {
http.Error(w, fmt.Sprintf("Invalid due date format: %v", err), http.StatusBadRequest)
return
}

logStore := models.GetLogStore()
job := Job{
Name: "Edit Task",
Execute: func() error {
logStore.AddLog("INFO", fmt.Sprintf("Editing task ID: %s", taskUUID), uuid, "Edit Task")
err := tw.EditTaskInTaskwarrior(uuid, description, email, encryptionSecret, taskUUID, tags, project, start, entry, wait, end, depends, due, recur, annotations)
err := tw.EditTaskInTaskwarrior(uuid, description, email, encryptionSecret, taskUUID, tags, project, startStr, entryStr, waitStr, endStr, depends, dueStr, recur, annotations)
if err != nil {
logStore.AddLog("ERROR", fmt.Sprintf("Failed to edit task ID %s: %v", taskUUID, err), uuid, "Edit Task")
return err
Expand Down
14 changes: 4 additions & 10 deletions backend/utils/tw/edit_task.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,8 @@ func EditTaskInTaskwarrior(uuid, description, email, encryptionSecret, taskID st

// Handle wait date
if wait != "" {
// Convert `2025-11-29` -> `2025-11-29T00:00:00`
formattedWait := wait + "T00:00:00"

if err := utils.ExecCommand("task", taskID, "modify", "wait:"+formattedWait); err != nil {
return fmt.Errorf("failed to set wait date %s: %v", formattedWait, err)
if err := utils.ExecCommand("task", taskID, "modify", "wait:"+wait); err != nil {
return fmt.Errorf("failed to set wait date %s: %v", wait, err)
}
}

Expand Down Expand Up @@ -103,11 +100,8 @@ func EditTaskInTaskwarrior(uuid, description, email, encryptionSecret, taskID st

// Handle due date
if due != "" {
// Convert `2025-11-29` -> `2025-11-29T00:00:00`
formattedDue := due + "T00:00:00"

if err := utils.ExecCommand("task", taskID, "modify", "due:"+formattedDue); err != nil {
return fmt.Errorf("failed to set due date %s: %v", formattedDue, err)
if err := utils.ExecCommand("task", taskID, "modify", "due:"+due); err != nil {
return fmt.Errorf("failed to set due date %s: %v", due, err)
}
}

Expand Down
90 changes: 69 additions & 21 deletions frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useState, useEffect } from 'react';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { DatePicker } from '@/components/ui/date-picker';

import { DateTimePicker } from '@/components/ui/date-time-picker';
import {
Dialog,
Expand Down Expand Up @@ -285,15 +285,27 @@ export const AddTaskdialog = ({
Start
</Label>
<div className="col-span-3">
<DatePicker
date={newTask.start ? new Date(newTask.start) : undefined}
onDateChange={(date) => {
<DateTimePicker
date={
newTask.start
? new Date(
newTask.start.includes('T')
? newTask.start
: `${newTask.start}T00:00:00`
)
: undefined
}
onDateTimeChange={(date, hasTime) => {
setNewTask({
...newTask,
start: date ? format(date, 'yyyy-MM-dd') : '',
start: date
? hasTime
? date.toISOString()
: format(date, 'yyyy-MM-dd')
: '',
});
}}
placeholder="Select a start date"
placeholder="Select start date and time"
/>
</div>
</div>
Expand All @@ -302,15 +314,27 @@ export const AddTaskdialog = ({
End
</Label>
<div className="col-span-3">
<DatePicker
date={newTask.end ? new Date(newTask.end) : undefined}
onDateChange={(date) => {
<DateTimePicker
date={
newTask.end
? new Date(
newTask.end.includes('T')
? newTask.end
: `${newTask.end}T00:00:00`
)
: undefined
}
onDateTimeChange={(date, hasTime) => {
setNewTask({
...newTask,
end: date ? format(date, 'yyyy-MM-dd') : '',
end: date
? hasTime
? date.toISOString()
: format(date, 'yyyy-MM-dd')
: '',
});
}}
placeholder="Select an end date"
placeholder="Select end date and time"
/>
</div>
</div>
Expand All @@ -319,15 +343,27 @@ export const AddTaskdialog = ({
Entry
</Label>
<div className="col-span-3">
<DatePicker
date={newTask.entry ? new Date(newTask.entry) : undefined}
onDateChange={(date) => {
<DateTimePicker
date={
newTask.entry
? new Date(
newTask.entry.includes('T')
? newTask.entry
: `${newTask.entry}T00:00:00`
)
: undefined
}
onDateTimeChange={(date, hasTime) => {
setNewTask({
...newTask,
entry: date ? format(date, 'yyyy-MM-dd') : '',
entry: date
? hasTime
? date.toISOString()
: format(date, 'yyyy-MM-dd')
: '',
});
}}
placeholder="Select an entry date"
placeholder="Select entry date and time"
/>
</div>
</div>
Expand All @@ -336,15 +372,27 @@ export const AddTaskdialog = ({
Wait
</Label>
<div className="col-span-3">
<DatePicker
date={newTask.wait ? new Date(newTask.wait) : undefined}
onDateChange={(date) => {
<DateTimePicker
date={
newTask.wait
? new Date(
newTask.wait.includes('T')
? newTask.wait
: `${newTask.wait}T00:00:00`
)
: undefined
}
onDateTimeChange={(date, hasTime) => {
setNewTask({
...newTask,
wait: date ? format(date, 'yyyy-MM-dd') : '',
wait: date
? hasTime
? date.toISOString()
: format(date, 'yyyy-MM-dd')
: '',
});
}}
placeholder="Select a wait date"
placeholder="Select wait date and time"
/>
</div>
</div>
Expand Down
Loading
Loading