@olea-bps/base 1.1.10 → 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.
- package/components/ComponentJobsFilter/index.js +137 -135
- package/components/CourseDetailDialog/index.js +100 -100
- package/components/NewsDetail/index.js +229 -289
- package/components/NewsDetail/styles.js +3 -4
- package/components/NewsListItem/index.js +77 -64
- package/components/NewsListItem/styles.js +34 -31
- package/components/RoomDetail/index.js +240 -212
- package/components/TabBarIcon/index.js +35 -0
- package/components/TimetableDay/index.js +211 -212
- package/components/TimetableMonth/index.js +57 -60
- package/components/TimetableWeek/index.js +72 -75
- package/components/TimetableWeek/styles.js +56 -56
- package/context/context-canteen/index.js +526 -498
- package/context/context-user/index.js +49 -64
- package/index.js +1 -0
- package/package.json +6 -1
- package/views/PublicTransportTicket/index.js +31 -3
- package/views/SettingsAppInfo/index.js +69 -50
- package/views/SettingsAppInfo/styles.js +25 -16
- package/views/SettingsUser/index.js +1 -1
|
@@ -14,7 +14,14 @@
|
|
|
14
14
|
|
|
15
15
|
import { createContext, useState, useEffect, useContext, useMemo, useReducer, useCallback } from 'react'
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
useAutoDiscovery,
|
|
19
|
+
makeRedirectUri,
|
|
20
|
+
useAuthRequest,
|
|
21
|
+
exchangeCodeAsync,
|
|
22
|
+
refreshAsync,
|
|
23
|
+
fetchUserInfoAsync,
|
|
24
|
+
} from 'expo-auth-session';
|
|
18
25
|
import * as WebBrowser from 'expo-web-browser';
|
|
19
26
|
import * as SecureStore from 'expo-secure-store';
|
|
20
27
|
|
|
@@ -59,9 +66,16 @@ import { DateTime } from 'luxon';
|
|
|
59
66
|
*/
|
|
60
67
|
|
|
61
68
|
class LoginError extends Error {
|
|
62
|
-
|
|
69
|
+
|
|
70
|
+
type;
|
|
71
|
+
error;
|
|
72
|
+
|
|
73
|
+
constructor(message, type, error) {
|
|
63
74
|
super(message);
|
|
64
75
|
this.name = this.constructor.name;
|
|
76
|
+
|
|
77
|
+
this.type = type;
|
|
78
|
+
this.error = error;
|
|
65
79
|
}
|
|
66
80
|
}
|
|
67
81
|
|
|
@@ -225,72 +239,38 @@ function UserContextProvider({ children }) {
|
|
|
225
239
|
useEffect(
|
|
226
240
|
() => {
|
|
227
241
|
if (accessToken && discovery?.userInfoEndpoint) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
242
|
+
fetchUserInfoAsync({ accessToken }, discovery)
|
|
243
|
+
.then(
|
|
244
|
+
userInfo => {
|
|
245
|
+
console.debug(componentName, ':', 'fetch user', ':', userInfo);
|
|
246
|
+
|
|
247
|
+
const userInfos = {
|
|
248
|
+
...userInfo,
|
|
249
|
+
organizational_units: userInfo?.ou?.map(
|
|
250
|
+
(organizational_unit_name, index) => ({
|
|
251
|
+
name: organizational_unit_name,
|
|
252
|
+
number: userInfo?.ounumber?.[index],
|
|
253
|
+
short_name: userInfo?.oushort?.[index],
|
|
254
|
+
})
|
|
255
|
+
) ?? [],
|
|
256
|
+
member_types: [
|
|
257
|
+
...(userInfo?.employeetype?.includes?.('Student') ? ['student'] : []),
|
|
258
|
+
...(userInfo?.employeetype?.includes?.('Mitarbeiter') ? ['employee'] : []),
|
|
259
|
+
]
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
console.debug(componentName, ':', 'convert response to user', ':', userInfos);
|
|
263
|
+
|
|
264
|
+
setUser(userInfos);
|
|
233
265
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
).then(
|
|
238
|
-
userInfoJsonResponse => {
|
|
239
|
-
console.debug(componentName, ':', 'fetch user', ':', userInfoJsonResponse);
|
|
240
|
-
|
|
241
|
-
const userInfos = {
|
|
242
|
-
...userInfoJsonResponse,
|
|
243
|
-
organizational_units: userInfoJsonResponse?.ou?.map(
|
|
244
|
-
(organizational_unit_name, index) => ({
|
|
245
|
-
name: organizational_unit_name,
|
|
246
|
-
number: userInfoJsonResponse?.ounumber?.[index],
|
|
247
|
-
short_name: userInfoJsonResponse?.oushort?.[index],
|
|
248
|
-
})
|
|
249
|
-
) ?? [],
|
|
250
|
-
member_types: [
|
|
251
|
-
...(userInfoJsonResponse?.employeetype?.includes?.('Student') ? ['student'] : null),
|
|
252
|
-
...(userInfoJsonResponse?.employeetype?.includes?.('Mitarbeiter') ? ['employee'] : null),
|
|
253
|
-
]
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
console.debug(componentName, ':', 'convert response to user', ':', userInfos);
|
|
257
|
-
|
|
258
|
-
setUser(userInfos);
|
|
259
|
-
}
|
|
260
|
-
).catch(
|
|
261
|
-
reason => console.warn(componentName, ':', 'can`t fetch user infos', ':', reason)
|
|
262
|
-
);
|
|
266
|
+
).catch(
|
|
267
|
+
reason => console.warn(componentName, ':', 'can`t fetch user infos', ':', reason)
|
|
268
|
+
);
|
|
263
269
|
}
|
|
264
270
|
},
|
|
265
271
|
[accessToken, discovery]
|
|
266
272
|
);
|
|
267
273
|
|
|
268
|
-
// Wenn das Format vom Server stimmt wird kann der oberer Hook mit diesem ersetzt werden
|
|
269
|
-
//useEffect(
|
|
270
|
-
// () => {
|
|
271
|
-
// if (accessToken && discovery) {
|
|
272
|
-
// fetchUserInfoAsync(
|
|
273
|
-
// {
|
|
274
|
-
// accessToken: accessToken
|
|
275
|
-
// },
|
|
276
|
-
// discovery,
|
|
277
|
-
// ).then(
|
|
278
|
-
// userInfo => console.warn(userInfo)
|
|
279
|
-
// ).then(
|
|
280
|
-
// response => response.json()
|
|
281
|
-
// ).then(
|
|
282
|
-
// jsonResponse => {
|
|
283
|
-
// console.debug(componentName, ':', 'fetch user ', jsonResponse);
|
|
284
|
-
// setUser(jsonResponse);
|
|
285
|
-
// }
|
|
286
|
-
// ).catch(
|
|
287
|
-
// reason => console.warn(componentName, ':', 'can`t fetch user infos', ':', reason)
|
|
288
|
-
// );
|
|
289
|
-
// }
|
|
290
|
-
// },
|
|
291
|
-
// [accessToken, discovery]
|
|
292
|
-
//);
|
|
293
|
-
|
|
294
274
|
useEffect(
|
|
295
275
|
() => {
|
|
296
276
|
if (refreshToken && refreshTokenAt && discovery) {
|
|
@@ -300,7 +280,7 @@ function UserContextProvider({ children }) {
|
|
|
300
280
|
() =>
|
|
301
281
|
refreshAsync(
|
|
302
282
|
{
|
|
303
|
-
clientId
|
|
283
|
+
clientId: clientId,
|
|
304
284
|
refreshToken: refreshToken,
|
|
305
285
|
},
|
|
306
286
|
discovery,
|
|
@@ -339,8 +319,13 @@ function UserContextProvider({ children }) {
|
|
|
339
319
|
reason => console.log(componentName, ': tokenResponse: Fehler', ':', reason)
|
|
340
320
|
);
|
|
341
321
|
} else {
|
|
322
|
+
console.debug(componentName, ':', 'login error', ':', codeResponse.type, '(', JSON.stringify(codeResponse.error), ')')
|
|
342
323
|
// TODO: Prüfen warum der Login nicht klappte und für die einzeilnen Gründe, genauere Fehlerinfos zurückgeben.
|
|
343
|
-
throw new LoginError(
|
|
324
|
+
throw new LoginError(
|
|
325
|
+
`Login Failed: ${codeResponse?.type}`,
|
|
326
|
+
codeResponse.type,
|
|
327
|
+
codeResponse.error,
|
|
328
|
+
);
|
|
344
329
|
}
|
|
345
330
|
}
|
|
346
331
|
);
|
package/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export { default as SettingsDialog } from './components/SettingsDialog';
|
|
|
32
32
|
export { default as SettingsDialogRadio } from './components/SettingsDialogRadio';
|
|
33
33
|
export { default as SettingsDialogSelect } from './components/SettingsDialogSelect';
|
|
34
34
|
export { default as SettingSection } from './components/SettingSection';
|
|
35
|
+
export { default as TabBarIcon } from './components/TabBarIcon';
|
|
35
36
|
export { default as TimetableCodeInput } from './components/TimetableCodeInput';
|
|
36
37
|
export { default as TimetableDay } from './components/TimetableDay';
|
|
37
38
|
export { default as TimetableEvent } from './components/TimetableEvent';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olea-bps/base",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.12",
|
|
4
4
|
"description": "OLEA base library",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
"email": "support@hrz.tu-chemnitz.de",
|
|
15
15
|
"url": "https://www.tu-chemnitz.de/urz/"
|
|
16
16
|
},
|
|
17
|
+
{
|
|
18
|
+
"name": "HTWK Leipzig",
|
|
19
|
+
"email": "feedback.app@htwk-leipzig.de",
|
|
20
|
+
"url": "https://www.htwk-leipzig.de/htwk-app"
|
|
21
|
+
},
|
|
17
22
|
{
|
|
18
23
|
"name": "codeculture",
|
|
19
24
|
"email": "info@codeculture.de",
|
|
@@ -174,7 +174,7 @@ export default function PublicTransportTicketView() {
|
|
|
174
174
|
</ScrollView>
|
|
175
175
|
: <>
|
|
176
176
|
<Text>
|
|
177
|
-
|
|
177
|
+
{t('user:notLoggedIn')}
|
|
178
178
|
</Text>
|
|
179
179
|
<Button
|
|
180
180
|
onPress={
|
|
@@ -183,10 +183,38 @@ export default function PublicTransportTicketView() {
|
|
|
183
183
|
? login()
|
|
184
184
|
.catch(
|
|
185
185
|
reason => {
|
|
186
|
-
console.debug(componentName, ':', 'login failed', ':', reason)
|
|
186
|
+
console.debug(componentName, ':', 'login failed', ':', reason, '(', JSON.stringify({ type: reason.type, error: reason.error }, ')'))
|
|
187
|
+
|
|
188
|
+
let loginFailedInfoMessage = t('user:tryLoginAgain');
|
|
189
|
+
switch (reason.type) {
|
|
190
|
+
case 'dismiss': {
|
|
191
|
+
loginFailedInfoMessage = [
|
|
192
|
+
t('user:tryLoginAgain'),
|
|
193
|
+
].join('\n');
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case 'error': {
|
|
197
|
+
const error_code = reason.error.code
|
|
198
|
+
|
|
199
|
+
loginFailedInfoMessage = [
|
|
200
|
+
t('user:tryLoginAgain'),
|
|
201
|
+
t(`user:error:${error_code}`),
|
|
202
|
+
JSON.stringify({ error: reason.error }),
|
|
203
|
+
].join('\n');
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
default: {
|
|
207
|
+
loginFailedInfoMessage = [
|
|
208
|
+
t('user:tryLoginAgain'),
|
|
209
|
+
`Errortype: ${reason.type}`,
|
|
210
|
+
JSON.stringify(reason.error),
|
|
211
|
+
].join('\n');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
187
215
|
Alert.alert(
|
|
188
216
|
t('user:loginFailed'),
|
|
189
|
-
|
|
217
|
+
loginFailedInfoMessage,
|
|
190
218
|
);
|
|
191
219
|
}
|
|
192
220
|
)
|
|
@@ -12,16 +12,16 @@
|
|
|
12
12
|
* limitations under the License.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import React from 'react'
|
|
16
|
-
import {SafeAreaView, View, Image, TouchableOpacity, Linking} from 'react-native'
|
|
15
|
+
import React from 'react'
|
|
16
|
+
import { SafeAreaView, View, ScrollView, Image, TouchableOpacity, Linking } from 'react-native'
|
|
17
17
|
|
|
18
|
-
import {List, withTheme} from 'react-native-paper'
|
|
19
|
-
import {withTranslation} from
|
|
18
|
+
import { List, Text, withTheme } from 'react-native-paper'
|
|
19
|
+
import { withTranslation } from 'react-i18next'
|
|
20
20
|
|
|
21
|
-
import * as Application from 'expo-application'
|
|
21
|
+
import * as Application from 'expo-application'
|
|
22
22
|
|
|
23
|
-
import AppbarComponent from '../../components/AppBar'
|
|
24
|
-
import componentStyles from
|
|
23
|
+
import AppbarComponent from '../../components/AppBar'
|
|
24
|
+
import componentStyles from './styles'
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Settings app info
|
|
@@ -33,54 +33,73 @@ import componentStyles from "./styles";
|
|
|
33
33
|
* - none
|
|
34
34
|
*/
|
|
35
35
|
class AppInfoSettingsView extends React.Component {
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
// Styles of this component
|
|
37
|
+
styles
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
constructor (props) {
|
|
40
|
+
super(props)
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
const { theme } = this.props
|
|
43
|
+
this.styles = componentStyles(theme)
|
|
44
|
+
}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
render () {
|
|
47
|
+
const { theme: { themeStyles, appSettings }, t } = this.props
|
|
48
|
+
const { legalNotices } = appSettings
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
50
|
+
return (
|
|
51
|
+
<SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
|
|
52
|
+
<AppbarComponent
|
|
53
|
+
{...this.props}
|
|
54
|
+
title={t('settings:version.title')}
|
|
55
|
+
/>
|
|
56
|
+
<View style={themeStyles.container}>
|
|
57
|
+
<ScrollView>
|
|
58
|
+
<List.Section>
|
|
59
|
+
<List.Item
|
|
60
|
+
key='version'
|
|
61
|
+
title={t('settings:version.version')}
|
|
62
|
+
description={Application.nativeApplicationVersion ?? t('settings:version.unknown')}
|
|
63
|
+
titleNumberOfLines={2}
|
|
64
|
+
titleStyle={this.styles.listItemTitle}
|
|
65
|
+
descriptionStyle={this.styles.listItemDescription}
|
|
66
|
+
/>
|
|
67
|
+
{legalNotices?.licenseText && (
|
|
68
|
+
<List.Accordion
|
|
69
|
+
title={t('settings:version.licenses', { defaultValue: 'Licenses' })}
|
|
70
|
+
titleStyle={this.styles.listItemTitle}
|
|
71
|
+
>
|
|
72
|
+
<View style={this.styles.licenseContent}>
|
|
73
|
+
{legalNotices.noticeText && (
|
|
74
|
+
<Text selectable style={this.styles.licenseText}>
|
|
75
|
+
{legalNotices.noticeText}
|
|
76
|
+
</Text>
|
|
77
|
+
)}
|
|
78
|
+
<Text selectable style={this.styles.licenseText}>
|
|
79
|
+
{legalNotices.licenseText}
|
|
80
|
+
</Text>
|
|
81
|
+
</View>
|
|
82
|
+
</List.Accordion>
|
|
83
|
+
)}
|
|
84
|
+
</List.Section>
|
|
67
85
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
{appSettings.infoBanner && (
|
|
87
|
+
<TouchableOpacity
|
|
88
|
+
onPress={() => Linking.openURL(appSettings.infoBannerUrl)}
|
|
89
|
+
activeOpacity={0.7}
|
|
90
|
+
>
|
|
91
|
+
<Image
|
|
92
|
+
style={this.styles.infoBanner}
|
|
93
|
+
source={appSettings.infoBanner}
|
|
94
|
+
resizeMode='contain'
|
|
95
|
+
/>
|
|
96
|
+
</TouchableOpacity>
|
|
97
|
+
)}
|
|
98
|
+
</ScrollView>
|
|
99
|
+
</View>
|
|
100
|
+
</SafeAreaView>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
84
103
|
}
|
|
85
104
|
|
|
86
105
|
export default (withTranslation()(withTheme(AppInfoSettingsView)))
|
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
export default function(theme) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
export default function (theme) {
|
|
2
|
+
return {
|
|
3
|
+
selectOption: {
|
|
4
|
+
display: 'flex',
|
|
5
|
+
flexDirection: 'row',
|
|
6
|
+
justifyContent: 'space-between'
|
|
7
|
+
},
|
|
8
|
+
listItemTitle: {
|
|
9
|
+
fontSize: theme.fontSizes.l
|
|
10
|
+
},
|
|
11
|
+
listItemDescription: {
|
|
12
|
+
fontSize: theme.fontSizes.m
|
|
13
|
+
},
|
|
14
|
+
licenseContent: {
|
|
15
|
+
paddingHorizontal: 16,
|
|
16
|
+
paddingBottom: 16
|
|
17
|
+
},
|
|
18
|
+
licenseText: {
|
|
19
|
+
fontSize: theme.fontSizes.m,
|
|
20
|
+
color: theme.colors.text,
|
|
21
|
+
marginBottom: 16
|
|
22
|
+
},
|
|
23
|
+
infoBanner: {
|
|
24
|
+
width: '100%'
|
|
17
25
|
}
|
|
26
|
+
}
|
|
18
27
|
}
|