feat: added delete list & list items
This commit is contained in:
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user