@olea-bps/base 1.1.8 → 1.1.9
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.
- package/components/ContactDetail/index.js +3 -3
- package/context/context-timetable/TimetableService.js +167 -172
- package/libraries/react-native-webview-autoheight/package.json +1 -1
- package/libraries/redux-offline/package.json +14 -14
- package/libraries/stored-state/index.js +114 -103
- package/package.json +17 -17
- package/libraries/redux-offline/yarn.lock +0 -6460
|
@@ -158,15 +158,15 @@ export default function ContactDetailComponent({ contact, ...restProps }) {
|
|
|
158
158
|
{
|
|
159
159
|
contact?.email
|
|
160
160
|
? <TouchableOpacity
|
|
161
|
-
key=
|
|
161
|
+
key='mail'
|
|
162
162
|
onPress={() => Linking.openURL('mailto:' + contact.email)}
|
|
163
163
|
>
|
|
164
|
-
<
|
|
164
|
+
<IconListItem
|
|
165
165
|
title={t('contact:email')}
|
|
166
166
|
description={contact.email}
|
|
167
167
|
descriptionStyle={themeStyles.textLighter}
|
|
168
168
|
titleStyle={themeStyles.searchDetailTitle}
|
|
169
|
-
|
|
169
|
+
icon={'mail'}
|
|
170
170
|
/>
|
|
171
171
|
</TouchableOpacity>
|
|
172
172
|
: null
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { useSyncExternalStore } from 'react'
|
|
1
|
+
import { useSyncExternalStore } from 'react'
|
|
2
2
|
|
|
3
|
-
import * as SecureStore from 'expo-secure-store'
|
|
3
|
+
import * as SecureStore from 'expo-secure-store'
|
|
4
|
+
import { getSecureItem, secureStoreOptions } from '../../libraries/stored-state'
|
|
4
5
|
|
|
5
|
-
import { groupBy } from 'lodash'
|
|
6
|
-
import { DateTime, Duration } from 'luxon'
|
|
6
|
+
import { groupBy } from 'lodash'
|
|
7
|
+
import { DateTime, Duration } from 'luxon'
|
|
7
8
|
|
|
8
|
-
import CollectorVersion2ApiProvider from './CollectorVersion2ApiProvider'
|
|
9
|
+
import CollectorVersion2ApiProvider from './CollectorVersion2ApiProvider'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @typedef TimetableProvider
|
|
@@ -44,21 +45,21 @@ import CollectorVersion2ApiProvider from './CollectorVersion2ApiProvider';
|
|
|
44
45
|
* @property {CourseTime[]} times
|
|
45
46
|
*/
|
|
46
47
|
|
|
47
|
-
const TimetableCodeStoreKey = 'timetable.code'
|
|
48
|
-
const TimetableCoursesStoreKey = 'timetable.courses'
|
|
48
|
+
const TimetableCodeStoreKey = 'timetable.code'
|
|
49
|
+
const TimetableCoursesStoreKey = 'timetable.courses'
|
|
49
50
|
|
|
50
51
|
export class ApiProviderNotInitializedError extends Error {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
constructor (message) {
|
|
53
|
+
super(message)
|
|
54
|
+
this.name = this.constructor.name
|
|
55
|
+
}
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
export class TimetableCodeNotInitializedError extends Error {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
constructor (message) {
|
|
60
|
+
super(message)
|
|
61
|
+
this.name = this.constructor.name
|
|
62
|
+
}
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
/**
|
|
@@ -71,13 +72,12 @@ export class TimetableCodeNotInitializedError extends Error {
|
|
|
71
72
|
* Der Service sollte über {@linkcode TimetableService.fromProviderSettingsObject} initialisert werden.
|
|
72
73
|
*/
|
|
73
74
|
export default class TimetableService {
|
|
74
|
-
|
|
75
|
-
/**
|
|
75
|
+
/**
|
|
76
76
|
* @type {TimetableProvider}
|
|
77
77
|
*/
|
|
78
|
-
|
|
78
|
+
#provider
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
/**
|
|
81
81
|
* Konstruktor des Stundenplan-Services.
|
|
82
82
|
* Es muss ein Provider Übergeben werden, damit der Stundenplan-Service Daten über den Provider abrufen kann.
|
|
83
83
|
* Es wird empfohlen {@linkcode TimetableService.fromProviderSettingsObject} zu verwenden.
|
|
@@ -92,199 +92,194 @@ export default class TimetableService {
|
|
|
92
92
|
*
|
|
93
93
|
* const timetableService = TimetableService.fromProviderSettingsObject(providerSettings, language);
|
|
94
94
|
*/
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
constructor (provider) {
|
|
96
|
+
this.#provider = provider
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
this.#code = getSecureItem(TimetableCodeStoreKey)
|
|
99
|
+
this.#courses = JSON.parse(getSecureItem(TimetableCoursesStoreKey))
|
|
100
|
+
}
|
|
101
101
|
|
|
102
|
+
#code = undefined
|
|
103
|
+
#codeSubscribers = new Set()
|
|
102
104
|
|
|
105
|
+
code () {
|
|
106
|
+
return this.#code
|
|
107
|
+
}
|
|
103
108
|
|
|
104
|
-
|
|
105
|
-
#codeSubscribers = new Set();
|
|
109
|
+
codeCallback = () => this.code()
|
|
106
110
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
#setCode (code) {
|
|
112
|
+
this.#code = code
|
|
113
|
+
this.#codeSubscribers.forEach(subscriber => subscriber(code))
|
|
114
|
+
}
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
async setCode(code) {
|
|
117
|
-
await SecureStore.setItemAsync(TimetableCodeStoreKey, code);
|
|
118
|
-
this.#setCode(code);
|
|
119
|
-
}
|
|
120
|
-
setCodeCallback = async (code) => this.setCode(code);
|
|
116
|
+
async setCode (code) {
|
|
117
|
+
await SecureStore.setItemAsync(TimetableCodeStoreKey, code, secureStoreOptions)
|
|
118
|
+
this.#setCode(code)
|
|
119
|
+
}
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
setCodeCallback = async (code) => this.setCode(code)
|
|
123
122
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
async deleteCode () {
|
|
124
|
+
await Promise.all([
|
|
125
|
+
SecureStore.deleteItemAsync(TimetableCodeStoreKey),
|
|
126
|
+
SecureStore.deleteItemAsync(TimetableCoursesStoreKey)
|
|
127
|
+
])
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
deleteCodeCallback = () => this.deleteCode();
|
|
129
|
+
this.#setCode(null)
|
|
130
|
+
this.#setCourses(null)
|
|
131
|
+
}
|
|
133
132
|
|
|
134
|
-
|
|
135
|
-
this.#codeSubscribers.add(subscriber);
|
|
133
|
+
deleteCodeCallback = () => this.deleteCode()
|
|
136
134
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
codeSubscribeCallback = (subscriber) => this.codeSubscribe(subscriber);
|
|
135
|
+
codeSubscribe (subscriber) {
|
|
136
|
+
this.#codeSubscribers.add(subscriber)
|
|
140
137
|
|
|
141
|
-
codeUnsubscribe(subscriber)
|
|
142
|
-
|
|
143
|
-
}
|
|
138
|
+
return () => this.codeUnsubscribe(subscriber)
|
|
139
|
+
}
|
|
144
140
|
|
|
141
|
+
codeSubscribeCallback = (subscriber) => this.codeSubscribe(subscriber)
|
|
145
142
|
|
|
143
|
+
codeUnsubscribe (subscriber) {
|
|
144
|
+
return this.#codeSubscribers.delete(subscriber)
|
|
145
|
+
}
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
/**
|
|
148
148
|
* @type {Object.<string, Course[]>}
|
|
149
149
|
*/
|
|
150
|
-
|
|
151
|
-
|
|
150
|
+
#courses = undefined
|
|
151
|
+
#coursesSubscribers = new Set()
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
/**
|
|
154
154
|
* Liefert die Vorlesungen, die von dem Service respeichert werden zurück.
|
|
155
155
|
* Dabei werden die Vorlesungen nach Vorlesungstagen gruppiert.
|
|
156
156
|
* Somit wird ein Object zurückgegeben, bei dem die Schlüssel ISO-Datums der Vorlesungstage sind und die Werte sind Listen mit Vorlesungen
|
|
157
157
|
*
|
|
158
158
|
* @returns {Object.<string, Course[]>} Vorlesungen gruppiert nach Vorlesungstagen
|
|
159
159
|
*/
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
courses () {
|
|
161
|
+
return this.#courses
|
|
162
|
+
}
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
#setCourses (courses) {
|
|
165
|
+
// Neue Vorlesungsdaten im Service hinterlegen
|
|
166
|
+
this.#courses = courses
|
|
167
167
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
// Jedem Subscriber werden die neuen Vorlesungstage bekannt gemacht
|
|
169
|
+
this.#coursesSubscribers.forEach(subscriber => subscriber(this.#courses))
|
|
170
|
+
}
|
|
171
171
|
|
|
172
|
-
|
|
172
|
+
coursesCallback = () => this.courses()
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
async refreshCourses (startDate, endDate) {
|
|
175
|
+
if (this.#provider === null) {
|
|
176
|
+
throw new ApiProviderNotInitializedError('Api Provider is not initilized')
|
|
177
|
+
}
|
|
175
178
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
+
if (this.#code === null) {
|
|
180
|
+
throw new TimetableCodeNotInitializedError('Timetable code is not initilized')
|
|
181
|
+
}
|
|
179
182
|
|
|
180
|
-
|
|
181
|
-
|
|
183
|
+
const courses = await this.#provider.getByCode(this.#code, startDate, endDate)
|
|
184
|
+
const transformedCourses = courses.map(
|
|
185
|
+
course => {
|
|
186
|
+
// Erstes Time-Element aus dem times-Array nehmen, da im neuen Format nur noch eine Zeit enthalten ist
|
|
187
|
+
const courseTime = course?.times?.[0]
|
|
188
|
+
if (courseTime) {
|
|
189
|
+
const courseDate = DateTime.fromISO(courseTime?.date)
|
|
190
|
+
// Startzeit und Endzeit der Vorlesung in ein DateTime umwandeln
|
|
191
|
+
const courseStartTime = Duration.fromISOTime(courseTime.start)
|
|
192
|
+
const courseStartDateTime = courseDate.plus(courseStartTime)
|
|
193
|
+
const courseEndTime = Duration.fromISOTime(courseTime.end)
|
|
194
|
+
const courseEndDateTime = courseDate.plus(courseEndTime)
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
...course,
|
|
198
|
+
startDateTime: courseStartDateTime.toISO(),
|
|
199
|
+
endDateTime: courseEndDateTime.toISO()
|
|
200
|
+
}
|
|
201
|
+
} else {
|
|
202
|
+
return course
|
|
182
203
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
// Vorlesungen, die keinem Tag zugeordnet werden können, werden untder dem Schlüssel `undefined` zusammengefasst
|
|
211
|
-
const addingCourses = groupBy(
|
|
212
|
-
transformedCourses,
|
|
213
|
-
course => {
|
|
214
|
-
// Datum der Vorlesung aus der Vorlesung holen
|
|
215
|
-
const courseDate = course?.times?.[0]?.date;
|
|
216
|
-
|
|
217
|
-
// Prüfen ob die Vorlesung einen Wert als Datum vorweist
|
|
218
|
-
return courseDate
|
|
219
|
-
// Ist ein Wert vorhanden, wird dieser für die Gruppierung verwendet
|
|
220
|
-
? courseDate
|
|
221
|
-
// Ansonsten wird undefined zurückgeben (lerrer String, null, undefined, ...)
|
|
222
|
-
: undefined;
|
|
223
|
-
}
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
//Entfernen der Vorlesungstage zwischen Startdatum und Enddatum
|
|
227
|
-
const rangeRemovedCourses = Object.fromEntries(
|
|
228
|
-
Object.entries(this.#courses ?? {})
|
|
229
|
-
.filter(([coursesDate,]) => startDate >= coursesDate && coursesDate <= endDate)
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
// Zusammenführen der neuen Vorlesungstagen der Vorlesungen des Providers und der schon vorhandenen Vorlesungstagen
|
|
233
|
-
const newCourses = {
|
|
234
|
-
...rangeRemovedCourses,
|
|
235
|
-
...addingCourses,
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
// Neue Vorlesungsdaten in den Cache ablegen
|
|
239
|
-
SecureStore.setItem(TimetableCoursesStoreKey, JSON.stringify(newCourses));
|
|
240
|
-
|
|
241
|
-
// Neue Vorlesungen hin Service hinterlegen und Äanderun bekannt geben
|
|
242
|
-
this.#setCourses(newCourses);
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
// Gruppieren der vom Provider abgeholten Vorlesungen
|
|
208
|
+
// Es wird nach dem Datum der Vorlesungen gruppiert
|
|
209
|
+
// Vorlesungen, die keinem Tag zugeordnet werden können, werden untder dem Schlüssel `undefined` zusammengefasst
|
|
210
|
+
const addingCourses = groupBy(
|
|
211
|
+
transformedCourses,
|
|
212
|
+
course => {
|
|
213
|
+
// Datum der Vorlesung aus der Vorlesung holen
|
|
214
|
+
const courseDate = course?.times?.[0]?.date
|
|
215
|
+
|
|
216
|
+
// Prüfen ob die Vorlesung einen Wert als Datum vorweist
|
|
217
|
+
return courseDate || undefined
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
// Entfernen der Vorlesungstage zwischen Startdatum und Enddatum
|
|
222
|
+
const rangeRemovedCourses = Object.fromEntries(
|
|
223
|
+
Object.entries(this.#courses ?? {})
|
|
224
|
+
.filter(([coursesDate]) => startDate >= coursesDate && coursesDate <= endDate)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
// Zusammenführen der neuen Vorlesungstagen der Vorlesungen des Providers und der schon vorhandenen Vorlesungstagen
|
|
228
|
+
const newCourses = {
|
|
229
|
+
...rangeRemovedCourses,
|
|
230
|
+
...addingCourses
|
|
243
231
|
}
|
|
244
|
-
refreshCoursesCallback = (startDate, endDate) => this.refreshCourses(startDate, endDate);
|
|
245
232
|
|
|
246
|
-
|
|
247
|
-
|
|
233
|
+
// Neue Vorlesungsdaten in den Cache ablegen
|
|
234
|
+
SecureStore.setItem(TimetableCoursesStoreKey, JSON.stringify(newCourses), secureStoreOptions)
|
|
248
235
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
236
|
+
// Neue Vorlesungen hin Service hinterlegen und Äanderun bekannt geben
|
|
237
|
+
this.#setCourses(newCourses)
|
|
238
|
+
}
|
|
252
239
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
240
|
+
refreshCoursesCallback = (startDate, endDate) => this.refreshCourses(startDate, endDate)
|
|
241
|
+
|
|
242
|
+
coursesSubscribe (subscriber) {
|
|
243
|
+
this.#coursesSubscribers.add(subscriber)
|
|
244
|
+
|
|
245
|
+
return () => this.coursesUnsubscribe(subscriber)
|
|
246
|
+
}
|
|
256
247
|
|
|
248
|
+
coursesSubscribeCallback = (subscriber) => this.coursesSubscribe(subscriber)
|
|
257
249
|
|
|
250
|
+
coursesUnsubscribe (subscriber) {
|
|
251
|
+
return this.#coursesSubscribers.delete(subscriber)
|
|
252
|
+
}
|
|
258
253
|
|
|
259
|
-
|
|
254
|
+
/**
|
|
260
255
|
* Erstellen eines Stundenplanservices mit Hilfe der Provider-Einstellungen und Sprache
|
|
261
256
|
*
|
|
262
257
|
* @param {ProviderSetting} providerSettingsObject
|
|
263
258
|
* @param {string} language
|
|
264
259
|
* @returns
|
|
265
260
|
*/
|
|
266
|
-
|
|
267
|
-
|
|
261
|
+
static fromProviderSettingsObject (providerSettingsObject, language) {
|
|
262
|
+
const provider = TimetableService.#createProvider(providerSettingsObject, language)
|
|
268
263
|
|
|
269
|
-
|
|
270
|
-
|
|
264
|
+
return new TimetableService(provider)
|
|
265
|
+
}
|
|
271
266
|
|
|
272
|
-
|
|
267
|
+
/**
|
|
273
268
|
* Erstellen des Providers mit Hilfe eines Provider-Einstellungen-Objektes und einer Sprache
|
|
274
269
|
*
|
|
275
270
|
* @param {ProviderSetting} providerSettingsObject Einstellungen welche zum auswählen und Initialisieren des Provider verwendet werden
|
|
276
271
|
* @param {string} language Sprachcode welcher für den Datenabruf verwendet werden soll
|
|
277
272
|
*/
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
273
|
+
static #createProvider (providerSettingsObject, language) {
|
|
274
|
+
const { provider } = providerSettingsObject
|
|
275
|
+
|
|
276
|
+
switch (provider) {
|
|
277
|
+
case CollectorVersion2ApiProvider.name:
|
|
278
|
+
return CollectorVersion2ApiProvider.fromSettingsObject(providerSettingsObject, language)
|
|
279
|
+
default:
|
|
280
|
+
return null
|
|
287
281
|
}
|
|
282
|
+
}
|
|
288
283
|
}
|
|
289
284
|
|
|
290
285
|
/**
|
|
@@ -311,13 +306,13 @@ export default class TimetableService {
|
|
|
311
306
|
* </Text>
|
|
312
307
|
* );
|
|
313
308
|
*/
|
|
314
|
-
export function useSyncTimetableCode(timetableService) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
309
|
+
export function useSyncTimetableCode (timetableService) {
|
|
310
|
+
const timetableCode = useSyncExternalStore(
|
|
311
|
+
timetableService.codeSubscribeCallback,
|
|
312
|
+
timetableService.codeCallback
|
|
313
|
+
)
|
|
319
314
|
|
|
320
|
-
|
|
315
|
+
return [timetableCode, timetableService.setCodeCallback, timetableService.deleteCodeCallback]
|
|
321
316
|
}
|
|
322
317
|
|
|
323
318
|
/**
|
|
@@ -347,11 +342,11 @@ export function useSyncTimetableCode(timetableService) {
|
|
|
347
342
|
* return (
|
|
348
343
|
* );
|
|
349
344
|
*/
|
|
350
|
-
export function useSyncCourses(timetableService) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
345
|
+
export function useSyncCourses (timetableService) {
|
|
346
|
+
const courses = useSyncExternalStore(
|
|
347
|
+
timetableService.coursesSubscribeCallback,
|
|
348
|
+
timetableService.coursesCallback
|
|
349
|
+
)
|
|
355
350
|
|
|
356
|
-
|
|
351
|
+
return [courses, timetableService.refreshCoursesCallback]
|
|
357
352
|
}
|
|
@@ -31,33 +31,33 @@
|
|
|
31
31
|
"src/**/*"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@babel/runtime": "^7.
|
|
34
|
+
"@babel/runtime": "^7.29.7",
|
|
35
35
|
"redux-persist": "^6.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@babel/cli": "^7.
|
|
39
|
-
"@babel/core": "^7.
|
|
38
|
+
"@babel/cli": "^7.29.7",
|
|
39
|
+
"@babel/core": "^7.29.7",
|
|
40
40
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
41
41
|
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
|
42
|
-
"@babel/plugin-transform-flow-strip-types": "^7.
|
|
43
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
44
|
-
"@babel/preset-env": "^7.
|
|
42
|
+
"@babel/plugin-transform-flow-strip-types": "^7.29.7",
|
|
43
|
+
"@babel/plugin-transform-runtime": "^7.29.7",
|
|
44
|
+
"@babel/preset-env": "^7.29.7",
|
|
45
45
|
"babel-core": "^7.0.0-bridge.0",
|
|
46
46
|
"babel-eslint": "^10.1.0",
|
|
47
47
|
"babel-jest": "^29.7.0",
|
|
48
|
-
"eslint": "^8.
|
|
48
|
+
"eslint": "^8.57.1",
|
|
49
49
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
50
|
-
"eslint-config-prettier": "^10.1.
|
|
50
|
+
"eslint-config-prettier": "^10.1.8",
|
|
51
51
|
"eslint-plugin-babel": "^5.3.1",
|
|
52
52
|
"eslint-plugin-flowtype": "^8.0.3",
|
|
53
|
-
"eslint-plugin-import": "^2.
|
|
54
|
-
"eslint-plugin-prettier": "^5.
|
|
55
|
-
"flow-bin": "^0.
|
|
53
|
+
"eslint-plugin-import": "^2.32.0",
|
|
54
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
55
|
+
"flow-bin": "^0.334.0",
|
|
56
56
|
"husky": "^9.1.7",
|
|
57
57
|
"jest": "^29.7.0",
|
|
58
|
-
"lint-staged": "^16.
|
|
59
|
-
"prettier": "^3.
|
|
60
|
-
"redux": "^4.
|
|
58
|
+
"lint-staged": "^16.4.0",
|
|
59
|
+
"prettier": "^3.9.9",
|
|
60
|
+
"redux": "^4.2.1",
|
|
61
61
|
"redux-devtools-instrument": "^1.10.0",
|
|
62
62
|
"redux-logger": "^3.0.6",
|
|
63
63
|
"redux-persist-node-storage": "^2.0.0",
|