Skip to content

Commit 733a53e

Browse files
authored
Merge pull request #15 from Steinvall/master
Implemented persistent reorder todo list functionality
2 parents 8dee6f5 + 2d8af68 commit 733a53e

File tree

9 files changed

+360
-20
lines changed

9 files changed

+360
-20
lines changed

backend/.eslintrc.cjs

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module.exports = {
22
env: {
33
node: true,
4+
"es6": true,
45
},
56
extends: 'eslint:recommended',
67
parserOptions: {

backend/src/app.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
createTodoItem,
99
fetchTodoItemById,
1010
updateTodoItem,
11-
deleteTodoItem
11+
deleteTodoItem,
12+
reorderTodoItems
1213
} from './todo-service.js'
1314

1415
const __filename = fileURLToPath(import.meta.url)
@@ -34,6 +35,12 @@ app.get('/api/todo-list/:listId', async (req, res) => {
3435
try {
3536
const todoList = await fetchTodoListById(req.params.listId)
3637
if (!todoList) return res.status(404).json({ message: 'Todo list not found' })
38+
39+
// Sort items by order before returning
40+
if (todoList.items) {
41+
todoList.items.sort((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity))
42+
}
43+
3744
res.json(todoList)
3845
} catch (error) {
3946
res.status(500).json({ message: error.message })
@@ -68,6 +75,16 @@ app.patch('/api/todo-list/:listId/item/:itemId', async (req, res) => {
6875
}
6976
})
7077

78+
app.patch('/api/todo-list/:listId/reorder', async (req, res) => {
79+
try {
80+
const { itemIds } = req.body
81+
const reorderedItems = await reorderTodoItems(req.params.listId, itemIds)
82+
res.json(reorderedItems)
83+
} catch (error) {
84+
res.status(500).json({ message: error.message })
85+
}
86+
})
87+
7188
app.delete('/api/todo-list/:listId/item/:itemId', async (req, res) => {
7289
try {
7390
const deletedTodoItem = await deleteTodoItem(req.params.listId, req.params.itemId)

backend/src/data-source.js

+26-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,34 @@ let dataSource = null
77
const seedData = async (dataSource) => {
88
const todoListRepository = dataSource.getRepository(TodoList)
99
const todoItemRepository = dataSource.getRepository(TodoItem)
10+
1011
const firstList = await todoListRepository.save({ title: 'First List' })
11-
await todoItemRepository.save({ itemTitle: 'First todo of first list!', list: firstList })
12+
await todoItemRepository.save([
13+
{
14+
itemTitle: 'First todo of first list!',
15+
list: firstList,
16+
order: 0
17+
},
18+
{
19+
itemTitle: 'Second todo of first list!',
20+
list: firstList,
21+
order: 1
22+
}
23+
])
24+
1225
const secondList = await todoListRepository.save({ title: 'Second List' })
13-
await todoItemRepository.save({ itemTitle: 'First todo of second list!', list: secondList })
26+
await todoItemRepository.save([
27+
{
28+
itemTitle: 'First todo of second list!',
29+
list: secondList,
30+
order: 0
31+
},
32+
{
33+
itemTitle: 'Second todo of second list!',
34+
list: secondList,
35+
order: 1
36+
}
37+
])
1438
}
1539

1640
export const getAppDataSource = async () => {

backend/src/todo-item.js

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ export const TodoItem = new EntitySchema({
1515
type: Boolean,
1616
default: false,
1717
},
18+
order: {
19+
type: Number,
20+
nullable: false,
21+
},
1822
},
1923
relations: {
2024
list: {

backend/src/todo-service.js

+48-4
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,26 @@ export const fetchTodoListById = async (listId) => {
1717

1818
export const createTodoItem = async (listId, todoItemData) => {
1919
const AppDataSource = await getAppDataSource()
20-
const todoList = await AppDataSource.getRepository(TodoList).findOneBy({ id: listId })
20+
const todoListRepository = AppDataSource.getRepository(TodoList)
21+
const todoItemRepository = AppDataSource.getRepository(TodoItem)
22+
23+
const todoList = await todoListRepository.findOneBy({ id: listId })
2124
if (!todoList) throw new Error(`Todo list ${listId} not found`)
22-
23-
const todoItem = AppDataSource.getRepository(TodoItem).create({ ...todoItemData, list: todoList })
24-
return AppDataSource.getRepository(TodoItem).save(todoItem)
25+
26+
const maxOrderItem = await todoItemRepository.findOne({
27+
where: { list: { id: listId } },
28+
order: { order: 'DESC' }
29+
})
30+
31+
const newOrder = maxOrderItem ? maxOrderItem.order + 1 : 0
32+
33+
const todoItem = todoItemRepository.create({
34+
...todoItemData,
35+
list: todoList,
36+
order: newOrder
37+
})
38+
39+
return todoItemRepository.save(todoItem)
2540
}
2641

2742
export const fetchTodoItemById = async (listId, itemId) => {
@@ -56,3 +71,32 @@ export const deleteTodoItem = async (listId, itemId) => {
5671
await todoRepository.delete(itemId)
5772
return todoItem
5873
}
74+
75+
export const reorderTodoItems = async (listId, itemIds) => {
76+
const AppDataSource = await getAppDataSource()
77+
const todoItemRepository = AppDataSource.getRepository(TodoItem)
78+
79+
try {
80+
const todoItems = await todoItemRepository.find({
81+
where: { list: { id: listId } }
82+
})
83+
84+
// Use Promise.all for concurrent updates
85+
await Promise.all(itemIds.map((itemId, index) => {
86+
const todoItem = todoItems.find(item => item.id === parseInt(itemId))
87+
88+
if (todoItem) {
89+
todoItem.order = index
90+
return todoItemRepository.save(todoItem)
91+
}
92+
}))
93+
94+
return todoItemRepository.find({
95+
where: { list: { id: listId } },
96+
order: { order: 'ASC' }
97+
})
98+
} catch (error) {
99+
console.error('Error reordering items:', error)
100+
throw error
101+
}
102+
}

0 commit comments

Comments
 (0)