@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,357 @@
1
+ import { useSyncExternalStore } from 'react';
2
+
3
+ import * as SecureStore from 'expo-secure-store';
4
+
5
+ import { groupBy } from 'lodash';
6
+ import { DateTime, Duration } from 'luxon';
7
+
8
+ import CollectorVersion2ApiProvider from './CollectorVersion2ApiProvider';
9
+
10
+ /**
11
+ * @typedef TimetableProvider
12
+ * @property {(timetableCode: string, startDate: string, startDate: string) => Course[]} getByCode Ruft zu einem Stundenplancode die entsprechenden Vorlesungen in einem bestimmten Zeitraum ab
13
+ */
14
+
15
+ /**
16
+ * @typedef CourseDataField
17
+ * @property {string} data
18
+ * @property {string} displayname
19
+ */
20
+
21
+ /**
22
+ * @typedef CourseDataField
23
+ * @property {string} data
24
+ * @property {string} displayname
25
+ */
26
+
27
+ /**
28
+ * @typedef CourseTime
29
+ * @property {number} dayOfWeek
30
+ * @property {string} date ISO Datum
31
+ * @property {string} start ISO Uhrzeit
32
+ * @property {string} end ISO Uhrzeit
33
+ * @property {string} displayname
34
+ * @property {string} weekmode
35
+ * @property {string} mode
36
+ */
37
+
38
+ /**
39
+ * @typedef Course
40
+ * @property {CourseDataField} title
41
+ * @property {CourseDataField} room
42
+ * @property {CourseDataField} type
43
+ * @property {CourseDataField[]} lecturer
44
+ * @property {CourseTime[]} times
45
+ */
46
+
47
+ const TimetableCodeStoreKey = 'timetable.code';
48
+ const TimetableCoursesStoreKey = 'timetable.courses';
49
+
50
+ export class ApiProviderNotInitializedError extends Error {
51
+ constructor(message) {
52
+ super(message);
53
+ this.name = this.constructor.name;
54
+ }
55
+ }
56
+
57
+ export class TimetableCodeNotInitializedError extends Error {
58
+ constructor(message) {
59
+ super(message);
60
+ this.name = this.constructor.name;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Eine Serviceklasse, die Zugriff auf die Daten des Stundenplan-Moduls ermöglicht.
66
+ *
67
+ * Der Stundenplan-Service ist Klasse für die Datenverwaltung der für das Stundenplan-Modul benötigten Daten.
68
+ * Dieser ist außerhalb des React-Kontextes angesiedelt, damit auf die Daten zugegriffen werden kann, wenn kein React-Kontext verfügbar ist.
69
+ * Alle Daten werden in lokalen Speichern zwischengespeichert, um beim ersten Zugriff veraltet Daten anzeigen zu können.
70
+ *
71
+ * Der Service sollte über {@linkcode TimetableService.fromProviderSettingsObject} initialisert werden.
72
+ */
73
+ export default class TimetableService {
74
+
75
+ /**
76
+ * @type {TimetableProvider}
77
+ */
78
+ #provider;
79
+
80
+ /**
81
+ * Konstruktor des Stundenplan-Services.
82
+ * Es muss ein Provider Übergeben werden, damit der Stundenplan-Service Daten über den Provider abrufen kann.
83
+ * Es wird empfohlen {@linkcode TimetableService.fromProviderSettingsObject} zu verwenden.
84
+ *
85
+ * @param {TimetableProvider} provider Provider, welcher für den Datenabruf zuständig ist
86
+ * @example
87
+ * const language = 'de';
88
+ * const providerSettings {
89
+ * name: 'normal-provider',
90
+ * url: 'https://provider.com/api/v1/'
91
+ * };
92
+ *
93
+ * const timetableService = TimetableService.fromProviderSettingsObject(providerSettings, language);
94
+ */
95
+ constructor(provider) {
96
+ this.#provider = provider;
97
+
98
+ this.#code = SecureStore.getItem(TimetableCodeStoreKey);
99
+ this.#courses = JSON.parse(SecureStore.getItem(TimetableCoursesStoreKey));
100
+ }
101
+
102
+
103
+
104
+ #code = undefined;
105
+ #codeSubscribers = new Set();
106
+
107
+ code() {
108
+ return this.#code;
109
+ }
110
+ codeCallback = () => this.code();
111
+
112
+ #setCode(code) {
113
+ this.#code = code;
114
+ this.#codeSubscribers.forEach(subscriber => subscriber(code));
115
+ }
116
+ async setCode(code) {
117
+ await SecureStore.setItemAsync(TimetableCodeStoreKey, code);
118
+ this.#setCode(code);
119
+ }
120
+ setCodeCallback = async (code) => this.setCode(code);
121
+
122
+ async deleteCode() {
123
+
124
+ await Promise.all([
125
+ SecureStore.deleteItemAsync(TimetableCodeStoreKey),
126
+ SecureStore.deleteItemAsync(TimetableCoursesStoreKey),
127
+ ]);
128
+
129
+ this.#setCode(null);
130
+ this.#setCourses(null);
131
+ }
132
+ deleteCodeCallback = () => this.deleteCode();
133
+
134
+ codeSubscribe(subscriber) {
135
+ this.#codeSubscribers.add(subscriber);
136
+
137
+ return () => this.codeUnsubscribe(subscriber);
138
+ }
139
+ codeSubscribeCallback = (subscriber) => this.codeSubscribe(subscriber);
140
+
141
+ codeUnsubscribe(subscriber) {
142
+ return this.#codeSubscribers.delete(subscriber);
143
+ }
144
+
145
+
146
+
147
+ /**
148
+ * @type {Object.<string, Course[]>}
149
+ */
150
+ #courses = undefined;
151
+ #coursesSubscribers = new Set();
152
+
153
+ /**
154
+ * Liefert die Vorlesungen, die von dem Service respeichert werden zurück.
155
+ * Dabei werden die Vorlesungen nach Vorlesungstagen gruppiert.
156
+ * Somit wird ein Object zurückgegeben, bei dem die Schlüssel ISO-Datums der Vorlesungstage sind und die Werte sind Listen mit Vorlesungen
157
+ *
158
+ * @returns {Object.<string, Course[]>} Vorlesungen gruppiert nach Vorlesungstagen
159
+ */
160
+ courses() {
161
+ return this.#courses;
162
+ }
163
+
164
+ #setCourses(courses) {
165
+ // Neue Vorlesungsdaten im Service hinterlegen
166
+ this.#courses = courses;
167
+
168
+ // Jedem Subscriber werden die neuen Vorlesungstage bekannt gemacht
169
+ this.#coursesSubscribers.forEach(subscriber => subscriber(this.#courses));
170
+ }
171
+
172
+ coursesCallback = () => this.courses();
173
+
174
+ async refreshCourses(startDate, endDate) {
175
+
176
+ if (this.#provider === null) {
177
+ throw new ApiProviderNotInitializedError('Api Provider is not initilized');
178
+ }
179
+
180
+ if (this.#code === null) {
181
+ throw new TimetableCodeNotInitializedError('Timetable code is not initilized');
182
+ }
183
+
184
+ const courses = await this.#provider.getByCode(this.#code, startDate, endDate);
185
+ const transformedCourses = courses.map(
186
+ course => {
187
+ // Erstes Time-Element aus dem times-Array nehmen, da im neuen Format nur noch eine Zeit enthalten ist
188
+ const courseTime = course?.times?.[0];
189
+ if (courseTime) {
190
+ const courseDate = DateTime.fromISO(courseTime?.date);
191
+ // Startzeit und Endzeit der Vorlesung in ein DateTime umwandeln
192
+ const courseStartTime = Duration.fromISOTime(courseTime.start);
193
+ const courseStartDateTime = courseDate.plus(courseStartTime);
194
+ const courseEndTime = Duration.fromISOTime(courseTime.end);
195
+ const courseEndDateTime = courseDate.plus(courseEndTime);
196
+
197
+ return {
198
+ ...course,
199
+ startDateTime: courseStartDateTime.toISO(),
200
+ endDateTime: courseEndDateTime.toISO(),
201
+ }
202
+ } else {
203
+ return course;
204
+ }
205
+ }
206
+ )
207
+
208
+ // Gruppieren der vom Provider abgeholten Vorlesungen
209
+ // Es wird nach dem Datum der Vorlesungen gruppiert
210
+ // Vorlesungen, die keinem Tag zugeordnet werden können, werden untder dem Schlüssel `undefined` zusammengefasst
211
+ const addingCourses = groupBy(
212
+ transformedCourses,
213
+ course => {
214
+ // Datum der Vorlesung aus der Vorlesung holen
215
+ const courseDate = course?.times?.[0]?.date;
216
+
217
+ // Prüfen ob die Vorlesung einen Wert als Datum vorweist
218
+ return courseDate
219
+ // Ist ein Wert vorhanden, wird dieser für die Gruppierung verwendet
220
+ ? courseDate
221
+ // Ansonsten wird undefined zurückgeben (lerrer String, null, undefined, ...)
222
+ : undefined;
223
+ }
224
+ );
225
+
226
+ //Entfernen der Vorlesungstage zwischen Startdatum und Enddatum
227
+ const rangeRemovedCourses = Object.fromEntries(
228
+ Object.entries(this.#courses ?? {})
229
+ .filter(([coursesDate,]) => startDate >= coursesDate && coursesDate <= endDate)
230
+ );
231
+
232
+ // Zusammenführen der neuen Vorlesungstagen der Vorlesungen des Providers und der schon vorhandenen Vorlesungstagen
233
+ const newCourses = {
234
+ ...rangeRemovedCourses,
235
+ ...addingCourses,
236
+ };
237
+
238
+ // Neue Vorlesungsdaten in den Cache ablegen
239
+ SecureStore.setItem(TimetableCoursesStoreKey, JSON.stringify(newCourses));
240
+
241
+ // Neue Vorlesungen hin Service hinterlegen und Äanderun bekannt geben
242
+ this.#setCourses(newCourses);
243
+ }
244
+ refreshCoursesCallback = (startDate, endDate) => this.refreshCourses(startDate, endDate);
245
+
246
+ coursesSubscribe(subscriber) {
247
+ this.#coursesSubscribers.add(subscriber);
248
+
249
+ return () => this.coursesUnsubscribe(subscriber);
250
+ }
251
+ coursesSubscribeCallback = (subscriber) => this.coursesSubscribe(subscriber);
252
+
253
+ coursesUnsubscribe(subscriber) {
254
+ return this.#coursesSubscribers.delete(subscriber);
255
+ }
256
+
257
+
258
+
259
+ /**
260
+ * Erstellen eines Stundenplanservices mit Hilfe der Provider-Einstellungen und Sprache
261
+ *
262
+ * @param {ProviderSetting} providerSettingsObject
263
+ * @param {string} language
264
+ * @returns
265
+ */
266
+ static fromProviderSettingsObject(providerSettingsObject, language) {
267
+ const provider = TimetableService.#createProvider(providerSettingsObject, language);
268
+
269
+ return new TimetableService(provider);
270
+ }
271
+
272
+ /**
273
+ * Erstellen des Providers mit Hilfe eines Provider-Einstellungen-Objektes und einer Sprache
274
+ *
275
+ * @param {ProviderSetting} providerSettingsObject Einstellungen welche zum auswählen und Initialisieren des Provider verwendet werden
276
+ * @param {string} language Sprachcode welcher für den Datenabruf verwendet werden soll
277
+ */
278
+ static #createProvider(providerSettingsObject, language) {
279
+ const { provider } = providerSettingsObject;
280
+
281
+ switch (provider) {
282
+ case CollectorVersion2ApiProvider.name:
283
+ return CollectorVersion2ApiProvider.fromSettingsObject(providerSettingsObject, language);
284
+ default:
285
+ return null;
286
+ }
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Ein React-Hook, um den Stundenplancode des Stundenplan-Services in den React-Kontext einzubinden.
292
+ *
293
+ * @param {TimetableService} timetableService Der Stundenplan-Service welche den Stundenplancode bereitstellen soll
294
+ * @returns {[string|null, (code: string) => Promise<void>, () => void]}
295
+ * @example
296
+ * const timetableService = TimetableService.fromProviderSettingsObject(
297
+ * {
298
+ * provider: 'hs-collector-v2',
299
+ * url: 'https://hsc-production.hrz.tu-chemnitz.de/hs_collector/api/v1/',
300
+ * },
301
+ * 'de',
302
+ * );
303
+ *
304
+ * const [timetableCode, saveTimetableCode, deleteTimetableCode] = useSyncTimetableCode(timetableService);
305
+ *
306
+ * saveTimetableCode('testcode');
307
+ *
308
+ * return (
309
+ * <Text>
310
+ * {timetableCode}
311
+ * </Text>
312
+ * );
313
+ */
314
+ export function useSyncTimetableCode(timetableService) {
315
+ const timetableCode = useSyncExternalStore(
316
+ timetableService.codeSubscribeCallback,
317
+ timetableService.codeCallback,
318
+ );
319
+
320
+ return [timetableCode, timetableService.setCodeCallback, timetableService.deleteCodeCallback];
321
+ }
322
+
323
+ /**
324
+ * React-Hook, welcher die Vorlesungen nach Vorlesungtagen gruppoert für React zur verfügung stellt.
325
+ * Zusätzlich wird eine Funktion zurückgegeben, welche für die Aktualisierung der Daten in einem bestimmten Zeitraum verwendet werden kann.
326
+ *
327
+ * @param {TimetableService} timetableService
328
+ * @returns {[Object.<string, Course[]>, (startDate: string, endDate: string)=> Promise<void>]}
329
+ * @example
330
+ * const timetableService = TimetableService.fromProviderSettingsObject(
331
+ * {
332
+ * provider: 'hs-collector-v2',
333
+ * url: 'https://hsc-production.hrz.tu-chemnitz.de/hs_collector/api/v1/',
334
+ * },
335
+ * 'de',
336
+ * );
337
+ *
338
+ * const [courses, refreshCourses] = useSyncCourses(timetableService);
339
+ *
340
+ * useEffect(
341
+ * () => {
342
+ * refreshCourses('2025-01-01', '2026-01-01');
343
+ * },
344
+ * []
345
+ * );
346
+ *
347
+ * return (
348
+ * );
349
+ */
350
+ export function useSyncCourses(timetableService) {
351
+ const courses = useSyncExternalStore(
352
+ timetableService.coursesSubscribeCallback,
353
+ timetableService.coursesCallback,
354
+ );
355
+
356
+ return [courses, timetableService.refreshCoursesCallback];
357
+ }
@@ -0,0 +1,215 @@
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 { createContext, useEffect, useContext, useMemo } from 'react'
16
+
17
+ import { useSelector } from 'react-redux';
18
+ import { useTheme } from 'react-native-paper';
19
+
20
+ import { DateTime, Duration } from 'luxon';
21
+
22
+ import { TimetableNotFoundError } from './ProviderErrors';
23
+ import TimetableService, {
24
+ ApiProviderNotInitializedError,
25
+ TimetableCodeNotInitializedError,
26
+ useSyncCourses,
27
+ useSyncTimetableCode
28
+ } from './TimetableService';
29
+
30
+ const CourseWeekModeWeekly = 'weekly';
31
+ const CourseWeekModeOdd = 'odd';
32
+ const CourseWeekModeEven = 'even';
33
+
34
+ const CourseWeekModes = {
35
+ weekly: CourseWeekModeWeekly,
36
+ odd: CourseWeekModeOdd,
37
+ even: CourseWeekModeEven,
38
+ }
39
+
40
+ const TimetableContext = createContext({
41
+ code: null,
42
+ courses: {},
43
+ });
44
+
45
+ /**
46
+ * Ein Monat ist die standart Zeispanne für das Vorladen der Stundenplandaten
47
+ *
48
+ * @constant
49
+ * @type {string} Zeitspanne im ISO Format(https://de.wikipedia.org/wiki/ISO_8601#Zeitspannen)
50
+ */
51
+ const defaultPrefetchDistance = 'P1M';
52
+
53
+ /**
54
+ * Selector für Wert, der anzeigt ob die Staging-Server genutzt werden sollen.
55
+ * @param {Object} reduxState
56
+ * @returns {boolean} true, wenn die Staging-Server verwendet werden sollen, ansonsten false
57
+ */
58
+ function selectUseStagingServer(reduxState) {
59
+ return reduxState?.settingReducer?.settingsDevelop?.useStaging ?? false;
60
+ }
61
+
62
+ /**
63
+ * Provider for timetable context
64
+ */
65
+ function TimetableContextProvider({ children }) {
66
+ const componentName = TimetableContextProvider.name;
67
+ const theme = useTheme();
68
+ const useStagingServers = useSelector(selectUseStagingServer);
69
+ const language = 'de';
70
+
71
+ // Einstellungen für das Stundenplan-Modul
72
+ const timetableSettings = theme?.appSettings?.modules?.timetable
73
+
74
+ // Einstellungen für Vorladen der Stundenplandaten
75
+ const timetablePrefetchSettings = timetableSettings?.prefetch;
76
+ const beginPrefetchDistance = timetablePrefetchSettings?.beginDistance ?? defaultPrefetchDistance;
77
+ const endPrefetchDistance = timetablePrefetchSettings?.beginDistance ?? defaultPrefetchDistance;
78
+
79
+ // Einstellungen für API-Provider
80
+ const timetableApiSettings = theme?.appSettings?.modules?.timetable?.api
81
+ // Soll der Staging-Provider verwendet werden?
82
+ const timetableApiProviderSettings = useStagingServers
83
+ // Wenn ja, werden die Staging Provider-Einstellungen geladen
84
+ ? timetableApiSettings?.staging
85
+ // Wenn nein, werden die productiven Provider-Einstellungen geladen
86
+ : timetableApiSettings?.production;
87
+
88
+ // Erstellen des Stundenplan-Services
89
+ const timetableService = useMemo(
90
+ () => TimetableService.fromProviderSettingsObject(
91
+ timetableApiProviderSettings,
92
+ language,
93
+ ),
94
+ [timetableApiProviderSettings, language]
95
+ );
96
+
97
+ // Stundenplan-Code aus dem Stundenplan-Service holen
98
+ // Es werden noch 2 Funktionen aus dem Stundenplan-Service geladen, um den Code zu speichern und zu löschen
99
+ const [timetableCode, saveTimetableCode, deleteTimetableCode] = useSyncTimetableCode(timetableService);
100
+
101
+ // Vorlesungen gruppiert nach Vorlesungstagen werden aus dem Stundenplan-Service geholt
102
+ // Es wird zusätzlich eine Funktion zum aktuallisieren der Vorlesungen mit geladen
103
+ const [courses, refreshCourses] = useSyncCourses(timetableService);
104
+
105
+ // Aktualiseren des course-States, wenn Provider oder Stundenplan-Code sich ändern.
106
+ useEffect(
107
+ () => {
108
+ // Stundenplan wird nur einmal geholt, wenn der Stundenplancode geladen ist
109
+ if ((timetableCode ?? false)) {
110
+ // Berechnen des Vorladezeitraumes
111
+ // ISO Zeitspannen(string) werden in Luxon Zeitspannen umgewandelt
112
+ const beginPrefetchDuration = Duration.fromISO(beginPrefetchDistance);
113
+ const endPrefetchDuration = Duration.fromISO(endPrefetchDistance);
114
+ // Jetztige Zeit ermitteln
115
+ const today = DateTime.now();
116
+ // Für den Anfang des Vorladezeitraumes das Datum berechnen
117
+ const prefetchStartDate = today.minus(beginPrefetchDuration).toISODate();
118
+ // Für das Ende des Vorlesungszeitraumes das Datum berechnen
119
+ const prefetchEndDate = today.plus(endPrefetchDuration).toISODate();
120
+
121
+ console.debug(componentName, 'prefetch timetable courses from', prefetchStartDate, 'to', prefetchEndDate);
122
+
123
+ refreshCourses(prefetchStartDate, prefetchEndDate)
124
+ .then(() => setSynchronizationCompleted(true))
125
+ .catch(
126
+ reason => {
127
+ if (!reason instanceof ApiProviderNotInitializedError || !reason instanceof TimetableCodeNotInitializedError) {
128
+ console.error(componentName, ': Error while update courses by timetable code: ', reason, 'base url: ', timetableApiBaseUrl);
129
+ }
130
+ }
131
+ );
132
+ }
133
+ }, [timetableService, beginPrefetchDistance, endPrefetchDistance, timetableCode]
134
+ );
135
+
136
+ return (
137
+ <TimetableContext.Provider
138
+ value={{
139
+ timetableCode: timetableCode,
140
+ saveTimetableCode: saveTimetableCode,
141
+ deleteTimetableCode: deleteTimetableCode,
142
+ courses: courses,
143
+ refreshCourses: refreshCourses,
144
+ }}
145
+ >
146
+ {children}
147
+ </TimetableContext.Provider>
148
+ );
149
+ }
150
+
151
+ /**
152
+ * Liefert den derzeitigen Stundenplan-Code und eine Funktion zum Speichern eines neues Stundenplan-Codes.
153
+ * @function
154
+ * @returns {[string, (timetableCode: string) => Promise<void>, () => Promise<void>]} Array mit 3 Elementen. Das erste Element ist der derzeitige gespeicherte Stundenplan-Code.
155
+ * Das zweite Element ist eine Funktion, welche das Speichern eines neuen Stundenplan-Codes ermlöglicht.
156
+ * Das dritte Element ist eine Funktion, die das Löschen des derzeitigen Stundenplan-Codes und der Courses ermöglicht.
157
+ * @example
158
+ * [timetableCode, saveTimetableCode, deleteTimetableCode] = useTimetableCode();
159
+ * saveTimetableCode(newTimetableCode);
160
+ * deleteTimetableCode();
161
+ */
162
+ function useTimetableCode() {
163
+ const { timetableCode, saveTimetableCode, deleteTimetableCode } = useContext(TimetableContext);
164
+
165
+ return [timetableCode, saveTimetableCode, deleteTimetableCode];
166
+ }
167
+
168
+ /**
169
+ * Dieser Hook stellt die Vorlesungen aus dem Stundenplan-Kontext zur Verfügung.
170
+ * Es werden 2 Rückgabewerte in einem Array zurückgegeben.
171
+ * Der erste Parameter ist eine Map der Vorlesungen für den derzeitigen Stundenplan-Code im Stundenplan-Kontext.
172
+ * Die Schlüsel sind die Vorlesungstage und die Werte sind Listen der entsprechenden Vorlesungen zu dem im Schlüssel enthaltenen Datum.
173
+ * Der zweite Parameter ist eine parameterlose Funktion, welche die Vorlesungen im Stundenplan-Kontext aktuallisiert.
174
+ * @returns {[Object.<string, Course[]>, (startDate: string, endDate: string) => Promise<void>]} Array, welches aus 2 Elementen besteht.
175
+ * @example
176
+ * const [courses, refreshCourses] = useCourses();
177
+ *
178
+ * refreshCourses('2025-01-01', '2025-02-01');
179
+ *
180
+ * const coursesOfDay = courses['2025-01-01'];
181
+ */
182
+ function useCourses() {
183
+ const { courses, refreshCourses } = useContext(TimetableContext);
184
+
185
+ return [courses, refreshCourses];
186
+ }
187
+
188
+ /**
189
+ *
190
+ *
191
+ * @param {string} date ISO Datum der Vorlesungen
192
+ * @returns {[Course[], (date : string) => Promise<void>]}
193
+ * @example
194
+ * const [dateCourses, refreshDateCourses] = useDateCourses('2025-01-01');
195
+ *
196
+ * refreshDateCourses();
197
+ */
198
+ function useDateCourses(date) {
199
+ const [courses, refreshCourses] = useCourses();
200
+
201
+ const dateCourses = courses?.[date] ?? [];
202
+
203
+
204
+ return [dateCourses, refreshCourses]
205
+ }
206
+
207
+ export {
208
+ TimetableContext as default,
209
+ TimetableContextProvider,
210
+ CourseWeekModes as weekModes,
211
+ useTimetableCode,
212
+ useCourses,
213
+ useDateCourses,
214
+ TimetableNotFoundError,
215
+ }