Files
TREK/client/src/store/slices/todoSlice.ts
T
jubnl 852f0085d1 feat: complete offline write support with mutation queue + runtime SW cache config
- Add offline CRUD to todoRepo, budgetRepo, reservationRepo, accommodationRepo,
  dayRepo, tripRepo, fileRepo with optimistic Dexie writes and mutation queue
- Wire all store slices (todo, budget, reservations, files, dayNotes, assignments,
  tripStore) through repos for offline-aware writes
- Cover archive/unarchive, file toggleStar/update/delete, assignment create/delete,
  day title/notes update offline paths
- Migrate service worker from generateSW to injectManifest (custom sw.ts) with
  runtime-configurable api-data (7d/500) and map-tiles (30d/1000) cache policies
- Add Settings → Offline cache configuration UI with save/reset and live SW postMessage
- Extend mutationQueue flush to cover all writable Dexie tables
2026-05-04 21:36:44 +02:00

68 lines
2.3 KiB
TypeScript

import { todoRepo } from '../../repo/todoRepo'
import type { StoreApi } from 'zustand'
import type { TripStoreState } from '../tripStore'
import type { TodoItem } from '../../types'
import { getApiErrorMessage } from '../../types'
type SetState = StoreApi<TripStoreState>['setState']
type GetState = StoreApi<TripStoreState>['getState']
export interface TodoSlice {
addTodoItem: (tripId: number | string, data: Partial<TodoItem>) => Promise<TodoItem>
updateTodoItem: (tripId: number | string, id: number, data: Partial<TodoItem>) => Promise<TodoItem>
deleteTodoItem: (tripId: number | string, id: number) => Promise<void>
toggleTodoItem: (tripId: number | string, id: number, checked: boolean) => Promise<void>
}
export const createTodoSlice = (set: SetState, get: GetState): TodoSlice => ({
addTodoItem: async (tripId, data) => {
try {
const result = await todoRepo.create(tripId, data as Record<string, unknown>)
set(state => ({ todoItems: [...state.todoItems, result.item] }))
return result.item
} catch (err: unknown) {
throw new Error(getApiErrorMessage(err, 'Error adding todo'))
}
},
updateTodoItem: async (tripId, id, data) => {
try {
const result = await todoRepo.update(tripId, id, data as Record<string, unknown>)
set(state => ({
todoItems: state.todoItems.map(item => item.id === id ? result.item : item)
}))
return result.item
} catch (err: unknown) {
throw new Error(getApiErrorMessage(err, 'Error updating todo'))
}
},
deleteTodoItem: async (tripId, id) => {
const prev = get().todoItems
set(state => ({ todoItems: state.todoItems.filter(item => item.id !== id) }))
try {
await todoRepo.delete(tripId, id)
} catch (err: unknown) {
set({ todoItems: prev })
throw new Error(getApiErrorMessage(err, 'Error deleting todo'))
}
},
toggleTodoItem: async (tripId, id, checked) => {
set(state => ({
todoItems: state.todoItems.map(item =>
item.id === id ? { ...item, checked: checked ? 1 : 0 } : item
)
}))
try {
await todoRepo.update(tripId, id, { checked })
} catch {
set(state => ({
todoItems: state.todoItems.map(item =>
item.id === id ? { ...item, checked: checked ? 0 : 1 } : item
)
}))
}
},
})