Projekt

Obecné

Profil

Stáhnout (6.36 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, { isMapPointDisplayable, MapPoint, PathVariant } from "./pathUtils"
6
import { sendTextForProcessing } from "./trackingToolThunks"
7
import storage from "redux-persist/lib/storage"
8
import TrackingToolState from './TrackingToolState'
9

    
10

    
11
const defaultPathsPerPage = 5
12

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

    
22
const calculateMapCenter = (pathVariant: PathVariant): LatLngTuple | undefined => {
23
    const displayableItems = pathVariant.filter((item) => isMapPointDisplayable(item))
24
    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

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

    
43
export const trackingToolSlice = createSlice({
44
    name: "trackingTool",
45
    initialState,
46
    reducers: {
47
        consumeErr: (state: TrackingToolState) => ({
48
            ...state,
49
            lastErr: undefined,
50
        }),
51
        setPrimaryIdx: (state: TrackingToolState, action: any) => ({
52
            ...state,
53
            primaryPathIdx: action.payload,
54
        }),
55
        resetDialogApiCallSuccess: (state: TrackingToolState) => ({
56
            ...state,
57
            dialogApiCallSuccess: false,
58
        }),
59
        setPage: (state: TrackingToolState, action: { payload: number }) => ({
60
            ...state,
61
            currentPage: action.payload,
62
        }),
63
        updateMapMarker: (state: TrackingToolState, action: { payload: { idx: number, item: MapPoint } }) => {
64
            const { idx, item } = action.payload
65
            if (!state.pathVariants || state.pathVariants.length <= idx) {
66
                return state
67
            }
68

    
69
            return {
70
                ...state,
71
                pathVariants: state.pathVariants.map((pathVariant, i) => {
72
                    if (i !== idx) {
73
                        return [...pathVariant]
74
                    }
75

    
76
                    return [
77
                        ...pathVariant.slice(0, item.idx),
78
                        item,
79
                        ...pathVariant.slice(item.idx + 1),
80
                    ]
81
                })
82
            }
83
        },
84
        clear: () => ({ ...initialState }),
85
        mergeWithCurrentPath: (state: TrackingToolState, action: { payload: PathVariant }) => {
86
            const { payload: jsonPath } = action
87
            if (!jsonPath) {
88
                return { ...state }
89
            }
90

    
91
            const pathVariants = [...state.pathVariants ?? []]
92
            let primaryPathIdx = state.primaryPathIdx
93
            let currentPage = state.currentPage
94

    
95
            // If there are no path append a new array to the pathVariants array and set primaryIdx to 0
96
            if (pathVariants.length === 0) {
97
                primaryPathIdx = 0
98
                currentPage = 0
99
                pathVariants.push([])
100
            }
101

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

    
106
            // Create an array of items to be replaced and items to be added to the end
107
            const itemsToReplace: MapPoint[] = []
108
            const itemsToAdd: MapPoint[] = []
109
            jsonPath.forEach((item) => {
110
                if (!pathMap.has(item.catalogItem.id as string)) {
111
                    itemsToAdd.push(item)
112
                    return
113
                }
114
                
115
                const idx = pathMap.get(item.catalogItem.id as string)!.idx
116
                item.idx = idx
117
                itemsToReplace.push(item)
118
            })
119

    
120
            // Iterate over items to replace and replace them
121
            const newPath = [...path]
122
            itemsToReplace.forEach((item) => {
123
                newPath[item.idx] = item
124
            })
125

    
126
            // Add items to the end
127
            itemsToAdd.forEach((item) => {
128
                item.active = false
129
                item.idx = newPath.length
130
                newPath.push(item)
131
            })
132

    
133
            // Return the new path
134
            return {
135
                ...state,
136
                pathVariants: [
137
                    ...pathVariants.slice(0, primaryPathIdx),
138
                    newPath,
139
                    ...pathVariants.slice(primaryPathIdx + 1),
140
                ],
141
                primaryPathIdx, // in case the list is empty
142
                currentPage, // in case the list is empty
143
            }
144
        }
145
    },
146
    extraReducers: (builder) => {
147
        builder.addCase(sendTextForProcessing.fulfilled, (state, action) => {
148
            const pathDto: PathDto = action.payload
149
            const pathVariants = buildPathVariants(pathDto)
150

    
151
            const mapCenter = calculateMapCenter(pathVariants[state.primaryPathIdx])
152
            return {
153
                ...state,
154
                pathVariants,
155
                pathDto,
156
                mapCenter: mapCenter ?? state.mapCenter,
157
                isLoading: false,
158
                dialogApiCallSuccess: true,
159
                currentPage: 0,
160
            }
161
        })
162
        builder.addCase(sendTextForProcessing.rejected, (_, action) => ({
163
            ...initialState,
164
            lastError: action.error.message,
165
            isLoading: false,
166
            dialogApiCallSuccess: false,
167
            currentPage: 0,
168
        }))
169
        builder.addCase(sendTextForProcessing.pending, (state) => {
170
            return {
171
                ...state,
172
                isLoading: true,
173
                dialogApiCallSuccess: false,
174
            }
175
        })
176
    },
177
})
178

    
179
export const { consumeErr, setPrimaryIdx, resetDialogApiCallSuccess, clear, updateMapMarker, mergeWithCurrentPath } =
180
    trackingToolSlice.actions
181
const trackingToolReducer = trackingToolSlice.reducer
182
export default trackingToolReducer
(7-7/8)