File size: 4,023 Bytes
cd99321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { placesApi } from '../api/client'
import { offlineDb, upsertPlaces } from '../db/offlineDb'
import { mutationQueue, generateUUID, nextTempId } from '../sync/mutationQueue'
import { onlineThenCache } from './withOfflineFallback'
import type { Place } from '../types'

export const placeRepo = {
  async list(tripId: number | string, params?: Record<string, unknown>): Promise<{ places: Place[] }> {
    return onlineThenCache(
      async () => {
        const result = await placesApi.list(tripId, params)
        upsertPlaces(result.places)
        return result
      },
      async () => ({
        places: await offlineDb.places
          .where('trip_id').equals(Number(tripId)).toArray(),
      }),
    )
  },

  async create(tripId: number | string, data: Record<string, unknown> & { name: string }): Promise<{ place: Place }> {
    if (!navigator.onLine) {
      const tempId = nextTempId()
      const tempPlace: Place = {
        ...(data as Partial<Place>),
        id: tempId,
        trip_id: Number(tripId),
        name: (data.name as string) ?? 'New place',
      } as Place
      await offlineDb.places.put(tempPlace)
      const id = generateUUID()
      await mutationQueue.enqueue({
        id,
        tripId: Number(tripId),
        method: 'POST',
        url: `/trips/${tripId}/places`,
        body: data,
        resource: 'places',
        tempId,
      })
      return { place: tempPlace }
    }
    const result = await placesApi.create(tripId, data)
    offlineDb.places.put(result.place)
    return result
  },

  async update(tripId: number | string, id: number | string, data: Record<string, unknown>): Promise<{ place: Place }> {
    if (!navigator.onLine) {
      const existing = await offlineDb.places.get(Number(id))
      const optimistic: Place = { ...(existing ?? {} as Place), ...(data as Partial<Place>), id: Number(id) }
      await offlineDb.places.put(optimistic)
      const mutId = generateUUID()
      const isTemp = Number(id) < 0
      await mutationQueue.enqueue({
        id: mutId,
        tripId: Number(tripId),
        method: 'PUT',
        url: isTemp ? `/trips/${tripId}/places/{id}` : `/trips/${tripId}/places/${id}`,
        body: data,
        resource: 'places',
        entityId: Number(id),
        ...(isTemp ? { tempEntityId: Number(id) } : {}),
      })
      return { place: optimistic }
    }
    const result = await placesApi.update(tripId, id, data)
    offlineDb.places.put(result.place)
    return result
  },

  async delete(tripId: number | string, id: number | string): Promise<unknown> {
    if (!navigator.onLine) {
      await offlineDb.places.delete(Number(id))
      const mutId = generateUUID()
      const isTemp = Number(id) < 0
      await mutationQueue.enqueue({
        id: mutId,
        tripId: Number(tripId),
        method: 'DELETE',
        url: isTemp ? `/trips/${tripId}/places/{id}` : `/trips/${tripId}/places/${id}`,
        body: undefined,
        resource: 'places',
        entityId: Number(id),
        ...(isTemp ? { tempEntityId: Number(id) } : {}),
      })
      return { success: true }
    }
    const result = await placesApi.delete(tripId, id)
    offlineDb.places.delete(Number(id))
    return result
  },

  async deleteMany(tripId: number | string, ids: number[]): Promise<unknown> {
    if (!navigator.onLine) {
      await offlineDb.places.bulkDelete(ids)
      for (const id of ids) {
        const mutId = generateUUID()
        const isTemp = id < 0
        await mutationQueue.enqueue({
          id: mutId,
          tripId: Number(tripId),
          method: 'DELETE',
          url: isTemp ? `/trips/${tripId}/places/{id}` : `/trips/${tripId}/places/${id}`,
          body: undefined,
          resource: 'places',
          entityId: id,
          ...(isTemp ? { tempEntityId: id } : {}),
        })
      }
      return { deleted: ids, count: ids.length }
    }
    const result = await placesApi.bulkDelete(tripId, ids)
    await offlineDb.places.bulkDelete(ids)
    return result
  },
}