refactor: refine type definitions
[e-mobility-charging-stations-simulator.git] / ui / web / src / views / ChargingStationsView.vue
CommitLineData
32de5a57 1<template>
ca1e5439 2 <Container id="charging-stations-container">
239bd875
JB
3 <Container id="buttons-container">
4 <Container
5 v-show="Array.isArray(uiServerConfigurations) && uiServerConfigurations.length > 1"
6 id="ui-server-container"
0344ad2b 7 >
239bd875
JB
8 <select
9 id="ui-server-selector"
10 v-model="state.uiServerIndex"
11 @change="
12 () => {
13 if (
14 getFromLocalStorage<number>('uiServerConfigurationIndex', 0) !== state.uiServerIndex
15 ) {
f4b3f35d
JB
16 $uiClient.setConfiguration(
17 ($configuration.value.uiServer as UIServerConfigurationSection[])[
18 state.uiServerIndex
19 ]
20 )
aa9b0a1e 21 registerWSEventListeners()
7e315430 22 $uiClient.registerWSEventListener(
239bd875
JB
23 'open',
24 () => {
25 setToLocalStorage<number>('uiServerConfigurationIndex', state.uiServerIndex)
26 clearToggleButtons()
877b880c 27 $route.name !== 'charging-stations' &&
239bd875
JB
28 $router.push({ name: 'charging-stations' })
29 },
30 { once: true }
31 )
7e315430 32 $uiClient.registerWSEventListener(
239bd875
JB
33 'error',
34 () => {
35 state.uiServerIndex = getFromLocalStorage<number>(
36 'uiServerConfigurationIndex',
37 0
38 )
7e315430 39 $uiClient.setConfiguration(
f4b3f35d 40 ($configuration.value.uiServer as UIServerConfigurationSection[])[
239bd875
JB
41 getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
42 ]
43 )
aa9b0a1e 44 registerWSEventListeners()
239bd875
JB
45 },
46 { once: true }
47 )
48 }
49 }
50 "
0344ad2b 51 >
239bd875
JB
52 <option
53 v-for="uiServerConfiguration in uiServerConfigurations"
54 :value="uiServerConfiguration.index"
55 >
56 {{
57 uiServerConfiguration.configuration.name ?? uiServerConfiguration.configuration.host
58 }}
59 </option>
60 </select>
61 </Container>
240fa4da
JB
62 <ToggleButton
63 :id="'simulator'"
64 :key="state.renderSimulator"
f6cb1767 65 :status="simulatorState?.started"
240fa4da
JB
66 :on="() => startSimulator()"
67 :off="() => stopSimulator()"
ec7366ed 68 :class="simulatorButtonClass"
240fa4da 69 >
ec7366ed 70 {{ simulatorButtonMessage }}
240fa4da 71 </ToggleButton>
2610da71
JB
72 <ToggleButton
73 :id="'add-charging-stations'"
d64ea57b 74 :key="state.renderAddChargingStations"
2610da71
JB
75 :shared="true"
76 :on="
77 () => {
78 $router.push({ name: 'add-charging-stations' })
79 }
80 "
81 :off="
82 () => {
83 $router.push({ name: 'charging-stations' })
84 }
85 "
83468764
JB
86 @clicked="
87 () => {
88 state.renderChargingStations = randomUUID()
89 }
90 "
2610da71 91 >
1eb5f592 92 Add Charging Stations
2610da71 93 </ToggleButton>
b9d447d2
JB
94 <ReloadButton
95 id="reload-button"
26cf7d99
JB
96 :loading="state.gettingChargingStations"
97 @click="getChargingStations()"
b9d447d2 98 />
13c19b7b 99 </Container>
5c0e9352 100 <CSTable
7e315430 101 v-show="Array.isArray($chargingStations.value) && $chargingStations.value.length > 0"
3eea3ebc 102 :key="state.renderChargingStations"
7e315430 103 :charging-stations="$chargingStations.value"
83468764
JB
104 @need-refresh="
105 () => {
106 state.renderAddChargingStations = randomUUID()
107 state.renderChargingStations = randomUUID()
108 }
109 "
5c0e9352 110 />
32de5a57
LM
111 </Container>
112</template>
113
114<script setup lang="ts">
f6cb1767 115import { computed, getCurrentInstance, onMounted, onUnmounted, ref, watch } from 'vue'
cea23fa0 116import { useToast } from 'vue-toast-notification'
66a7748d 117import CSTable from '@/components/charging-stations/CSTable.vue'
f4b3f35d
JB
118import type {
119 ChargingStationData,
120 ResponsePayload,
121 SimulatorState,
122 UIServerConfigurationSection
123} from '@/types'
66a7748d
JB
124import Container from '@/components/Container.vue'
125import ReloadButton from '@/components/buttons/ReloadButton.vue'
2610da71 126import {
b767fda7 127 deleteFromLocalStorage,
2610da71
JB
128 getFromLocalStorage,
129 getLocalStorage,
130 randomUUID,
39cd8fcb
JB
131 setToLocalStorage,
132 useUIClient
2610da71
JB
133} from '@/composables'
134import ToggleButton from '@/components/buttons/ToggleButton.vue'
a4868fd7 135
f6cb1767
JB
136const simulatorState = ref<SimulatorState | undefined>(undefined)
137
138const simulatorButtonClass = computed<string>(() =>
139 simulatorState.value?.started === true ? 'simulator-stop-button' : 'simulator-start-button'
140)
141const simulatorButtonMessage = computed<string>(
142 () =>
143 `${simulatorState.value?.started === true ? 'Stop' : 'Start'} Simulator${simulatorState.value?.version != null ? ` (${simulatorState.value.version})` : ''}`
144)
145
240fa4da
JB
146const state = ref<{
147 renderSimulator: `${string}-${string}-${string}-${string}-${string}`
148 renderAddChargingStations: `${string}-${string}-${string}-${string}-${string}`
149 renderChargingStations: `${string}-${string}-${string}-${string}-${string}`
26cf7d99
JB
150 gettingSimulatorState: boolean
151 gettingTemplates: boolean
152 gettingChargingStations: boolean
240fa4da
JB
153 uiServerIndex: number
154}>({
155 renderSimulator: randomUUID(),
156 renderAddChargingStations: randomUUID(),
157 renderChargingStations: randomUUID(),
26cf7d99
JB
158 gettingSimulatorState: false,
159 gettingTemplates: false,
160 gettingChargingStations: false,
240fa4da
JB
161 uiServerIndex: getFromLocalStorage<number>('uiServerConfigurationIndex', 0)
162})
163
d64ea57b
JB
164const clearToggleButtons = (): void => {
165 for (const key in getLocalStorage()) {
166 if (key.includes('toggle-button')) {
b767fda7 167 deleteFromLocalStorage(key)
d64ea57b
JB
168 }
169 }
26cf7d99
JB
170 state.value.renderChargingStations = randomUUID()
171 state.value.renderAddChargingStations = randomUUID()
d64ea57b
JB
172}
173
97cd0ef3
JB
174const app = getCurrentInstance()
175
f4b3f35d 176watch(app!.appContext.config.globalProperties.$chargingStations, () => {
f6cb1767
JB
177 state.value.renderChargingStations = randomUUID()
178})
179
180watch(simulatorState, () => {
181 state.value.renderSimulator = randomUUID()
182})
183
184const clearTemplates = (): void => {
185 if (app != null) {
186 app.appContext.config.globalProperties.$templates.value = []
187 }
188}
189
d64ea57b 190const clearChargingStations = (): void => {
26cf7d99 191 if (app != null) {
7e315430 192 app.appContext.config.globalProperties.$chargingStations.value = []
26cf7d99 193 }
d64ea57b
JB
194}
195
39cd8fcb 196const uiClient = useUIClient()
240fa4da 197
97cd0ef3
JB
198const $toast = useToast()
199
240fa4da 200const getSimulatorState = (): void => {
26cf7d99
JB
201 if (state.value.gettingSimulatorState === false) {
202 state.value.gettingSimulatorState = true
3b0c6e17 203 uiClient
26cf7d99 204 .simulatorState()
3b0c6e17 205 .then((response: ResponsePayload) => {
f6cb1767 206 simulatorState.value = response.state as SimulatorState
3b0c6e17
JB
207 })
208 .catch((error: Error) => {
26cf7d99
JB
209 $toast.error('Error at fetching simulator state')
210 console.error('Error at fetching simulator state:', error)
3b0c6e17 211 })
240fa4da 212 .finally(() => {
26cf7d99 213 state.value.gettingSimulatorState = false
240fa4da 214 })
26cf7d99
JB
215 }
216}
217
97cd0ef3
JB
218const getTemplates = (): void => {
219 if (state.value.gettingTemplates === false) {
220 state.value.gettingTemplates = true
221 uiClient
222 .listTemplates()
223 .then((response: ResponsePayload) => {
224 if (app != null) {
f4b3f35d 225 app.appContext.config.globalProperties.$templates.value = response.templates as string[]
97cd0ef3
JB
226 }
227 })
228 .catch((error: Error) => {
f6cb1767 229 clearTemplates()
97cd0ef3
JB
230 $toast.error('Error at fetching charging station templates')
231 console.error('Error at fetching charging station templates:', error)
232 })
233 .finally(() => {
234 state.value.gettingTemplates = false
235 })
236 }
916fe456
JB
237}
238
26cf7d99
JB
239const getChargingStations = (): void => {
240 if (state.value.gettingChargingStations === false) {
241 state.value.gettingChargingStations = true
57c0ba05
JB
242 uiClient
243 .listChargingStations()
244 .then((response: ResponsePayload) => {
245 if (app != null) {
f4b3f35d
JB
246 app.appContext.config.globalProperties.$chargingStations.value =
247 response.chargingStations as ChargingStationData[]
57c0ba05
JB
248 }
249 })
250 .catch((error: Error) => {
f6cb1767 251 clearChargingStations()
cea23fa0 252 $toast.error('Error at fetching charging stations')
57c0ba05
JB
253 console.error('Error at fetching charging stations:', error)
254 })
255 .finally(() => {
26cf7d99 256 state.value.gettingChargingStations = false
57c0ba05 257 })
2113b3c6 258 }
32de5a57 259}
5a010bf0 260
aa9b0a1e
JB
261const getData = (): void => {
262 getSimulatorState()
263 getTemplates()
264 getChargingStations()
265}
266
267const registerWSEventListeners = () => {
268 uiClient.registerWSEventListener('open', getData)
97cd0ef3
JB
269 uiClient.registerWSEventListener('error', clearChargingStations)
270 uiClient.registerWSEventListener('close', clearChargingStations)
271}
272
aa9b0a1e
JB
273const unregisterWSEventListeners = () => {
274 uiClient.unregisterWSEventListener('open', getData)
275 uiClient.unregisterWSEventListener('error', clearChargingStations)
276 uiClient.unregisterWSEventListener('close', clearChargingStations)
277}
278
97cd0ef3 279onMounted(() => {
aa9b0a1e
JB
280 registerWSEventListeners()
281})
282
283onUnmounted(() => {
284 unregisterWSEventListeners()
97cd0ef3
JB
285})
286
f4b3f35d
JB
287const uiServerConfigurations: { index: number; configuration: UIServerConfigurationSection }[] = (
288 app?.appContext.config.globalProperties.$configuration.value
289 .uiServer as UIServerConfigurationSection[]
290).map((configuration: UIServerConfigurationSection, index: number) => ({
291 index,
292 configuration
293}))
97cd0ef3 294
fa5d129a 295const startSimulator = (): void => {
cea23fa0
JB
296 uiClient
297 .startSimulator()
298 .then(() => {
299 $toast.success('Simulator successfully started')
300 })
301 .catch((error: Error) => {
302 $toast.error('Error at starting simulator')
303 console.error('Error at starting simulator:', error)
304 })
240fa4da
JB
305 .finally(() => {
306 getSimulatorState()
307 })
5a010bf0 308}
fa5d129a 309const stopSimulator = (): void => {
cea23fa0
JB
310 uiClient
311 .stopSimulator()
312 .then(() => {
f6cb1767 313 clearChargingStations()
cea23fa0
JB
314 $toast.success('Simulator successfully stopped')
315 })
316 .catch((error: Error) => {
317 $toast.error('Error at stopping simulator')
318 console.error('Error at stopping simulator:', error)
319 })
240fa4da
JB
320 .finally(() => {
321 getSimulatorState()
322 })
5a010bf0 323}
32de5a57
LM
324</script>
325
326<style>
ca1e5439 327#charging-stations-container {
1d41bc6b 328 height: fit-content;
32de5a57 329 width: 100%;
5a010bf0 330 display: flex;
32de5a57 331 flex-direction: column;
5a010bf0
JB
332}
333
0344ad2b
JB
334#ui-server-container {
335 display: flex;
239bd875 336 justify-content: center;
754d8199 337 border-style: outset;
0344ad2b
JB
338}
339
340#ui-server-selector {
341 width: 100%;
239bd875 342 background-color: rgb(239, 239, 239);
c6308554 343 font: small-caption;
0344ad2b
JB
344 text-align: center;
345}
346
239bd875 347#ui-server-selector:hover {
bad93db3 348 background-color: rgb(229, 229, 229);
239bd875
JB
349}
350
13c19b7b
JB
351#buttons-container {
352 display: flex;
353 flex-direction: row;
354}
355
6027002f 356.simulator-start-button {
3802683b
JB
357 color: ivory;
358 background-color: green;
359}
360
fec03138 361.simulator-start-button:hover {
fec03138
JB
362 background-color: rgb(0, 98, 0);
363}
364
6027002f 365.simulator-stop-button {
3802683b
JB
366 color: ivory;
367 background-color: red;
368}
369
fec03138
JB
370.simulator-stop-button:hover {
371 background-color: rgb(225, 0, 0);
372}
373
14ee627a
JB
374#action-button {
375 flex: none;
878855a2
JB
376}
377
32de5a57 378#reload-button {
3802683b 379 color: ivory;
9dc8b66f 380 background-color: blue;
c6308554 381 font-size: 2rem;
32de5a57
LM
382}
383
384#reload-button:hover {
9dc8b66f 385 background-color: rgb(0, 0, 225);
32de5a57
LM
386}
387
388#reload-button:active {
4b10e4f9 389 background-color: darkblue;
32de5a57 390}
229d8c34
JB
391
392#action {
916f0920 393 min-width: max-content;
3802683b 394 color: ivory;
229d8c34 395 background-color: black;
916f0920 396 padding: 0.8%;
229d8c34 397}
32de5a57 398</style>