Skip to content
Merged
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
3 changes: 2 additions & 1 deletion backend/controllers/add_task.go
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract entryDate from request body and passed it to the function

Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func AddTaskHandler(w http.ResponseWriter, r *http.Request) {
priority := requestBody.Priority
dueDate := requestBody.DueDate
start := requestBody.Start
entryDate := requestBody.EntryDate
waitDate := requestBody.WaitDate
end := requestBody.End
recur := requestBody.Recur
Expand All @@ -67,7 +68,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, waitDate, end, recur, tags, annotations)
err := tw.AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDateStr, start, entryDate, waitDate, end, recur, tags, annotations)
if err != nil {
logStore.AddLog("ERROR", fmt.Sprintf("Failed to add task: %v", err), uuid, "Add Task")
return err
Expand Down
1 change: 1 addition & 0 deletions backend/models/request_body.go
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added the entry field to this struct to accept it from frontend

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type AddTaskRequestBody struct {
Priority string `json:"priority"`
DueDate *string `json:"due"`
Start string `json:"start"`
EntryDate string `json:"entry"`
WaitDate string `json:"wait"`
End string `json:"end"`
Recur string `json:"recur"`
Expand Down
5 changes: 4 additions & 1 deletion backend/utils/tw/add_task.go
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the function to accept entrydate parameter

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

// add task to the user's tw client
func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDate, start, waitDate string, end, recur string, tags []string, annotations []models.Annotation) error {
func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, priority, dueDate, start, entryDate string, waitDate string, end, 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)
}
Expand Down Expand Up @@ -43,6 +43,9 @@ func AddTaskToTaskwarrior(email, encryptionSecret, uuid, description, project, p
if start != "" {
cmdArgs = append(cmdArgs, "start:"+start)
}
if entryDate != "" {
cmdArgs = append(cmdArgs, "entry:"+entryDate)
}
if waitDate != "" {
cmdArgs = append(cmdArgs, "wait:"+waitDate)
}
Expand Down
27 changes: 23 additions & 4 deletions backend/utils/tw/taskwarrior_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func TestSetTaskwarriorConfig(t *testing.T) {
fmt.Println("SetTaskwarriorConfig test passed")
}
}

func TestSyncTaskwarrior(t *testing.T) {
err := SyncTaskwarrior("./")
if err != nil {
Expand Down Expand Up @@ -42,7 +43,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", "2025-03-01", "2025-03-03", "daily", nil, []models.Annotation{{Description: "note"}})
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", "2025-03-01", "2025-03-01", "2025-03-03", "daily", nil, []models.Annotation{{Description: "note"}})
if err != nil {
t.Errorf("AddTaskToTaskwarrior failed: %v", err)
} else {
Expand All @@ -51,14 +52,23 @@ func TestAddTaskToTaskwarrior(t *testing.T) {
}

func TestAddTaskToTaskwarriorWithWaitDate(t *testing.T) {
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "project", "H", "2025-03-03", "2025-03-04", "2025-03-04", "2025-03-04", "", nil, []models.Annotation{})
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "project", "H", "2025-03-03", "2025-03-04", "2025-03-04", "2025-03-04", "2025-03-04", "", nil, []models.Annotation{})
if err != nil {
t.Errorf("AddTaskToTaskwarrior with wait date failed: %v", err)
} else {
fmt.Println("Add task with wait date passed")
}
}

func TestAddTaskToTaskwarriorWithEntryDate(t *testing.T) {
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "project", "H", "2025-03-05", "2025-03-04", "2025-03-04", "2025-03-04", "2025-03-10", "", nil, nil)
if err != nil {
t.Errorf("AddTaskToTaskwarrior failed: %v", err)
} else {
fmt.Println("Add task with entry date passed ")
}
}

func TestCompleteTaskInTaskwarrior(t *testing.T) {
err := CompleteTaskInTaskwarrior("email", "encryptionSecret", "client_id", "taskuuid")
if err != nil {
Expand All @@ -69,16 +79,25 @@ func TestCompleteTaskInTaskwarrior(t *testing.T) {
}

func TestAddTaskWithTags(t *testing.T) {
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", "2025-03-01", "2025-03-03", "daily", []string{"work", "important"}, []models.Annotation{{Description: "note"}})
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "", "H", "2025-03-03", "2025-03-01", "2025-03-01", "2025-03-01", "2025-03-03", "daily", []string{"work", "important"}, []models.Annotation{{Description: "note"}})
if err != nil {
t.Errorf("AddTaskToTaskwarrior with tags failed: %v", err)
} else {
fmt.Println("Add task with tags passed")
}
}

func TestAddTaskToTaskwarriorWithEntryDateAndTags(t *testing.T) {
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "project", "H", "2025-03-05", "2025-03-04", "2025-03-04", "2025-03-04", "2025-03-10", "", []string{"work", "important"}, nil)
if err != nil {
t.Errorf("AddTaskToTaskwarrior with entry date and tags failed: %v", err)
} else {
fmt.Println("Add task with entry date and tags passed")
}
}

func TestAddTaskToTaskwarriorWithWaitDateWithTags(t *testing.T) {
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "project", "H", "2025-03-03", "2025-03-04", "2025-03-04", "2025-03-04", "", []string{"work", "important"}, []models.Annotation{})
err := AddTaskToTaskwarrior("email", "encryption_secret", "clientId", "description", "project", "H", "2025-03-03", "2025-03-04", "2025-03-04", "2025-03-04", "2025-03-04", "", []string{"work", "important"}, []models.Annotation{})
if err != nil {
t.Errorf("AddTaskToTaskwarrior with wait date failed: %v", err)
} else {
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/components/HomeComponents/Tasks/AddTaskDialog.tsx
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added entry-date ui

Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,23 @@ export const AddTaskdialog = ({
/>
</div>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="entry" className="text-right">
Entry
</Label>
<div className="col-span-3">
<DatePicker
date={newTask.entry ? new Date(newTask.entry) : undefined}
onDateChange={(date) => {
setNewTask({
...newTask,
entry: date ? format(date, 'yyyy-MM-dd') : '',
});
}}
placeholder="Select an entry date"
/>
</div>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="wait" className="text-right">
Wait
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/HomeComponents/Tasks/Tasks.tsx
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added entry field to new task state and pass it to addTaskToBackend when submitting, and after submission, reset it.

Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export const Tasks = (
project: '',
due: '',
start: '',
entry: '',
wait: '',
end: '',
recur: '',
Expand Down Expand Up @@ -311,6 +312,7 @@ export const Tasks = (
priority: task.priority,
due: task.due || undefined,
start: task.start || '',
entry: task.entry,
wait: task.wait,
end: task.end || '',
recur: task.recur || '',
Expand All @@ -326,6 +328,7 @@ export const Tasks = (
project: '',
due: '',
start: '',
entry: '',
wait: '',
end: '',
recur: '',
Expand Down
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added new test cases for entry field

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import { AddTaskdialog } from '../AddTaskDialog';
import '@testing-library/jest-dom';

jest.mock('date-fns', () => ({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed date-fns mock from static to dynamic, now returns the actual formatted date based on input.

format: jest.fn(() => '2024-12-25'),
format: jest.fn((date) => {
const d = new Date(date);
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}),
}));

jest.mock('@/components/ui/date-picker', () => ({
Expand Down Expand Up @@ -59,6 +65,7 @@ describe('AddTaskDialog Component', () => {
project: '',
due: '',
start: '',
entry: '',
wait: '',
end: '',
recur: '',
Expand Down Expand Up @@ -224,6 +231,7 @@ describe('AddTaskDialog Component', () => {
project: 'Work',
due: '2024-12-25',
start: '',
entry: '2025-12-20',
wait: '2025-12-20',
end: '',
recur: '',
Expand Down Expand Up @@ -313,7 +321,7 @@ describe('AddTaskDialog Component', () => {

expect(mockProps.setNewTask).toHaveBeenCalledWith({
...mockProps.newTask,
wait: '2024-12-25', // Mocked format() always returns this value regardless of input
wait: '2025-12-20',
});
});

Expand Down Expand Up @@ -342,4 +350,65 @@ describe('AddTaskDialog Component', () => {

expect(mockProps.onSubmit).toHaveBeenCalledWith(mockProps.newTask);
});

test('renders entry date picker with correct placeholder', () => {
mockProps.isOpen = true;
render(<AddTaskdialog {...mockProps} />);

const entryDatePicker =
screen.getByPlaceholderText(/select an entry date/i);
expect(entryDatePicker).toBeInTheDocument();
});

test('updates entry when user selects a date', () => {
mockProps.isOpen = true;
render(<AddTaskdialog {...mockProps} />);

const entryDatePicker =
screen.getByPlaceholderText(/select an entry date/i);
fireEvent.change(entryDatePicker, { target: { value: '2025-12-20' } });

expect(mockProps.setNewTask).toHaveBeenCalledWith({
...mockProps.newTask,
entry: '2025-12-20',
});
});

test('submits task with entry date when provided', () => {
mockProps.isOpen = true;
mockProps.newTask = {
description: 'Test task',
priority: 'H',
project: 'Work',
due: '2024-12-25',
entry: '2025-12-20',
tags: ['urgent'],
annotations: [],
};
render(<AddTaskdialog {...mockProps} />);

const submitButton = screen.getByRole('button', { name: /add task/i });
fireEvent.click(submitButton);

expect(mockProps.onSubmit).toHaveBeenCalledWith(mockProps.newTask);
});

test('allows empty entry date (optional field)', () => {
mockProps.isOpen = true;
mockProps.newTask = {
description: 'Test task',
priority: 'M',
project: '',
due: '',
entry: '',
tags: [],
annotations: [],
};
render(<AddTaskdialog {...mockProps} />);

const submitButton = screen.getByRole('button', { name: /add task/i });
fireEvent.click(submitButton);

expect(mockProps.onSubmit).toHaveBeenCalledWith(mockProps.newTask);
});
});
3 changes: 3 additions & 0 deletions frontend/src/components/HomeComponents/Tasks/hooks.ts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added entry field to addTaskToBackend function parameter, type definition and request body.

Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const addTaskToBackend = async ({
priority,
due,
start,
entry,
wait,
end,
recur,
Expand All @@ -58,6 +59,7 @@ export const addTaskToBackend = async ({
priority: string;
due?: string;
start: string;
entry: string;
wait: string;
end?: string;
recur: string;
Expand All @@ -72,6 +74,7 @@ export const addTaskToBackend = async ({
description,
project,
priority,
entry,
wait,
tags,
};
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export interface TaskFormData {
project: string;
due: string;
start: string;
entry: string;
wait: string;
end: string;
recur: string;
Expand Down
Loading