@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
package/Opal/styles.js ADDED
@@ -0,0 +1,11 @@
1
+ export default function(theme) {
2
+ return {
3
+ container: {
4
+ flex: 1,
5
+ backgroundColor: theme.colors.background,
6
+ },
7
+ activity: {
8
+ padding: 20
9
+ }
10
+ }
11
+ };
@@ -0,0 +1,173 @@
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 { useState, useEffect, useMemo, useCallback } from 'react';
16
+ import { AppState, SafeAreaView, View, ScrollView, StyleSheet, Alert, useWindowDimensions, RefreshControl } from 'react-native';
17
+
18
+ import { useTheme, Text, Button } from 'react-native-paper';
19
+ import { useFocusEffect } from '@react-navigation/native';
20
+ import { useTranslation } from 'react-i18next';
21
+ import QRCode from 'react-native-qrcode-svg';
22
+
23
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
24
+ import { useUser } from '@olea-bps/context-user';
25
+ import { usePublicTransportTicket } from '@olea-bps/context-public-transport-ticket';
26
+
27
+ import componentStyles from './styles';
28
+
29
+ /**
30
+ * View zum Anzeigen eines OPNV-Tickets.
31
+ */
32
+ export default function PublicTransportTicketView() {
33
+ const componentName = PublicTransportTicketView.name;
34
+ // Get theme from theme context
35
+ const theme = useTheme();
36
+ const { themeStyles } = theme;
37
+ // Get translation function from translation hook
38
+ const { t } = useTranslation();
39
+
40
+ const [user, login] = useUser();
41
+ const [ticketBarcode, ticketOwner, ticketValidFrom, ticketValidTo, refreshTicket] = usePublicTransportTicket();
42
+ const { width } = useWindowDimensions();
43
+
44
+ const [refreshingTicketScrollView, setRefreshingTicketScrollView] = useState(false);
45
+
46
+ // Create styles object using useMemo to prevent unnecessary re-renders
47
+ const styles = useMemo(
48
+ () => StyleSheet.create(componentStyles(theme)),
49
+ [theme]
50
+ );
51
+
52
+ useFocusEffect(
53
+ useCallback(
54
+ () => {
55
+ console.log(componentName, ':', 'useFocusEffect', ':', 'update ticket');
56
+ refreshTicket?.()
57
+ },
58
+ [refreshTicket]
59
+ )
60
+ );
61
+
62
+ useEffect(
63
+ () => {
64
+ const focusSubscription = AppState.addEventListener(
65
+ 'focus',
66
+ () => {
67
+ console.log(componentName, ':', 'focus', ':', 'update ticket');
68
+ refreshTicket?.();
69
+ }
70
+ );
71
+
72
+ return () => {
73
+ focusSubscription.remove();
74
+ };
75
+ },
76
+ []
77
+ );
78
+
79
+ const onRefreshTicketScrollView = useCallback(
80
+ () => {
81
+ if (refreshTicket) {
82
+ setRefreshingTicketScrollView(true);
83
+ refreshTicket()
84
+ .finally(() => setRefreshingTicketScrollView(false));
85
+ }
86
+ },
87
+ [setRefreshingTicketScrollView, refreshTicket]
88
+ );
89
+
90
+ return (
91
+ // SafeAreaView is used to render content within the safe area boundaries of a device.
92
+ <SafeAreaView style={[styles.container, themeStyles.appSafeAreaContainer]}>
93
+ {/* AppbarComponent is a custom component for the app's header bar. */}
94
+ <AppbarComponent title={t('publictransportticket:title')} />
95
+
96
+ {/* This View contains the main content of the screen. */}
97
+ <View accessible={false} style={themeStyles.container}>
98
+ {
99
+ user
100
+ ? <ScrollView
101
+ style={
102
+ {
103
+ padding: '10%',
104
+ }
105
+ }
106
+ refreshControl={
107
+ <RefreshControl
108
+ refreshing={refreshingTicketScrollView}
109
+ onRefresh={onRefreshTicketScrollView}
110
+ />
111
+ }
112
+ >
113
+ {
114
+ ticketBarcode
115
+ ? <>
116
+ <View>
117
+ <QRCode
118
+ value={ticketBarcode}
119
+ size={width * 0.8}
120
+ />
121
+ </View>
122
+ <Text>
123
+ <Text
124
+ style={styles.infoName}
125
+ >
126
+ Inhaber:
127
+ </Text>
128
+ {ticketOwner}
129
+ </Text>
130
+ <Text>
131
+ <Text
132
+ style={styles.infoName}
133
+ >
134
+ Gültigkeit:
135
+ </Text>
136
+ {ticketValidFrom} - {ticketValidTo}
137
+ </Text>
138
+ </>
139
+ : null
140
+ }
141
+ </ScrollView>
142
+ : <>
143
+ <Text>
144
+ Sie sind nicht eingeloogt
145
+ </Text>
146
+ <Button
147
+ onPress={
148
+ () =>
149
+ login
150
+ ? login()
151
+ .catch(
152
+ reason => {
153
+ console.debug(componentName, ':', 'login failed', ':', reason);
154
+ Alert.alert(
155
+ t('user:loginFailed'),
156
+ t('user:tryLoginAgain'),
157
+ );
158
+ }
159
+ )
160
+ : Alert.alert(
161
+ t('user:connectionError'),
162
+ t('user:connectionErrorTryLoginAgain'),
163
+ )
164
+ }
165
+ >
166
+ {t('user:logginButton')}
167
+ </Button>
168
+ </>
169
+ }
170
+ </View>
171
+ </SafeAreaView>
172
+ );
173
+ }
@@ -0,0 +1,17 @@
1
+ export default function (theme) {
2
+ return {
3
+ infoName: {
4
+ fontSize: theme.fontSizes.l,
5
+ fontWeight: 'bold'
6
+ },
7
+ userinfoHeadline: {
8
+ paddingLeft: '5%',
9
+ fontWeight: 'bold',
10
+ fontSize: theme.fontSizes.l,
11
+ },
12
+ userinfoValue: {
13
+ paddingLeft: '10%',
14
+ fontSize: theme.fontSizes.l,
15
+ },
16
+ }
17
+ }
@@ -0,0 +1,186 @@
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, { useState, useEffect, useMemo } from 'react';
16
+ import { StyleSheet, SafeAreaView, View, ActivityIndicator } from 'react-native';
17
+ import { connect } from 'react-redux'
18
+ import { Searchbar, Text, withTheme } from 'react-native-paper';
19
+ import { TabView, TabBar } from 'react-native-tab-view';
20
+ import { withTranslation } from "react-i18next";
21
+
22
+ import NetInfo from '@react-native-community/netinfo';
23
+
24
+ import { SearchService } from "@olea-bps/core";
25
+
26
+ import componentStyles from "./styles";
27
+ import IconsOpenasist from "@olea-bps/icons-openasist";
28
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
29
+ import { SearchResults as SearchResultsComponent } from '@olea-bps/components';
30
+
31
+
32
+ /**
33
+ * Search View
34
+ *
35
+ * Shows a search view with taps for every category.
36
+ *
37
+ * Parameters:
38
+ * - none
39
+ *
40
+ * Navigation-Parameters:
41
+ * - none
42
+ */
43
+
44
+
45
+ function SearchView(props) {
46
+ const [searchTabIndex, setSearchTabIndex] = useState(0);
47
+ const [hasConnection, setHasConnection] = useState(true);
48
+ const [inProgress, setInProgress] = useState(false);
49
+ const [searchString, setSearchString] = useState(props.searchTopic ? props.searchTopic : '');
50
+
51
+ const { theme, theme: { themeStyles, colors }, t } = props;
52
+ const activeSearchCategories = props?.theme?.appSettings?.modules?.search?.activeCategories ?? SearchService.categories;
53
+
54
+ const searchTabRoutes = useMemo(
55
+ () => [
56
+ { key: 'all', title: t('search:tabs.all') },
57
+ ...activeSearchCategories.map(activeSearchCategory => ({
58
+ key: activeSearchCategory,
59
+ title: t(`search:tabs.${activeSearchCategory}`)
60
+ }))
61
+ ],
62
+ [activeSearchCategories, t]
63
+ );
64
+
65
+ useEffect(
66
+ () => NetInfo.addEventListener(state => setHasConnection(state.isInternetReachable && state.isConnected)),
67
+ [NetInfo]
68
+ );
69
+
70
+ const styles = useMemo(
71
+ () => StyleSheet.create(componentStyles(theme)),
72
+ [theme]
73
+ )
74
+
75
+ const _onPressButton = () => {
76
+ if (searchString.length > 0) {
77
+ _executeSearch();
78
+ }
79
+ };
80
+
81
+ const _executeSearch = () => {
82
+ const includedSearches = props.theme.appSettings.modules.search.activeCategories;
83
+ const searchService = new SearchService();
84
+
85
+ setInProgress(true);
86
+
87
+ if (searchTabIndex > 0 && searchTabRoutes.length > 0) {
88
+ searchService.searchByType(
89
+ searchTabRoutes[searchTabIndex]?.key,
90
+ searchString,
91
+ () => {
92
+ setInProgress(false);
93
+ });
94
+ } else {
95
+ searchService.searchAll(searchString, () => {
96
+ setInProgress(false);
97
+ }, includedSearches);
98
+ }
99
+ };
100
+
101
+ /**
102
+ * Render the top bar for categories
103
+ *
104
+ * @param props
105
+ * @returns {*}
106
+ * @private
107
+ */
108
+ const _renderTabBar = (props) => {
109
+
110
+ return (
111
+ <View style={styles.tabBarContainer}>
112
+ <TabBar
113
+ {...props}
114
+ scrollEnabled
115
+ style={themeStyles.tabs}
116
+ activeColor={themeStyles.tabs.activeColor}
117
+ inactiveColor={themeStyles.tabs.inactiveColor}
118
+ labelStyle={themeStyles.tab}
119
+ indicatorStyle={themeStyles.tabIndicator}
120
+ tabStyle={{ width: 'auto', paddingHorizontal: 20 }}
121
+ />
122
+ <Searchbar
123
+ onSubmitEditing={() => _onPressButton()}
124
+ onIconPress={() => _onPressButton()}
125
+ onChangeText={setSearchString}
126
+ icon={(props) =>
127
+ <IconsOpenasist icon={"search"} size={32} color={colors.icon} />
128
+ }
129
+ style={styles.searchBar}
130
+ inputStyle={styles.searchBarInput}
131
+ value={searchString}
132
+ placeholder={t('search:title') + ' ...'}
133
+ placeholderTextColor={colors.textLighter}
134
+ clearAccessibilityLabel={t('accessibility:search:searchBarClearButton')}
135
+ />
136
+ </View>
137
+ );
138
+ };
139
+
140
+ return (
141
+ <SafeAreaView style={[styles.container, themeStyles.appSafeAreaContainer]}>
142
+ <AppbarComponent title={t('search:title')} {...props} />
143
+ <TabView
144
+ style={styles}
145
+ navigationState={{ index: searchTabIndex, routes: searchTabRoutes }}
146
+ renderScene={
147
+ ({ route, jumpTo }) =>
148
+ hasConnection
149
+ ? <View style={styles.containerInner}>
150
+ {
151
+ inProgress
152
+ ? <View style={[styles.containerInner, styles.containerLoading]}>
153
+ <Text>{t('search:inProgress')}</Text>
154
+ <ActivityIndicator style={styles.activity} size="large" color={props.theme.colors.loadingIndicator} />
155
+ </View>
156
+ : <SearchResultsComponent type={route.key} {...props} />
157
+ }
158
+ </View>
159
+ : <View style={[styles.containerInner, styles.containerLoading]}>
160
+ <IconsOpenasist icon={"search"} size={48} color={props.theme.colors.loadingIndicator} />
161
+ <Text style={styles.title}>{t('search:noInternetTitle')}</Text>
162
+ <Text style={styles.subtitle}>{t('search:noInternetSubtitle')}</Text>
163
+ </View>
164
+
165
+ }
166
+ renderTabBar={_renderTabBar}
167
+ onIndexChange={setSearchTabIndex}
168
+ />
169
+ </SafeAreaView>
170
+ );
171
+
172
+ }
173
+
174
+ const mapStateToProps = state => {
175
+ return {
176
+ pluginComponent: state.pluginReducer.search.component,
177
+ pluginStyles: state.pluginReducer.search.styles,
178
+ searchTopic: state.stateReducer.searchTopic
179
+ };
180
+ };
181
+
182
+ export default connect(mapStateToProps, null)(withTranslation()(withTheme(SearchView)));
183
+
184
+
185
+
186
+
@@ -0,0 +1,67 @@
1
+ export default function(theme) {
2
+ return {
3
+ container: {
4
+ flex: 1,
5
+ },
6
+ containerInner: {
7
+ flex: 1,
8
+ backgroundColor: theme.colors.contentBackground
9
+ },
10
+ containerLoading: {
11
+ flexDirection: 'column',
12
+ justifyContent: 'center',
13
+ alignContent: 'center',
14
+ alignItems: 'center'
15
+ },
16
+ tabs: {
17
+ backgroundColor: theme.colors.primary,
18
+ },
19
+ tab: {
20
+ ...theme.fonts.medium,
21
+ },
22
+ tabBarContainer: {
23
+ position: 'relative',
24
+ zIndex: 2
25
+ },
26
+ tabIndicator: {
27
+ backgroundColor: theme.colors.tabs.tabIndicator,
28
+ height: 5
29
+ },
30
+ searchBar: {
31
+ borderRadius: 0,
32
+ height: 50,
33
+ paddingHorizontal: theme.paddings.small,
34
+ shadowOpacity: 0.0,
35
+ borderBottomColor: theme.colors.accent,
36
+ borderBottomWidth: 1,
37
+ fontSize: theme.fontSizes.searchBar
38
+ },
39
+ searchBarInput: {
40
+ fontSize: theme.fontSizes.xl
41
+ },
42
+ activity: {
43
+ marginTop: theme.paddings.default,
44
+ width: 160,
45
+ height: 160
46
+ },
47
+
48
+ title : {
49
+ fontSize: theme.fontSizes.title,
50
+ color: theme.colors.text,
51
+ textAlign: 'center',
52
+ marginTop: theme.paddings.default,
53
+ marginLeft: theme.paddings.default,
54
+ marginRight: theme.paddings.default,
55
+ },
56
+
57
+ subtitle : {
58
+ fontSize: theme.fontSizes.subtitle,
59
+ color: theme.colors.text,
60
+ textAlign: 'center',
61
+ marginTop: theme.paddings.default,
62
+ marginLeft: theme.paddings.default,
63
+ marginRight: theme.paddings.default,
64
+ },
65
+
66
+ }
67
+ };
@@ -0,0 +1,148 @@
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, View, Alert} from 'react-native';
17
+ import { reloadAppAsync } from 'expo'
18
+
19
+ import {connect} from 'react-redux'
20
+ import { withTheme, Checkbox} from "react-native-paper";
21
+ import {withTranslation} from "react-i18next";
22
+
23
+ import merge from 'lodash/merge';
24
+
25
+ import { onSettingAccessibilityOverride, store } from "@olea-bps/core";
26
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
27
+ import componentStyles from "./styles";
28
+
29
+ /**
30
+ * Settings Accessibility
31
+ *
32
+ * Parameters:
33
+ * - none
34
+ *
35
+ * Navigation-Parameters:
36
+ * - none
37
+ */
38
+ class AccessibilitySettingsView extends React.Component {
39
+ // Styles of this component
40
+ styles;
41
+
42
+ constructor(props) {
43
+ super(props);
44
+
45
+ // ------------------------------------------------------------------------
46
+ // PLUGIN FUNCTIONALITY
47
+ // ------------------------------------------------------------------------
48
+
49
+ const {pluginStyles, theme, settings} = this.props;
50
+ this.styles = componentStyles(theme);
51
+
52
+ if (pluginStyles) {
53
+ this.styles = merge(this.styles, pluginStyles);
54
+ }
55
+
56
+ const {highContrast, increaseFontSize} = settings.settingsAccessibility;
57
+
58
+ this.state = {
59
+ highContrast: highContrast ? highContrast : false,
60
+ increaseFontSize: increaseFontSize ? increaseFontSize : false
61
+ };
62
+ }
63
+
64
+
65
+ /**
66
+ * update the settings
67
+ *
68
+ * @private
69
+ */
70
+ _handleChange(key) {
71
+ const {t} = this.props;
72
+ if(key in this.state){
73
+ const settings = Object.assign({}, this.state, {[key]: !this.state[key]});
74
+ Alert.alert(
75
+ t('settings:accessibility.restartRequired'),
76
+ t('settings:accessibility.restartRequiredDesc'),
77
+ [
78
+ {
79
+ text: t('settings:accessibility.cancelRestart'),
80
+ style: 'cancel',
81
+ onPress: () => {}
82
+ },
83
+ {
84
+ text: t('settings:accessibility.doRestart'),
85
+ onPress: async () => {
86
+ this.setState(settings)
87
+ store.dispatch(onSettingAccessibilityOverride('accessibilitySettings', settings));
88
+ setTimeout(async () => {
89
+ await reloadAppAsync();
90
+ }, 500);
91
+ },
92
+ },
93
+ ]
94
+ );
95
+ }
96
+ }
97
+
98
+
99
+ render() {
100
+ // ------------------------------------------------------------------------
101
+ // PLUGIN FUNCTIONALITY
102
+ // ------------------------------------------------------------------------
103
+ const PluginComponent = this.props.pluginComponent;
104
+ if (PluginComponent) {
105
+ return <PluginComponent />;
106
+ }
107
+ // ------------------------------------------------------------------------
108
+
109
+ const { theme: { themeStyles, colors }, t } = this.props;
110
+ const { highContrast, increaseFontSize } = this.state;
111
+ const accessibilitySettings = [
112
+ {key: 'highContrast', checked: highContrast, title: t('settings:accessibility.highContrast') },
113
+ {key: 'increaseFontSize', checked: increaseFontSize, title: t('settings:accessibility.increaseFontSize') }
114
+ ].map(({key, checked, title}) =>
115
+ <Checkbox.Item
116
+ key={key}
117
+ status={checked ? 'checked' : 'unchecked'}
118
+ label={title}
119
+ labelStyle={this.styles.labelStyle}
120
+ onPress={() => this._handleChange(key)}
121
+ color={colors.checkboxChecked}
122
+ uncheckedColor={colors.checkboxUnchecked}
123
+ mode={'android'}
124
+ />
125
+ );
126
+
127
+
128
+
129
+ return (
130
+ <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
131
+ <AppbarComponent {...this.props} title={t('settings:accessibility.title')}/>
132
+ <View style={themeStyles.container}>
133
+ {accessibilitySettings}
134
+ </View>
135
+ </SafeAreaView>
136
+ );
137
+ }
138
+ }
139
+
140
+ const mapStateToProps = state => {
141
+ return {
142
+ pluginComponent: state.pluginReducer.settingsAccessibility.component,
143
+ pluginStyles: state.pluginReducer.settingsAccessibility.styles,
144
+ settings: state.settingReducer
145
+ };
146
+ };
147
+
148
+ export default connect(mapStateToProps, null)(withTranslation()(withTheme(AccessibilitySettingsView)))
@@ -0,0 +1,13 @@
1
+ export default function(theme) {
2
+ return {
3
+ selectOption: {
4
+ display: 'flex',
5
+ flexDirection: 'row',
6
+ justifyContent: 'space-between'
7
+ },
8
+ labelStyle: {
9
+ fontSize: theme.fontSizes.l,
10
+ color: theme.colors.text
11
+ }
12
+ }
13
+ };