Files
TREK/client/src/store/slices/filesSlice.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

48 lines
1.5 KiB
TypeScript

import { filesApi } from '../../api/client'
import { fileRepo } from '../../repo/fileRepo'
import type { StoreApi } from 'zustand'
import type { TripStoreState } from '../tripStore'
import type { TripFile } from '../../types'
import { getApiErrorMessage } from '../../types'
type SetState = StoreApi<TripStoreState>['setState']
type GetState = StoreApi<TripStoreState>['getState']
export interface FilesSlice {
loadFiles: (tripId: number | string) => Promise<void>
addFile: (tripId: number | string, formData: FormData) => Promise<TripFile>
deleteFile: (tripId: number | string, id: number) => Promise<void>
}
export const createFilesSlice = (set: SetState, get: GetState): FilesSlice => ({
loadFiles: async (tripId) => {
try {
const data = await fileRepo.list(tripId)
set({ files: data.files })
} catch (err: unknown) {
console.error('Failed to load files:', err)
}
},
addFile: async (tripId, formData) => {
try {
const data = await filesApi.upload(tripId, formData)
set(state => ({ files: [data.file, ...state.files] }))
return data.file
} catch (err: unknown) {
throw new Error(getApiErrorMessage(err, 'Error uploading file'))
}
},
deleteFile: async (tripId, id) => {
const prev = get().files
set(state => ({ files: state.files.filter(f => f.id !== id) }))
try {
await fileRepo.delete(tripId, id)
} catch (err: unknown) {
set({ files: prev })
throw new Error(getApiErrorMessage(err, 'Error deleting file'))
}
},
})