From baa8b64ba2468e5f67f6bbb1e1480a9d7800fd39 Mon Sep 17 00:00:00 2001 From: Rajat yadav Date: Sat, 20 Dec 2025 12:13:53 +0530 Subject: [PATCH] Add recur field to task creation panel Implemented recur dropdown in AddTaskDialog with daily, weekly, monthly, yearly options. Backend now handles recur field with proper validation requiring due date before setting recurrence. Updated all related types, handlers and tests to support task recurrence functionality. --- backend/controllers/add_task.go | 3 ++- backend/models/request_body.go | 1 + backend/utils/tw/add_task.go | 7 +++++- backend/utils/tw/taskwarrior_test.go | 4 +-- .../HomeComponents/Tasks/AddTaskDialog.tsx | 25 +++++++++++++++++++ .../components/HomeComponents/Tasks/Tasks.tsx | 3 +++ .../Tasks/__tests__/AddTaskDialog.test.tsx | 2 ++ .../components/HomeComponents/Tasks/hooks.ts | 7 ++++++ frontend/src/components/utils/types.ts | 1 + 9 files changed, 49 insertions(+), 4 deletions(-) diff --git a/backend/controllers/add_task.go b/backend/controllers/add_task.go index 4dfa465e..bd372136 100644 --- a/backend/controllers/add_task.go +++ b/backend/controllers/add_task.go @@ -47,6 +47,7 @@ func AddTaskHandler(w http.ResponseWriter, r *http.Request) { priority := requestBody.Priority dueDate := requestBody.DueDate start := requestBody.Start + recur := requestBody.Recur tags := requestBody.Tags annotations := requestBody.Annotations @@ -64,7 +65,7 @@ func AddTaskHandler(w http.ResponseWriter, r *http.Request) { 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, tags, annotations) + err := tw.AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDateStr, start, recur, tags, annotations) if err != nil { logStore.AddLog("ERROR", fmt.Sprintf("Failed to add task: %v", err), uuid, "Add Task") return err diff --git a/backend/models/request_body.go b/backend/models/request_body.go index 30f7dddb..8579239c 100644 --- a/backend/models/request_body.go +++ b/backend/models/request_body.go @@ -10,6 +10,7 @@ type AddTaskRequestBody struct { Priority string `json:"priority"` DueDate *string `json:"due"` Start string `json:"start"` + Recur string `json:"recur"` Tags []string `json:"tags"` Annotations []Annotation `json:"annotations"` } diff --git a/backend/utils/tw/add_task.go b/backend/utils/tw/add_task.go index 56178fb9..79fe4061 100644 --- a/backend/utils/tw/add_task.go +++ b/backend/utils/tw/add_task.go @@ -10,7 +10,7 @@ import ( ) // add task to the user's tw client -func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDate, start string, tags []string, annotations []models.Annotation) error { +func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDate, start, recur string, tags []string, annotations []models.Annotation) error { if err := utils.ExecCommand("rm", "-rf", "/root/.task"); err != nil { return fmt.Errorf("error deleting Taskwarrior data: %v", err) } @@ -43,6 +43,11 @@ func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, p if start != "" { cmdArgs = append(cmdArgs, "start:"+start) } + // Note: Taskwarrior requires a due date to be set before recur can be set + // Only add recur if dueDate is also provided + if recur != "" && dueDate != "" { + cmdArgs = append(cmdArgs, "recur:"+recur) + } // Add tags to the task if len(tags) > 0 { for _, tag := range tags { diff --git a/backend/utils/tw/taskwarrior_test.go b/backend/utils/tw/taskwarrior_test.go index 98a004f4..f08fbb18 100644 --- a/backend/utils/tw/taskwarrior_test.go +++ b/backend/utils/tw/taskwarrior_test.go @@ -42,7 +42,7 @@ func TestExportTasks(t *testing.T) { } func TestAddTaskToTaskwarrior(t *testing.T) { - err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", nil, []models.Annotation{{Description: "note"}}) + err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", "daily", nil, []models.Annotation{{Description: "note"}}) if err != nil { t.Errorf("AddTaskToTaskwarrior failed: %v", err) } else { @@ -60,7 +60,7 @@ func TestCompleteTaskInTaskwarrior(t *testing.T) { } func TestAddTaskWithTags(t *testing.T) { - err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", []string{"work", "important"}, []models.Annotation{{Description: "note"}}) + err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", "daily", []string{"work", "important"}, []models.Annotation{{Description: "note"}}) if err != nil { t.Errorf("AddTaskToTaskwarrior with tags failed: %v", err) } else { diff --git a/frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx b/frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx index 7ea37277..9a1e466b 100644 --- a/frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx +++ b/frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx @@ -245,6 +245,31 @@ export const AddTaskdialog = ({ /> +
+ +
+ +
+