diff --git a/backend/controllers/add_task.go b/backend/controllers/add_task.go index 6c6a0aac..b4ec8c7e 100644 --- a/backend/controllers/add_task.go +++ b/backend/controllers/add_task.go @@ -52,9 +52,9 @@ func AddTaskHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, "Description is required, and cannot be empty!", http.StatusBadRequest) return } - if dueDate == "" { - http.Error(w, "Due Date is required, and cannot be empty!", http.StatusBadRequest) - return + var dueDateStr string + if dueDate != nil && *dueDate != "" { + dueDateStr = *dueDate } logStore := models.GetLogStore() @@ -62,7 +62,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, dueDate, tags) + err := tw.AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDateStr, tags) if err != nil { logStore.AddLog("ERROR", fmt.Sprintf("Failed to add task: %v", err), uuid, "Add Task") return err diff --git a/backend/controllers/controllers_test.go b/backend/controllers/controllers_test.go index b21ae91d..88368f05 100644 --- a/backend/controllers/controllers_test.go +++ b/backend/controllers/controllers_test.go @@ -1,6 +1,7 @@ package controllers import ( + "bytes" "encoding/gob" "encoding/json" "net/http" @@ -122,3 +123,76 @@ func Test_LogoutHandler(t *testing.T) { session, _ := app.SessionStore.Get(req, "session-name") assert.Equal(t, -1, session.Options.MaxAge) } + +func Test_AddTaskHandler_WithDueDate(t *testing.T) { + // Initialize job queue + GlobalJobQueue = NewJobQueue() + + requestBody := map[string]interface{}{ + "email": "test@example.com", + "encryptionSecret": "secret", + "UUID": "test-uuid", + "description": "Test task", + "project": "TestProject", + "priority": "H", + "due": "2025-12-31", + "tags": []string{"test", "important"}, + } + + body, _ := json.Marshal(requestBody) + req, err := http.NewRequest("POST", "/add-task", bytes.NewBuffer(body)) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + AddTaskHandler(rr, req) + + assert.Equal(t, http.StatusAccepted, rr.Code) +} + +func Test_AddTaskHandler_WithoutDueDate(t *testing.T) { + // Initialize job queue + GlobalJobQueue = NewJobQueue() + + requestBody := map[string]interface{}{ + "email": "test@example.com", + "encryptionSecret": "secret", + "UUID": "test-uuid", + "description": "Test task without due date", + "project": "TestProject", + "priority": "M", + "tags": []string{"test"}, + } + + body, _ := json.Marshal(requestBody) + req, err := http.NewRequest("POST", "/add-task", bytes.NewBuffer(body)) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + AddTaskHandler(rr, req) + + assert.Equal(t, http.StatusAccepted, rr.Code) +} + +func Test_AddTaskHandler_MissingDescription(t *testing.T) { + requestBody := map[string]interface{}{ + "email": "test@example.com", + "encryptionSecret": "secret", + "UUID": "test-uuid", + "description": "", + "project": "TestProject", + "priority": "H", + } + + body, _ := json.Marshal(requestBody) + req, err := http.NewRequest("POST", "/add-task", bytes.NewBuffer(body)) + assert.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + AddTaskHandler(rr, req) + + assert.Equal(t, http.StatusBadRequest, rr.Code) + assert.Contains(t, rr.Body.String(), "Description is required") +} diff --git a/backend/models/request_body.go b/backend/models/request_body.go index 7f281c12..32290070 100644 --- a/backend/models/request_body.go +++ b/backend/models/request_body.go @@ -8,7 +8,7 @@ type AddTaskRequestBody struct { Description string `json:"description"` Project string `json:"project"` Priority string `json:"priority"` - DueDate string `json:"due"` + DueDate *string `json:"due"` Tags []string `json:"tags"` } type ModifyTaskRequestBody struct { diff --git a/frontend/src/components/HomeComponents/Tasks/Tasks.tsx b/frontend/src/components/HomeComponents/Tasks/Tasks.tsx index 5043fba0..34051644 100644 --- a/frontend/src/components/HomeComponents/Tasks/Tasks.tsx +++ b/frontend/src/components/HomeComponents/Tasks/Tasks.tsx @@ -19,7 +19,6 @@ import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { getDisplayedPages, - handleDate, markTaskAsCompleted, markTaskAsDeleted, Props, @@ -296,32 +295,30 @@ export const Tasks = ( }, [props.email, props.encryptionSecret, props.UUID]); // Add dependencies async function handleAddTask(task: TaskFormData) { - if (handleDate(newTask.due)) { - try { - await addTaskToBackend({ - 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, - }); - - console.log('Task added successfully!'); - setNewTask({ - description: '', - priority: '', - project: '', - due: '', - tags: [], - }); - setIsAddTaskOpen(false); - } catch (error) { - console.error('Failed to add task:', error); - } + try { + await addTaskToBackend({ + email: props.email, + encryptionSecret: props.encryptionSecret, + UUID: props.UUID, + description: task.description, + project: task.project, + priority: task.priority, + due: task.due || undefined, + tags: task.tags, + backendURL: url.backendURL, + }); + + console.log('Task added successfully!'); + setNewTask({ + description: '', + priority: '', + project: '', + due: '', + tags: [], + }); + setIsAddTaskOpen(false); + } catch (error) { + console.error('Failed to add task:', error); } } diff --git a/frontend/src/components/HomeComponents/Tasks/hooks.ts b/frontend/src/components/HomeComponents/Tasks/hooks.ts index d0c0d93d..8b9c6191 100644 --- a/frontend/src/components/HomeComponents/Tasks/hooks.ts +++ b/frontend/src/components/HomeComponents/Tasks/hooks.ts @@ -51,22 +51,27 @@ export const addTaskToBackend = async ({ description: string; project: string; priority: string; - due: string; + due?: string; tags: string[]; backendURL: string; }) => { + const requestBody: any = { + email, + encryptionSecret, + UUID, + description, + project, + priority, + tags, + }; + + // Only include due if it's provided + if (due !== undefined && due !== '') { + requestBody.due = due; + } const response = await fetch(`${backendURL}add-task`, { method: 'POST', - body: JSON.stringify({ - email, - encryptionSecret, - UUID, - description, - project, - priority, - due, - tags, - }), + body: JSON.stringify(requestBody), headers: { 'Content-Type': 'application/json', },