Skip to content

Commit e54aede

Browse files
✨ feat(dnd-tasks): implement drag and drop for tasks (#1273)
* ✨ feat(dnd-tasks): implement drag and drop for tasks * Update packages/web/src/views/Day/hooks/tasks/useDNDTasks.test.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update packages/web/src/views/Day/context/DNDTasksProvider.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update packages/web/src/views/Day/components/Tasks/Tasks.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update packages/web/src/views/Day/context/DNDTasksProvider.tsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update packages/web/src/views/Day/hooks/tasks/useDNDTasks.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * ✨ feat(dnd-tasks): implement drag and drop for tasks * fix(dnd-tasks): correct task index references during drag and drop * fix(dnd-tasks): correct announcement text for task drop position --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent e5847f0 commit e54aede

File tree

18 files changed

+634
-122
lines changed

18 files changed

+634
-122
lines changed

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,26 @@ _A focused workspace for organizing your day and staying on track; All your even
44

55
https://github.com/user-attachments/assets/ba7b91b9-1984-49f2-afc6-7fcda1100b31
66

7-
87
---
98

10-
119
## Benefits
1210

1311
### 🧘 Get clear
12+
1413
Plan your Month → Week → Day → Now
1514

1615
### 1️⃣ Simplify your life
16+
1717
One app for tasks, events, and plans
1818

1919
### ⚡ Go fast
20+
2021
Shortcuts, command palette, lightweight code
2122

2223
### 🔄 Keep your GCal
23-
Events sync to Google Calendar*
24-
24+
25+
Events sync to Google Calendar\*
26+
2527
## Features
2628

2729
### The unique stuff
@@ -53,7 +55,7 @@ Events sync to Google Calendar*
5355

5456
Features we don't support yet:
5557

56-
- 📂 Sub-calendars (*only primary calendar is supported)
58+
- 📂 Sub-calendars (\*only primary calendar is supported)
5759
- 🔗 Sharing
5860
- 📍 Location
5961
- ⏰ Reminders
@@ -76,4 +78,3 @@ Features we don't support yet:
7678
![Jest](https://img.shields.io/badge/-jest-%23C21325?style=for-the-badge&logo=jest&logoColor=white)
7779
![Testing-Library](https://img.shields.io/badge/-TestingLibrary-%23E33332?style=for-the-badge&logo=testing-library&logoColor=white)
7880
![Ngrok](https://img.shields.io/badge/ngrok-1F1F1F?style=for-the-badge&logo=ngrok&logoColor=white)
79-

packages/web/package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
"react": "^18.1.0",
2525
"react-cmdk": "^1.3.9",
2626
"react-datepicker": "^4.2.1",
27-
"react-dnd": "^16.0.1",
28-
"react-dnd-html5-backend": "^16.0.1",
2927
"react-dom": "^18.1.0",
3028
"react-google-button": "^0.8.0",
3129
"react-hotkeys-hook": "^4.4.1",

packages/web/src/__tests__/web.test.start.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import "@testing-library/jest-dom";
12
import { mockNodeModules } from "@web/__tests__/__mocks__/mock.setup";
23
import { server } from "@web/__tests__/__mocks__/server/mock.server";
34

packages/web/src/common/types/task.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const TaskSchema = z.object({
44
id: z.string(),
55
title: z.string(),
66
status: z.enum(["todo", "completed"]),
7+
order: z.number().default(0),
78
createdAt: z.string().datetime(),
89
});
910

packages/web/src/common/utils/task/sort.task.test.ts

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@ describe("taskSort.util", () => {
99
id: "task-1",
1010
title: "Task 1",
1111
status: "todo",
12+
order: 0,
1213
createdAt: "2024-01-01T10:00:00Z",
1314
},
1415
{
1516
id: "task-2",
1617
title: "Task 2",
1718
status: "completed",
19+
order: 0,
1820
createdAt: "2024-01-01T11:00:00Z",
1921
},
2022
{
2123
id: "task-3",
2224
title: "Task 3",
2325
status: "todo",
26+
order: 1,
2427
createdAt: "2024-01-01T12:00:00Z",
2528
},
2629
];
@@ -32,62 +35,68 @@ describe("taskSort.util", () => {
3235
expect(result[2].id).toBe("task-2");
3336
});
3437

35-
it("should maintain order of incomplete tasks", () => {
38+
it("should sort incomplete tasks by order", () => {
3639
const tasks: Task[] = [
3740
{
3841
id: "task-1",
3942
title: "First todo",
4043
status: "todo",
44+
order: 2,
4145
createdAt: "2024-01-01T10:00:00Z",
4246
},
4347
{
4448
id: "task-2",
4549
title: "Second todo",
4650
status: "todo",
51+
order: 0,
4752
createdAt: "2024-01-01T11:00:00Z",
4853
},
4954
{
5055
id: "task-3",
5156
title: "Third todo",
5257
status: "todo",
58+
order: 1,
5359
createdAt: "2024-01-01T12:00:00Z",
5460
},
5561
];
5662

5763
const result = sortTasksByStatus(tasks);
5864

59-
expect(result[0].id).toBe("task-1");
60-
expect(result[1].id).toBe("task-2");
61-
expect(result[2].id).toBe("task-3");
65+
expect(result[0].id).toBe("task-2"); // order 0
66+
expect(result[1].id).toBe("task-3"); // order 1
67+
expect(result[2].id).toBe("task-1"); // order 2
6268
});
6369

64-
it("should maintain order of completed tasks", () => {
70+
it("should sort completed tasks by order", () => {
6571
const tasks: Task[] = [
6672
{
6773
id: "task-1",
6874
title: "First completed",
6975
status: "completed",
76+
order: 2,
7077
createdAt: "2024-01-01T10:00:00Z",
7178
},
7279
{
7380
id: "task-2",
7481
title: "Second completed",
7582
status: "completed",
83+
order: 0,
7684
createdAt: "2024-01-01T11:00:00Z",
7785
},
7886
{
7987
id: "task-3",
8088
title: "Third completed",
8189
status: "completed",
90+
order: 1,
8291
createdAt: "2024-01-01T12:00:00Z",
8392
},
8493
];
8594

8695
const result = sortTasksByStatus(tasks);
8796

88-
expect(result[0].id).toBe("task-1");
89-
expect(result[1].id).toBe("task-2");
90-
expect(result[2].id).toBe("task-3");
97+
expect(result[0].id).toBe("task-2"); // order 0
98+
expect(result[1].id).toBe("task-3"); // order 1
99+
expect(result[2].id).toBe("task-1"); // order 2
91100
});
92101

93102
it("should handle empty array", () => {
@@ -101,44 +110,49 @@ describe("taskSort.util", () => {
101110
id: "task-1",
102111
title: "Todo 1",
103112
status: "todo",
113+
order: 1,
104114
createdAt: "2024-01-01T10:00:00Z",
105115
},
106116
{
107117
id: "task-2",
108118
title: "Completed 1",
109119
status: "completed",
120+
order: 0,
110121
createdAt: "2024-01-01T11:00:00Z",
111122
},
112123
{
113124
id: "task-3",
114125
title: "Todo 2",
115126
status: "todo",
127+
order: 0,
116128
createdAt: "2024-01-01T12:00:00Z",
117129
},
118130
{
119131
id: "task-4",
120132
title: "Completed 2",
121133
status: "completed",
134+
order: 1,
122135
createdAt: "2024-01-01T13:00:00Z",
123136
},
124137
{
125138
id: "task-5",
126139
title: "Todo 3",
127140
status: "todo",
141+
order: 2,
128142
createdAt: "2024-01-01T14:00:00Z",
129143
},
130144
];
131145

132146
const result = sortTasksByStatus(tasks);
133147

134-
// All todos should come first
135-
expect(result[0].id).toBe("task-1");
136-
expect(result[1].id).toBe("task-3");
137-
expect(result[2].id).toBe("task-5");
148+
// All todos should come first, sorted by order
149+
expect(result[0].id).toBe("task-3"); // todo order 0
150+
expect(result[1].id).toBe("task-1"); // todo order 1
151+
expect(result[2].id).toBe("task-5"); // todo order 2
138152

139-
// All completed should come after
140-
expect(result[3].id).toBe("task-2");
141-
expect(result[4].id).toBe("task-4");
153+
// All completed should come after, sorted by order
154+
expect(result[3].id).toBe("task-2"); // completed order 0
155+
expect(result[4].id).toBe("task-4"); // completed order 1
142156
});
143157

144158
it("should not mutate original array", () => {
@@ -147,12 +161,14 @@ describe("taskSort.util", () => {
147161
id: "task-1",
148162
title: "Task 1",
149163
status: "todo",
164+
order: 0,
150165
createdAt: "2024-01-01T10:00:00Z",
151166
},
152167
{
153168
id: "task-2",
154169
title: "Task 2",
155170
status: "completed",
171+
order: 0,
156172
createdAt: "2024-01-01T11:00:00Z",
157173
},
158174
];
@@ -171,18 +187,21 @@ describe("taskSort.util", () => {
171187
id: "task-1",
172188
title: "Todo 1",
173189
status: "todo",
190+
order: 0,
174191
createdAt: "2024-01-01T10:00:00Z",
175192
},
176193
{
177194
id: "task-2",
178195
title: "Completed 1",
179196
status: "completed",
197+
order: 0,
180198
createdAt: "2024-01-01T11:00:00Z",
181199
},
182200
{
183201
id: "task-3",
184202
title: "Todo 2",
185203
status: "todo",
204+
order: 0,
186205
createdAt: "2024-01-01T12:00:00Z",
187206
},
188207
];
@@ -201,18 +220,21 @@ describe("taskSort.util", () => {
201220
id: "task-1",
202221
title: "Oldest",
203222
status: "todo",
223+
order: 0,
204224
createdAt: "2024-01-01T10:00:00Z",
205225
},
206226
{
207227
id: "task-2",
208228
title: "Middle",
209229
status: "todo",
230+
order: 0,
210231
createdAt: "2024-01-01T12:00:00Z",
211232
},
212233
{
213234
id: "task-3",
214235
title: "Newest",
215236
status: "todo",
237+
order: 0,
216238
createdAt: "2024-01-01T14:00:00Z",
217239
},
218240
];
@@ -231,18 +253,21 @@ describe("taskSort.util", () => {
231253
id: "task-1",
232254
title: "First",
233255
status: "todo",
256+
order: 0,
234257
createdAt: sameTimestamp,
235258
},
236259
{
237260
id: "task-2",
238261
title: "Second",
239262
status: "todo",
263+
order: 0,
240264
createdAt: sameTimestamp,
241265
},
242266
{
243267
id: "task-3",
244268
title: "Third",
245269
status: "todo",
270+
order: 0,
246271
createdAt: sameTimestamp,
247272
},
248273
];
@@ -266,12 +291,14 @@ describe("taskSort.util", () => {
266291
id: "task-1",
267292
title: "Completed 1",
268293
status: "completed",
294+
order: 0,
269295
createdAt: "2024-01-01T10:00:00Z",
270296
},
271297
{
272298
id: "task-2",
273299
title: "Completed 2",
274300
status: "completed",
301+
order: 0,
275302
createdAt: "2024-01-01T11:00:00Z",
276303
},
277304
];
@@ -287,18 +314,21 @@ describe("taskSort.util", () => {
287314
id: "task-1",
288315
title: "Todo 1",
289316
status: "todo",
317+
order: 0,
290318
createdAt: "2024-01-01T10:00:00Z",
291319
},
292320
{
293321
id: "task-2",
294322
title: "Todo 2",
295323
status: "todo",
324+
order: 0,
296325
createdAt: "2024-01-01T12:00:00Z",
297326
},
298327
{
299328
id: "task-3",
300329
title: "Todo 3",
301330
status: "todo",
331+
order: 0,
302332
createdAt: "2024-01-01T11:00:00Z",
303333
},
304334
];
@@ -317,12 +347,14 @@ describe("taskSort.util", () => {
317347
id: "task-1",
318348
title: "Task 1",
319349
status: "todo",
350+
order: 0,
320351
createdAt: "2024-01-01T10:00:00Z",
321352
},
322353
{
323354
id: "task-2",
324355
title: "Task 2",
325356
status: "completed",
357+
order: 0,
326358
createdAt: "2024-01-01T11:00:00Z",
327359
},
328360
];
@@ -339,24 +371,28 @@ describe("taskSort.util", () => {
339371
id: "task-1",
340372
title: "Old todo",
341373
status: "todo",
374+
order: 0,
342375
createdAt: "2024-01-01T10:00:00Z",
343376
},
344377
{
345378
id: "task-2",
346379
title: "Completed",
347380
status: "completed",
381+
order: 0,
348382
createdAt: "2024-01-01T11:00:00Z",
349383
},
350384
{
351385
id: "task-3",
352386
title: "New todo",
353387
status: "todo",
388+
order: 0,
354389
createdAt: "2024-01-01T14:00:00Z",
355390
},
356391
{
357392
id: "task-4",
358393
title: "Middle todo",
359394
status: "todo",
395+
order: 0,
360396
createdAt: "2024-01-01T12:00:00Z",
361397
},
362398
];

0 commit comments

Comments
 (0)