Projekt

Obecné

Profil

Stáhnout (7.67 KB) Statistiky
| Větev: | Tag: | Revize:
1
import { createSlice } from '@reduxjs/toolkit'
2
import mapConfig from '../../config/mapConfig'
3
import { PathDto } from '../../swagger/data-contracts'
4
import generateUuid from '../../utils/id/uuidGenerator'
5
import buildPathVariants from './Map/mapUtils'
6
import TrackingToolState from './trackingToolState'
7
import { sendTextForProcessing } from './trackingToolThunks'
8
import { calculateMapCenter, MapPoint, PathVariant, setMapPointIds } from './trackingToolUtils'
9

    
10
const initialState: TrackingToolState = {
11
    isLoading: false,
12
    mapCenter: [mapConfig.defaultCoordinates[0], mapConfig.defaultCoordinates[1]],
13
    displayedPathIdx: 0,
14
    dialogApiCallSuccess: true,
15
}
16

    
17
export const trackingToolSlice = createSlice({
18
    name: 'trackingTool',
19
    initialState,
20
    reducers: {
21
        consumeErr: (state: TrackingToolState) => ({ ...state, lastErr: undefined, }),
22
        setSelectedPathIdx: (state: TrackingToolState, action: { payload: number }) =>
23
            ({ ...state, selectedPathIdx: action.payload, }),
24
        resetDialogApiCallSuccess: (state: TrackingToolState) =>
25
            ({ ...state, dialogApiCallSuccess: false, }),
26
        // Updates currently displayed path
27
        updateDisplayedPath: (state: TrackingToolState, action: { payload: PathVariant }) =>
28
            ({ ...state, displayedPath: action.payload, }),
29
        updateMapPointAtIndex: (state: TrackingToolState, action: { payload: MapPoint }) => {
30
            const newPath = [...state.displayedPath ?? []]
31
            if (newPath.length <= action.payload.idx) {
32
                return state // do nothing if there is no path
33
            }
34

    
35
            newPath[action.payload.idx] = action.payload
36
            return {
37
                ...state,
38
                displayedPath: newPath,
39
            }
40
        },
41
        // Updates map marker
42
        updateMapPoint: (state: TrackingToolState, action: { payload: MapPoint }) => {
43
            const newPath = [...state.displayedPath ?? []]
44
            return {
45
                ...state,
46
                displayedPath: newPath.map((point, _) => point.id === action.payload.id ? {...action.payload, idx: point.idx} : point)
47
            }
48
        },
49
        // Removes map marker from currently used path
50
        removeMapMarker: (state: TrackingToolState, action: { payload: { id: string, idx: number } }) => {
51
            const newPath = [...state.displayedPath ?? []]
52
            if (newPath.length <= action.payload.idx) {
53
                return state // do nothing if there is no path
54
            }
55

    
56
            return {
57
                ...state,
58
                displayedPath: [...newPath.slice(0, action.payload.idx), ...newPath.slice(action.payload.idx + 1)],
59
            }
60
        },
61
        // Changes marker index
62
        changeMarkerIdx: (state: TrackingToolState, action: { payload: { destination: number, source: number } }) => {
63
            const { destination, source } = action.payload
64
            const newPath = [...state.displayedPath ?? []]
65
            if (newPath.length <= source
66
                || newPath.length <= destination
67
                || source === destination) {
68
                return state // do nothing if there is no path
69
            }
70

    
71
            // JS array dark magic
72
            const [removed] = newPath.splice(action.payload.source, 1)
73
            newPath.splice(destination, 0, removed)
74
            return {
75
                ...state,
76
                displayedPath: newPath.map((item, idx) => ({ ...item, idx })),
77
            }
78
        },
79
        clear: () => ({ ...initialState }),
80
        mergeWithCurrentPath: (state: TrackingToolState, action: { payload: PathVariant }) => {
81
            const { payload: jsonPath } = action
82
            if (!jsonPath) {
83
                return state
84
            }
85

    
86
            const newPath = [...state.displayedPath ?? []]
87
            const existingIds = new Set(newPath.map(item => item.id ?? ''))
88
            const newItems: MapPoint[] = []
89
            jsonPath.forEach(item => {
90
                if (!existingIds.has(item.id ?? '')) {
91
                    newItems.push(item)
92
                }
93
            })
94

    
95
            newItems.forEach(item => {
96
                item.addToPath = !state.pathVariants || state.pathVariants.length === 0
97
                item.idx = newPath.length
98
                const uuid = generateUuid()
99
                item.reactId = uuid
100
                item.id = item.catalogItem.id ? item.catalogItem.id : uuid
101
                newPath.push(item)
102
            })
103

    
104
            return {
105
                ...state,
106
                displayedPath: newPath,
107
            }
108
        },
109
        // Updates currently used path - payload must be a number indexed from 1 since this is default behavior
110
        // for MUI Pagination
111
        // This function should only ever be called if there is some displayed path
112
        setDisplayedPathIdx: (state: TrackingToolState, action: { payload: number }) => {
113
            const newIdx = action.payload - 1 // subtract one to make index start from 0
114
            const pathVariants = [...state.pathVariants ?? []]
115
            const previousIdx = state.displayedPathIdx
116
            if (pathVariants.length < newIdx || newIdx < 0) {
117
                return state
118
            }
119

    
120
            // We will always have displayedPath defined if this function is called
121
            pathVariants.splice(previousIdx, 0, [...state.displayedPath ?? []])
122
            const newPath = setMapPointIds(pathVariants.splice(newIdx, 1)[0])
123
            return {
124
                ...state,
125
                displayedPath: newPath,
126
                displayedPathIdx: newIdx,
127
                pathVariants,
128
            }
129
        },
130
    },
131
    extraReducers: (builder) => {
132
        builder.addCase(sendTextForProcessing.fulfilled, (state, action) => {
133
            const pathDto: PathDto = action.payload
134
            const pathVariants = buildPathVariants(pathDto)
135
            const selectedPath = pathVariants.length > 0 ? setMapPointIds(pathVariants[0]) : undefined
136
            pathVariants.splice(0, 1) // remove the selected path so that we do not have to update it here
137
            if (!selectedPath) {
138
                return {
139
                    ...state,
140
                    pathDto,
141
                    pathVariants,
142
                    displayedPath: undefined,
143
                    displayedPathIdx: 0,
144
                    dialogApiCallSuccess: true,
145
                    isLoading: false,
146
                }
147
            }
148

    
149
            const mapCenter = calculateMapCenter(selectedPath)
150
            return {
151
                ...state,
152
                pathVariants,
153
                pathDto,
154
                mapCenter: mapCenter ?? state.mapCenter,
155
                isLoading: false,
156
                dialogApiCallSuccess: true,
157
                currentPage: 0,
158
                displayedPath: selectedPath,
159
                displayedPathIdx: 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
            displayedPath: undefined,
169
            displayedPathIdx: 0,
170
            pathDto: undefined,
171
            pathVariants: undefined,
172
        }))
173
        builder.addCase(sendTextForProcessing.pending, (state) => ({
174
            ...state,
175
            isLoading: true,
176
            dialogApiCallSuccess: false,
177
        }))
178
    }
179
})
180

    
181
export const {
182
    consumeErr,
183
    setSelectedPathIdx,
184
    resetDialogApiCallSuccess,
185
    updateDisplayedPath,
186
    updateMapPoint,
187
    removeMapMarker,
188
    changeMarkerIdx,
189
    clear,
190
    mergeWithCurrentPath,
191
    setDisplayedPathIdx,
192
    updateMapPointAtIndex
193
} = trackingToolSlice.actions
194

    
195
const trackingToolReducer = trackingToolSlice.reducer
196
export default trackingToolReducer
(3-3/5)