feat: added delete list & list items

This commit is contained in:
2026-08-21 21:52:26 +02:00
parent 7273fe85d3
commit 0007f96c35
17 changed files with 1639 additions and 10 deletions
+43
View File
@@ -92,6 +92,8 @@ const listsApiMocks = vi.hoisted(() => ({
setListItemCompletedApi: vi.fn<() => Promise<unknown>>(),
addUserToListApi: vi.fn<() => Promise<unknown>>(),
removeUserFromListApi: vi.fn<() => Promise<unknown>>(),
deleteListApi: vi.fn<() => Promise<unknown>>(),
deleteListItemApi: vi.fn<() => Promise<unknown>>(),
}))
vi.mock('@/api/lists', () => listsApiMocks)
@@ -276,4 +278,45 @@ describe('useListsStore', () => {
expect(stillLocal?.name).toBe('Local only')
expect(stillLocal?.pendingSync).toBe(true)
})
it('deletes a list locally and syncs deletion to the server', async () => {
listsApiMocks.deleteListApi.mockResolvedValueOnce(undefined)
const store = useListsStore()
await fakeDb.lists.put({ id: 'list-to-delete', name: 'Delete Me' })
await fakeDb.listItems.put({ id: 'item-in-list', list_id: 'list-to-delete', title: 'Item' })
await store.refresh()
expect(store.lists.find((l) => l.id === 'list-to-delete')).toBeDefined()
expect(store.listItems.find((i) => i.id === 'item-in-list')).toBeDefined()
await store.deleteList('list-to-delete')
expect(store.lists.find((l) => l.id === 'list-to-delete')).toBeUndefined()
expect(store.listItems.find((i) => i.id === 'item-in-list')).toBeUndefined()
await store.sync()
expect(listsApiMocks.deleteListApi).toHaveBeenCalledWith('list-to-delete')
expect(store.pendingCount).toBe(0)
})
it('deletes a list item locally and syncs deletion to the server', async () => {
listsApiMocks.deleteListItemApi.mockResolvedValueOnce(undefined)
const store = useListsStore()
await fakeDb.listItems.put({ id: 'item-to-delete', list_id: 'list-1', title: 'Delete Me' })
await store.refresh()
expect(store.listItems.find((i) => i.id === 'item-to-delete')).toBeDefined()
await store.deleteListItem('item-to-delete')
expect(store.listItems.find((i) => i.id === 'item-to-delete')).toBeUndefined()
await store.sync()
expect(listsApiMocks.deleteListItemApi).toHaveBeenCalledWith('item-to-delete')
expect(store.pendingCount).toBe(0)
})
})
+52 -4
View File
@@ -10,6 +10,8 @@ import {
setListItemCompletedApi,
addUserToListApi,
removeUserFromListApi,
deleteListApi,
deleteListItemApi,
} from '@/api/lists'
function generateId(): string {
@@ -162,6 +164,32 @@ export const useListsStore = defineStore('lists', () => {
void sync()
}
async function deleteList(listId: string) {
await db.lists.delete(listId)
const affectedItems = await db.listItems.where('list_id').equals(listId).toArray()
for (const item of affectedItems) {
await db.listItems.delete(item.id)
}
await enqueue({
type: 'deleteList',
payload: { id: listId },
localListId: listId,
})
await refresh()
void sync()
}
async function deleteListItem(itemId: string) {
await db.listItems.delete(itemId)
await enqueue({
type: 'deleteListItem',
payload: { id: itemId },
localListItemId: itemId,
})
await refresh()
void sync()
}
// Remaps a client-generated temporary list id to the id assigned by the
// server once the "createList" sync operation succeeds. This keeps any
// items or queued operations referencing the temporary id consistent.
@@ -183,10 +211,14 @@ export const useListsStore = defineStore('lists', () => {
.filter((entry) => entry.localListId === oldId)
.toArray()
for (const entry of affectedQueueEntries) {
const payload = entry.payload as { list_id?: string }
const payload = entry.payload as { list_id?: string; id?: string }
await db.syncQueue.update(entry.id!, {
localListId: newId,
payload: payload?.list_id ? { ...payload, list_id: newId } : entry.payload,
payload: payload?.list_id
? { ...payload, list_id: newId }
: payload?.id
? { ...payload, id: newId }
: entry.payload,
})
}
}
@@ -208,10 +240,14 @@ export const useListsStore = defineStore('lists', () => {
.filter((queueEntry) => queueEntry.localListItemId === oldId)
.toArray()
for (const queueEntry of affectedQueueEntries) {
const payload = queueEntry.payload as { list_item_id?: string }
const payload = queueEntry.payload as { list_item_id?: string; id?: string }
await db.syncQueue.update(queueEntry.id!, {
localListItemId: newId,
payload: payload?.list_item_id ? { ...payload, list_item_id: newId } : queueEntry.payload,
payload: payload?.list_item_id
? { ...payload, list_item_id: newId }
: payload?.id
? { ...payload, id: newId }
: queueEntry.payload,
})
}
}
@@ -262,6 +298,16 @@ export const useListsStore = defineStore('lists', () => {
await removeUserFromListApi(entry.payload as { list_id: string; email: string })
break
}
case 'deleteList': {
const payload = entry.payload as { id: string }
await deleteListApi(payload.id)
break
}
case 'deleteListItem': {
const payload = entry.payload as { id: string }
await deleteListItemApi(payload.id)
break
}
}
}
@@ -390,6 +436,8 @@ export const useListsStore = defineStore('lists', () => {
setListItemCompleted,
addUserToList,
removeUserFromList,
deleteList,
deleteListItem,
sync,
pullFromServer,
pullListItems,