@olea-bps/base 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 (268) hide show
  1. package/components/AppBar/index.js +84 -0
  2. package/components/AppBar/styles.js +27 -0
  3. package/components/BookDetail/index.js +268 -0
  4. package/components/BookDetail/styles.js +124 -0
  5. package/components/ComponentJobsFilter/index.js +188 -0
  6. package/components/ComponentJobsFilter/styles.js +12 -0
  7. package/components/ConnectivityWarning/index.js +65 -0
  8. package/components/ConnectivityWarning/styles.js +19 -0
  9. package/components/ContactDetail/index.js +232 -0
  10. package/components/ContactDetail/styles.js +32 -0
  11. package/components/CourseDetail/index.js +357 -0
  12. package/components/CourseDetail/styles.js +59 -0
  13. package/components/CourseDetailDialog/index.js +169 -0
  14. package/components/CourseDetailDialog/styles.js +116 -0
  15. package/components/CourseInfo/index.js +219 -0
  16. package/components/CourseInfo/styles.js +40 -0
  17. package/components/DevelopmentDialog/index.js +214 -0
  18. package/components/DevelopmentDialog/styles.js +10 -0
  19. package/components/EventCodeInput/index.js +149 -0
  20. package/components/EventCodeInput/styles.js +108 -0
  21. package/components/FlexMenuEntry/index.js +84 -0
  22. package/components/FlexMenuEntry/styles.js +27 -0
  23. package/components/MainMenuEntry/index.js +88 -0
  24. package/components/MainMenuEntry/styles.js +28 -0
  25. package/components/MealItem/index.js +87 -0
  26. package/components/MealItem/styles.js +84 -0
  27. package/components/MensaMenu/index.js +305 -0
  28. package/components/MensaMenu/styles.js +94 -0
  29. package/components/MensaSlider/index.js +188 -0
  30. package/components/MensaSlider/styles.js +53 -0
  31. package/components/Modal/index.js +106 -0
  32. package/components/Modal/styles.js +8 -0
  33. package/components/NewsDetail/index.js +377 -0
  34. package/components/NewsDetail/styles.js +77 -0
  35. package/components/NewsList/index.js +120 -0
  36. package/components/NewsList/styles.js +19 -0
  37. package/components/NewsListItem/index.js +89 -0
  38. package/components/NewsListItem/styles.js +32 -0
  39. package/components/OtherCourses/index.js +152 -0
  40. package/components/OtherCourses/styles.js +10 -0
  41. package/components/PtsDeparture/index.js +140 -0
  42. package/components/PtsDeparture/styles.js +7 -0
  43. package/components/PtsStation/index.js +186 -0
  44. package/components/PtsStation/styles.js +47 -0
  45. package/components/QuickLinks/index.js +127 -0
  46. package/components/QuickLinks/styles.js +45 -0
  47. package/components/RoomDetail/index.js +281 -0
  48. package/components/RoomDetail/styles.js +56 -0
  49. package/components/ScaledImage/index.js +92 -0
  50. package/components/SearchResults/index.js +362 -0
  51. package/components/SearchResults/styles.js +59 -0
  52. package/components/SettingSection/index.js +54 -0
  53. package/components/SettingSection/styles.js +15 -0
  54. package/components/SettingsDialog/index.js +52 -0
  55. package/components/SettingsDialog/styles.js +12 -0
  56. package/components/SettingsDialogRadio/index.js +66 -0
  57. package/components/SettingsDialogRadio/styles.js +7 -0
  58. package/components/SettingsDialogSelect/index.js +73 -0
  59. package/components/SettingsDialogSelect/styles.js +7 -0
  60. package/components/TimetableCodeInput/index.js +205 -0
  61. package/components/TimetableCodeInput/styles.js +28 -0
  62. package/components/TimetableDay/index.js +252 -0
  63. package/components/TimetableDay/styles.js +103 -0
  64. package/components/TimetableEvent/index.js +163 -0
  65. package/components/TimetableEvent/styles.js +108 -0
  66. package/components/TimetableList/index.js +180 -0
  67. package/components/TimetableList/styles.js +106 -0
  68. package/components/TimetableMonth/index.js +156 -0
  69. package/components/TimetableMonth/styles.js +29 -0
  70. package/components/TimetableWeek/index.js +230 -0
  71. package/components/TimetableWeek/styles.js +58 -0
  72. package/components/TopNews/index.js +282 -0
  73. package/components/TopNews/styles.js +125 -0
  74. package/components/TopNewsHtwk/index.js +279 -0
  75. package/components/TopNewsHtwk/styles.js +142 -0
  76. package/components/WebView/index.js +108 -0
  77. package/components/WebView/styles.js +11 -0
  78. package/context/context-callmanager/TucCallManager.js +74 -0
  79. package/context/context-callmanager/index.js +128 -0
  80. package/context/context-canteen/AsistServerApiProvider.js +126 -0
  81. package/context/context-canteen/CollektorVersion2ApiProvider.js +100 -0
  82. package/context/context-canteen/index.js +692 -0
  83. package/context/context-connectivity/index.js +85 -0
  84. package/context/context-event/AsistServerClient.js +82 -0
  85. package/context/context-event/index.js +205 -0
  86. package/context/context-flex-menu/AsistServerApiProvider.js +0 -0
  87. package/context/context-flex-menu/CollectorVersion2ApiProvider.js +32 -0
  88. package/context/context-flex-menu/index.js +160 -0
  89. package/context/context-info-dialog/CollektorVersion2ApiProvider.js +53 -0
  90. package/context/context-info-dialog/ProviderErrors.js +22 -0
  91. package/context/context-info-dialog/index.js +190 -0
  92. package/context/context-mails/MailService.js +147 -0
  93. package/context/context-mails/TucUnseenApiProvider.js +65 -0
  94. package/context/context-mails/index.js +131 -0
  95. package/context/context-news/CollektorVersion2ApiProvider.js +68 -0
  96. package/context/context-news/index.js +155 -0
  97. package/context/context-public-transport-ticket/CollektorVersion2ApiProvider.js +45 -0
  98. package/context/context-public-transport-ticket/ProviderErrors.js +11 -0
  99. package/context/context-public-transport-ticket/index.js +175 -0
  100. package/context/context-timetable/CollectorVersion2ApiProvider.js +102 -0
  101. package/context/context-timetable/ProviderErrors.js +22 -0
  102. package/context/context-timetable/TimetableService.js +357 -0
  103. package/context/context-timetable/index.js +215 -0
  104. package/context/context-user/index.js +586 -0
  105. package/index.js +178 -0
  106. package/libraries/base-api-provider/hooks.js +24 -0
  107. package/libraries/base-api-provider/http-api-provider.js +168 -0
  108. package/libraries/base-api-provider/index.js +20 -0
  109. package/libraries/core/api/canteens.js +88 -0
  110. package/libraries/core/api/corona.js +45 -0
  111. package/libraries/core/api/courses.js +54 -0
  112. package/libraries/core/api/device.js +98 -0
  113. package/libraries/core/api/feed.js +144 -0
  114. package/libraries/core/api/feedback.js +123 -0
  115. package/libraries/core/api/jobs.js +48 -0
  116. package/libraries/core/api/library.js +67 -0
  117. package/libraries/core/api/lostfound.js +77 -0
  118. package/libraries/core/api/occupancy.js +44 -0
  119. package/libraries/core/api/officehours.js +25 -0
  120. package/libraries/core/api/poi.js +25 -0
  121. package/libraries/core/api/pts.js +68 -0
  122. package/libraries/core/api/rooms.js +31 -0
  123. package/libraries/core/api/survey.js +121 -0
  124. package/libraries/core/api/telephone.js +32 -0
  125. package/libraries/core/api/tucrooms.js +31 -0
  126. package/libraries/core/constants/actions.js +75 -0
  127. package/libraries/core/constants/api.js +146 -0
  128. package/libraries/core/constants/enums.js +5 -0
  129. package/libraries/core/helper/date.js +9 -0
  130. package/libraries/core/helper/format.helper.js +2 -0
  131. package/libraries/core/index.js +60 -0
  132. package/libraries/core/redux/actions/notifications.js +6 -0
  133. package/libraries/core/redux/actions/setting.js +75 -0
  134. package/libraries/core/redux/actions/state.js +74 -0
  135. package/libraries/core/redux/asyncDispatch.js +27 -0
  136. package/libraries/core/redux/reducers/api.js +190 -0
  137. package/libraries/core/redux/reducers/index.js +32 -0
  138. package/libraries/core/redux/reducers/notifications.js +16 -0
  139. package/libraries/core/redux/reducers/setting.js +99 -0
  140. package/libraries/core/redux/reducers/state.js +122 -0
  141. package/libraries/core/redux/selectors.js +123 -0
  142. package/libraries/core/redux/store.js +40 -0
  143. package/libraries/core/services/data.js +96 -0
  144. package/libraries/core/services/root-navigation.js +36 -0
  145. package/libraries/core/services/search.js +175 -0
  146. package/libraries/core-plugins/enums/replaceTypes.js +53 -0
  147. package/libraries/core-plugins/index.js +21 -0
  148. package/libraries/core-plugins/redux/actions/plugin.js +13 -0
  149. package/libraries/core-plugins/redux/reducers/plugin.js +210 -0
  150. package/libraries/icons-openasist/index.js +143 -0
  151. package/libraries/notifications/index.js +268 -0
  152. package/libraries/notifications/services/subscriber.service.js +123 -0
  153. package/libraries/react-native-webview-autoheight/README.md +47 -0
  154. package/libraries/react-native-webview-autoheight/index.js +140 -0
  155. package/libraries/react-native-webview-autoheight/package.json +37 -0
  156. package/libraries/react-native-webview-autoheight/utils.js +268 -0
  157. package/libraries/redux-offline/.eslintignore +1 -0
  158. package/libraries/redux-offline/.github/ISSUE_TEMPLATE/redux-offline-core-issues-template.md +25 -0
  159. package/libraries/redux-offline/.prettierrc +6 -0
  160. package/libraries/redux-offline/LICENSE +21 -0
  161. package/libraries/redux-offline/README.md +133 -0
  162. package/libraries/redux-offline/flow-typed/npm/redux-logger_vx.x.x.js +109 -0
  163. package/libraries/redux-offline/flow-typed/npm/redux_v4.x.x.js +100 -0
  164. package/libraries/redux-offline/lib/actions.js +46 -0
  165. package/libraries/redux-offline/lib/config.js +15 -0
  166. package/libraries/redux-offline/lib/constants.js +17 -0
  167. package/libraries/redux-offline/lib/defaults/defaultCommit.js +11 -0
  168. package/libraries/redux-offline/lib/defaults/defaultRollback.js +11 -0
  169. package/libraries/redux-offline/lib/defaults/detectNetwork.js +33 -0
  170. package/libraries/redux-offline/lib/defaults/detectNetwork.native.js +211 -0
  171. package/libraries/redux-offline/lib/defaults/discard.js +18 -0
  172. package/libraries/redux-offline/lib/defaults/effect.js +87 -0
  173. package/libraries/redux-offline/lib/defaults/index.js +32 -0
  174. package/libraries/redux-offline/lib/defaults/offlineStateLens.js +24 -0
  175. package/libraries/redux-offline/lib/defaults/persist.js +9 -0
  176. package/libraries/redux-offline/lib/defaults/persist.native.js +17 -0
  177. package/libraries/redux-offline/lib/defaults/persistAutoRehydrate.js +8 -0
  178. package/libraries/redux-offline/lib/defaults/queue.js +27 -0
  179. package/libraries/redux-offline/lib/defaults/retry.js +29 -0
  180. package/libraries/redux-offline/lib/index.js +115 -0
  181. package/libraries/redux-offline/lib/middleware.js +56 -0
  182. package/libraries/redux-offline/lib/offlineActionTracker.js +43 -0
  183. package/libraries/redux-offline/lib/send.js +112 -0
  184. package/libraries/redux-offline/lib/types.js +3 -0
  185. package/libraries/redux-offline/lib/updater.js +111 -0
  186. package/libraries/redux-offline/package.json +69 -0
  187. package/libraries/redux-offline/src/__tests__/defaults/discard.js +22 -0
  188. package/libraries/redux-offline/src/__tests__/defaults/effect.js +118 -0
  189. package/libraries/redux-offline/src/__tests__/index.js +116 -0
  190. package/libraries/redux-offline/src/__tests__/middleware.js +185 -0
  191. package/libraries/redux-offline/src/__tests__/offlineActionTracker.js +54 -0
  192. package/libraries/redux-offline/src/__tests__/send.js +208 -0
  193. package/libraries/redux-offline/src/actions.js +36 -0
  194. package/libraries/redux-offline/src/config.js +9 -0
  195. package/libraries/redux-offline/src/constants.js +18 -0
  196. package/libraries/redux-offline/src/defaults/defaultCommit.js +7 -0
  197. package/libraries/redux-offline/src/defaults/defaultRollback.js +7 -0
  198. package/libraries/redux-offline/src/defaults/detectNetwork.js +16 -0
  199. package/libraries/redux-offline/src/defaults/detectNetwork.native.js +148 -0
  200. package/libraries/redux-offline/src/defaults/discard.js +19 -0
  201. package/libraries/redux-offline/src/defaults/effect.js +86 -0
  202. package/libraries/redux-offline/src/defaults/index.js +25 -0
  203. package/libraries/redux-offline/src/defaults/offlineStateLens.js +11 -0
  204. package/libraries/redux-offline/src/defaults/persist.js +4 -0
  205. package/libraries/redux-offline/src/defaults/persist.native.js +9 -0
  206. package/libraries/redux-offline/src/defaults/persistAutoRehydrate.js +4 -0
  207. package/libraries/redux-offline/src/defaults/queue.js +20 -0
  208. package/libraries/redux-offline/src/defaults/retry.js +18 -0
  209. package/libraries/redux-offline/src/index.js +138 -0
  210. package/libraries/redux-offline/src/middleware.js +52 -0
  211. package/libraries/redux-offline/src/offlineActionTracker.js +40 -0
  212. package/libraries/redux-offline/src/send.js +111 -0
  213. package/libraries/redux-offline/src/types.js +127 -0
  214. package/libraries/redux-offline/src/updater.js +141 -0
  215. package/libraries/redux-offline/typings.d.ts +150 -0
  216. package/libraries/redux-offline/yarn.lock +6460 -0
  217. package/libraries/stored-state/index.js +155 -0
  218. package/package.json +68 -0
  219. package/views/Callmanager/index.js +148 -0
  220. package/views/Callmanager/styles.js +62 -0
  221. package/views/Canteens/index.js +383 -0
  222. package/views/Canteens/styles.js +89 -0
  223. package/views/Dashboard/index.js +176 -0
  224. package/views/Dashboard/styles.js +16 -0
  225. package/views/DashboardHtwk/index.js +197 -0
  226. package/views/DashboardHtwk/styles.js +24 -0
  227. package/views/Event/index.js +373 -0
  228. package/views/Event/styles.js +63 -0
  229. package/views/FeedList/index.js +165 -0
  230. package/views/FeedList/styles.js +15 -0
  231. package/views/FeedNews/index.js +243 -0
  232. package/views/FeedNews/styles.js +32 -0
  233. package/views/Flexmenu/index.js +185 -0
  234. package/views/Flexmenu/styles.js +62 -0
  235. package/views/FlexmenuWebview/index.js +167 -0
  236. package/views/FlexmenuWebview/styles.js +16 -0
  237. package/views/Howhy/index.js +151 -0
  238. package/views/Howhy/styles.js +11 -0
  239. package/views/Jobs/index.js +217 -0
  240. package/views/Jobs/styles.js +41 -0
  241. package/views/MainMenu/index.js +283 -0
  242. package/views/MainMenu/styles.js +36 -0
  243. package/views/NewsTabbar/index.js +164 -0
  244. package/views/NewsTabbar/styles.js +27 -0
  245. package/views/Opal/index.js +136 -0
  246. package/views/Opal/styles.js +11 -0
  247. package/views/PublicTransportTicket/index.js +173 -0
  248. package/views/PublicTransportTicket/styles.js +17 -0
  249. package/views/Search/index.js +186 -0
  250. package/views/Search/styles.js +67 -0
  251. package/views/SettingsAccessibility/index.js +148 -0
  252. package/views/SettingsAccessibility/styles.js +13 -0
  253. package/views/SettingsAppInfo/index.js +86 -0
  254. package/views/SettingsAppInfo/styles.js +18 -0
  255. package/views/SettingsCanteens/index.js +249 -0
  256. package/views/SettingsCanteens/styles.js +33 -0
  257. package/views/SettingsGeneral/index.js +173 -0
  258. package/views/SettingsGeneral/styles.js +28 -0
  259. package/views/SettingsNotifications/index.js +204 -0
  260. package/views/SettingsNotifications/styles.js +38 -0
  261. package/views/SettingsUser/index.js +170 -0
  262. package/views/SettingsUser/styles.js +17 -0
  263. package/views/TimetableCalendar/index.js +387 -0
  264. package/views/TimetableCalendar/styles.js +121 -0
  265. package/views/TimetableList/index.js +402 -0
  266. package/views/TimetableList/styles.js +55 -0
  267. package/views/Webviews/index.js +158 -0
  268. package/views/Webviews/styles.js +11 -0
@@ -0,0 +1,387 @@
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, useMemo, useCallback, useEffect } from 'react';
16
+ import { View, Text, TextInput, TouchableOpacity, StyleSheet, Dimensions, SafeAreaView, KeyboardAvoidingView, Platform, ActivityIndicator, Linking } from 'react-native';
17
+ import { connect } from 'react-redux';
18
+ import { withTheme, Headline } from 'react-native-paper';
19
+ import componentStyles from "./styles";
20
+ import { withTranslation } from 'react-i18next';
21
+
22
+ import { DateTime, Duration } from 'luxon';
23
+ import moment from 'moment';
24
+ import 'moment/locale/de';
25
+
26
+ import { onUpdateRefreshing, useLanguage } from '../../libraries/core';
27
+ import {
28
+ useCourses,
29
+ useTimetableCode,
30
+ TimetableNotFoundError,
31
+ } from '../../context/context-timetable';
32
+ import { Ionicons } from '@expo/vector-icons';
33
+ import AppbarComponent from '../../components/AppBar';
34
+ import { TabView, TabBar } from 'react-native-tab-view';
35
+ import CalendarDay from '../../components/TimetableDay';
36
+ import CalendarWeek from '../../components/TimetableWeek';
37
+ import CalendarMonth from '../../components/TimetableMonth';
38
+ import CourseDetailDialog from '../../components/CourseDetailDialog';
39
+
40
+ function TimetableViewCalendar(props) {
41
+ const { theme, theme: { themeStyles, colors, appSettings, appSettings: { modules: { timetable: { code, calendarStarttime } } } }, t, settings } = props;
42
+ const language = useLanguage();
43
+
44
+ const styles = useMemo(
45
+ () => StyleSheet.create(componentStyles(theme)),
46
+ [theme]
47
+ );
48
+
49
+ const whiteAppbar = theme?.appSettings?.modules?.timetable?.whiteAppbar ?? colors.primary;
50
+ const [timetableCode, saveTimetableCode, deleteTimetableCode] = useTimetableCode();
51
+
52
+ const [timetableCodeInput, setTimetableCodeInput] = useState(timetableCode);
53
+ const [selectedDayModeDate, setSelectedDayModeDate] = useState(() => DateTime.now());
54
+ const [selectedWeekModeISOWeekDate, setSelectedWeekModeISOWeekDate] = useState(() => DateTime.now().startOf('week').toISOWeekDate());
55
+ const [index, setIndex] = useState(0);
56
+ const [formVisible, setFormVisible] = useState(false);
57
+ const [infoVisible, setInfoVisible] = useState(timetableCode ? false : true);
58
+ const [loading, setLoading] = useState(false);
59
+ const [today, setToday] = useState(new Date());
60
+ const [selectedEvent, setSelectedEvent] = useState(null);
61
+
62
+ const [errorMessage, setErrorMessage] = useState('');
63
+ const [infoMessage, setInfoMessage] = useState('');
64
+
65
+ /**
66
+ * Höhe des Kalenders in Pixeln.
67
+ * Wird an die Calendar-Komponente in TimetableDay/TimetableWeek übergeben.
68
+ * WICHTIG: Bei Änderung dieses Wertes muss auch die height-Prop in TimetableDay und TimetableWeek angepasst werden!
69
+ */
70
+ const CALENDAR_HEIGHT = 800;
71
+
72
+ /**
73
+ * Interne Mindesthöhe der react-native-big-calendar Bibliothek.
74
+ * Siehe: node_modules/react-native-big-calendar/build/index.es.js (MIN_HEIGHT = 1200)
75
+ */
76
+ const CALENDAR_MIN_HEIGHT = 1200;
77
+
78
+ /**
79
+ * Berechnet die Höhe einer Stunden-Zelle in Pixeln.
80
+ * Verwendet die gleiche Formel wie react-native-big-calendar intern:
81
+ * cellHeight = Math.max(height - 30, MIN_HEIGHT) / 24
82
+ */
83
+ const calculateCellHeight = (height) => Math.max(height - 30, CALENDAR_MIN_HEIGHT) / 24;
84
+
85
+ // Berechnen der Uhrzeit zu der beim Öffnen des Stundenplan Kalenders hingepsrungen werden soll.
86
+ // Wird in einem State gespeichert, weil später noch beim Focus-Wechsel erneut berechnet werden muss.
87
+ const [calendarScrollOffsetMinutes, setCalendarScrollOffsetMinutes] = useState(
88
+ () => {
89
+ // Berechnen der Uhrzeit, falls im Custemizing eine angegeben ist, ansonsten wird die jetzige Stunde verwendet.
90
+ // Speichern als Duration.
91
+ const calendarScrollOffsetDuration = calendarStarttime
92
+ ? Duration.fromISOTime(calendarStarttime)
93
+ : Duration.fromObject({ hours: DateTime.now().hour });
94
+
95
+ // Duration wird in Minuten umgewandelt, weil der Kalender ein Minutenoffset erwartet
96
+ const offsetMinutes = calendarScrollOffsetDuration.as('minutes');
97
+
98
+ /**
99
+ * iOS Workaround für Bug in react-native-big-calendar (v4.0.19)
100
+ *
101
+ * Problem: Die Bibliothek behandelt scrollOffsetMinutes auf iOS falsch.
102
+ * - Android verwendet: scrollTo({ y: (cellHeight * scrollOffsetMinutes) / 60 })
103
+ * - iOS verwendet: contentOffset.y = scrollOffsetMinutes (direkt als Pixel!)
104
+ *
105
+ * Lösung: Auf iOS den Wert vorab in Pixel umrechnen mit der gleichen Formel wie Android.
106
+ *
107
+ * Siehe: node_modules/react-native-big-calendar/build/index.es.js (Zeile 799 und 895)
108
+ */
109
+ if (Platform.OS === 'ios') {
110
+ const cellHeight = calculateCellHeight(CALENDAR_HEIGHT);
111
+ return (cellHeight * offsetMinutes) / 60;
112
+ }
113
+
114
+ return offsetMinutes;
115
+ }
116
+ );
117
+
118
+ const [courses, refreshCourses] = useCourses();
119
+
120
+ // Einstellungen für den Stundenplan-Code
121
+ const timetableCodeInputLength = code?.length ?? 0;
122
+ const timetableCodeInputFilters = code?.filters;
123
+ const timetableCodeInputPreSaveFilters = Array.isArray(code?.preSaveFilters) ? code.preSaveFilters : [];
124
+ const timetableCodeInputFilterToUpperCase = timetableCodeInputFilters?.toUpperCase ?? false;
125
+
126
+ const routes = [
127
+ appSettings?.modules?.timetable?.enableDayTab ? { key: 'day', title: t('timetable:day') } : null,
128
+ appSettings?.modules?.timetable?.enableWeekTab ? { key: 'week', title: t('timetable:week') } : null,
129
+ appSettings?.modules?.timetable?.enableMonthTab ? { key: 'month', title: t('timetable:month') } : null,
130
+ ].filter(Boolean); // Filter out null values
131
+
132
+ const activeMode = routes?.[index]?.key;
133
+ const activeHeaderDate =
134
+ activeMode === 'day'
135
+ ? selectedDayModeDate
136
+ : DateTime.fromISO(selectedWeekModeISOWeekDate);
137
+
138
+ const unsetSelectedEvent = useCallback(
139
+ () => setSelectedEvent(null),
140
+ [setSelectedEvent]
141
+ );
142
+
143
+ const renderScene = useCallback(({ route }) => {
144
+ switch (route.key) {
145
+ case 'day':
146
+ return <CalendarDay
147
+ selectedDate={selectedDayModeDate}
148
+ calendarScrollOffsetMinutes={calendarScrollOffsetMinutes}
149
+ calendarHeight={CALENDAR_HEIGHT}
150
+ onDateChanged={setSelectedDayModeDate}
151
+ onCourseSelected={setSelectedEvent}
152
+ />;
153
+ case 'week':
154
+ return <CalendarWeek
155
+ selectedISOWeek={selectedWeekModeISOWeekDate}
156
+ calendarScrollOffsetMinutes={calendarScrollOffsetMinutes}
157
+ calendarHeight={CALENDAR_HEIGHT}
158
+ onWeekChanged={setSelectedWeekModeISOWeekDate}
159
+ onCourseSelected={setSelectedEvent}
160
+ />;
161
+ case 'month':
162
+ return <CalendarMonth today={today} setToday={setToday} month={month} setMonth={setMonth} calendarScrollOffsetMinutes={calendarScrollOffsetMinutes} calendarHeight={CALENDAR_HEIGHT} />;
163
+ default:
164
+ return null;
165
+ }
166
+ },
167
+ [language, selectedDayModeDate, calendarScrollOffsetMinutes, selectedDayModeDate, setSelectedDayModeDate, selectedWeekModeISOWeekDate, setSelectedWeekModeISOWeekDate]
168
+ );
169
+
170
+ // Unter verwendung von Luxon wird eine Liste der Monatsnamen generiert, dabei wird die eingestellte Sprache berücksichtigt
171
+ const months = moment.months();
172
+
173
+ const renderTextWithLinks = (text) => {
174
+ const parts = text.split(/(https?:\/\/[^\s]+)/g);
175
+ return parts.map((part, index) => {
176
+ if (part.match(/https?:\/\/[^\s]+/)) {
177
+ const displayText = part.replace(/https?:\/\//, '');
178
+ return (
179
+ <Text
180
+ key={index}
181
+ style={styles.link}
182
+ onPress={() => Linking.openURL(part)}
183
+ >
184
+ {displayText}
185
+ </Text>
186
+ );
187
+ }
188
+ return part;
189
+ });
190
+ };
191
+
192
+ const handleImportButtonPress = () => {
193
+ setLoading(true);
194
+ setErrorMessage('');
195
+ setInfoMessage('');
196
+
197
+ saveTimetableCode(
198
+ // Falls Filter eingestellt sind, werden diese nacheinander auf den Stundenplancode angewendet
199
+ timetableCodeInputPreSaveFilters.reduce(
200
+ (currentTimetableCode, preSaveFilter) => preSaveFilter?.(currentTimetableCode) ?? currentTimetableCode,
201
+ timetableCodeInput
202
+ )
203
+ )
204
+ .then(
205
+ () => {
206
+ const now = DateTime.now();
207
+ const startDate = now.startOf('week');
208
+ const endDate = now.endOf('week');
209
+ return refreshCourses(startDate.toISODate(), endDate.toISODate())
210
+ .then(
211
+ () => {
212
+ setFormVisible(false);
213
+ setLoading(false);
214
+ }
215
+ );
216
+ }
217
+ ).catch(
218
+ (error) => {
219
+ if (error instanceof TimetableNotFoundError) {
220
+ setErrorMessage(t('timetable:codeNotFoundError', { timetableCode: timetableCodeInput }));
221
+ setLoading(false);
222
+ } else {
223
+ console.error(TimetableViewCalendar.name, ':', 'can´t import timetable code', timetableCode, ':', error);
224
+ setErrorMessage(t('timetable:importError'));
225
+ }
226
+ }
227
+ ).finally(
228
+ () => setLoading(false)
229
+ );
230
+ };
231
+
232
+ useEffect(() => {
233
+ setErrorMessage('')
234
+ if (infoVisible) {
235
+ setInfoMessage(t(timetableCode ? 'timetable:inputTimetableCode' : 'timetable:notImportedYet', { timetableCodeInputLength }));
236
+ } else {
237
+ setInfoMessage('');
238
+ }
239
+ }, [infoVisible]);
240
+ const tabView = useMemo(() => {
241
+ return (
242
+ <TabView
243
+ style={{ backgroundColor: '#fff' }}
244
+ navigationState={{ index, routes }}
245
+ renderScene={renderScene}
246
+ onIndexChange={setIndex}
247
+ initialLayout={{ width: Dimensions.get('window').width }}
248
+ swipeEnabled={false}
249
+ lazy={true}
250
+ lazyPreloadDistance={0}
251
+ renderTabBar={props => (
252
+ <TabBar
253
+ {...props}
254
+ activeColor={themeStyles.tabs.activeColor}
255
+ inactiveColor={themeStyles.tabs.inactiveColor}
256
+ style={themeStyles.tabs}
257
+ labelStyle={themeStyles.tab}
258
+ indicatorStyle={themeStyles.tabIndicator}
259
+ />
260
+ )}
261
+ />
262
+ )
263
+ }, [renderScene, index, routes, setIndex, themeStyles.tab, themeStyles.tabIndicator]);
264
+
265
+ const renderForm = () => (
266
+ <View style={styles.formContainer}>
267
+ <View style={styles.inputContainer}>
268
+ <TextInput
269
+ style={styles.codeInput}
270
+ placeholder={t('timetable:inputPlaceholder')}
271
+ value={timetableCodeInput}
272
+ onChangeText={(code) => {
273
+ setTimetableCodeInput(code);
274
+ setErrorMessage('');
275
+ }}
276
+ autoCapitalize={timetableCodeInputFilterToUpperCase ? 'characters' : 'none'}
277
+ maxLength={timetableCodeInputLength ? timetableCodeInputLength : undefined}
278
+ contextMenuHidden={false}
279
+ />
280
+ <TouchableOpacity style={styles.infoIcon} onPress={() => {
281
+ setInfoVisible(!infoVisible);
282
+ }}>
283
+ <Ionicons name="information-circle-outline" size={30} color={colors.icon} />
284
+ </TouchableOpacity>
285
+ </View>
286
+ {loading ? <ActivityIndicator size="large" color={colors.loadingIndicator} /> : null}
287
+ {errorMessage ? <Text style={styles.errorText}>{errorMessage}</Text> : null}
288
+ {infoMessage ? (
289
+ <Text
290
+ style={styles.infoText}
291
+ dataDetectorType="link"
292
+ selectable
293
+ >
294
+ {renderTextWithLinks(infoMessage)}
295
+ </Text>
296
+ ) : null}
297
+
298
+ <TouchableOpacity
299
+ style={styles.importButton}
300
+ labelStyle={styles.importButtonLabel}
301
+ label={t('eventCode:importButton')}
302
+ onPress={() => {
303
+ handleImportButtonPress();
304
+ }}
305
+ >
306
+ <Headline style={styles.importButtonLabel} color={colors.buttonText}>
307
+ {t('timetable:importButton')}
308
+ </Headline>
309
+ </TouchableOpacity>
310
+ <View style={styles.buttonContainer}>
311
+ <TouchableOpacity
312
+ style={styles.deleteButtonContainer}
313
+ onPress={() => {
314
+ deleteTimetableCode();
315
+ setTimetableCodeInput('');
316
+ }}
317
+ >
318
+ <Text style={styles.deleteButton}>{t('timetable:deleteCode')}</Text>
319
+ <Ionicons name="trash-outline" size={20} color="red" />
320
+ </TouchableOpacity>
321
+ <TouchableOpacity
322
+ onPress={() => {
323
+ setFormVisible(false);
324
+ setErrorMessage('');
325
+ setInfoVisible(false);
326
+ }}
327
+ >
328
+ <Text style={styles.dismissButton}>{t("timetable:close")}</Text>
329
+ </TouchableOpacity>
330
+ </View>
331
+ </View>
332
+ );
333
+
334
+ return (
335
+ <SafeAreaView style={{ flex: 1, backgroundColor: whiteAppbar }}>
336
+ <AppbarComponent
337
+ rightAction={
338
+ <TouchableOpacity
339
+ onPress={
340
+ activeMode === 'day'
341
+ ? () => setSelectedDayModeDate(() => DateTime.now())
342
+ : () => setSelectedWeekModeISOWeekDate(() => DateTime.now().startOf('week').toISOWeekDate())
343
+ }
344
+ >
345
+ <Text style={{ color: whiteAppbar === colors.primary ? '#fff' : '#000' }}>{t("timetable:today")}</Text>
346
+ </TouchableOpacity>
347
+ }
348
+ style={{ backgroundColor: colors.primary /* whiteAppbar */ }}//hintergrundappbar
349
+ title={
350
+ activeMode === 'month'
351
+ ? `${months[activeHeaderDate.month - 1]}`
352
+ : `${months[activeHeaderDate.month - 1]} ${t('timetable:weekNumber', { kw: activeHeaderDate.weekNumber })}`
353
+ }
354
+ />
355
+ {tabView}
356
+ {formVisible && (
357
+ <KeyboardAvoidingView
358
+ behavior='position'
359
+ keyboardVerticalOffset={Platform.OS === 'android' ? 50 : 0}
360
+ >
361
+ {renderForm()}
362
+ </KeyboardAvoidingView>
363
+ )}
364
+
365
+ {!formVisible && (
366
+ <TouchableOpacity
367
+ style={styles.floatingButton}
368
+ onPress={() => setFormVisible(true)}
369
+ >
370
+ <Ionicons name="add-outline" size={40} color="#000" />
371
+ </TouchableOpacity>
372
+ )}
373
+ <CourseDetailDialog
374
+ course={selectedEvent}
375
+ visible={selectedEvent ? true : false}
376
+ onClose={unsetSelectedEvent}
377
+ onDismiss={unsetSelectedEvent}
378
+ />
379
+ </SafeAreaView>
380
+ );
381
+ }
382
+
383
+ const mapStateToProps = state => ({
384
+ settings: state.settingReducer,
385
+ });
386
+
387
+ export default connect(mapStateToProps, { onUpdateRefreshing })(withTranslation()(withTheme(TimetableViewCalendar)));
@@ -0,0 +1,121 @@
1
+ export default function (theme) {
2
+ return {
3
+ formContainer: {
4
+ backgroundColor: '#F6F7F7',
5
+ borderRadius: 10,
6
+ padding: 20,
7
+ elevation: 5,
8
+ shadowColor: '#000',
9
+ shadowOffset: { width: 0, height: 2 },
10
+ shadowOpacity: 0.3,
11
+ shadowRadius: 3,
12
+ left: '5%',
13
+ right: '5%',
14
+ position: 'absolute',
15
+ bottom: 100,
16
+ },
17
+ inputContainer: {
18
+ flex: 1,
19
+ width: '100%',
20
+ justifyContent: 'flex-end',
21
+ alignItems: 'center',
22
+ flexDirection: 'row',
23
+ marginBottom: 15,
24
+ },
25
+ infoIcon: {
26
+ width: '10%',
27
+ marginLeft: '3%',
28
+ },
29
+ codeInput: {
30
+ height: 50,
31
+ width: '87%',
32
+ borderColor: '#ddd',
33
+ borderWidth: 1,
34
+ borderRadius: 8,
35
+ paddingLeft: 10,
36
+ },
37
+ checkboxContainer: {
38
+ flexDirection: 'row',
39
+ alignItems: 'center',
40
+ marginBottom: 20,
41
+ },
42
+ checkboxLabel: {
43
+ marginLeft: 10,
44
+ fontSize: 16,
45
+ },
46
+ buttonContainer: {
47
+ marginTop: 20,
48
+ justifyContent: 'space-between',
49
+ alignItems: 'center',
50
+ flexDirection: 'row',
51
+ },
52
+ dismissButton: {
53
+ color: '#007bff',
54
+ textAlign: 'right',
55
+ fontWeight: 'bold',
56
+ fontSize: 16,
57
+ },
58
+ deleteButtonContainer: {
59
+ flexDirection: 'row',
60
+ },
61
+ deleteButton: {
62
+ color: 'red',
63
+ fontWeight: 'bold',
64
+ textAlign: 'left',
65
+ fontSize: 16,
66
+ marginRight: 3,
67
+ },
68
+ floatingButton: {
69
+ position: 'absolute',
70
+ bottom: 20,
71
+ right: 20,
72
+ width: 60,
73
+ height: 60,
74
+ borderRadius: 40,
75
+ backgroundColor: '#fff',
76
+ justifyContent: 'center',
77
+ alignItems: 'center',
78
+ shadowColor: '#000',
79
+ shadowOffset: { width: 0, height: 2 },
80
+ shadowOpacity: 0.3,
81
+ shadowRadius: 3,
82
+ elevation: 5,
83
+ },
84
+ importButton: {
85
+ width: '100%',
86
+ flexDirection: 'row',
87
+ flexWrap: 'wrap',
88
+ justifyContent: 'center',
89
+ alignItems: 'center',
90
+ marginTop: 10,
91
+ padding: theme.paddings.small,
92
+ flex: 1,
93
+ backgroundColor: theme.colors.primary,
94
+ borderBottomRightRadius: 10,
95
+ borderBottomLeftRadius: 10,
96
+ borderTopRightRadius: 10,
97
+ borderTopLeftRadius: 10
98
+
99
+ },
100
+ importButtonLabel: {
101
+ color: theme.colors.messages.noticeText,
102
+ ...theme.fonts.medium,
103
+ fontSize: theme.fontSizes.xl,
104
+ lineHeight: theme.lineHeights.l,
105
+ marginLeft: theme.paddings.small
106
+ },
107
+ errorText: {
108
+ color: 'red',
109
+ marginLeft: 5,
110
+ marginBottom: 10,
111
+ },
112
+ infoText: {
113
+ color: 'black',
114
+ marginLeft: 5,
115
+ },
116
+ link: {
117
+ textDecorationLine: 'underline',
118
+ color: '#007bff',
119
+ }
120
+ };
121
+ };