@olea-bps/base 1.1.11 → 1.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,18 +12,18 @@
12
12
  * limitations under the License.
13
13
  */
14
14
 
15
- import { createContext, useCallback, useEffect, useContext, useReducer, useMemo } from 'react'
15
+ import { createContext, useCallback, useEffect, useContext, useReducer, useMemo, useState } from 'react'
16
16
  import { connect, useDispatch, useSelector } from 'react-redux'
17
- import { useTheme } from 'react-native-paper';
17
+ import { useTheme } from 'react-native-paper'
18
18
  import AsyncStorage from '@react-native-async-storage/async-storage'
19
- import { DateTime } from 'luxon';
19
+ import { DateTime } from 'luxon'
20
20
 
21
- import { onSettingCanteenMerge, useStagingServer } from '../../libraries/core';
22
- import { useUser } from '../context-user';
23
- import { intersection } from 'lodash';
21
+ import { onSettingCanteenMerge, useStagingServer } from '../../libraries/core'
22
+ import { useUser } from '../context-user'
23
+ import { intersection } from 'lodash'
24
24
 
25
- import CollektorVersion2ApiProvider, { NotModifiedResponse } from './CollektorVersion2ApiProvider.js';
26
- import AsistServerApiProvider from './AsistServerApiProvider.js';
25
+ import CollektorVersion2ApiProvider, { NotModifiedResponse } from './CollektorVersion2ApiProvider.js'
26
+ import AsistServerApiProvider from './AsistServerApiProvider.js'
27
27
 
28
28
  /**
29
29
  * @typedef {Object} Canteen
@@ -34,23 +34,27 @@ import AsistServerApiProvider from './AsistServerApiProvider.js';
34
34
  * @typedef {Object.<string, Canteen>} CanteenState
35
35
  */
36
36
 
37
- const AsistServerProviderName = 'asist-server';
38
- const CollectorVersion2ProviderName = 'hs-collector-v2';
37
+ const AsistServerProviderName = 'asist-server'
38
+ const CollectorVersion2ProviderName = 'hs-collector-v2'
39
39
 
40
40
  // Create a context for the canteen data
41
41
  const CanteenContext = createContext({
42
- canteens: {},
43
- });
42
+ canteens: {}
43
+ })
44
44
 
45
- const CanteensStoreKey = 'canteen:canteens';
45
+ const CanteensStoreKey = 'canteen:canteens'
46
46
  const FavoriteCanteensStoreKey = 'canteen:favorite_canteens'
47
47
 
48
- const RestoreCanteens = 'restore_canteens';
49
- const SetMenuAction = 'set_menu';
50
- const SetCanteenAction = 'set_canteen';
48
+ const RestoreCanteens = 'restore_canteens'
49
+ const SetMenuAction = 'set_menu'
50
+ const SetCanteenAction = 'set_canteen'
51
51
  const RemoveUnusedCanteensAction = 'remove_unused_canteens'
52
52
  const RemoveUnusedMenusAction = 'remove_unused_menus'
53
53
 
54
+ function hasCanteenTitle (canteen) {
55
+ return typeof canteen?.title === 'string' && canteen.title.trim().length > 0
56
+ }
57
+
54
58
  /**
55
59
  *
56
60
  * @param {CanteenState} state
@@ -58,92 +62,105 @@ const RemoveUnusedMenusAction = 'remove_unused_menus'
58
62
  * @param {string} action.type
59
63
  * @returns {CanteenState}
60
64
  */
61
- function CanteensStateReducer(state, action) {
62
- switch (action.type) {
63
-
64
- // Essensangebot einer Mensa zuordnen
65
- case SetMenuAction: {
66
- const canteenId = action.canteenId;
67
- const menuDate = action.date;
68
- const menu = action.menu;
69
-
70
- // Einfügen des Essensangebot(menu) für eine Mensa(canteenId) an einem Tag(menuDate)
71
- return {
72
- // Kopieren der vorherigen Mensen
73
- ...state ?? {},
74
- //Mense mit id(canteenId) neu erstellen
75
- [canteenId]: {
76
- // Kopieren der vorherigen Daten der Mense
77
- ...state?.[canteenId] ?? {},
78
- // Essensangebote werden neu erstellt
79
- menus: {
80
- // Kopieren der alten Essensangebote
81
- ...state?.[canteenId]?.menus ?? {},
82
- // Es wird das Essensangebote(menu) für ein Datum(menuDate) hinterlegt
83
- [menuDate]: menu,
84
- }
85
- }
86
- };
87
- }
88
-
89
- // Anhand eines Datums werden alte Mensen entfernt
90
- case RemoveUnusedMenusAction: {
91
- const expiryDate = action.expiryDate;
92
- const expiryTimestamp = Date.parse(expiryDate);
93
-
94
- return Object.fromEntries(
95
- Object.entries(state ?? {})
96
- .map(
97
- ([canteenId, canteenData]) =>
98
- [
99
- canteenId,
100
- {
101
- ...canteenData,
102
- menus: Object.fromEntries(
103
- Object.entries(canteenData?.menus ?? {})
104
- .filter(([menuDate, menu]) => Date.parse(menuDate) >= expiryTimestamp)
105
- )
106
- }
107
- ]
108
- )
109
- );
65
+ function CanteensStateReducer (state, action) {
66
+ switch (action.type) {
67
+ // Essensangebot einer Mensa zuordnen
68
+ case SetMenuAction: {
69
+ const canteenId = action.canteenId
70
+ const menuDate = action.date
71
+ const menu = action.menu
72
+
73
+ if (hasCanteenTitle(state?.[canteenId])) {
74
+ // Einfügen des Essensangebot(menu) für eine Mensa(canteenId) an einem Tag(menuDate)
75
+ return {
76
+ // Kopieren der vorherigen Mensen
77
+ ...state ?? {},
78
+ // Bestehende Mensa aktualisieren
79
+ [canteenId]: {
80
+ // Kopieren der vorherigen Daten der Mense
81
+ ...state?.[canteenId] ?? {},
82
+ // Essensangebote werden neu erstellt
83
+ menus: {
84
+ // Kopieren der alten Essensangebote
85
+ ...state?.[canteenId]?.menus ?? {},
86
+ // Es wird das Essensangebote(menu) für ein Datum(menuDate) hinterlegt
87
+ [menuDate]: menu
88
+ }
89
+ }
110
90
  }
91
+ } else {
92
+ // Late menu responses must not recreate a canteen removed by the server list.
93
+ return state
94
+ }
95
+ }
111
96
 
112
- // Es werden die Basisdaten einer Mensa hinzugefügt oder aktualisiert
113
- case SetCanteenAction: {
114
- const canteen = action.canteen;
115
-
116
- return {
117
- ...state ?? {},
118
- [canteen.id]: {
119
- ...state?.[canteen.id] ?? {},
120
- ...canteen,
97
+ // Anhand eines Datums werden alte Mensen entfernt
98
+ case RemoveUnusedMenusAction: {
99
+ const expiryDate = action.expiryDate
100
+ const expiryTimestamp = Date.parse(expiryDate)
101
+
102
+ return Object.fromEntries(
103
+ Object.entries(state ?? {})
104
+ .map(
105
+ ([canteenId, canteenData]) =>
106
+ [
107
+ canteenId,
108
+ {
109
+ ...canteenData,
110
+ menus: Object.fromEntries(
111
+ Object.entries(canteenData?.menus ?? {})
112
+ .filter(([menuDate, menu]) => Date.parse(menuDate) >= expiryTimestamp)
113
+ )
121
114
  }
122
- };
123
- }
115
+ ]
116
+ )
117
+ )
118
+ }
124
119
 
125
- // Anhand einer Liste von Mensa-IDs werden alte Mensen entfernt
126
- case RemoveUnusedCanteensAction: {
127
- const activeCanteenIds = action.activeCanteenIds;
120
+ // Es werden die Basisdaten einer Mensa hinzugefügt oder aktualisiert
121
+ case SetCanteenAction: {
122
+ const canteen = action.canteen
128
123
 
129
- return Object.fromEntries(
130
- Object.entries(state ?? {})
131
- .filter(([canteenId, canteenData]) => activeCanteenIds.includes(canteenId))
132
- );
124
+ return {
125
+ ...state ?? {},
126
+ [canteen.id]: {
127
+ ...state?.[canteen.id] ?? {},
128
+ ...canteen
133
129
  }
130
+ }
131
+ }
134
132
 
135
- // Mensen und zugehörige Essensangebote aus dem Cache wiederherstellen
136
- case RestoreCanteens: {
137
- const restoredCanteens = action.canteens;
133
+ // Anhand einer Liste von Mensa-IDs werden alte Mensen entfernt
134
+ case RemoveUnusedCanteensAction: {
135
+ const activeCanteenIds = action.activeCanteenIds.map(String)
138
136
 
139
- return state
140
- ? { ...state }
141
- : restoredCanteens;
142
- }
137
+ return Object.fromEntries(
138
+ Object.entries(state ?? {})
139
+ .filter(([canteenId, canteenData]) => activeCanteenIds.includes(canteenId))
140
+ )
141
+ }
142
+
143
+ // Mensen und zugehörige Essensangebote aus dem Cache wiederherstellen
144
+ case RestoreCanteens: {
145
+ // Remove incomplete entries persisted by older app versions, also offline.
146
+ // Entries are considered incomplete if their canteen title is missing or blank.
147
+ const restoredCanteens = Object.fromEntries(
148
+ Object.entries(action.canteens ?? {})
149
+ .filter(([, canteen]) => hasCanteenTitle(canteen))
150
+ )
151
+
152
+ return state
153
+ ? { ...state }
154
+ : restoredCanteens
143
155
  }
156
+
157
+ default:
158
+ // Preserve the current state for unhandled actions instead of returning undefined.
159
+ return state
160
+ }
144
161
  }
145
162
 
146
- const SetCanteensAction = 'set_canteens_ids';
163
+ const SetCanteensAction = 'set_canteens_ids'
147
164
 
148
165
  /**
149
166
  *
@@ -152,35 +169,36 @@ const SetCanteensAction = 'set_canteens_ids';
152
169
  * @param {string} action.type
153
170
  * @returns {string[]}
154
171
  */
155
- function FavoriteCanteensStateReducer(state, action) {
156
- switch (action.type) {
157
-
158
- // Setzen der IDs der favoriten Mensen
159
- case SetCanteensAction: {
160
- const canteensIds = action?.canteensIds;
161
-
162
- return canteensIds;
163
- }
172
+ function FavoriteCanteensStateReducer (state, action) {
173
+ switch (action.type) {
174
+ // Setzen der IDs der favoriten Mensen
175
+ case SetCanteensAction: {
176
+ const canteensIds = Array.isArray(action?.canteensIds) && action.canteensIds.length > 0
177
+ ? [...new Set(action.canteensIds.map(String))]
178
+ : null
179
+
180
+ return canteensIds
181
+ }
164
182
 
165
- // Filtert IDs aus der Einstellung heraus, welche nicht mehr vom Kollektor übersendet werden
166
- case RemoveUnusedCanteensAction: {
167
- const activeCanteenIds = action?.activeCanteenIds;
183
+ // Filtert IDs aus der Einstellung heraus, welche nicht mehr vom Kollektor übersendet werden
184
+ case RemoveUnusedCanteensAction: {
185
+ const activeCanteenIds = action.activeCanteenIds.map(String)
168
186
 
169
- const favoriteCanteensIds = intersection(state, activeCanteenIds);
187
+ const favoriteCanteensIds = intersection(state, activeCanteenIds)
170
188
 
171
- return Array.isArray(favoriteCanteensIds) && favoriteCanteensIds.length > 0
172
- ? favoriteCanteensIds
173
- : null;
174
- }
189
+ return Array.isArray(favoriteCanteensIds) && favoriteCanteensIds.length > 0
190
+ ? favoriteCanteensIds
191
+ : null
192
+ }
175
193
 
176
- // Falls ein unbekannter Actionstyp übergeben wurde, wird nichts gemacht
177
- default: {
178
- return state;
179
- }
194
+ // Falls ein unbekannter Actionstyp übergeben wurde, wird nichts gemacht
195
+ default: {
196
+ return state
180
197
  }
198
+ }
181
199
  }
182
200
 
183
- //const providersInitializers = {
201
+ // const providersInitializers = {
184
202
  // 'hs-collector-v2': ({appSettings }) => {
185
203
  // const baseUrl = appSettings?.modules?.canteen?.api?.baseUrl;
186
204
  // CollektorVersion2ApiProvider.from(baseUrl,)
@@ -188,359 +206,369 @@ function FavoriteCanteensStateReducer(state, action) {
188
206
  // 'asist-server': ({ }) => {
189
207
  //
190
208
  // },
191
- //}
209
+ // }
192
210
 
193
211
  // Define a provider component for the canteen context
194
- function CanteenContextProvider({ children, settings, rootUrl, rootStgUrl, useStaging }) {
195
- const componentName = CanteenContextProvider.name;
212
+ function CanteenContextProvider ({ children, settings, rootUrl, rootStgUrl, useStaging }) {
213
+ const componentName = CanteenContextProvider.name
196
214
 
197
- const reduxDispatch = useDispatch();
198
- const [user] = useUser();
199
- const theme = useTheme();
215
+ const reduxDispatch = useDispatch()
216
+ const [user] = useUser()
217
+ const theme = useTheme()
200
218
 
201
- const appSettings = theme?.appSettings;
202
- const groupsOfPersons = appSettings?.groupsOfPersons;
203
- const language = settings.language;
204
- const availableSelections = theme?.appSettings?.mealSelections;
205
- const favoriteSelections = settings?.settingsCanteens?.favoriteSelection;
219
+ const appSettings = theme?.appSettings
220
+ const groupsOfPersons = appSettings?.groupsOfPersons
221
+ const language = settings.language
222
+ const availableSelections = theme?.appSettings?.mealSelections
223
+ const favoriteSelections = settings?.settingsCanteens?.favoriteSelection
206
224
 
207
- // Ermitteln des Preisgruppen-Codes des Nutzers
208
- const priceGroupCode =
225
+ // Ermitteln des Preisgruppen-Codes des Nutzers
226
+ const priceGroupCode =
209
227
  // Wenn der Nutzer selber eine Preisgruppe festgelegt hast, ist diese im Redux hinterlegt
210
228
  // Prüfen ob im Redux eine Preisgruppe hinterlegt ist
211
229
  useSelector(
212
- (reduxState) =>
213
- // Wenn der Preisgruppen-Code ein leerer String ist, wird stattdessen null zurückgegeben
214
- reduxState?.settingReducer?.settingsCanteens?.favoritePrice
215
- ? reduxState?.settingReducer?.settingsCanteens?.favoritePrice
216
- : null
217
- )
230
+ (reduxState) =>
231
+ // Wenn der Preisgruppen-Code ein leerer String ist, wird stattdessen null zurückgegeben
232
+ reduxState?.settingReducer?.settingsCanteens?.favoritePrice
233
+ ? reduxState?.settingReducer?.settingsCanteens?.favoritePrice
234
+ : null
235
+ ) ??
218
236
  // Ist im Redux keine Preisgruppe hinterlegt, wird anhand des angemeldeten Nutzers die Preisgruppe ermittelt
219
237
  // Dabei werden die Angehörigkeiten(user.member_types) des Nutzer mit den möglichen Personengruppen-Codes verglichen
220
238
  // Ist eine Angehörigkeit, welche einem Code einer Personengruppe gleicht, vorhanden, wird die entsprechende Personengruppe verwendet
221
239
  // Besitzt ein Nutzer mehrer Angehörigkeiten (z.B. Student, Mitarbeiter) wird anhand der Reihenfolge der Personengruppen in der Settings.js priorisiert.
222
240
  // Dabei besetzt die erste bzw. oberste Personengruppe die höchste Priorität
223
- ?? groupsOfPersons.find((personGroup) => user?.member_types?.includes?.(personGroup?.code))?.code
241
+ groupsOfPersons.find((personGroup) => user?.member_types?.includes?.(personGroup?.code))?.code ??
224
242
  // Wenn der Nutzer nicht eingeloogt ist oder durch den Angehörigkeiten keine Personengruppe ermittelt werden konnt, wird die Standartgruppe ausgewählt
225
243
  // Bei der Standartpersonengruppe ist in der Sttings.js das 'default'-Feld auf Wahr/true gesetzt.
226
- ?? groupsOfPersons.find(personGroup => personGroup?.default)?.code;
227
-
228
- // Daten für Essenstypen
229
- const availableMealTypes = theme?.appSettings?.mealTypes;
230
- const favoriteMealTypes = settings?.settingsCanteens?.favoriteMealTypes;
231
-
232
- // Einstellung für Serverauswahl
233
- const isStagingServerActive = useStagingServer();
234
-
235
- // Einstellungen für Mensa-Modul
236
- const canteenSettings = appSettings?.modules?.canteen;
237
-
238
- // Einstellungen für Fallback API-Provider
239
- const fallbackApiSettings = theme?.appSettings?.api;
240
- const fallbackApiProvider = AsistServerProviderName;
241
- const fallbackApiBaseUrl = (isStagingServerActive ? fallbackApiSettings.rootStgUrl : fallbackApiSettings.rootUrl) + 'app/';
242
- const fallbbackApiUniversity = fallbackApiSettings?.university;
243
-
244
- // Einstellungen für API-Provider
245
- const canteenApiSettings = canteenSettings.api;
246
- // Soll der Staging-Provider verwendet werden?
247
- const canteenApiProviderSettings = isStagingServerActive
248
- // Wenn ja, werden die Staging Provider-Einstellungen geladen
249
- ? canteenApiSettings?.staging
250
- // Wenn nein, werden die productiven Provider-Einstellungen geladen
251
- : canteenApiSettings?.production;
252
- const canteenApiProvider = canteenApiProviderSettings?.provider ?? fallbackApiProvider;
253
- const canteenApiBaseUrl = canteenApiProviderSettings?.url ?? fallbackApiBaseUrl;
254
- const canteenApiUniversity = canteenApiProviderSettings?.university ?? fallbbackApiUniversity;
255
-
256
- const [canteens, dispatchCanteens] = useReducer(CanteensStateReducer, null);
257
- const [favoriteCanteens, dispatchFavoriteCanteens] = useReducer(FavoriteCanteensStateReducer, null);
258
-
259
- // Einmaliges Laden der gecachten Mensadaten und der zugehörigen Speisepläne aus dem Cache in den Kontext
260
- useEffect(
261
- () => {
262
- AsyncStorage
263
- .getItem(CanteensStoreKey)
264
- .then(storedCanteens => {
265
- dispatchCanteens({ type: RestoreCanteens, canteens: JSON.parse(storedCanteens) });
266
- dispatchCanteens({ type: RemoveUnusedMenusAction, expiryDate: DateTime.now().minus({ weeks: 1 }).endOf('week').toISODate() });
267
- })
268
- .catch(reason => console.error(componentName, ':', 'can not restore canteens', ':', reason, 'key', ':', CanteensStoreKey));
269
- }
270
- , []
271
- )
272
-
273
- // Wenn die Mensa-Daten sich ändern, werden diese in den Cache zurückgespeichert
274
- useEffect(
275
- () => {
276
- if (canteens) {
277
- AsyncStorage
278
- .setItem(CanteensStoreKey, JSON.stringify(canteens))
279
- .catch(reason => console.error(componentName, ':', 'can`t store canteens: ', reason, 'key:', CanteensStoreKey, 'value:', canteens));
280
- }
281
- }
282
- , [canteens]
283
- )
284
-
285
- // Einmaliges laden der favorisirten Mensen
286
- useEffect(
287
- () => {
288
- AsyncStorage
289
- .getItem(FavoriteCanteensStoreKey)
290
- .then(storedFavoriteCanteens => {
291
- console.debug(componentName, ':', 'restore favorite canteens ids', ':', storedFavoriteCanteens);
292
- dispatchFavoriteCanteens({ type: SetCanteensAction, canteensIds: JSON.parse(storedFavoriteCanteens) });
293
- })
294
- .catch(reason => console.error(componentName, ':', 'can not restore favorite canteens ids', ':', reason, 'key', ':', FavoriteCanteensStoreKey));
295
- },
296
- []
297
- )
298
-
299
- // Wenn die favorisirten Mensen sich ändern, werden diese in den Cache zurückgespeichert
300
- useEffect(
301
- () => {
302
- if (Array.isArray(favoriteCanteens)) {
303
- console.debug(componentName, ':', 'store favorite canteens', favoriteCanteens);
304
- AsyncStorage
305
- .setItem(FavoriteCanteensStoreKey, JSON.stringify(favoriteCanteens))
306
- .catch(reason => console.error(componentName, ':', 'can`t store canteens: ', reason, 'key:', FavoriteCanteensStoreKey, 'value:', favoriteCanteens));
307
- }
308
- },
309
- [favoriteCanteens]
310
- )
311
-
312
- console.debug(componentName, ':', 'favorite selections', ':', favoriteSelections);
313
- console.debug(componentName, ':', 'available selections', ':', availableSelections);
314
-
315
- const activeSelections = useMemo(
316
- () => {
317
- if (Array.isArray(favoriteSelections) && favoriteSelections.length > 0 && Array.isArray(availableSelections)) {
318
- return availableSelections
319
- .filter(availableSelection => favoriteSelections.includes(availableSelection.code));
320
- } else {
321
- return null;
322
- }
323
- },
324
- [favoriteSelections, availableSelections]
325
- );
326
-
327
- console.debug(componentName, ':', 'active selections', ':', activeSelections);
328
-
329
- const activeSelectionFilters = useMemo(
330
- () => {
331
- if (Array.isArray(activeSelections) && activeSelections.length > 0) {
332
- return [
333
- ...new Set(
334
- activeSelections
335
- .flatMap(activeSelection => activeSelection?.filters)
336
- )
337
- ];
338
- } else {
339
- return null;
340
- }
341
- },
342
- [activeSelections]
343
- )
344
-
345
- console.debug(componentName, ':', 'active selection filter', ':', activeSelectionFilters);
346
-
347
-
348
- console.debug(componentName, ':', 'available meal typeas', ':', availableMealTypes);
349
- console.debug(componentName, ':', 'favorite meal types', ':', favoriteMealTypes);
350
-
351
- const activeMealtypes = useMemo(
352
- () => {
353
- if (Array.isArray(favoriteMealTypes) && favoriteMealTypes.length > 0 && Array.isArray(availableMealTypes)) {
354
- return availableMealTypes
355
- .filter(activeMealtype => favoriteMealTypes.includes(activeMealtype.code));
356
- }
357
- else {
358
- return null;
359
- }
360
- },
361
- [favoriteMealTypes, availableMealTypes]
362
- )
363
-
364
- console.debug(componentName, ':', 'active meal types', ':', activeMealtypes);
365
-
366
- const activeMealtypeFilters = useMemo(
367
- () => {
368
- if (Array.isArray(activeMealtypes) && activeMealtypes.length > 0) {
369
- return [
370
- ... new Set(
371
- activeMealtypes
372
- .flatMap(activeMealtype => activeMealtype?.filters ?? activeMealtype?.code ?? [])
373
- )
374
- ];
375
- } else {
376
- return null;
377
- }
378
- }
379
- )
380
-
381
- console.debug(componentName, ':', 'active meal type filters', ':', activeMealtypeFilters);
382
-
383
- // Estellen des API-Providers bzw. erneuern wenn sich Einstellungen sich ändern.
384
- const apiProvider = useMemo(
385
- () => {
386
- switch (canteenApiProvider?.toLowerCase()) {
387
- case AsistServerProviderName:
388
- console.debug(componentName, ': use asist server api');
389
- return AsistServerApiProvider.from(canteenApiBaseUrl, canteenApiUniversity, language);
390
- case CollectorVersion2ProviderName:
391
- console.debug(componentName, ': use collector v2 api');
392
- return CollektorVersion2ApiProvider.from(canteenApiBaseUrl, language);
393
- default:
394
- console.log(`${componentName}: Can't build api provider: ${canteenApiProvider}`)
395
- return null;
396
- }
397
- },
398
- [canteenApiSettings, canteenApiProvider, canteenApiBaseUrl, canteenApiUniversity, language]
399
- );
400
-
401
- // Sobald der Mensa-Context erstellt wird, werden die Mensen vom Server geholt
402
- useEffect(
403
- () => {
404
- if (apiProvider) {
405
- apiProvider.getCanteens()
406
- .then(
407
- canteens => {
408
- // Jede Mensa wird einzeln in den Mensa-State hineinreduziert
409
- canteens.forEach(canteen => dispatchCanteens({ type: SetCanteenAction, canteen }));
410
-
411
- // Danach werden die alten Mensen, die nicht in der Serverantwort sind, herausreduziert
412
- // Liste der IDs der in der Serverantwort enthaltenen Mensen erstellen
413
- const activeCanteenIds = canteens.map(canteen => canteen?.id);
414
- // Alte Mensen aus den gecachten Mensa-Daten löschen
415
- dispatchCanteens(
416
- {
417
- type: RemoveUnusedCanteensAction,
418
- activeCanteenIds: activeCanteenIds,
419
- }
420
- );
421
- // Alte Mensen aus den favorisierten Mensen löschen
422
- dispatchFavoriteCanteens(
423
- {
424
- type: RemoveUnusedCanteensAction,
425
- activeCanteenIds: activeCanteenIds,
426
- }
427
- );
428
- }
429
- );
244
+ groupsOfPersons.find(personGroup => personGroup?.default)?.code
245
+
246
+ // Daten für Essenstypen
247
+ const availableMealTypes = theme?.appSettings?.mealTypes
248
+ const favoriteMealTypes = settings?.settingsCanteens?.favoriteMealTypes
249
+
250
+ // Einstellung für Serverauswahl
251
+ const isStagingServerActive = useStagingServer()
252
+
253
+ // Einstellungen für Mensa-Modul
254
+ const canteenSettings = appSettings?.modules?.canteen
255
+
256
+ // Einstellungen für Fallback API-Provider
257
+ const fallbackApiSettings = theme?.appSettings?.api
258
+ const fallbackApiProvider = AsistServerProviderName
259
+ const fallbackApiBaseUrl = (isStagingServerActive ? fallbackApiSettings.rootStgUrl : fallbackApiSettings.rootUrl) + 'app/'
260
+ const fallbbackApiUniversity = fallbackApiSettings?.university
261
+
262
+ // Einstellungen für API-Provider
263
+ const canteenApiSettings = canteenSettings.api
264
+ // Soll der Staging-Provider verwendet werden?
265
+ const canteenApiProviderSettings = isStagingServerActive
266
+ // Wenn ja, werden die Staging Provider-Einstellungen geladen
267
+ ? canteenApiSettings?.staging
268
+ // Wenn nein, werden die productiven Provider-Einstellungen geladen
269
+ : canteenApiSettings?.production
270
+ const canteenApiProvider = canteenApiProviderSettings?.provider ?? fallbackApiProvider
271
+ const canteenApiBaseUrl = canteenApiProviderSettings?.url ?? fallbackApiBaseUrl
272
+ const canteenApiUniversity = canteenApiProviderSettings?.university ?? fallbbackApiUniversity
273
+
274
+ const [canteens, dispatchCanteens] = useReducer(CanteensStateReducer, null)
275
+ const [favoriteCanteens, dispatchFavoriteCanteens] = useReducer(FavoriteCanteensStateReducer, null)
276
+ const [cacheRestored, setCacheRestored] = useState(false)
277
+
278
+ // Einmaliges Laden der gecachten Mensadaten und der zugehörigen Speisepläne aus dem Cache in den Kontext
279
+ useEffect(
280
+ () => {
281
+ let active = true
282
+ const restoreCanteens = AsyncStorage
283
+ .getItem(CanteensStoreKey)
284
+ .then(storedCanteens => {
285
+ if (!active) return
286
+ dispatchCanteens({ type: RestoreCanteens, canteens: JSON.parse(storedCanteens) })
287
+ dispatchCanteens({ type: RemoveUnusedMenusAction, expiryDate: DateTime.now().minus({ weeks: 1 }).endOf('week').toISODate() })
288
+ })
289
+ .catch(reason => console.error(componentName, ':', 'can not restore canteens', ':', reason, 'key', ':', CanteensStoreKey))
290
+
291
+ const restoreFavorites = AsyncStorage
292
+ .getItem(FavoriteCanteensStoreKey)
293
+ .then(storedFavoriteCanteens => {
294
+ if (!active) return
295
+ dispatchFavoriteCanteens({ type: SetCanteensAction, canteensIds: JSON.parse(storedFavoriteCanteens) })
296
+ })
297
+ .catch(reason => console.error(componentName, ':', 'can not restore favorite canteens ids', ':', reason, 'key', ':', FavoriteCanteensStoreKey))
298
+
299
+ // The server list must reconcile both restored caches, never race them.
300
+ Promise.all([restoreCanteens, restoreFavorites]).then(() => {
301
+ if (active) setCacheRestored(true)
302
+ })
303
+
304
+ return () => { active = false }
305
+ }
306
+ , []
307
+ )
308
+
309
+ // Wenn die Mensa-Daten sich ändern, werden diese in den Cache zurückgespeichert
310
+ useEffect(
311
+ () => {
312
+ if (cacheRestored && canteens) {
313
+ AsyncStorage
314
+ .setItem(CanteensStoreKey, JSON.stringify(canteens))
315
+ .catch(reason => console.error(componentName, ':', 'can`t store canteens: ', reason, 'key:', CanteensStoreKey, 'value:', canteens))
316
+ }
317
+ }
318
+ , [cacheRestored, canteens]
319
+ )
320
+
321
+ // Wenn die favorisirten Mensen sich ändern, werden diese in den Cache zurückgespeichert
322
+ useEffect(
323
+ () => {
324
+ if (cacheRestored) {
325
+ console.debug(componentName, ':', 'store favorite canteens', favoriteCanteens)
326
+ AsyncStorage
327
+ .setItem(FavoriteCanteensStoreKey, JSON.stringify(favoriteCanteens))
328
+ .catch(reason => console.error(componentName, ':', 'can`t store canteens: ', reason, 'key:', FavoriteCanteensStoreKey, 'value:', favoriteCanteens))
329
+ }
330
+ },
331
+ [cacheRestored, favoriteCanteens]
332
+ )
333
+
334
+ console.debug(componentName, ':', 'favorite selections', ':', favoriteSelections)
335
+ console.debug(componentName, ':', 'available selections', ':', availableSelections)
336
+
337
+ const activeSelections = useMemo(
338
+ () => {
339
+ if (Array.isArray(favoriteSelections) && favoriteSelections.length > 0 && Array.isArray(availableSelections)) {
340
+ return availableSelections
341
+ .filter(availableSelection => favoriteSelections.includes(availableSelection.code))
342
+ } else {
343
+ return null
344
+ }
345
+ },
346
+ [favoriteSelections, availableSelections]
347
+ )
348
+
349
+ console.debug(componentName, ':', 'active selections', ':', activeSelections)
350
+
351
+ const activeSelectionFilters = useMemo(
352
+ () => {
353
+ if (Array.isArray(activeSelections) && activeSelections.length > 0) {
354
+ return [
355
+ ...new Set(
356
+ activeSelections
357
+ .flatMap(activeSelection => activeSelection?.filters)
358
+ )
359
+ ]
360
+ } else {
361
+ return null
362
+ }
363
+ },
364
+ [activeSelections]
365
+ )
366
+
367
+ console.debug(componentName, ':', 'active selection filter', ':', activeSelectionFilters)
368
+
369
+ console.debug(componentName, ':', 'available meal typeas', ':', availableMealTypes)
370
+ console.debug(componentName, ':', 'favorite meal types', ':', favoriteMealTypes)
371
+
372
+ const activeMealtypes = useMemo(
373
+ () => {
374
+ if (Array.isArray(favoriteMealTypes) && favoriteMealTypes.length > 0 && Array.isArray(availableMealTypes)) {
375
+ return availableMealTypes
376
+ .filter(activeMealtype => favoriteMealTypes.includes(activeMealtype.code))
377
+ } else {
378
+ return null
379
+ }
380
+ },
381
+ [favoriteMealTypes, availableMealTypes]
382
+ )
383
+
384
+ console.debug(componentName, ':', 'active meal types', ':', activeMealtypes)
385
+
386
+ const activeMealtypeFilters = useMemo(
387
+ () => {
388
+ if (Array.isArray(activeMealtypes) && activeMealtypes.length > 0) {
389
+ return [
390
+ ...new Set(
391
+ activeMealtypes
392
+ .flatMap(activeMealtype => activeMealtype?.filters ?? activeMealtype?.code ?? [])
393
+ )
394
+ ]
395
+ } else {
396
+ return null
397
+ }
398
+ }
399
+ )
400
+
401
+ console.debug(componentName, ':', 'active meal type filters', ':', activeMealtypeFilters)
402
+
403
+ // Estellen des API-Providers bzw. erneuern wenn sich Einstellungen sich ändern.
404
+ const apiProvider = useMemo(
405
+ () => {
406
+ switch (canteenApiProvider?.toLowerCase()) {
407
+ case AsistServerProviderName:
408
+ console.debug(componentName, ': use asist server api')
409
+ return AsistServerApiProvider.from(canteenApiBaseUrl, canteenApiUniversity, language)
410
+ case CollectorVersion2ProviderName:
411
+ console.debug(componentName, ': use collector v2 api')
412
+ return CollektorVersion2ApiProvider.from(canteenApiBaseUrl, language)
413
+ default:
414
+ console.log(`${componentName}: Can't build api provider: ${canteenApiProvider}`)
415
+ return null
416
+ }
417
+ },
418
+ [canteenApiSettings, canteenApiProvider, canteenApiBaseUrl, canteenApiUniversity, language]
419
+ )
420
+
421
+ // Sobald der Mensa-Context erstellt wird, werden die Mensen vom Server geholt
422
+ useEffect(
423
+ () => {
424
+ let active = true
425
+ if (apiProvider && cacheRestored) {
426
+ apiProvider.getCanteens()
427
+ .then(
428
+ canteens => {
429
+ if (!active) return
430
+ if (!Array.isArray(canteens) || canteens.some(canteen => canteen?.id == null || !hasCanteenTitle(canteen))) {
431
+ throw new Error('Invalid canteen list')
432
+ }
433
+ // Jede Mensa wird einzeln in den Mensa-State hineinreduziert
434
+ canteens.forEach(canteen => dispatchCanteens({ type: SetCanteenAction, canteen }))
435
+
436
+ // Danach werden die alten Mensen, die nicht in der Serverantwort sind, herausreduziert
437
+ // Liste der IDs der in der Serverantwort enthaltenen Mensen erstellen
438
+ const activeCanteenIds = canteens.map(canteen => canteen?.id)
439
+ // Alte Mensen aus den gecachten Mensa-Daten löschen
440
+ dispatchCanteens(
441
+ {
442
+ type: RemoveUnusedCanteensAction,
443
+ activeCanteenIds
444
+ }
445
+ )
446
+ // Alte Mensen aus den favorisierten Mensen löschen
447
+ dispatchFavoriteCanteens(
448
+ {
449
+ type: RemoveUnusedCanteensAction,
450
+ activeCanteenIds
451
+ }
452
+ )
430
453
  }
431
- },
432
- [apiProvider]
433
- );
434
-
435
- /**
454
+ )
455
+ .catch(reason => console.warn(componentName, ':', 'can not refresh canteens', ':', reason))
456
+ }
457
+ return () => { active = false }
458
+ },
459
+ [apiProvider, cacheRestored]
460
+ )
461
+
462
+ /**
436
463
  * Refresh a menu in canteens object.
437
464
  *
438
465
  * @param {String} canteenId ID of the canteen of the menu to be refreshing
439
466
  * @param {String} date Date of the menu to be refreshing
440
467
  * @returns {Promise<void>} Promise as an indicator of whether the refresh is in progress
441
468
  */
442
- function refreshMenu(canteenId, date) {
443
- return apiProvider.getMenu(canteenId, date)
444
- .then(
445
- menu =>
446
- dispatchCanteens(
447
- {
448
- type: SetMenuAction,
449
- menu,
450
- canteenId: canteenId,
451
- date: date,
452
- }
453
- ),
454
- reason => {
455
- if (reason instanceof NotModifiedResponse) {
456
- console.debug(componentName, ':', 'Meal from', date, 'and canteen', canteenId, 'not modified');
457
- } else {
458
- throw reason;
459
- }
460
- }
461
- );
462
- }
469
+ function refreshMenu (canteenId, date) {
470
+ return apiProvider.getMenu(canteenId, date)
471
+ .then(
472
+ menu =>
473
+ dispatchCanteens(
474
+ {
475
+ type: SetMenuAction,
476
+ menu,
477
+ canteenId,
478
+ date
479
+ }
480
+ ),
481
+ reason => {
482
+ if (reason instanceof NotModifiedResponse) {
483
+ console.debug(componentName, ':', 'Meal from', date, 'and canteen', canteenId, 'not modified')
484
+ } else {
485
+ // Keep cached menus when a request fails (e.g. a removed ID).
486
+ console.warn(componentName, ':', 'can not refresh menu', canteenId, date, ':', reason)
487
+ }
488
+ }
489
+ )
490
+ }
463
491
 
464
- /**
492
+ /**
465
493
  * Setz den vom Nutzer gewünschen Mensapreis, anhand des Codes der entsprechnden Personengruppe.
466
494
  * @function
467
495
  * @param {string} personGroupCode Code der Personengruppe, welche für die Mensapreise zu verwenden ist
468
496
  */
469
- const setPriceGroupCode = useCallback(
470
- /**
497
+ const setPriceGroupCode = useCallback(
498
+ /**
471
499
  * @param {string} personGroupCode Code der Personengruppe, welche für die Mensapreise zu verwenden ist
472
500
  */
473
- (personGroupCode) =>
474
- reduxDispatch(
475
- onSettingCanteenMerge(
476
- "canteenSettings",
477
- { favoritePrice: personGroupCode }
478
- )
479
- ),
480
- [reduxDispatch]
481
- );
501
+ (personGroupCode) =>
502
+ reduxDispatch(
503
+ onSettingCanteenMerge(
504
+ 'canteenSettings',
505
+ { favoritePrice: personGroupCode }
506
+ )
507
+ ),
508
+ [reduxDispatch]
509
+ )
482
510
 
483
- /**
511
+ /**
484
512
  * Setzt die favorsierten Mensen, anhand einer Liste der IDs
485
513
  */
486
- const setFavoriteCanteens = useCallback(
487
- /**
514
+ const setFavoriteCanteens = useCallback(
515
+ /**
488
516
  * @param {string[]} favoriteCanteens IDs der Mensen, die als favorisiert gesetzt werden sollen
489
517
  */
490
- (favoriteCanteens) => {
491
- console.debug(componentName, ':', 'set favorite canteens', ':', favoriteCanteens);
492
- dispatchFavoriteCanteens(
493
- {
494
- type: SetCanteensAction,
495
- canteensIds: favoriteCanteens,
496
- }
497
- );
498
- },
499
- [dispatchFavoriteCanteens, SetCanteensAction]
500
- );
501
-
502
- // Render the provider component with the filtered canteens and canteens data
503
- return (
504
- <CanteenContext.Provider
505
- value={{
506
- canteens: canteens ?? {},
507
- favoriteCanteens: favoriteCanteens ?? Object.keys(canteens ?? {}),
508
- setFavoriteCanteens,
509
- priceGroupCode,
510
- setPriceGroupCode,
511
- activeSelections,
512
- activeSelectionFilters,
513
- activeMealtypes,
514
- activeMealtypeFilters,
515
- refreshMenu,
516
- }}
517
- >
518
- {children}
519
- </CanteenContext.Provider>
520
- );
518
+ (favoriteCanteens) => {
519
+ console.debug(componentName, ':', 'set favorite canteens', ':', favoriteCanteens)
520
+ dispatchFavoriteCanteens(
521
+ {
522
+ type: SetCanteensAction,
523
+ canteensIds: favoriteCanteens
524
+ }
525
+ )
526
+ },
527
+ [dispatchFavoriteCanteens, SetCanteensAction]
528
+ )
529
+
530
+ // Render the provider component with the filtered canteens and canteens data
531
+ return (
532
+ <CanteenContext.Provider
533
+ value={{
534
+ canteens: canteens ?? {},
535
+ favoriteCanteens: (favoriteCanteens ?? Object.keys(canteens ?? {}))
536
+ .filter(canteenId => hasCanteenTitle(canteens?.[canteenId])),
537
+ setFavoriteCanteens,
538
+ priceGroupCode,
539
+ setPriceGroupCode,
540
+ activeSelections,
541
+ activeSelectionFilters,
542
+ activeMealtypes,
543
+ activeMealtypeFilters,
544
+ refreshMenu
545
+ }}
546
+ >
547
+ {children}
548
+ </CanteenContext.Provider>
549
+ )
521
550
  }
522
551
 
523
552
  // Map the Redux state to props
524
553
  const mapStateToProps = storeState => {
525
- return {
526
- settings: storeState.settingReducer,
527
- rootUrl: storeState.settingReducer.api.rootUrl,
528
- rootStgUrl: storeState.settingReducer.api.rootStgUrl,
529
- useStaging: storeState.settingReducer.settingsDevelop.useStaging,
530
- };
531
- };
554
+ return {
555
+ settings: storeState.settingReducer,
556
+ rootUrl: storeState.settingReducer.api.rootUrl,
557
+ rootStgUrl: storeState.settingReducer.api.rootStgUrl,
558
+ useStaging: storeState.settingReducer.settingsDevelop.useStaging
559
+ }
560
+ }
532
561
 
533
562
  // Connect the CanteenContextProvider component to Redux
534
- const ConnectedCanteenContextProvider = connect(mapStateToProps)(CanteenContextProvider);
535
-
563
+ const ConnectedCanteenContextProvider = connect(mapStateToProps)(CanteenContextProvider)
536
564
 
537
565
  // Custom hook to use the CanteenContext
538
- function useCanteenContext() {
539
- const context = useContext(CanteenContext);
540
- if (context === undefined) {
541
- throw new Error('useCanteenContext must be used within a CanteenContextProvider')
542
- }
543
- return context;
566
+ function useCanteenContext () {
567
+ const context = useContext(CanteenContext)
568
+ if (context === undefined) {
569
+ throw new Error('useCanteenContext must be used within a CanteenContextProvider')
570
+ }
571
+ return context
544
572
  }
545
573
 
546
574
  /**
@@ -554,10 +582,10 @@ function useCanteenContext() {
554
582
  *
555
583
  * refreshMenu('1', '2024-12-31');
556
584
  */
557
- function useCanteens() {
558
- const canteenContext = useCanteenContext();
585
+ function useCanteens () {
586
+ const canteenContext = useCanteenContext()
559
587
 
560
- return [canteenContext.canteens ?? null, canteenContext.refreshMenu];
588
+ return [canteenContext.canteens ?? null, canteenContext.refreshMenu]
561
589
  }
562
590
 
563
591
  /**
@@ -566,13 +594,13 @@ function useCanteens() {
566
594
  * @param {String} canteenId
567
595
  * @returns {[?Object, (menuDate: String) => Promise<void>]}
568
596
  */
569
- function useCanteen(canteenId) {
570
- const [canteens, refreshMenu] = useCanteens();
597
+ function useCanteen (canteenId) {
598
+ const [canteens, refreshMenu] = useCanteens()
571
599
 
572
- return [
573
- canteens?.[canteenId] ?? null, // Holt die Mensa mit der ID canteenId aus dem Mensa-Objekt
574
- (menuDate) => refreshMenu(canteenId, menuDate), // Erstellt eine Funktion, die das Essen ohne angeben der canteenId aktualisiert
575
- ];
600
+ return [
601
+ canteens?.[canteenId] ?? null, // Holt die Mensa mit der ID canteenId aus dem Mensa-Objekt
602
+ (menuDate) => refreshMenu(canteenId, menuDate) // Erstellt eine Funktion, die das Essen ohne angeben der canteenId aktualisiert
603
+ ]
576
604
  }
577
605
 
578
606
  /**
@@ -582,13 +610,13 @@ function useCanteen(canteenId) {
582
610
  * @param {String} menuDate
583
611
  * @returns {[?Object[], () => Promise<void>]}
584
612
  */
585
- function useMenu(canteenId, menuDate) {
586
- const [canteen, refreshMenu] = useCanteen(canteenId);
613
+ function useMenu (canteenId, menuDate) {
614
+ const [canteen, refreshMenu] = useCanteen(canteenId)
587
615
 
588
- return [
589
- canteen?.menus?.[menuDate] ?? null, // Holt das Essen aus der Mensa mit der ID canteenId
590
- () => refreshMenu(menuDate), // Erstellt eine Funktion, die das Essen ohne angeben von canteenId und menuDate aktualisiert
591
- ];
616
+ return [
617
+ canteen?.menus?.[menuDate] ?? null, // Holt das Essen aus der Mensa mit der ID canteenId
618
+ () => refreshMenu(menuDate) // Erstellt eine Funktion, die das Essen ohne angeben von canteenId und menuDate aktualisiert
619
+ ]
592
620
  }
593
621
 
594
622
  /**
@@ -598,49 +626,49 @@ function useMenu(canteenId, menuDate) {
598
626
  * @param {String} menuDate
599
627
  * @returns {[?Object, () => Promise<void>]}
600
628
  */
601
- function useFilteredMenu(canteenId, menuDate) {
602
- //const hookName = arguments.callee.name;
603
- //const hookCall = `${hookName}(canteenId: ${canteenId}, menuDate: ${menuDate})`;
604
-
605
- const {
606
- activeSelections,
607
- activeSelectionFilters,
608
- activeMealtypes,
609
- activeMealtypeFilters
610
- } = useCanteenContext();
611
- const [menu, refreshMenu] = useMenu(canteenId, menuDate);
612
-
613
- let filteredMenu = menu;
614
-
615
- if (activeSelectionFilters) {
616
- filteredMenu = filteredMenu?.filter(
617
- meal => activeSelectionFilters.every(
618
- activeSelectionFilter => meal.selections.includes(activeSelectionFilter)
619
- )
620
- );
621
- }
622
-
623
- if (activeMealtypeFilters) {
624
- filteredMenu = filteredMenu
625
- ?.filter(
626
- meal =>
627
- meal?.type
628
- ? activeMealtypeFilters.includes(meal.type)
629
- : true
630
- );
631
- }
632
-
633
- const mealAmount = menu?.length ?? 0;
634
- const filteredMealAmount = filteredMenu?.length ?? 0;
635
-
636
- return [
637
- filteredMenu,
638
- refreshMenu,
639
- mealAmount,
640
- filteredMealAmount,
641
- activeSelections,
642
- activeMealtypes,
643
- ];
629
+ function useFilteredMenu (canteenId, menuDate) {
630
+ // const hookName = arguments.callee.name;
631
+ // const hookCall = `${hookName}(canteenId: ${canteenId}, menuDate: ${menuDate})`;
632
+
633
+ const {
634
+ activeSelections,
635
+ activeSelectionFilters,
636
+ activeMealtypes,
637
+ activeMealtypeFilters
638
+ } = useCanteenContext()
639
+ const [menu, refreshMenu] = useMenu(canteenId, menuDate)
640
+
641
+ let filteredMenu = menu
642
+
643
+ if (activeSelectionFilters) {
644
+ filteredMenu = filteredMenu?.filter(
645
+ meal => activeSelectionFilters.every(
646
+ activeSelectionFilter => meal.selections.includes(activeSelectionFilter)
647
+ )
648
+ )
649
+ }
650
+
651
+ if (activeMealtypeFilters) {
652
+ filteredMenu = filteredMenu
653
+ ?.filter(
654
+ meal =>
655
+ meal?.type
656
+ ? activeMealtypeFilters.includes(meal.type)
657
+ : true
658
+ )
659
+ }
660
+
661
+ const mealAmount = menu?.length ?? 0
662
+ const filteredMealAmount = filteredMenu?.length ?? 0
663
+
664
+ return [
665
+ filteredMenu,
666
+ refreshMenu,
667
+ mealAmount,
668
+ filteredMealAmount,
669
+ activeSelections,
670
+ activeMealtypes
671
+ ]
644
672
  }
645
673
 
646
674
  /**
@@ -658,10 +686,10 @@ function useFilteredMenu(canteenId, menuDate) {
658
686
  * console.log(priceGroupCode);
659
687
  * setPriceGroupCode('guest');
660
688
  */
661
- function usePriceGroupCode() {
662
- const { priceGroupCode, setPriceGroupCode } = useCanteenContext();
689
+ function usePriceGroupCode () {
690
+ const { priceGroupCode, setPriceGroupCode } = useCanteenContext()
663
691
 
664
- return [priceGroupCode, setPriceGroupCode];
692
+ return [priceGroupCode, setPriceGroupCode]
665
693
  }
666
694
 
667
695
  /**
@@ -673,20 +701,20 @@ function usePriceGroupCode() {
673
701
  *
674
702
  * setFavoriteCanteens(['canteen1', 'canteen2']);
675
703
  */
676
- function useFavoriteCanteens() {
677
- const { favoriteCanteens, setFavoriteCanteens } = useCanteenContext();
704
+ function useFavoriteCanteens () {
705
+ const { favoriteCanteens, setFavoriteCanteens } = useCanteenContext()
678
706
 
679
- return [favoriteCanteens, setFavoriteCanteens];
707
+ return [favoriteCanteens, setFavoriteCanteens]
680
708
  }
681
709
 
682
710
  export {
683
- ConnectedCanteenContextProvider as CanteenContextProvider,
684
- CanteenContext as default,
685
- useCanteenContext,
686
- useCanteens,
687
- useCanteen,
688
- useMenu,
689
- useFilteredMenu,
690
- usePriceGroupCode,
691
- useFavoriteCanteens,
692
- };
711
+ ConnectedCanteenContextProvider as CanteenContextProvider,
712
+ CanteenContext as default,
713
+ useCanteenContext,
714
+ useCanteens,
715
+ useCanteen,
716
+ useMenu,
717
+ useFilteredMenu,
718
+ usePriceGroupCode,
719
+ useFavoriteCanteens
720
+ }