205 lines
7.2 KiB
TypeScript
205 lines
7.2 KiB
TypeScript
import axios from 'axios';
|
|
import { encode as btoa } from 'base-64';
|
|
import { format } from 'date-fns';
|
|
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 Login from './screens/Login';
|
|
|
|
export const InterfaceContext = createContext<any>(null);
|
|
|
|
const Interface = ({ children }) => {
|
|
const colors = useColors();
|
|
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);
|
|
|
|
const fetchData = async () => {
|
|
try {
|
|
setLoading(true)
|
|
if (settings.requireAuth ? !settings.username : false) throw new InterfaceError("Authentication Required")
|
|
if (!settings.url) throw new InterfaceError("Invalid URL")
|
|
const userinformation = await fetchUserInformation(settings.username);
|
|
const basedata = await fetchBaseData();
|
|
setUserInformation(userinformation)
|
|
setBaseData(basedata)
|
|
if (!userinformation || !basedata) throw new InterfaceError("Data returned is Null");
|
|
setError(false)
|
|
setInitialLoading(false)
|
|
} catch (error) {
|
|
console.error(error);
|
|
setErrorObject(error);
|
|
setError(true)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
fetchData();
|
|
}, [settings]);
|
|
|
|
const refresh = () => {
|
|
fetchData();
|
|
};
|
|
|
|
const axiosInstance = axios.create({
|
|
baseURL: settings.url,
|
|
});
|
|
|
|
axiosInstance.interceptors.request.use(
|
|
(config) => {
|
|
if (!settings.url) {
|
|
throw new InterfaceError("Invalid URL")
|
|
}
|
|
if (settings.requireAuth) {
|
|
const { username, password } = settings;
|
|
const token = btoa(`${username}:${password}`);
|
|
config.headers.Authorization = `Basic ${token}`;
|
|
}
|
|
|
|
return config;
|
|
},
|
|
(error) => Promise.reject(error)
|
|
);
|
|
|
|
const fetchBaseData = async () => {
|
|
return await requestGet('basedata/');
|
|
};
|
|
|
|
const fetchUserInformation = async (username) => {
|
|
const userinformation = await requestGet(`userinformation/?username=${username}`, false);
|
|
if (!userinformation) {
|
|
return await requestGet(`demoinformation/`);
|
|
}
|
|
return userinformation;
|
|
};
|
|
|
|
const fetchTimes = async () => {
|
|
return await requestGet('hours/');
|
|
};
|
|
|
|
const fetchScheduleByWeek = async (type, value, group, week, year) => {
|
|
const groupparam = type === 'class' && group ? `&group=${group}` : '';
|
|
return await requestGet(`schedule/week/?type=${type}&value=${value}${groupparam}&week=${week}&year=${year}`);
|
|
};
|
|
|
|
const fetchScheduleByDate = async (type, value, group, date) => {
|
|
const groupparam = type === 'class' ? `&group=${group}` : '';
|
|
return await requestGet(`schedule/date/?type=${type}&value=${value}${groupparam}&date=${format(date, 'yyyy-MM-dd')}`);
|
|
};
|
|
|
|
const fetchAppointments = async (date) => {
|
|
return await requestGet(`appointments/?date=${format(date, 'yyyy-MM-dd')}`);
|
|
};
|
|
|
|
const fetchTests = async (type, value, date) => {
|
|
return await requestGet(`tests/?type=${type}&value=${value}&date=${format(date, 'yyyy-MM-dd')}`);
|
|
};
|
|
|
|
const fetchDayTypes = async (from, until) => {
|
|
return await requestGet(`daytypes/?from=${format(from, 'yyyy-MM-dd')}&until=${format(until, 'yyyy-MM-dd')}`);
|
|
};
|
|
|
|
const fetchFreeRooms = async (date, from, until) => {
|
|
return await requestGet(`freerooms/?date=${format(date, 'yyyy-MM-dd')}&from=${from}&until=${until}`);
|
|
};
|
|
|
|
|
|
const requestGet = async (url, handleError = true) => {
|
|
console.log(url)
|
|
try {
|
|
const response = await axiosInstance.get(url);
|
|
if (response.status === 200 && response.data.success === true) {
|
|
return response.data.data;
|
|
} else {
|
|
throw new NetworkError(response.data.message, url);
|
|
}
|
|
} catch (error) {
|
|
if (!handleError) {
|
|
return null
|
|
} else if (error.response) {
|
|
if (error.response.data.message) {
|
|
throw new NetworkError(error.response.status + ": " + error.response.data.message, url);
|
|
} else if (error.response.status === 404) {
|
|
throw new NetworkError('404: URL wurde auf dem Server nicht gefunden', url);
|
|
} else if (error.response.status === 502) {
|
|
throw new NetworkError('502: Webservice ist unerreichbar', url);
|
|
}
|
|
throw new NetworkError(`${error.response.status}: Ein unbekannter ist auf dem Server aufgetreten`, url);
|
|
} else if (error.request) {
|
|
throw new NetworkError('Netzwerkfehler', url);
|
|
} else {
|
|
throw new NetworkError(error.message || 'Ein unbekannter fehler ist aufgetreten', url);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
paddingTop: 30,
|
|
flex: 1,
|
|
},
|
|
titleBox: {
|
|
paddingHorizontal: 20,
|
|
paddingVertical: 10,
|
|
backgroundColor: colors.backSecondary,
|
|
},
|
|
title: {
|
|
fontSize: 20,
|
|
fontWeight: 'bold',
|
|
},
|
|
button: {
|
|
marginTop: 5,
|
|
}
|
|
})
|
|
|
|
const renderContent = () => {
|
|
let needsCredentials = settings.requireAuth ? !settings.username : false;
|
|
if (error && !loading) return (
|
|
<View style={styles.container}>
|
|
{!needsCredentials &&
|
|
<View style={styles.titleBox}>
|
|
<ThemeText style={styles.title}>Fehler beim laden der Daten</ThemeText>
|
|
<ThemeText>{errorObject?.message}</ThemeText>
|
|
<ThemeButton style={styles.button} onPress={refresh}><Text>Neu Versuchen</Text></ThemeButton>
|
|
</View>
|
|
}
|
|
<Login />
|
|
</View>
|
|
)
|
|
if (!initialLoading) return (children)
|
|
}
|
|
|
|
return (
|
|
<InterfaceContext.Provider value={{ userInformation, baseData, refreshInterface: refresh, fetchBaseData, fetchTimes, fetchScheduleByWeek, fetchScheduleByDate, fetchAppointments, fetchTests, fetchDayTypes, fetchFreeRooms }}>
|
|
{renderContent()}
|
|
</InterfaceContext.Provider>
|
|
);
|
|
};
|
|
|
|
export default Interface;
|
|
|
|
export class InterfaceError extends Error {
|
|
constructor(message) {
|
|
super(message);
|
|
this.name = "InterfaceError";
|
|
}
|
|
}
|
|
export class NetworkError extends Error {
|
|
url: string;
|
|
|
|
constructor(message: string, url: string) {
|
|
super(message);
|
|
this.name = "NetworkError";
|
|
this.url = url;
|
|
}
|
|
} |