Compare commits
10 Commits
d4319d0269
...
17049cdf04
| Author | SHA1 | Date | |
|---|---|---|---|
| 17049cdf04 | |||
| c564108c5d | |||
| faece890f8 | |||
| dafefb83f2 | |||
| 09fd5f3032 | |||
| 22f24947ae | |||
| 0b13955ffe | |||
| 0ece80359f | |||
| 0d5c46001c | |||
| 5805bc6bf3 |
@@ -1,22 +1,24 @@
|
||||
import React, { createContext, useContext, useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { SettingsContext } from './SettingsProvider';
|
||||
import { encode as btoa } from 'base-64';
|
||||
import { format } from 'date-fns';
|
||||
import Settings from './screens/Settings';
|
||||
import { ThemeButton, ThemeText } from './common/ThemeTypes';
|
||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { SettingsContext } from './SettingsProvider';
|
||||
import { ThemeButton, ThemeText } from './common/ThemeTypes';
|
||||
import { useColors } from './common/colors';
|
||||
import { decode as atob, encode as btoa } from 'base-64'
|
||||
import Login from './screens/Login';
|
||||
import { ToastType, useToast } from './common/ToastProvider';
|
||||
|
||||
export const InterfaceContext = createContext<any>(null);
|
||||
|
||||
const Interface = ({ children }) => {
|
||||
const colors = useColors();
|
||||
const { showToast, hideToast } = useToast();
|
||||
const { settings } = useContext(SettingsContext);
|
||||
const [userInformation, setUserInformation] = useState(null);
|
||||
const [baseData, setBaseData] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [initialLoading, setInitialLoading] = useState(true);
|
||||
const [error, setError] = useState(false);
|
||||
const [errorObject, setErrorObject] = useState(null);
|
||||
|
||||
@@ -31,6 +33,7 @@ const Interface = ({ children }) => {
|
||||
setBaseData(basedata)
|
||||
if (!userinformation || !basedata) throw new InterfaceError("Data returned is Null");
|
||||
setError(false)
|
||||
setInitialLoading(false)
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setErrorObject(error);
|
||||
@@ -73,11 +76,20 @@ const Interface = ({ children }) => {
|
||||
};
|
||||
|
||||
const fetchUserInformation = async (username) => {
|
||||
const userinformation = await requestGet(`userinformation/?username=${username}`, false);
|
||||
if (!userinformation) {
|
||||
return await requestGet(`demoinformation/`);
|
||||
try {
|
||||
return await requestGet(`userinformation/?username=${username}`, false);
|
||||
} catch (error) {
|
||||
if (error.response.status === 404) {
|
||||
const demoinformation = await requestGet(`demoinformation/`);
|
||||
if (demoinformation) {
|
||||
console.log("Using Demoinformation");
|
||||
showToast(ToastType.Info, "You are using a DEMOUSER", 5000);
|
||||
}
|
||||
return demoinformation;
|
||||
}
|
||||
console.error("Error fetching user information:", error);
|
||||
return Null;
|
||||
}
|
||||
return userinformation;
|
||||
};
|
||||
|
||||
const fetchTimes = async () => {
|
||||
@@ -122,7 +134,7 @@ const Interface = ({ children }) => {
|
||||
}
|
||||
} catch (error) {
|
||||
if (!handleError) {
|
||||
return null
|
||||
throw(error);
|
||||
} else if (error.response) {
|
||||
if (error.response.data.message) {
|
||||
throw new NetworkError(error.response.status + ": " + error.response.data.message, url);
|
||||
@@ -175,7 +187,7 @@ const Interface = ({ children }) => {
|
||||
<Login />
|
||||
</View>
|
||||
)
|
||||
if (!loading) return (children)
|
||||
if (!initialLoading) return (children)
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -201,4 +213,4 @@ export class NetworkError extends Error {
|
||||
this.name = "NetworkError";
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
app.json
6
app.json
@@ -2,7 +2,7 @@
|
||||
"expo": {
|
||||
"name": "KlaTab",
|
||||
"slug": "klatab",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/icon.png",
|
||||
"userInterfaceStyle": "automatic",
|
||||
@@ -15,12 +15,12 @@
|
||||
"**/*"
|
||||
],
|
||||
"ios": {
|
||||
"buildNumber": "24",
|
||||
"buildNumber": "30",
|
||||
"supportsTablet": true,
|
||||
"bundleIdentifier": "de.edvschule-plattling.klatab.klatab"
|
||||
},
|
||||
"android": {
|
||||
"versionCode": 27,
|
||||
"versionCode": 30,
|
||||
"adaptiveIcon": {
|
||||
"foregroundImage": "./assets/adaptive-icon.png",
|
||||
"backgroundColor": "#ffffff"
|
||||
|
||||
1018
package-lock.json
generated
1018
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@
|
||||
"base-64": "^1.0.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"expo": "^51.0.32",
|
||||
"expo": "~51.0.37",
|
||||
"expo-application": "~5.9.1",
|
||||
"expo-build-properties": "~0.12.5",
|
||||
"expo-status-bar": "~1.12.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { addMonths, addDays, format, isSameDay, isWithinInterval, parseISO, getDay, parse, differenceInDays } from 'date-fns';
|
||||
import React, { useContext, useEffect, useState, useMemo, useCallback } from 'react';
|
||||
import { FlatList, ScrollView, StyleSheet, View, Text, TouchableOpacity, Modal } from 'react-native';
|
||||
import { FlatList, ScrollView, StyleSheet, View, Text, TouchableOpacity, Modal, Linking } from 'react-native';
|
||||
import ErrorBoundary from 'react-native-error-boundary';
|
||||
import { RefreshControl } from 'react-native-web-refresh-control';
|
||||
import { InterfaceContext } from '../Interface';
|
||||
@@ -107,26 +107,39 @@ const Calendar = () => {
|
||||
);
|
||||
} else if (selectedView === 'tests') {
|
||||
return (
|
||||
<FlatList
|
||||
refreshControl={<RefreshControl refreshing={loading} onRefresh={refresh} colors={[colors.primary]} />}
|
||||
data={calendarData.tests}
|
||||
keyExtractor={(item) => item.date + item.hourFrom + item.hourUntil + item.subject}
|
||||
renderItem={({ item }) => (
|
||||
<View style={[styles.dayBox, styles.rowContainer, { backgroundColor: colors.backPrimary }]}>
|
||||
<ThemeText style={{ width: 82, fontWeight: 'bold' }}>{format(item.date, 'dd.MM.yyyy')}</ThemeText>
|
||||
<ThemeText style={{ width: 60 }}>{item.subject}</ThemeText>
|
||||
<ThemeText style={{ width: 25 }}>{item.type}</ThemeText>
|
||||
<ThemeText style={{ width: 40 }}>{item.room}</ThemeText>
|
||||
<ThemeText style={{ width: 40 }}>{item.hourFrom}-{item.hourUntil}</ThemeText>
|
||||
<ThemeText style={{ width: 82 }}>{item.timeFrom}-{item.timeUntil}</ThemeText>
|
||||
{userInformation.usertype == 'teacher' && <ThemeText style={{ width: 30 }}>{item.class}</ThemeText>}
|
||||
{userInformation.usertype == 'pupil' && <ThemeText style={{ width: 30 }}>{item.teacher}</ThemeText>}
|
||||
</View>
|
||||
)}
|
||||
getItemLayout={(data, index) => (
|
||||
{ length: 70, offset: 70 * index, index }
|
||||
)}
|
||||
/>
|
||||
<View style={{ marginLeft: 5 }}>
|
||||
<TouchableOpacity onPress={() => Linking.openURL('https://ux4.edvschule-plattling.de/~hthaler/tests-calendar/')}>
|
||||
<Text style={{ color: colors.primary }}>Prüfungen in einen Kalender importieren (.ics)</Text>
|
||||
</TouchableOpacity>
|
||||
<FlatList
|
||||
refreshControl={<RefreshControl refreshing={loading} onRefresh={refresh} colors={[colors.primary]} />}
|
||||
data={calendarData.tests}
|
||||
keyExtractor={(item) => item.date + item.hourFrom + item.hourUntil + item.subject}
|
||||
renderItem={({ item }) => (
|
||||
<View style={{ marginTop: 5, borderBottomWidth: 1, borderColor: '#ccc', flexDirection: 'row', flexWrap: 'wrap' }}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 5, marginRight: 20 }}>
|
||||
<ThemeText style={{ fontWeight: 'bold', marginRight: 5 }}>{format(item.date, 'dd.MM.yyyy')}</ThemeText>
|
||||
<ThemeText>{`${item.timeFrom}-${item.timeUntil}`}</ThemeText>
|
||||
</View>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 5 }}>
|
||||
<ThemeText style={{ marginRight: 5 }}>{item.subject}</ThemeText>
|
||||
<ThemeText style={{ marginRight: 5 }}>{item.type}</ThemeText>
|
||||
{userInformation.usertype === 'teacher' && (
|
||||
<ThemeText style={{ marginRight: 5 }}>{item.class}</ThemeText>
|
||||
)}
|
||||
{userInformation.usertype === 'pupil' && (
|
||||
<ThemeText style={{ marginRight: 5 }}>{item.teacher}</ThemeText>
|
||||
)}
|
||||
<ThemeText style={{ marginRight: 5 }}>{item.room}</ThemeText>
|
||||
<ThemeText style={{ marginRight: 5 }}>{`${item.hourFrom||'n'}-${item.hourUntil||'n'}`}</ThemeText>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
getItemLayout={(data, index) => (
|
||||
{ length: 70, offset: 70 * index, index }
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
} else if (selectedView === 'appointments') {
|
||||
// Group appointments by day
|
||||
@@ -154,7 +167,7 @@ const Calendar = () => {
|
||||
data={groupedAppointmentsArray}
|
||||
keyExtractor={(item) => format(item.date, 'yyyy-MM-dd')}
|
||||
renderItem={({ item }) => (
|
||||
<View style={{ marginTop: 5, borderBottomWidth: 1, borderColor: '#ccc', }}>
|
||||
<View style={{ marginTop: 5, borderBottomWidth: 1, borderColor: '#ccc' }}>
|
||||
<ThemeText style={{ fontSize: 18, marginBottom: 10, marginLeft: 20 }}>{format(item.date, 'dd.MM.yyyy')}</ThemeText>
|
||||
{item.appointments.map((appointment, index) => (
|
||||
<View key={index} style={{ flexDirection: 'row', alignItems: 'center', marginLeft: 5, marginBottom: 10 }}>
|
||||
@@ -377,11 +390,22 @@ const DayModal = React.memo(({ date, calendarData, onClose, dayColors, colors, u
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
const getDayType = (date, calendarData) => {
|
||||
const dayType = calendarData.dayTypes.find((d) =>
|
||||
new Date(d.from) <= date && date <= new Date(d.until)
|
||||
);
|
||||
// Set the date to midnight to avoid timezone issues
|
||||
const targetDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
||||
|
||||
const dayType = calendarData.dayTypes.find((d) => {
|
||||
// Create midnight dates for comparison
|
||||
const fromDate = new Date(d.from);
|
||||
const untilDate = new Date(d.until);
|
||||
|
||||
// Set both dates to midnight
|
||||
fromDate.setHours(0, 0, 0, 0);
|
||||
untilDate.setHours(0, 0, 0, 0);
|
||||
|
||||
return fromDate <= targetDate && targetDate <= untilDate;
|
||||
});
|
||||
|
||||
return dayType ? dayType.type : "schultag";
|
||||
};
|
||||
|
||||
@@ -441,4 +465,4 @@ function endsNextDayMidnight(start, end) {
|
||||
|
||||
const endTimeIsMidnight = endD.getHours() === 0 && endD.getMinutes() === 0 && endD.getSeconds() === 0;
|
||||
return (daysDifference == 1 || daysDifference == -1) && endTimeIsMidnight
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import FontAwesome5 from '@expo/vector-icons/FontAwesome5';
|
||||
import * as Application from 'expo-application';
|
||||
import { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { ActivityIndicator, Alert, Animated, Button, Image, Linking, Platform, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { ActivityIndicator, Alert, Animated, Button, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import ErrorBoundary from 'react-native-error-boundary';
|
||||
import { SettingsContext } from '../SettingsProvider';
|
||||
import Credits from '../common/Credits';
|
||||
@@ -55,10 +54,6 @@ const Settings = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleLinkPress = (url) => {
|
||||
Linking.openURL(url);
|
||||
};
|
||||
|
||||
const handleChange = (setter) => (value) => {
|
||||
setter(value);
|
||||
showToast(ToastType.Warn, 'Ungespeicherte Änderungen');
|
||||
|
||||
Reference in New Issue
Block a user