Projekt

Obecné

Profil

Stáhnout (8.42 KB) Statistiky
| Větev: | Tag: | Revize:
1 de12c6be Vaclav Honzik
import { createSlice } from "@reduxjs/toolkit"
2
import { LatLngTuple } from "leaflet"
3
import mapConfig from "../../config/mapConfig"
4
import { PathDto } from "../../swagger/data-contracts"
5 812b9f90 Vaclav Honzik
import buildPathVariants, { isMapPointDisplayable, MapPoint, PathVariant } from "./Map/pathUtils"
6 de12c6be Vaclav Honzik
import { sendTextForProcessing } from "./trackingToolThunks"
7
import storage from "redux-persist/lib/storage"
8 a7ae217f Vaclav Honzik
import TrackingToolState from './TrackingToolState'
9 8c57f958 Vaclav Honzik
10
11 81698b9a Vaclav Honzik
const defaultPathsPerPage = 5
12
13 8c57f958 Vaclav Honzik
const initialState: TrackingToolState = {
14
    isLoading: false,
15 de12c6be Vaclav Honzik
    mapCenter: [mapConfig.defaultCoordinates[0], mapConfig.defaultCoordinates[1]],
16 8c57f958 Vaclav Honzik
    primaryPathIdx: 0,
17
    dialogApiCallSuccess: true,
18 81698b9a Vaclav Honzik
    pathsPerPage: defaultPathsPerPage,
19
    currentPage: 0,
20 8c57f958 Vaclav Honzik
}
21
22 11fca75a Vaclav Honzik
const calculateMapCenter = (pathVariant: PathVariant): LatLngTuple | undefined => {
23 a7ae217f Vaclav Honzik
    const displayableItems = pathVariant.filter((item) => isMapPointDisplayable(item))
24 11fca75a Vaclav Honzik
    if (displayableItems.length === 0) {
25
        return undefined
26
    }
27
28
    return [
29
        displayableItems
30
            .map((item) => item.catalogItem.latitude ?? 0)
31
            .reduce((a, b) => a + b, 0) / displayableItems.length,
32
        displayableItems
33
            .map((item) => item.catalogItem.longitude ?? 0)
34
            .reduce((a, b) => a + b, 0) / displayableItems.length,
35
    ]
36
}
37 8c57f958 Vaclav Honzik
38 04fdedc6 Vaclav Honzik
const persistConfig = {
39 de12c6be Vaclav Honzik
    key: "auth",
40 04fdedc6 Vaclav Honzik
    storage, // localStorage for browsers
41
}
42
43 8c57f958 Vaclav Honzik
export const trackingToolSlice = createSlice({
44 de12c6be Vaclav Honzik
    name: "trackingTool",
45 8c57f958 Vaclav Honzik
    initialState,
46
    reducers: {
47 de12c6be Vaclav Honzik
        consumeErr: (state: TrackingToolState) => ({
48
            ...state,
49
            lastErr: undefined,
50
        }),
51 c0cf1dbc Vaclav Honzik
        setPrimaryIdx: (state: TrackingToolState, action: any) => ({
52 8c57f958 Vaclav Honzik
            ...state,
53
            primaryPathIdx: action.payload,
54
        }),
55 c0cf1dbc Vaclav Honzik
        resetDialogApiCallSuccess: (state: TrackingToolState) => ({
56 8c57f958 Vaclav Honzik
            ...state,
57
            dialogApiCallSuccess: false,
58
        }),
59 de12c6be Vaclav Honzik
        setPage: (state: TrackingToolState, action: { payload: number }) => ({
60 81698b9a Vaclav Honzik
            ...state,
61
            currentPage: action.payload,
62
        }),
63 812b9f90 Vaclav Honzik
        // Updates map marker while ignoring its idx property
64
        updateMapMarkerWithId: (state: TrackingToolState, action: { payload: { id: string, item: MapPoint } }) => {
65
            const { item } = action.payload
66
            const idx = state.primaryPathIdx
67
            if (!state.pathVariants || state.pathVariants.length <= idx) {
68
                return state
69
            }
70
71
            const mapMarkerIdx = state.pathVariants[idx].findIndex((item) => item.id === action.payload.id)
72
            if (mapMarkerIdx === -1) {
73
                return state
74
            }
75
76
            const newPathVariant = [...state.pathVariants[idx]]
77
            newPathVariant[mapMarkerIdx] = item
78
            return {
79
                ...state,
80
                pathVariants: [...state.pathVariants.slice(0, idx), newPathVariant, ...state.pathVariants.slice(idx + 1)],
81
            }
82
        },
83
        // Updates map marker based on its idx property
84
        updateMapMarker: (state: TrackingToolState, action: { payload: { item: MapPoint } }) => {
85
            const { item } = action.payload
86
            const idx = state.primaryPathIdx
87 de12c6be Vaclav Honzik
            if (!state.pathVariants || state.pathVariants.length <= idx) {
88
                return state
89
            }
90
91
            return {
92
                ...state,
93
                pathVariants: state.pathVariants.map((pathVariant, i) => {
94
                    if (i !== idx) {
95
                        return [...pathVariant]
96
                    }
97
98
                    return [
99 7b864a5c Vaclav Honzik
                        ...pathVariant.slice(0, item.idx),
100
                        item,
101
                        ...pathVariant.slice(item.idx + 1),
102 de12c6be Vaclav Honzik
                    ]
103
                })
104
            }
105
        },
106 812b9f90 Vaclav Honzik
        swapMapMarkerIndices: (state: TrackingToolState, action: { payload: { destination: number, source: number } }) => {
107
            const { destination, source } = action.payload
108
            if (!state.pathVariants || state.pathVariants.length === 0) {
109
                return state
110
            }
111
112
            return {
113
                ...state,
114
                pathVariants: state.pathVariants.map((pathVariant, i) => {
115
                    if (state.primaryPathIdx !== i) {
116
                        return [...pathVariant]
117
                    }
118
119
                    if (pathVariant.length <= destination || pathVariant.length <= source) {
120
                        return [...pathVariant]
121
                    }
122
123
                    // JS dark magic splice
124
                    const result = [...pathVariant]
125
                    const [removed] = result.splice(source, 1)
126
                    result.splice(destination, 0, removed)
127
                    return result
128
                })
129
            }
130
        },
131 de12c6be Vaclav Honzik
        clear: () => ({ ...initialState }),
132 a7ae217f Vaclav Honzik
        mergeWithCurrentPath: (state: TrackingToolState, action: { payload: PathVariant }) => {
133
            const { payload: jsonPath } = action
134
            if (!jsonPath) {
135
                return { ...state }
136
            }
137
138
            const pathVariants = [...state.pathVariants ?? []]
139
            let primaryPathIdx = state.primaryPathIdx
140
            let currentPage = state.currentPage
141
142
            // If there are no path append a new array to the pathVariants array and set primaryIdx to 0
143
            if (pathVariants.length === 0) {
144
                primaryPathIdx = 0
145
                currentPage = 0
146
                pathVariants.push([])
147
            }
148
149
            // Get the path and create a map to check whether some point with the same id already exists
150
            const path = pathVariants[primaryPathIdx]
151
            const pathMap = new Map(path.map((item) => [item.catalogItem.id as string, item]))
152
153
            // Create an array of items to be replaced and items to be added to the end
154 812b9f90 Vaclav Honzik
            // const itemsToReplace: MapPoint[] = []
155 a7ae217f Vaclav Honzik
            const itemsToAdd: MapPoint[] = []
156
            jsonPath.forEach((item) => {
157
                if (!pathMap.has(item.catalogItem.id as string)) {
158
                    itemsToAdd.push(item)
159
                    return
160
                }
161 812b9f90 Vaclav Honzik
162
                // const idx = pathMap.get(item.catalogItem.id as string)!.idx
163
                // item.idx = idx
164
                // itemsToReplace.push(item)
165 a7ae217f Vaclav Honzik
            })
166
167
            // Iterate over items to replace and replace them
168
            const newPath = [...path]
169 812b9f90 Vaclav Honzik
            // itemsToReplace.forEach((item) => {
170
            //     newPath[item.idx] = item
171
            // })
172 a7ae217f Vaclav Honzik
173
            // Add items to the end
174
            itemsToAdd.forEach((item) => {
175 812b9f90 Vaclav Honzik
                item.active = !state.pathVariants || state.pathVariants.length === 0
176 a7ae217f Vaclav Honzik
                item.idx = newPath.length
177
                newPath.push(item)
178
            })
179
180
            // Return the new path
181
            return {
182
                ...state,
183
                pathVariants: [
184
                    ...pathVariants.slice(0, primaryPathIdx),
185
                    newPath,
186
                    ...pathVariants.slice(primaryPathIdx + 1),
187
                ],
188
                primaryPathIdx, // in case the list is empty
189
                currentPage, // in case the list is empty
190
            }
191
        }
192 8c57f958 Vaclav Honzik
    },
193
    extraReducers: (builder) => {
194
        builder.addCase(sendTextForProcessing.fulfilled, (state, action) => {
195 04fdedc6 Vaclav Honzik
            const pathDto: PathDto = action.payload
196
            const pathVariants = buildPathVariants(pathDto)
197 11fca75a Vaclav Honzik
198
            const mapCenter = calculateMapCenter(pathVariants[state.primaryPathIdx])
199 8c57f958 Vaclav Honzik
            return {
200
                ...state,
201
                pathVariants,
202 04fdedc6 Vaclav Honzik
                pathDto,
203 11fca75a Vaclav Honzik
                mapCenter: mapCenter ?? state.mapCenter,
204 8c57f958 Vaclav Honzik
                isLoading: false,
205
                dialogApiCallSuccess: true,
206 81698b9a Vaclav Honzik
                currentPage: 0,
207 8c57f958 Vaclav Honzik
            }
208
        })
209 b45d0300 Vaclav Honzik
        builder.addCase(sendTextForProcessing.rejected, (_, action) => ({
210 8c57f958 Vaclav Honzik
            ...initialState,
211 dd270a41 Vaclav Honzik
            lastError: action.error.message,
212 8c57f958 Vaclav Honzik
            isLoading: false,
213
            dialogApiCallSuccess: false,
214 81698b9a Vaclav Honzik
            currentPage: 0,
215 8c57f958 Vaclav Honzik
        }))
216
        builder.addCase(sendTextForProcessing.pending, (state) => {
217
            return {
218
                ...state,
219
                isLoading: true,
220
                dialogApiCallSuccess: false,
221
            }
222
        })
223
    },
224
})
225
226 812b9f90 Vaclav Honzik
export const {
227
    consumeErr,
228
    setPrimaryIdx,
229
    resetDialogApiCallSuccess,
230
    clear,
231
    updateMapMarker,
232
    mergeWithCurrentPath,
233
    swapMapMarkerIndices,
234
    updateMapMarkerWithId
235
} = trackingToolSlice.actions
236 8c57f958 Vaclav Honzik
const trackingToolReducer = trackingToolSlice.reducer
237
export default trackingToolReducer