@olea-bps/base 1.1.3 → 1.1.5
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/AppbarAction/index.js +42 -0
- package/components/BookDetail/index.js +7 -4
- package/components/ContactDetail/index.js +7 -4
- package/components/CourseDetail/index.js +8 -5
- package/components/NewsDetail/index.js +11 -4
- package/components/RoomDetail/index.js +16 -9
- package/index.js +3 -2
- package/libraries/icons-openasist/index.js +112 -113
- package/package.json +1 -1
- package/views/PublicTransportTicket/index.js +2 -2
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import { ColorValue } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Appbar,
|
|
6
|
+
useTheme,
|
|
7
|
+
} from 'react-native-paper';
|
|
8
|
+
|
|
9
|
+
import IconsOpenasist from '../../libraries/icons-openasist';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Eine Action, welche die Icons über die {@link IconsOpenasist}-Komponente einbindet.
|
|
13
|
+
* Es werden alle Properties der {@link Appbar.Action}-Komponente unterstüzt.
|
|
14
|
+
* Die `icon`-Property wird auf eine andere Art und Weise verwendet.
|
|
15
|
+
* Wird keine Farbe übergeben, wird die primäre Textfarbe (`primaryText`) aus den Theme verwendet.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} props - Es werden die Properties der {@link Appbar.Action}-Komponente unsterstützt
|
|
18
|
+
* @param {string} props.icon - Name eines Icons, welches über die {@link IconsOpenasist} angezeigt werden kann.
|
|
19
|
+
* @param {?ColorValue} props.color - Farbe des Icons. Wenn keine Farbe übergeben wird, wird die primäre Textfarbe (`primaryText`) aus den Theme verwendet.
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
22
|
+
export default function AppbarAction({ icon, color, ...rest }) {
|
|
23
|
+
const theme = useTheme();
|
|
24
|
+
const iconColor = color ?? theme?.colors?.primaryText;
|
|
25
|
+
|
|
26
|
+
const iconCallback = useCallback(
|
|
27
|
+
props =>
|
|
28
|
+
<IconsOpenasist
|
|
29
|
+
{...props}
|
|
30
|
+
icon={icon}
|
|
31
|
+
color={iconColor}
|
|
32
|
+
/>,
|
|
33
|
+
[icon, iconColor]
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<Appbar.Action
|
|
38
|
+
{...rest}
|
|
39
|
+
icon={iconCallback}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -30,8 +30,9 @@ import { libraryApi } from '../../libraries/core';
|
|
|
30
30
|
import { handleHtmlEntities } from '../../libraries/core/helper/format.helper';
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
import componentStyles from
|
|
33
|
+
import componentStyles from './styles';
|
|
34
34
|
import AppbarComponent from '../AppBar';
|
|
35
|
+
import AppbarAction from '../AppbarAction';
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
class BookDetailComponent extends React.Component {
|
|
@@ -248,9 +249,11 @@ class BookDetailComponent extends React.Component {
|
|
|
248
249
|
|
|
249
250
|
return (
|
|
250
251
|
<SafeAreaView style={[this.styles.container, themeStyles.safeAreaContainer]}>
|
|
251
|
-
<AppbarComponent
|
|
252
|
-
|
|
253
|
-
|
|
252
|
+
<AppbarComponent
|
|
253
|
+
{...this.props}
|
|
254
|
+
title={t('search:title')}
|
|
255
|
+
rightAction={<AppbarAction icon='share' onPress={this._onShare.bind(this)} />}
|
|
256
|
+
/>
|
|
254
257
|
{this._renderContent()}
|
|
255
258
|
</SafeAreaView>
|
|
256
259
|
);
|
|
@@ -32,8 +32,9 @@ import { connect } from 'react-redux'
|
|
|
32
32
|
import {withTranslation} from "react-i18next";
|
|
33
33
|
import merge from 'lodash/merge';
|
|
34
34
|
|
|
35
|
-
import componentStyles from
|
|
35
|
+
import componentStyles from './styles';
|
|
36
36
|
import AppbarComponent from '../AppBar';
|
|
37
|
+
import AppbarAction from '../AppbarAction';
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
/**
|
|
@@ -212,9 +213,11 @@ class ContactDetailComponent extends React.Component {
|
|
|
212
213
|
|
|
213
214
|
return (
|
|
214
215
|
<SafeAreaView style={[this.styles.container, themeStyles.safeAreaContainer]}>
|
|
215
|
-
<AppbarComponent
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
<AppbarComponent
|
|
217
|
+
{...this.props}
|
|
218
|
+
title={t('contact:contactInformation')}
|
|
219
|
+
rightAction={<AppbarAction icon='share' onPress={this._onShare.bind(this)} />}
|
|
220
|
+
/>
|
|
218
221
|
{this._renderContent()}
|
|
219
222
|
</SafeAreaView>
|
|
220
223
|
);
|
|
@@ -24,10 +24,11 @@ import {Appbar, Headline, List, withTheme} from "react-native-paper";
|
|
|
24
24
|
import { connect } from 'react-redux'
|
|
25
25
|
import merge from 'lodash/merge';
|
|
26
26
|
|
|
27
|
-
import componentStyles from
|
|
27
|
+
import componentStyles from './styles';
|
|
28
28
|
import AppbarComponent from '../AppBar';
|
|
29
|
+
import AppbarAction from '../AppbarAction';
|
|
29
30
|
import IconsOpenasist from '../../libraries/icons-openasist';
|
|
30
|
-
import {withTranslation} from
|
|
31
|
+
import { withTranslation } from 'react-i18next';
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
/**
|
|
@@ -339,9 +340,11 @@ class CourseDetailComponent extends React.Component {
|
|
|
339
340
|
|
|
340
341
|
return (
|
|
341
342
|
<SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
|
|
342
|
-
<AppbarComponent
|
|
343
|
-
|
|
344
|
-
|
|
343
|
+
<AppbarComponent
|
|
344
|
+
{...this.props}
|
|
345
|
+
title={t('course:lectureInformation')}
|
|
346
|
+
rightAction={<AppbarAction icon='share' onPress={this._onShare.bind(this)} />}
|
|
347
|
+
/>
|
|
345
348
|
{this._renderContent()}
|
|
346
349
|
</SafeAreaView>
|
|
347
350
|
);
|
|
@@ -37,8 +37,9 @@ import moment from "moment";
|
|
|
37
37
|
import WebViewAutoHeight from '../../libraries/react-native-webview-autoheight';
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
import componentStyles from
|
|
40
|
+
import componentStyles from './styles';
|
|
41
41
|
import AppbarComponent from '../AppBar';
|
|
42
|
+
import AppbarAction from '../AppbarAction';
|
|
42
43
|
import { selectFeedById } from '../../libraries/core/redux/reducers/api';
|
|
43
44
|
|
|
44
45
|
|
|
@@ -350,9 +351,15 @@ class NewsDetailComponent extends React.Component {
|
|
|
350
351
|
|
|
351
352
|
return (
|
|
352
353
|
<SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
|
|
353
|
-
<AppbarComponent
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
<AppbarComponent
|
|
355
|
+
{...this.props}
|
|
356
|
+
title={title}
|
|
357
|
+
rightAction={
|
|
358
|
+
newsType
|
|
359
|
+
? null
|
|
360
|
+
: <AppbarAction icon='share' onPress={this._onShare.bind(this)} />
|
|
361
|
+
}
|
|
362
|
+
/>
|
|
356
363
|
{newsType === NewsDetailComponent.newsTypes.topNews ? this._renderTopNewsContent(news) : this._renderContent(news)}
|
|
357
364
|
</SafeAreaView>
|
|
358
365
|
);
|
|
@@ -20,17 +20,22 @@ import {
|
|
|
20
20
|
Share,
|
|
21
21
|
TouchableOpacity, ActivityIndicator
|
|
22
22
|
} from 'react-native';
|
|
23
|
-
import {connect} from 'react-redux'
|
|
24
|
-
import {
|
|
25
|
-
|
|
23
|
+
import { connect } from 'react-redux'
|
|
24
|
+
import {
|
|
25
|
+
Appbar,
|
|
26
|
+
Headline,
|
|
27
|
+
List,
|
|
28
|
+
withTheme,
|
|
29
|
+
} from "react-native-paper";
|
|
30
|
+
import { withTranslation } from "react-i18next";
|
|
31
|
+
import { WebView } from "react-native-webview";
|
|
26
32
|
import merge from 'lodash/merge';
|
|
27
33
|
|
|
28
|
-
|
|
29
34
|
import AppbarComponent from '../AppBar';
|
|
35
|
+
import AppbarAction from '../AppbarAction';
|
|
30
36
|
import IconsOpenasist from '../../libraries/icons-openasist';
|
|
31
37
|
|
|
32
|
-
import componentStyles from
|
|
33
|
-
import {WebView} from "react-native-webview";
|
|
38
|
+
import componentStyles from './styles';
|
|
34
39
|
|
|
35
40
|
/**
|
|
36
41
|
* Room Detail Component
|
|
@@ -262,9 +267,11 @@ class RoomDetailComponent extends React.Component {
|
|
|
262
267
|
|
|
263
268
|
return (
|
|
264
269
|
<SafeAreaView style={[this.styles.container, themeStyles.safeAreaContainer]}>
|
|
265
|
-
<AppbarComponent
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
<AppbarComponent
|
|
271
|
+
{...this.props}
|
|
272
|
+
title={t('room:directory')}
|
|
273
|
+
rightAction={<AppbarAction icon='share' onPress={this._onShare.bind(this)} />}
|
|
274
|
+
/>
|
|
268
275
|
{this._renderContent()}
|
|
269
276
|
</SafeAreaView>
|
|
270
277
|
);
|
package/index.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// Exports Components
|
|
3
3
|
|
|
4
4
|
export { default as AppBar } from './components/AppBar';
|
|
5
|
+
export { default as AppbarAction } from './components/AppbarAction';
|
|
5
6
|
export { default as BookDetail } from './components/BookDetail';
|
|
7
|
+
export { default as ComponentJobsFilter } from './components/ComponentJobsFilter';
|
|
6
8
|
export { default as ConnectivityWarning } from './components/ConnectivityWarning';
|
|
7
9
|
export { default as ContactDetail } from './components/ContactDetail';
|
|
8
10
|
export { default as CourseDetail } from './components/CourseDetail';
|
|
@@ -26,10 +28,10 @@ export { default as QuickLinks } from './components/QuickLinks';
|
|
|
26
28
|
export { default as RoomDetail } from './components/RoomDetail';
|
|
27
29
|
export { default as ScaledImage } from './components/ScaledImage';
|
|
28
30
|
export { default as SearchResults } from './components/SearchResults';
|
|
29
|
-
export { default as SettingSection } from './components/SettingSection';
|
|
30
31
|
export { default as SettingsDialog } from './components/SettingsDialog';
|
|
31
32
|
export { default as SettingsDialogRadio } from './components/SettingsDialogRadio';
|
|
32
33
|
export { default as SettingsDialogSelect } from './components/SettingsDialogSelect';
|
|
34
|
+
export { default as SettingSection } from './components/SettingSection';
|
|
33
35
|
export { default as TimetableCodeInput } from './components/TimetableCodeInput';
|
|
34
36
|
export { default as TimetableDay } from './components/TimetableDay';
|
|
35
37
|
export { default as TimetableEvent } from './components/TimetableEvent';
|
|
@@ -39,7 +41,6 @@ export { default as TimetableWeek } from './components/TimetableWeek';
|
|
|
39
41
|
export { default as TopNews } from './components/TopNews';
|
|
40
42
|
export { default as TopNewsHtwk } from './components/TopNewsHtwk';
|
|
41
43
|
export { default as WebView } from './components/WebView';
|
|
42
|
-
export { default as ComponentJobsFilter } from './components/ComponentJobsFilter';
|
|
43
44
|
|
|
44
45
|
// Exports Views
|
|
45
46
|
|
|
@@ -12,70 +12,69 @@
|
|
|
12
12
|
* limitations under the License.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import React from 'react'
|
|
15
|
+
import React from 'react'
|
|
16
16
|
|
|
17
|
-
import { useTheme } from
|
|
18
|
-
import createIconSet from '@expo/vector-icons/createIconSet'
|
|
19
|
-
import PropTypes from
|
|
20
|
-
import { SvgCssUri } from 'react-native-svg';
|
|
21
|
-
const glyphMap = {
|
|
22
|
-
"bus": "a",
|
|
23
|
-
"train": "b",
|
|
24
|
-
"close": "c",
|
|
25
|
-
"messages": "d",
|
|
26
|
-
"menu": "e",
|
|
27
|
-
"grid": "f",
|
|
28
|
-
"more-horizontal": "g",
|
|
29
|
-
"more-vertical": "h",
|
|
30
|
-
"paperplane-outline": "i",
|
|
31
|
-
"partlysunny": "j",
|
|
32
|
-
"partlysunny-outline": "k",
|
|
33
|
-
"rainy": "l",
|
|
34
|
-
"rainy-outline": "m",
|
|
35
|
-
"thunderstorm": "n",
|
|
36
|
-
"thunderstorm-outline": "o",
|
|
37
|
-
"sunny": "p",
|
|
38
|
-
"sunny-outline": "q",
|
|
39
|
-
"down": "r",
|
|
40
|
-
"download": "s",
|
|
41
|
-
"print": "t",
|
|
42
|
-
"hilfe": "u",
|
|
43
|
-
"back": "v",
|
|
44
|
-
"lock": "w",
|
|
45
|
-
"lock-open": "x",
|
|
46
|
-
"navigation": "y",
|
|
47
|
-
"forward": "z",
|
|
48
|
-
"profile": "A",
|
|
49
|
-
"opal": "B",
|
|
50
|
-
"mensa": "C",
|
|
51
|
-
"location": "D",
|
|
52
|
-
"inbox": "E",
|
|
53
|
-
"imprint": "F",
|
|
54
|
-
"pts": "G",
|
|
55
|
-
"feedback": "H",
|
|
56
|
-
"book": "I",
|
|
57
|
-
"news": "J",
|
|
58
|
-
"up": "K",
|
|
59
|
-
"tram": "L",
|
|
60
|
-
"rss": "M",
|
|
61
|
-
"map-search": "N",
|
|
62
|
-
"m-start1": "O",
|
|
63
|
-
"dashboard": "P",
|
|
64
|
-
"timetable": "Q",
|
|
65
|
-
"search": "R",
|
|
66
|
-
"settings": "S",
|
|
67
|
-
"coffee": "T",
|
|
68
|
-
"check": "V",
|
|
69
|
-
"star": "W",
|
|
70
|
-
"star-selected": "X",
|
|
71
|
-
"edit": "Y",
|
|
72
|
-
"time": "A1",
|
|
73
|
-
"open-external": "A2",
|
|
74
|
-
"share": "1",
|
|
75
|
-
"accessibility": "A3",
|
|
76
|
-
};
|
|
77
|
-
const CustomIcon = createIconSet(glyphMap, 'openasist');
|
|
17
|
+
import { useTheme } from 'react-native-paper'
|
|
18
|
+
import createIconSet from '@expo/vector-icons/createIconSet'
|
|
19
|
+
import PropTypes from 'prop-types'
|
|
78
20
|
|
|
21
|
+
const glyphMap = {
|
|
22
|
+
bus: 'a',
|
|
23
|
+
train: 'b',
|
|
24
|
+
close: 'c',
|
|
25
|
+
messages: 'd',
|
|
26
|
+
menu: 'e',
|
|
27
|
+
grid: 'f',
|
|
28
|
+
'more-horizontal': 'g',
|
|
29
|
+
'more-vertical': 'h',
|
|
30
|
+
'paperplane-outline': 'i',
|
|
31
|
+
partlysunny: 'j',
|
|
32
|
+
'partlysunny-outline': 'k',
|
|
33
|
+
rainy: 'l',
|
|
34
|
+
'rainy-outline': 'm',
|
|
35
|
+
thunderstorm: 'n',
|
|
36
|
+
'thunderstorm-outline': 'o',
|
|
37
|
+
sunny: 'p',
|
|
38
|
+
'sunny-outline': 'q',
|
|
39
|
+
down: 'r',
|
|
40
|
+
download: 's',
|
|
41
|
+
print: 't',
|
|
42
|
+
hilfe: 'u',
|
|
43
|
+
back: 'v',
|
|
44
|
+
lock: 'w',
|
|
45
|
+
'lock-open': 'x',
|
|
46
|
+
navigation: 'y',
|
|
47
|
+
forward: 'z',
|
|
48
|
+
profile: 'A',
|
|
49
|
+
opal: 'B',
|
|
50
|
+
mensa: 'C',
|
|
51
|
+
location: 'D',
|
|
52
|
+
inbox: 'E',
|
|
53
|
+
imprint: 'F',
|
|
54
|
+
pts: 'G',
|
|
55
|
+
feedback: 'H',
|
|
56
|
+
book: 'I',
|
|
57
|
+
news: 'J',
|
|
58
|
+
up: 'K',
|
|
59
|
+
tram: 'L',
|
|
60
|
+
rss: 'M',
|
|
61
|
+
'map-search': 'N',
|
|
62
|
+
'm-start1': 'O',
|
|
63
|
+
dashboard: 'P',
|
|
64
|
+
timetable: 'Q',
|
|
65
|
+
search: 'R',
|
|
66
|
+
settings: 'S',
|
|
67
|
+
coffee: 'T',
|
|
68
|
+
check: 'V',
|
|
69
|
+
star: 'W',
|
|
70
|
+
'star-selected': 'X',
|
|
71
|
+
edit: 'Y',
|
|
72
|
+
time: 'A1',
|
|
73
|
+
'open-external': 'A2',
|
|
74
|
+
share: '1',
|
|
75
|
+
accessibility: 'A3'
|
|
76
|
+
}
|
|
77
|
+
const CustomIcon = createIconSet(glyphMap, 'openasist')
|
|
79
78
|
|
|
80
79
|
/**
|
|
81
80
|
* Icons of the Openasist app
|
|
@@ -97,62 +96,62 @@ const CustomIcon = createIconSet(glyphMap, 'openasist');
|
|
|
97
96
|
* Navigation-Parameters:
|
|
98
97
|
* - none
|
|
99
98
|
*/
|
|
100
|
-
function IconsOpenasist({ icon, iconSVG: IconSVG, size, color, accessibilityLabel, ...props }) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
function IconsOpenasist ({ icon, iconSVG: IconSVG, size, color, accessibilityLabel, ...props }) {
|
|
100
|
+
const theme = useTheme()
|
|
101
|
+
const { AppIcons } = theme
|
|
102
|
+
const ThemeIcon = theme.icons?.[icon]
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
104
|
+
const iconSize = size ?? 24
|
|
105
|
+
const iconAriaLabel = props?.['aria-label'] ?? accessibilityLabel ?? null
|
|
106
|
+
const iconAriaHidden = !iconAriaLabel
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
const iconProps = {
|
|
109
|
+
color: color ?? 'black',
|
|
110
|
+
'aria-hidden': iconAriaHidden,
|
|
111
|
+
'aria-label': iconAriaLabel
|
|
112
|
+
}
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
114
|
+
if (IconSVG) {
|
|
115
|
+
return (
|
|
116
|
+
<IconSVG
|
|
117
|
+
{...iconProps}
|
|
118
|
+
width={iconSize}
|
|
119
|
+
height={iconSize}
|
|
120
|
+
/>
|
|
121
|
+
)
|
|
122
|
+
} else if (typeof ThemeIcon === 'function') {
|
|
123
|
+
return (
|
|
124
|
+
<ThemeIcon
|
|
125
|
+
{...iconProps}
|
|
126
|
+
width={iconSize}
|
|
127
|
+
height={iconSize}
|
|
128
|
+
/>
|
|
129
|
+
)
|
|
130
|
+
} else if (AppIcons) {
|
|
131
|
+
return (
|
|
132
|
+
<AppIcons
|
|
133
|
+
{...iconProps}
|
|
134
|
+
name={icon}
|
|
135
|
+
size={iconSize}
|
|
136
|
+
/>
|
|
137
|
+
)
|
|
138
|
+
} else {
|
|
139
|
+
return (
|
|
140
|
+
<CustomIcon
|
|
141
|
+
{...iconProps}
|
|
142
|
+
name={icon}
|
|
143
|
+
size={iconSize}
|
|
144
|
+
/>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
// propTypes für Funktionen wird in react.js 19 entfernt
|
|
151
150
|
IconsOpenasist.propTypes = {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
151
|
+
icon: PropTypes.string,
|
|
152
|
+
iconSVG: PropTypes.func,
|
|
153
|
+
size: PropTypes.number,
|
|
154
|
+
color: PropTypes.string
|
|
155
|
+
}
|
|
157
156
|
|
|
158
|
-
export default IconsOpenasist
|
|
157
|
+
export default IconsOpenasist
|
package/package.json
CHANGED
|
@@ -56,10 +56,10 @@ export default function PublicTransportTicketView() {
|
|
|
56
56
|
const [ticketBarcode, ticketOwner, ticketValidFrom, ticketValidTo, refreshTicket] = usePublicTransportTicket();
|
|
57
57
|
// Gültikeitsangabem in lokaliesierte Strings umwandeln
|
|
58
58
|
// Es wird immer in deutsche Datumangaben umgewandelt, weil das Deutschlandticket nur in deutschland gültig ist.
|
|
59
|
-
const localizedTicketValidFrom = ticketValidFrom?.isValid
|
|
59
|
+
const localizedTicketValidFrom = ticketValidFrom?.isValid
|
|
60
60
|
? ticketValidFrom?.setLocale('de')?.toLocaleString()
|
|
61
61
|
: null;
|
|
62
|
-
const localizedTicketValidTo = ticketValidTo?.isValid
|
|
62
|
+
const localizedTicketValidTo = ticketValidTo?.isValid
|
|
63
63
|
? ticketValidTo?.setLocale('de')?.toLocaleString()
|
|
64
64
|
: null;
|
|
65
65
|
|