Projekt

Obecné

Profil

Stáhnout (9.97 KB) Statistiky
| Větev: | Tag: | Revize:
1
import { createSlice } from "@reduxjs/toolkit"
2
import { LatLngTuple } from "leaflet"
3
import mapConfig from "../../config/mapConfig"
4
import { PathDto } from "../../swagger/data-contracts"
5
import buildPathVariants from "./Map/pathUtils"
6
import { isMapPointDisplayable, MapPoint, PathVariant } from "./trackingToolUtils"
7
import { sendTextForProcessing } from "./trackingToolThunks"
8
import storage from "redux-persist/lib/storage"
9
import TrackingToolState from './trackingToolState'
10

    
11

    
12
const defaultPathsPerPage = 5
13

    
14
const initialState: TrackingToolState = {
15
    isLoading: false,
16
    mapCenter: [mapConfig.defaultCoordinates[0], mapConfig.defaultCoordinates[1]],
17
    primaryPathIdx: 0,
18
    dialogApiCallSuccess: true,
19
    pathsPerPage: defaultPathsPerPage,
20
    currentPage: 0,
21
}
22

    
23
const calculateMapCenter = (pathVariant: PathVariant): LatLngTuple | undefined => {
24
    const displayableItems = pathVariant.filter((item) => isMapPointDisplayable(item))
25
    if (displayableItems.length === 0) {
26
        return undefined
27
    }
28

    
29
    return [
30
        displayableItems
31
            .map((item) => item.catalogItem.latitude ?? 0)
32
            .reduce((a, b) => a + b, 0) / displayableItems.length,
33
        displayableItems
34
            .map((item) => item.catalogItem.longitude ?? 0)
35
            .reduce((a, b) => a + b, 0) / displayableItems.length,
36
    ]
37
}
38

    
39
const persistConfig = {
40
    key: "auth",
41
    storage, // localStorage for browsers
42
}
43

    
44
export const trackingToolSlice = createSlice({
45
    name: "trackingTool",
46
    initialState,
47
    reducers: {
48
        consumeErr: (state: TrackingToolState) => ({
49
            ...state,
50
            lastErr: undefined,
51
        }),
52
        setPrimaryIdx: (state: TrackingToolState, action: any) => ({
53
            ...state,
54
            primaryPathIdx: action.payload,
55
        }),
56
        resetDialogApiCallSuccess: (state: TrackingToolState) => ({
57
            ...state,
58
            dialogApiCallSuccess: false,
59
        }),
60
        setPage: (state: TrackingToolState, action: { payload: number }) => ({
61
            ...state,
62
            currentPage: action.payload,
63
        }),
64
        updatePrimaryPath: (state: TrackingToolState, action: { payload: PathVariant }) => {
65
            const { primaryPathIdx } = state
66
            const path = action.payload
67
            const paths = [...state.pathVariants ?? []]
68

    
69
            if (paths.length <= primaryPathIdx) {
70
                return { ...state }
71
            }
72

    
73
            return {
74
                ...state,
75
                pathVariants: [
76
                    ...paths.slice(0, primaryPathIdx),
77
                    path,
78
                    ...paths.slice(primaryPathIdx + 1),
79
                ],
80
            }
81
        },
82
        // Updates map marker while ignoring its idx property
83
        updateMapMarkerWithId: (state: TrackingToolState, action: { payload: { id: string, item: MapPoint } }) => {
84
            const { item } = action.payload
85
            const { primaryPathIdx } = state
86
            if (!state.pathVariants || state.pathVariants.length <= primaryPathIdx) {
87
                return state
88
            }
89

    
90
            const mapMarkerIdx = state.pathVariants[primaryPathIdx].findIndex((item) => item.id === action.payload.id)
91
            if (mapMarkerIdx === -1) {
92
                return state
93
            }
94

    
95
            const newPathVariant = [...state.pathVariants[primaryPathIdx]]
96
            newPathVariant[mapMarkerIdx] = item
97
            return {
98
                ...state,
99
                pathVariants: [...state.pathVariants.slice(0, primaryPathIdx), newPathVariant, ...state.pathVariants.slice(primaryPathIdx + 1)],
100
            }
101
        },
102
        // Updates map marker based on its idx property
103
        updateMapMarker: (state: TrackingToolState, action: { payload: MapPoint }) => {
104
            const item = action.payload
105
            const { primaryPathIdx } = state
106
            if (!state.pathVariants || state.pathVariants.length <= primaryPathIdx) {
107
                return state
108
            }
109

    
110
            return {
111
                ...state,
112
                pathVariants: state.pathVariants.map((pathVariant, i) => {
113
                    if (i !== primaryPathIdx) {
114
                        return [...pathVariant]
115
                    }
116

    
117
                    return [
118
                        ...pathVariant.slice(0, item.idx),
119
                        item,
120
                        ...pathVariant.slice(item.idx + 1),
121
                    ]
122
                })
123
            }
124
        },
125
        // Removes map marker based on its idx property
126
        removeMapMarker: (state: TrackingToolState, action: { payload: { id: string, idx: number } }) => {
127
            const item = action.payload
128
            const idx = state.primaryPathIdx
129
            if (!state.pathVariants || state.pathVariants.length <= idx) {
130
                return state
131
            }
132

    
133
            return {
134
                ...state,
135
                pathVariants: state.pathVariants.map((pathVariant, i) => {
136
                    if (i !== idx) {
137
                        return [...pathVariant]
138
                    }
139

    
140
                    return [
141
                        ...pathVariant.slice(0, item.idx),
142
                        ...pathVariant.slice(item.idx + 1),
143
                    ]
144
                })
145
            }
146
        },
147
        moveMarkerToDestination: (state: TrackingToolState, action: { payload: { destination: number, source: number } }) => {
148
            const { destination, source } = action.payload
149
            if (!state.pathVariants || state.pathVariants.length === 0) {
150
                return state
151
            }
152

    
153
            return {
154
                ...state,
155
                pathVariants: state.pathVariants.map((pathVariant, i) => {
156
                    if (state.primaryPathIdx !== i) {
157
                        return [...pathVariant]
158
                    }
159

    
160
                    if (pathVariant.length <= destination || pathVariant.length <= source) {
161
                        return [...pathVariant]
162
                    }
163

    
164
                    // JS dark magic splice
165
                    const result = [...pathVariant]
166
                    const [removed] = result.splice(source, 1)
167
                    result.splice(destination, 0, removed)
168
                    return result.map((item, idx) => ({ ...item, idx }))
169
                })
170
            }
171
        },
172
        clear: () => ({ ...initialState }),
173
        mergeWithCurrentPath: (state: TrackingToolState, action: { payload: PathVariant }) => {
174
            const { payload: jsonPath } = action
175
            if (!jsonPath) {
176
                return { ...state }
177
            }
178

    
179
            const pathVariants = [...state.pathVariants ?? []]
180
            let primaryPathIdx = state.primaryPathIdx
181
            let currentPage = state.currentPage
182

    
183
            // If there are no path append a new array to the pathVariants array and set primaryIdx to 0
184
            if (pathVariants.length === 0) {
185
                primaryPathIdx = 0
186
                currentPage = 0
187
                pathVariants.push([])
188
            }
189

    
190
            // Get the path and create a map to check whether some point with the same id already exists
191
            const path = pathVariants[primaryPathIdx]
192
            const pathMap = new Map(path.map((item) => [item.catalogItem.id as string, item]))
193

    
194
            // Create an array of items to be replaced and items to be added to the end
195
            // const itemsToReplace: MapPoint[] = []
196
            const itemsToAdd: MapPoint[] = []
197
            jsonPath.forEach((item) => {
198
                if (!pathMap.has(item.catalogItem.id ?? '')) {
199
                    itemsToAdd.push(item)
200
                    return
201
                }
202

    
203
                // const idx = pathMap.get(item.catalogItem.id as string)!.idx
204
                // item.idx = idx
205
                // itemsToReplace.push(item)
206
            })
207

    
208
            // Iterate over items to replace and replace them
209
            const newPath = [...path]
210
            // itemsToReplace.forEach((item) => {
211
            //     newPath[item.idx] = item
212
            // })
213

    
214
            // Add items to the end
215
            itemsToAdd.forEach((item) => {
216
                item.addToPath = !state.pathVariants || state.pathVariants.length === 0
217
                item.idx = newPath.length
218
                newPath.push(item)
219
            })
220

    
221
            // Return the new path
222
            return {
223
                ...state,
224
                pathVariants: [
225
                    ...pathVariants.slice(0, primaryPathIdx),
226
                    newPath,
227
                    ...pathVariants.slice(primaryPathIdx + 1),
228
                ],
229
                primaryPathIdx, // in case the list is empty
230
                currentPage, // in case the list is empty
231
            }
232
        }
233
    },
234
    extraReducers: (builder) => {
235
        builder.addCase(sendTextForProcessing.fulfilled, (state, action) => {
236
            const pathDto: PathDto = action.payload
237
            const pathVariants = buildPathVariants(pathDto)
238

    
239
            const mapCenter = calculateMapCenter(pathVariants[state.primaryPathIdx])
240
            return {
241
                ...state,
242
                pathVariants,
243
                pathDto,
244
                mapCenter: mapCenter ?? state.mapCenter,
245
                isLoading: false,
246
                dialogApiCallSuccess: true,
247
                currentPage: 0,
248
            }
249
        })
250
        builder.addCase(sendTextForProcessing.rejected, (_, action) => ({
251
            ...initialState,
252
            lastError: action.error.message,
253
            isLoading: false,
254
            dialogApiCallSuccess: false,
255
            currentPage: 0,
256
        }))
257
        builder.addCase(sendTextForProcessing.pending, (state) => {
258
            return {
259
                ...state,
260
                isLoading: true,
261
                dialogApiCallSuccess: false,
262
            }
263
        })
264
    },
265
})
266

    
267
export const {
268
    consumeErr,
269
    setPrimaryIdx,
270
    resetDialogApiCallSuccess,
271
    clear,
272
    updateMapMarker,
273
    mergeWithCurrentPath,
274
    moveMarkerToDestination,
275
    updateMapMarkerWithId,
276
    removeMapMarker,
277
    updatePrimaryPath
278
} = trackingToolSlice.actions
279
const trackingToolReducer = trackingToolSlice.reducer
280
export default trackingToolReducer
(4-4/6)