@olea-bps/views 1.0.0

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.
Files changed (52) hide show
  1. package/Callmanager/index.js +148 -0
  2. package/Callmanager/styles.js +62 -0
  3. package/Canteens/index.js +383 -0
  4. package/Canteens/styles.js +89 -0
  5. package/Dashboard/index.js +176 -0
  6. package/Dashboard/styles.js +16 -0
  7. package/DashboardHtwk/index.js +197 -0
  8. package/DashboardHtwk/styles.js +24 -0
  9. package/Event/index.js +369 -0
  10. package/Event/styles.js +63 -0
  11. package/FeedList/index.js +165 -0
  12. package/FeedList/styles.js +15 -0
  13. package/FeedNews/index.js +243 -0
  14. package/FeedNews/styles.js +32 -0
  15. package/Flexmenu/index.js +185 -0
  16. package/Flexmenu/styles.js +62 -0
  17. package/FlexmenuWebview/index.js +167 -0
  18. package/FlexmenuWebview/styles.js +16 -0
  19. package/Howhy/index.js +151 -0
  20. package/Howhy/styles.js +11 -0
  21. package/Jobs/index.js +217 -0
  22. package/Jobs/styles.js +41 -0
  23. package/MainMenu/index.js +329 -0
  24. package/MainMenu/styles.js +36 -0
  25. package/NewsTabbar/index.js +164 -0
  26. package/NewsTabbar/styles.js +27 -0
  27. package/Opal/index.js +136 -0
  28. package/Opal/styles.js +11 -0
  29. package/PublicTransportTicket/index.js +173 -0
  30. package/PublicTransportTicket/styles.js +17 -0
  31. package/Search/index.js +186 -0
  32. package/Search/styles.js +67 -0
  33. package/SettingsAccessibility/index.js +148 -0
  34. package/SettingsAccessibility/styles.js +13 -0
  35. package/SettingsAppInfo/index.js +86 -0
  36. package/SettingsAppInfo/styles.js +18 -0
  37. package/SettingsCanteens/index.js +249 -0
  38. package/SettingsCanteens/styles.js +33 -0
  39. package/SettingsGeneral/index.js +173 -0
  40. package/SettingsGeneral/styles.js +28 -0
  41. package/SettingsNotifications/index.js +204 -0
  42. package/SettingsNotifications/styles.js +38 -0
  43. package/SettingsUser/index.js +170 -0
  44. package/SettingsUser/styles.js +17 -0
  45. package/TimetableCalendar/index.js +322 -0
  46. package/TimetableCalendar/styles.js +117 -0
  47. package/TimetableList/index.js +397 -0
  48. package/TimetableList/styles.js +55 -0
  49. package/Webviews/index.js +158 -0
  50. package/Webviews/styles.js +11 -0
  51. package/index.js +25 -0
  52. package/package.json +41 -0
@@ -0,0 +1,329 @@
1
+ /**
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import React, { useMemo, useEffect } from 'react';
16
+ import {
17
+ SafeAreaView,
18
+ ScrollView,
19
+ StyleSheet,
20
+ Text,
21
+ } from 'react-native';
22
+
23
+ import { connect } from 'react-redux'
24
+ import { withTheme, useTheme, Appbar } from 'react-native-paper';
25
+ import { TabView, TabBar, TabBarItem } from "react-native-tab-view";
26
+ import { withTranslation, useTranslation } from 'react-i18next';
27
+
28
+ import merge from 'lodash/merge';
29
+ import moment from "moment/moment";
30
+
31
+ import { onUpdateRefreshing, useActiveStagingMenuItems } from '@olea-bps/core';
32
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
33
+ import { MainMenuEntry } from '@olea-bps/components';
34
+ import { DevelopmentDialog } from '@olea-bps/components';
35
+ import { useMainMenuEntries } from '@olea-bps/context-flex-menu';
36
+
37
+ import componentStyles from './styles'
38
+
39
+ /**
40
+ * Die Daten für einen Menüeintrag, welche für das Rendern eines Menüseintarges in einem Menü verwendet wird.
41
+ * Es kann eine Views oder eine URL als Ziel hinterlegt werden.
42
+ * Soll eine URL in einer webview geöffnet werden, muss eine URL als String über das Datenfels `url` hinterlegt werden.
43
+ * Eine View wird geöffnet, wenn das Datenfeld `view` einen View-Namen enthält.
44
+ * Das anzuzeigende Icon kann über das Datenfeld `icon` oder `iconSVG` übergeben werden.
45
+ *
46
+ * @typedef {object} MenuItem
47
+ * @property {string} title - Titel des Menüeintrages
48
+ * @property {string} [icon] Schlüssel des Icons, welches mit dem Titel angeziegt werden soll. Stattdessen kann auch `iconSVG` verwendet werden.
49
+ * @property {React.ReactNode} [iconSVG] Icon als SVG-ReactNode. Stattdessen kann auch `icon` verwendet werden.
50
+ * @property {string} [url] URL welche in einer Webview geöffnet werden soll, wenn der Nutzer den Menueintrag auswählt.
51
+ * @property {string} [view] Name der zu öffnenden View
52
+ */
53
+
54
+ /**
55
+ * Liste von Hauptmenüeinträgen
56
+ *
57
+ * @param {object} props
58
+ * @param {MenuItem[]} props.menuItems Liste der anzuzeigenden Menueinträge als {@link MenuItem}s
59
+ * @returns {React.JSX.Element[]}
60
+ */
61
+ function MainMenuEntryList({ menuItems }) {
62
+ return menuItems
63
+ ? menuItems.map(
64
+ menuItem =>
65
+ <MainMenuEntry
66
+ key={menuItem.title}
67
+ title={menuItem.title}
68
+ view={menuItem?.view}
69
+ url={menuItem?.url}
70
+ icon={menuItem?.icon}
71
+ iconSVG={menuItem?.iconSVG}
72
+ isLocalized={menuItem?.isLocalized}
73
+ />
74
+ )
75
+ : (
76
+ <Text>Nicht verfügbar</Text>
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Tabbar für die Kategorien des Menüs.
82
+ */
83
+ function MainMenuTabbar(props) {
84
+ const { t } = useTranslation();
85
+ const theme = useTheme();
86
+ const { themeStyles } = theme;
87
+
88
+ return (
89
+ <TabBar
90
+ {...props}
91
+ scrollEnabled
92
+ style={themeStyles.tabs}
93
+ labelStyle={themeStyles.tab}
94
+ activeColor={themeStyles.tabs.activeColor}
95
+ inactiveColor={themeStyles.tabs.inactiveColor}
96
+ indicatorStyle={themeStyles.tabIndicator}
97
+ tabStyle={{ width: 'auto', paddingHorizontal: 20 }}
98
+ renderTabBarItem={({ route, navigationState, ...rest}) =>
99
+ <TabBarItem
100
+ {...rest}
101
+ key={route.key}
102
+ route={route}
103
+ navigationState={navigationState}
104
+ labelStyle={themeStyles.tab}
105
+ activeColor={themeStyles.tabs.activeColor}
106
+ inactiveColor={themeStyles.tabs.inactiveColor}
107
+ // Die einbindung von moment.js zum Anzeigen des Wochentages sollte langfristig entfernt werden.
108
+ // Funktioniert die Luxon funktionalität der Wochenanzeige nicht unter iOS datetime.toFormat('ccc')
109
+ labelText={t(route.title).toUpperCase()}
110
+ accessible={true}
111
+ accessibilityLabel={t(route.title)}
112
+ />
113
+ }
114
+ />
115
+ );
116
+ }
117
+
118
+ /**
119
+ * Scene/Inhalt eines Tabs des Hauptmenüs.
120
+ *
121
+ * @param {object} props
122
+ * @param {object} props.route
123
+ * @param {string} props.route.key Schlüssel der Route und Schlüssel, welcher für die errechnung der Menüeintrage verwendet wird
124
+ */
125
+ function MainMenuScene({ route: { key: mainMenuItemsKey } }) {
126
+ const theme = useTheme();
127
+ const { i18n } = useTranslation();
128
+ const appSettings = theme?.appSettings;
129
+ const availableMenuItems = appSettings?.mainMenu?.items?.[mainMenuItemsKey];
130
+ const activeStagingMenuItems = useActiveStagingMenuItems();
131
+ const [flexMainMenuEntries, refreshFlexMenuEntries] = useMainMenuEntries();
132
+
133
+ useEffect(
134
+ () => {
135
+ refreshFlexMenuEntries?.();
136
+ },
137
+ [refreshFlexMenuEntries]
138
+ )
139
+
140
+ // Verfügbare Sprachen
141
+ const languages = appSettings?.languages;
142
+ // Eingestellte Sprache aus der Übersetzung holen
143
+ const selectedLanguage = i18n.language;
144
+ // Hinterlegte Sprachen durchgehen und nach dem erweiterten Sprachcode holen
145
+ const selectedExtLanguageCode = languages
146
+ // Finde die derzeitige eingestellte Sprache
147
+ .find(language => language?.code === selectedLanguage)
148
+ // Erweiterten Sprachcode von der gefundenen Sprache auslesen
149
+ ?.extCode;
150
+
151
+ const styles = useMemo(
152
+ () => StyleSheet.create(componentStyles(theme)),
153
+ [theme]
154
+ );
155
+
156
+
157
+
158
+ // Es werden Hauptmenüeintrage herausgefiltert, die nur im Stagingmodus angezeigt werden sollen, aber nicht aktiv sind
159
+ const activeMenuItems = useMemo(
160
+ () => availableMenuItems.filter(
161
+ menuItem => {
162
+ const menuItemKey = `${menuItem?.title}`;
163
+ // Ist der Menüpunkt durch Appeinstellungen aktiv?
164
+ const isActive = menuItem?.active ?? true;
165
+ // Ist der Menüpunkt durch die Entwicklereinstellungen aktiviert?
166
+ const isActiveStagingMenuItem = activeStagingMenuItems.includes(menuItemKey);
167
+
168
+ // Entweder ist der Menüpunkt standadtmäßig aktiv oder er wurde durch den Developmenteinstellungen-Dialog aktiviert
169
+ return isActive || isActiveStagingMenuItem;
170
+ }
171
+ ),
172
+ [availableMenuItems, activeStagingMenuItems]
173
+ );
174
+
175
+ const flexMenuItems = useMemo(
176
+ () => flexMainMenuEntries
177
+ .filter(flexMainMenuEntry => flexMainMenuEntry.language === selectedExtLanguageCode)
178
+ .filter(flexMainMenuEntry => flexMainMenuEntry.type === mainMenuItemsKey)
179
+ .map(
180
+ flexMainMenuEntry =>
181
+ ({
182
+ title: flexMainMenuEntry?.title,
183
+ icon: flexMainMenuEntry?.icon,
184
+ ...(
185
+ flexMainMenuEntry?.url
186
+ ? { url: flexMainMenuEntry.url }
187
+ : { view: flexMainMenuEntry?.id }
188
+ )
189
+ })
190
+ ),
191
+ [flexMainMenuEntries, selectedExtLanguageCode, mainMenuItemsKey]
192
+ )
193
+
194
+ return (
195
+ <ScrollView style={styles.container}>
196
+ <MainMenuEntryList
197
+ menuItems={[
198
+ ...activeMenuItems,
199
+ ...flexMenuItems,
200
+ ]}
201
+ />
202
+ </ScrollView>
203
+ );
204
+ }
205
+
206
+ /**
207
+ * Main Menu View
208
+ *
209
+ * Show a menu of views which are not available in
210
+ * the bottom tab bar. The menu split in categories.
211
+ * Each category has its own tab.
212
+ *
213
+ * Parameters:
214
+ * - none
215
+ *
216
+ * Navigation-Parameters:
217
+ * - none
218
+ */
219
+ class MainMenuView extends React.Component {
220
+ static navigationOptions = {
221
+ header: null
222
+ };
223
+
224
+ // Styles of this component
225
+ styles;
226
+
227
+ state = {
228
+ index: 0,
229
+ routes: null,
230
+ developCounter: 0,
231
+ isDevelopMenuVisible: false,
232
+ };
233
+
234
+
235
+ constructor(props) {
236
+ super(props);
237
+
238
+ // ------------------------------------------------------------------------
239
+ // PLUGIN FUNCTIONALITY
240
+ // ------------------------------------------------------------------------
241
+
242
+ const { pluginStyles, theme } = this.props;
243
+ this.styles = componentStyles(theme);
244
+
245
+ if (pluginStyles) {
246
+ this.styles = merge(this.styles, pluginStyles);
247
+ }
248
+
249
+ this.styles = StyleSheet.create(this.styles);
250
+
251
+ // ------------------------------------------------------------------------
252
+
253
+ const { appSettings } = this.props.theme;
254
+ const menuRoutes = appSettings.mainMenu.routes;
255
+ if (menuRoutes) {
256
+ this.state.routes = menuRoutes;
257
+ }
258
+ }
259
+
260
+ componentDidMount() {
261
+ this.props.navigation.addListener('focus', () => {
262
+ this.setState({ developCounter: 0 });
263
+ });
264
+ }
265
+
266
+ _hideDevDialog = () => {
267
+ this.setState({ isDevelopMenuVisible: false });
268
+ }
269
+
270
+ render() {
271
+ // ------------------------------------------------------------------------
272
+ // PLUGIN FUNCTIONALITY
273
+ // ------------------------------------------------------------------------
274
+ const PluginComponent = this.props.pluginComponent;
275
+ if (PluginComponent) {
276
+ return <PluginComponent />;
277
+ }
278
+ // ------------------------------------------------------------------------
279
+
280
+ const {
281
+ t,
282
+ theme: { themeStyles, colors },
283
+ settings: { settingsDevelop: { useStaging } } } = this.props;
284
+ const {
285
+ developCounter
286
+ } = this.state;
287
+
288
+ return (
289
+ <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
290
+ <AppbarComponent title={t('menu:title')} {...this.props}
291
+ rightAction={
292
+ <>
293
+ {useStaging ? <Text>Server: Staging</Text> : null}
294
+ <Appbar.Action icon={developCounter >= 10 ? 'grid' : undefined} onPress={this._handlePressDevelop.bind(this)} />
295
+ </>
296
+ }
297
+ />
298
+ {this.state.routes && <TabView
299
+ style={this.props.style}
300
+ navigationState={this.state}
301
+ renderTabBar={MainMenuTabbar}
302
+ renderScene={(props) => <MainMenuScene {...props} />}
303
+ onIndexChange={index => this.setState({ index })}
304
+ />}
305
+ <DevelopmentDialog
306
+ visible={this.state.isDevelopMenuVisible}
307
+ onDismiss={this._hideDevDialog}
308
+ />
309
+ </SafeAreaView>
310
+ );
311
+ }
312
+
313
+ _handlePressDevelop = () => {
314
+ if (this.state.developCounter >= 10) {
315
+ this.setState({ isDevelopMenuVisible: true });
316
+ }
317
+ this.setState({ developCounter: this.state.developCounter + 1 });
318
+ }
319
+ }
320
+
321
+ const mapStateToProps = state => {
322
+ return {
323
+ pluginComponent: state.pluginReducer.mainMenu.component,
324
+ pluginStyles: state.pluginReducer.mainMenu.styles,
325
+ settings: state.settingReducer
326
+ };
327
+ };
328
+
329
+ export default connect(mapStateToProps, { onUpdateRefreshing })(withTranslation()(withTheme(MainMenuView)))
@@ -0,0 +1,36 @@
1
+ export default function (theme) {
2
+ return {
3
+ container: {
4
+ flex: 1,
5
+ paddingTop: 0,
6
+ backgroundColor: theme.colors.background,
7
+ },
8
+ optionTextContainer: {
9
+ flex: 1,
10
+ flexDirection: 'row',
11
+ paddingVertical: 20,
12
+ paddingHorizontal: 20,
13
+ alignContent: 'center'
14
+ },
15
+ optionsTitleText: {
16
+ fontSize: theme.fontSizes.l,
17
+ textAlign: 'left'
18
+ },
19
+ optionIconContainer: {
20
+ flex: 0.2
21
+ },
22
+ option: {
23
+ backgroundColor: theme.colors.background,
24
+ paddingHorizontal: 0,
25
+ paddingVertical: 5,
26
+ borderBottomWidth: 1,
27
+ borderBottomColor: theme.colors.accent
28
+ },
29
+ optionText: {
30
+ flex: 1,
31
+ fontSize: theme.fontSizes.subtitle,
32
+ marginTop: 1,
33
+ alignSelf: 'center'
34
+ }
35
+ }
36
+ };
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import React, { useMemo, useState, useEffect } from 'react';
16
+ import {
17
+ ActivityIndicator,
18
+ SafeAreaView,
19
+ StyleSheet,
20
+ Text,
21
+ View,
22
+ Dimensions
23
+ } from 'react-native';
24
+
25
+ import { TabView, TabBar, TabBarItem } from "react-native-tab-view";
26
+ import { useTheme } from 'react-native-paper';
27
+ import { useTranslation } from 'react-i18next';
28
+
29
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
30
+ import { NewsList } from '@olea-bps/components';
31
+ import { useNewsChannels } from '@olea-bps/context-news';
32
+
33
+ import componentStyles from './styles';
34
+
35
+ export default function NewsTabBarView(props) {
36
+ const theme = useTheme();
37
+ const { colors, themeStyles } = theme;
38
+ const { t } = useTranslation();
39
+ const [newsChannels, refreshNewsChannels] = useNewsChannels();
40
+
41
+ const [newsTabIndex, setNewsTabIndex] = useState(0);
42
+
43
+ const newsTabRoutes = useMemo(
44
+ () =>
45
+ Array.isArray(newsChannels)
46
+ ? newsChannels?.map(
47
+ newschannel =>
48
+ ({
49
+ key: newschannel.feedid,
50
+ title: newschannel.title,
51
+ })
52
+ )
53
+ : null,
54
+ [newsChannels]
55
+ );
56
+
57
+ const styles = useMemo(
58
+ () => StyleSheet.create(componentStyles(theme)),
59
+ [theme, componentStyles]
60
+ );
61
+
62
+ useEffect(
63
+ () => {
64
+ refreshNewsChannels?.();
65
+ },
66
+ [refreshNewsChannels]
67
+ )
68
+
69
+ return (
70
+ <SafeAreaView style={[styles.container, themeStyles.appSafeAreaContainer]}>
71
+ <AppbarComponent
72
+ {...props}
73
+ title={t('news:feeds')}
74
+ />
75
+ <View style={themeStyles.container}>
76
+ {
77
+ !Array.isArray(newsTabRoutes)
78
+ ? <ActivityIndicator
79
+ style={styles.activity}
80
+ size="large"
81
+ color={colors.loadingIndicator}
82
+ />
83
+ : newsTabRoutes.length
84
+ ? newsTabRoutes.length === 1
85
+ ? <View style={styles.screenView} >
86
+ <View style={styles.tabHeaderView} >
87
+ <Text style={styles.tabHeaderText} >
88
+ {newsTabRoutes[0].title}
89
+ </Text>
90
+ </View>
91
+ <NewsList
92
+ active={true}
93
+ newsChannelId={newsTabRoutes[0].key}
94
+ navigation={props.navigation}
95
+ />
96
+ </View>
97
+ : <TabView
98
+ style={props.style}
99
+ navigationState={{
100
+ routes: newsTabRoutes,
101
+ index: newsTabIndex,
102
+ }}
103
+ renderTabBar={
104
+ props => {
105
+ const { key, ...restProps } = props;
106
+ return (<View style={styles.tabBarContainer}>
107
+ <TabBar
108
+ {...restProps}
109
+ scrollEnabled
110
+ style={themeStyles.tabs}
111
+ labelStyle={themeStyles.tab}
112
+ indicatorStyle={themeStyles.tabIndicator}
113
+ tabStyle={{ width: 'auto', paddingHorizontal: 20 }}
114
+ initialLayout={{
115
+ width: Dimensions.get('window').width,
116
+ height: Dimensions.get('window').height
117
+ }}
118
+ renderTabBarItem={({ route, navigationState, ...rest}) =>
119
+ <TabBarItem
120
+ {...rest}
121
+ key={route.key}
122
+ route={route}
123
+ navigationState={navigationState}
124
+ labelStyle={themeStyles.tab}
125
+ activeColor={themeStyles.tabs.activeColor}
126
+ inactiveColor={themeStyles.tabs.inactiveColor}
127
+ // Die einbindung von moment.js zum Anzeigen des Wochentages sollte langfristig entfernt werden.
128
+ // Funktioniert die Luxon funktionalität der Wochenanzeige nicht unter iOS datetime.toFormat('ccc')
129
+ labelText={route.title}
130
+ accessible={true}
131
+ accessibilityLabel={route.title}
132
+ />
133
+ }
134
+ />
135
+ </View>);
136
+ }
137
+ }
138
+ renderScene={
139
+ ({ route }) =>
140
+ <NewsList
141
+ active={route.key === newsTabRoutes[newsTabIndex].key}
142
+ newsChannelId={route.key}
143
+ navigation={props.navigation}
144
+ />
145
+ }
146
+ onIndexChange={setNewsTabIndex}
147
+ lazy
148
+ lazyPreloadDistance={1}
149
+ />
150
+ : <View style={styles.screenView} >
151
+ <View style={styles.tabHeaderView} >
152
+ <Text style={styles.tabHeaderText} >
153
+ {t('news:noResult')}
154
+ </Text>
155
+ </View>
156
+ <Text>
157
+ {t('news:noResult')}
158
+ </Text>
159
+ </View>
160
+ }
161
+ </View>
162
+ </SafeAreaView>
163
+ );
164
+ }
@@ -0,0 +1,27 @@
1
+ export default function(theme) {
2
+ return {
3
+ container: {
4
+ flex: 1
5
+ },
6
+ innerContainer: {
7
+ flex: 1
8
+ },
9
+ cardContent: {
10
+ paddingLeft: theme.paddings.large,
11
+ paddingTop: theme.paddings.small,
12
+ paddingBottom: theme.paddings.small
13
+ },
14
+ screenView: {
15
+ flex: 1
16
+ },
17
+ tabHeaderText: {
18
+ ...theme.fonts.medium,
19
+ color: theme.colors.primaryText
20
+ },
21
+ tabHeaderView: {
22
+ backgroundColor: theme.colors.primary,
23
+ alignItems: "center",
24
+ padding: theme.paddings.xsmall
25
+ }
26
+ }
27
+ };
package/Opal/index.js ADDED
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import React from 'react';
16
+ import {SafeAreaView, StyleSheet, ActivityIndicator, View} from 'react-native';
17
+ import {connect} from 'react-redux'
18
+ import {Appbar, withTheme} from "react-native-paper";
19
+ import { WebView } from 'react-native-webview';
20
+ import {withTranslation} from "react-i18next";
21
+ import merge from 'lodash/merge';
22
+
23
+ import componentStyles from "./styles";
24
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
25
+ import IconsOpenasist from "@olea-bps/icons-openasist";
26
+
27
+ /**
28
+ * Opal View
29
+ *
30
+ * Shows the opal site in a webview
31
+ *
32
+ * Parameters:
33
+ * - none
34
+ *
35
+ * Navigation-Parameters:
36
+ * - none
37
+ */
38
+ class OpalView extends React.Component {
39
+ static navigationOptions = {
40
+ header: null
41
+ };
42
+
43
+
44
+ state = {
45
+ refreshing: false,
46
+ };
47
+
48
+ // Styles of this component
49
+ styles;
50
+
51
+ webView = {
52
+ canGoBack: false,
53
+ ref: null,
54
+ };
55
+
56
+ constructor(props) {
57
+ super(props);
58
+
59
+ // ------------------------------------------------------------------------
60
+ // PLUGIN FUNCTIONALITY
61
+ // ------------------------------------------------------------------------
62
+
63
+ const {pluginStyles, theme} = this.props;
64
+ this.styles = componentStyles(theme);
65
+
66
+ if (pluginStyles) {
67
+ this.styles = merge(this.styles, pluginStyles);
68
+ }
69
+
70
+ this.styles = StyleSheet.create(this.styles);
71
+
72
+ // ------------------------------------------------------------------------
73
+ }
74
+
75
+
76
+ render() {
77
+ // ------------------------------------------------------------------------
78
+ // PLUGIN FUNCTIONALITY
79
+ // ------------------------------------------------------------------------
80
+ const PluginComponent = this.props.pluginComponent;
81
+ if (PluginComponent) {
82
+ return <PluginComponent />;
83
+ }
84
+ // ------------------------------------------------------------------------
85
+
86
+ const {theme:{colors, themeStyles, customScript}, t } = this.props;
87
+
88
+ return (
89
+ <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
90
+ <View style={{zIndex: 100, position: 'relative'}}>
91
+ <AppbarComponent {...this.props}
92
+ title={t('opal:title')}
93
+ leftAction={
94
+ <Appbar.Action
95
+ icon={props => <IconsOpenasist {...props} icon={'back'} color={colors.primaryText} /> }
96
+ onPress={() => {
97
+ if (this.webView.canGoBack) {
98
+ this.webView.ref.goBack();
99
+ } else {
100
+ this.props.navigation.goBack(null);
101
+ }
102
+ }}
103
+ accessible={true}
104
+ accessibilityLabel={(this.webView.canGoBack) ? t('accessibility:appbar.navigateBack') : t('accessibility:appbar.back')}
105
+ />
106
+ }
107
+ rightAction={
108
+ <Appbar.Action
109
+ icon="refresh"
110
+ onPress={() => this.webView.ref.reload()}
111
+ accessible={true}
112
+ accessibilityLabel={t('accessibility:appbar.reload')}
113
+ />
114
+ }/>
115
+ </View>
116
+ <WebView
117
+ ref={ref => this.webView.ref = ref}
118
+ source={{uri: t('opal:url')}}
119
+ startInLoadingState={true}
120
+ injectedJavaScript={customScript}
121
+ renderLoading={() => <ActivityIndicator style={this.styles.activity} size="large" color={colors.loadingIndicator} />}
122
+ onNavigationStateChange={(navState) => { this.webView.canGoBack = navState.canGoBack; }}
123
+ />
124
+ </SafeAreaView>
125
+ );
126
+ }
127
+ }
128
+
129
+ const mapStateToProps = state => {
130
+ return {
131
+ pluginComponent: state.pluginReducer.opal.component,
132
+ pluginStyles: state.pluginReducer.opal.styles,
133
+ };
134
+ };
135
+
136
+ export default connect(mapStateToProps, null)(withTranslation()(withTheme(OpalView)))