Compare commits

..

3 commits

25 changed files with 295 additions and 353 deletions

View file

@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<application

View file

@ -8,11 +8,11 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission tools:node="remove" android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission tools:node="remove" android:name="android.permission.MANAGE_DOCUMENTS"/>
<uses-permission tools:node="remove" android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission tools:node="remove" android:name="android.permission.USE_FINGERPRINT"/>
<uses-permission tools:node="remove" android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission tools:node="remove" android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission tools:node="remove" android:name="android.permission.ACCESS_FINE_LOCATION"/>

View file

@ -0,0 +1,13 @@
export default {
websites: {
AMICALE: "https://www.amicale-insat.fr/",
AVAILABLE_ROOMS: "http://planex.insa-toulouse.fr/salles.php",
BIB: "https://bibbox.insa-toulouse.fr/",
BLUEMIND: "https://etud-mel.insa-toulouse.fr/webmail/",
ELUS_ETUDIANTS: "https://etud.insa-toulouse.fr/~eeinsat/",
ENT: "https://ent.insa-toulouse.fr/",
INSA_ACCOUNT: "https://moncompte.insa-toulouse.fr/",
TUTOR_INSA: "https://www.etud.insa-toulouse.fr/~tutorinsa/",
WIKETUD: "https://wiki.etud.insa-toulouse.fr/",
},
}

View file

@ -1,3 +1,5 @@
// @flow
import i18n from "i18n-js";
/**
@ -43,8 +45,8 @@ export default class Update {
this.titleList = [];
this.descriptionList = [];
for (let i = 0; i < Update.slidesNumber; i++) {
this.titleList.push(i18n.t('intro.updateSlide'+ i + '.title'))
this.descriptionList.push(i18n.t('intro.updateSlide'+ i + '.text'))
this.titleList.push(i18n.t('intro.updateSlide' + i + '.title'))
this.descriptionList.push(i18n.t('intro.updateSlide' + i + '.text'))
}
}

View file

@ -1,14 +1,13 @@
// @flow
import type {Machine} from "../screens/Proxiwash/ProxiwashScreen";
/**
* Singleton class used to manage themes
* Singleton class used to manage april fools
*/
export default class AprilFoolsManager {
static instance: AprilFoolsManager | null = null;
aprilFoolsEnabled: boolean;
static fakeMachineNumber = [
"",
"cos(ln(1))",
@ -24,6 +23,7 @@ export default class AprilFoolsManager {
"1×10¹+1×10⁰",
"Re(√192e^(iπ/6))",
];
aprilFoolsEnabled: boolean;
constructor() {
let today = new Date();
@ -40,7 +40,13 @@ export default class AprilFoolsManager {
AprilFoolsManager.instance;
}
static getFakeMenuItem(menu: Object) {
/**
* Adds fake menu entries
*
* @param menu
* @returns {Object}
*/
static getFakeMenuItem(menu: Array<{dishes: Array<{name: string}>}>) {
menu[1]["dishes"].splice(4, 0, {name: "Coq au vin"});
menu[1]["dishes"].splice(2, 0, {name: "Bat'Soupe"});
menu[1]["dishes"].splice(1, 0, {name: "Pave de loup"});
@ -49,16 +55,26 @@ export default class AprilFoolsManager {
return menu;
}
static getNewProxiwashDryerOrderedList(dryers: Array<Object>) {
if (dryers !== undefined) {
/**
* Changes proxiwash dryers order
*
* @param dryers
*/
static getNewProxiwashDryerOrderedList(dryers: Array<Machine> | null) {
if (dryers != null) {
let second = dryers[1];
dryers.splice(1, 1);
dryers.push(second);
}
}
static getNewProxiwashWasherOrderedList(washers: Array<Object>) {
if (washers !== undefined) {
/**
* Changes proxiwash washers order
*
* @param washers
*/
static getNewProxiwashWasherOrderedList(washers: Array<Machine> | null) {
if (washers != null) {
let first = washers[0];
let second = washers[1];
let fifth = washers[4];
@ -67,14 +83,25 @@ export default class AprilFoolsManager {
washers.splice(4, 1, ninth);
washers.splice(1, 1, first);
washers.splice(0, 1, fifth);
// washers.push(fifth);
}
}
/**
* Gets the new display number for the given machine number
*
* @param number
* @returns {string}
*/
static getProxiwashMachineDisplayNumber(number: number) {
return AprilFoolsManager.fakeMachineNumber[number];
}
/**
* Gets the new and ugly april fools theme
*
* @param currentTheme
* @returns {{colors: {textDisabled: string, agendaDayTextColor: string, surface: string, background: string, dividerBackground: string, accent: string, agendaBackgroundColor: string, tabIcon: string, card: string, primary: string}}}
*/
static getAprilFoolsTheme(currentTheme: Object) {
return {
...currentTheme,

View file

@ -23,15 +23,13 @@ export default class ConnectionManager {
#email: string;
#token: string | null;
listeners: Array<Function>;
constructor() {
this.#token = null;
this.listeners = [];
}
/**
* Get this class instance or create one if none is found
* Gets this class instance or create one if none is found
*
* @returns {ConnectionManager}
*/
static getInstance(): ConnectionManager {
@ -40,21 +38,20 @@ export default class ConnectionManager {
ConnectionManager.instance;
}
getToken() {
/**
* Gets the current token
*
* @returns {string | null}
*/
getToken(): string | null {
return this.#token;
}
onLoginStateChange(newState: boolean) {
for (let i = 0; i < this.listeners.length; i++) {
if (this.listeners[i] !== undefined)
this.listeners[i](newState);
}
}
addLoginStateListener(listener: Function) {
this.listeners.push(listener);
}
/**
* Tries to recover login token from the secure keychain
*
* @returns {Promise<R>}
*/
async recoverLogin() {
return new Promise((resolve, reject) => {
if (this.getToken() !== null)
@ -64,7 +61,6 @@ export default class ConnectionManager {
.then((data) => {
if (data) {
this.#token = data.password;
this.onLoginStateChange(true);
resolve(this.#token);
} else
reject(false);
@ -76,17 +72,28 @@ export default class ConnectionManager {
});
}
/**
* Check if the user has a valid token
*
* @returns {boolean}
*/
isLoggedIn() {
return this.getToken() !== null;
}
/**
* Saves the login token in the secure keychain
*
* @param email
* @param token
* @returns {Promise<R>}
*/
async saveLogin(email: string, token: string) {
return new Promise((resolve, reject) => {
Keychain.setInternetCredentials(SERVER_NAME, 'token', token)
.then(() => {
this.#token = token;
this.#email = email;
this.onLoginStateChange(true);
resolve(true);
})
.catch(() => {
@ -95,12 +102,16 @@ export default class ConnectionManager {
});
}
/**
* Deletes the login token from the keychain
*
* @returns {Promise<R>}
*/
async disconnect() {
return new Promise((resolve, reject) => {
Keychain.resetInternetCredentials(SERVER_NAME)
.then(() => {
this.#token = null;
this.onLoginStateChange(false);
resolve(true);
})
.catch(() => {
@ -109,6 +120,16 @@ export default class ConnectionManager {
});
}
/**
* Sends the given login and password to the api.
* If the combination is valid, the login token is received and saved in the secure keychain.
* If not, the promise is rejected with the corresponding error code.
*
* @param email
* @param password
* @returns {Promise<R>}
*/
async connect(email: string, password: string) {
return new Promise((resolve, reject) => {
const data = {
@ -117,19 +138,28 @@ export default class ConnectionManager {
};
apiRequest(AUTH_PATH, 'POST', data)
.then((response) => {
this.saveLogin(email, response.token)
.then(() => {
resolve(true);
})
.catch(() => {
reject(ERROR_TYPE.TOKEN_SAVE);
});
if (this.isConnectionResponseValid(response)) {
this.saveLogin(email, response.token)
.then(() => {
resolve(true);
})
.catch(() => {
reject(ERROR_TYPE.TOKEN_SAVE);
});
} else
reject(ERROR_TYPE.SERVER_ERROR);
})
.catch((error) => reject(error));
});
}
isConnectionResponseValid(response: Object) {
/**
* Checks if the API connection response is correctly formatted
*
* @param response
* @returns {boolean}
*/
isConnectionResponseValid(response: { [key: string]: any }) {
let valid = isResponseValid(response);
if (valid && response.error === ERROR_TYPE.SUCCESS)
@ -140,6 +170,13 @@ export default class ConnectionManager {
return valid;
}
/**
* Sends an authenticated request with the login token to the API
*
* @param path
* @param params
* @returns {Promise<R>}
*/
async authenticatedRequest(path: string, params: Object) {
return new Promise((resolve, reject) => {
if (this.getToken() !== null) {

View file

@ -45,6 +45,10 @@ export default class DateManager {
DateManager.instance;
}
static isWeekend(date: Date) {
return date.getDay() === 6 || date.getDay() === 0;
}
/**
* Gets a translated string representing the given date.
*
@ -58,8 +62,4 @@ export default class DateManager {
return this.daysOfWeek[date.getDay()] + " " + date.getDate() + " " + this.monthsOfYear[date.getMonth()] + " " + date.getFullYear();
}
static isWeekend(date: Date) {
return date.getDay() === 6 || date.getDay() === 0;
}
}

View file

@ -19,8 +19,4 @@ export default class LocaleManager {
i18n.translations = {fr, en};
i18n.locale = RNLocalize.findBestAvailableLanguage(["en", "fr"]).languageTag;
}
static getCurrentLocale() {
return RNLocalize.findBestAvailableLanguage(["en", "fr"]).languageTag;
}
}

View file

@ -46,15 +46,15 @@ export type CustomTheme = {
// Tetris
tetrisBackground: string,
tetrisBorder:string,
tetrisScore:string,
tetrisI : string,
tetrisO : string,
tetrisT : string,
tetrisS : string,
tetrisZ : string,
tetrisJ : string,
tetrisL : string,
tetrisBorder: string,
tetrisScore: string,
tetrisI: string,
tetrisO: string,
tetrisT: string,
tetrisS: string,
tetrisZ: string,
tetrisJ: string,
tetrisL: string,
},
}
@ -116,16 +116,16 @@ export default class ThemeManager {
tutorinsaColor: '#f93943',
// Tetris
tetrisBackground:'#e6e6e6',
tetrisBorder:'#2f2f2f',
tetrisScore:'#e2bd33',
tetrisI : '#3cd9e6',
tetrisO : '#ffdd00',
tetrisT : '#a716e5',
tetrisS : '#09c528',
tetrisZ : '#ff0009',
tetrisJ : '#2a67e3',
tetrisL : '#da742d',
tetrisBackground: '#e6e6e6',
tetrisBorder: '#2f2f2f',
tetrisScore: '#e2bd33',
tetrisI: '#3cd9e6',
tetrisO: '#ffdd00',
tetrisT: '#a716e5',
tetrisS: '#09c528',
tetrisZ: '#ff0009',
tetrisJ: '#2a67e3',
tetrisL: '#da742d',
},
};
}
@ -176,16 +176,16 @@ export default class ThemeManager {
tutorinsaColor: '#f93943',
// Tetris
tetrisBackground:'#2c2c2c',
tetrisBorder:'#1b1b1b',
tetrisScore:'#e2d707',
tetrisI : '#30b3be',
tetrisO : '#c1a700',
tetrisT : '#9114c7',
tetrisS : '#08a121',
tetrisZ : '#b50008',
tetrisJ : '#0f37b9',
tetrisL : '#b96226',
tetrisBackground: '#2c2c2c',
tetrisBorder: '#1b1b1b',
tetrisScore: '#e2d707',
tetrisI: '#30b3be',
tetrisO: '#c1a700',
tetrisT: '#9114c7',
tetrisS: '#08a121',
tetrisZ: '#b50008',
tetrisJ: '#0f37b9',
tetrisL: '#b96226',
},
};
}

View file

@ -12,24 +12,17 @@ import TetrisScreen from "../screens/Tetris/TetrisScreen";
import VoteScreen from "../screens/Amicale/VoteScreen";
import LoginScreen from "../screens/Amicale/LoginScreen";
import {Platform} from "react-native";
import AvailableRoomScreen from "../screens/Services/Websites/AvailableRoomScreen";
import BibScreen from "../screens/Services/Websites/BibScreen";
import SelfMenuScreen from "../screens/Services/SelfMenuScreen";
import ProximoMainScreen from "../screens/Services/Proximo/ProximoMainScreen";
import ProximoListScreen from "../screens/Services/Proximo/ProximoListScreen";
import ProximoAboutScreen from "../screens/Services/Proximo/ProximoAboutScreen";
import {AmicaleWebsiteScreen} from "../screens/Services/Websites/AmicaleWebsiteScreen";
import {ElusEtudiantsWebsiteScreen} from "../screens/Services/Websites/ElusEtudiantsWebsiteScreen";
import {WiketudWebsiteScreen} from "../screens/Services/Websites/WiketudWebsiteScreen";
import {TutorInsaWebsiteScreen} from "../screens/Services/Websites/TutorInsaWebsiteScreen";
import {ENTWebsiteScreen} from "../screens/Services/Websites/ENTWebsiteScreen";
import {BlueMindWebsiteScreen} from "../screens/Services/Websites/BlueMindWebsiteScreen";
import ProfileScreen from "../screens/Amicale/ProfileScreen";
import ClubListScreen from "../screens/Amicale/Clubs/ClubListScreen";
import ClubAboutScreen from "../screens/Amicale/Clubs/ClubAboutScreen";
import ClubDisplayScreen from "../screens/Amicale/Clubs/ClubDisplayScreen";
import {createScreenCollapsibleStack, getWebsiteStack} from "../utils/CollapsibleUtils";
import BugReportScreen from "../screens/Other/FeedbackScreen";
import WebsiteScreen from "../screens/Services/WebsiteScreen";
const modalTransition = Platform.OS === 'ios' ? TransitionPresets.ModalPresentationIOS : TransitionPresets.ModalSlideFromBottomIOS;
@ -102,12 +95,10 @@ function MainStackComponent(props: { createTabNavigator: () => React.Node }) {
}}
/>
{/* INSA */}
{getWebsiteStack("available-rooms", MainStack, AvailableRoomScreen, i18n.t('screens.availableRooms'))}
{getWebsiteStack("bib", MainStack, BibScreen, i18n.t('screens.bib'))}
{createScreenCollapsibleStack("self-menu", MainStack, SelfMenuScreen, i18n.t('screens.menuSelf'))}
{getWebsiteStack("website", MainStack, WebsiteScreen, "")}
{/* STUDENTS */}
{createScreenCollapsibleStack("self-menu", MainStack, SelfMenuScreen, i18n.t('screens.menuSelf'))}
{createScreenCollapsibleStack("proximo", MainStack, ProximoMainScreen, i18n.t('screens.proximo'))}
{createScreenCollapsibleStack(
"proximo-list",
@ -125,15 +116,7 @@ function MainStackComponent(props: { createTabNavigator: () => React.Node }) {
...modalTransition,
}}
/>
{getWebsiteStack("amicale-website", MainStack, AmicaleWebsiteScreen, i18n.t('screens.amicaleWebsite'))}
{getWebsiteStack("elus-etudiants", MainStack, ElusEtudiantsWebsiteScreen, "Élus Étudiants")}
{getWebsiteStack("wiketud", MainStack, WiketudWebsiteScreen, "Wiketud")}
{getWebsiteStack("tutorinsa", MainStack, TutorInsaWebsiteScreen, "Tutor'INSA")}
{getWebsiteStack("ent", MainStack, ENTWebsiteScreen, i18n.t('screens.ent'))}
{getWebsiteStack("bluemind", MainStack, BlueMindWebsiteScreen, i18n.t('screens.bluemind'))}
{/* AMICALE */}
{createScreenCollapsibleStack("profile", MainStack, ProfileScreen, i18n.t('screens.profile'))}
{createScreenCollapsibleStack("club-list", MainStack, ClubListScreen, i18n.t('clubs.clubList'))}
<MainStack.Screen

View file

@ -12,6 +12,7 @@ import CustomTabBar from "../../components/Tabbar/CustomTabBar";
import type {CustomTheme} from "../../managers/ThemeManager";
import AsyncStorageManager from "../../managers/AsyncStorageManager";
import {StackNavigationProp} from "@react-navigation/stack";
import AvailableWebsites from "../../constants/AvailableWebsites";
type Props = {
navigation: StackNavigationProp,
@ -110,7 +111,7 @@ class LoginScreen extends React.Component<Props, State> {
/**
* Navigates to the Amicale website screen with the reset password link as navigation parameters
*/
onResetPasswordClick = () => this.props.navigation.navigate('amicale-website', {path: RESET_PASSWORD_PATH});
onResetPasswordClick = () => this.props.navigation.navigate("website", {host: AvailableWebsites.websites.AMICALE, path: RESET_PASSWORD_PATH, title: i18n.t('screens.amicaleWebsite')});
/**
* The user has unfocused the input, his email is ready to be validated

View file

@ -14,6 +14,7 @@ import type {cardList} from "../../components/Lists/CardList/CardList";
import CardList from "../../components/Lists/CardList/CardList";
import {StackNavigationProp} from "@react-navigation/stack";
import type {CustomTheme} from "../../managers/ThemeManager";
import AvailableWebsites from "../../constants/AvailableWebsites";
type Props = {
navigation: StackNavigationProp,
@ -83,7 +84,7 @@ class ProfileScreen extends React.Component<Props, State> {
title: i18n.t('screens.amicaleWebsite'),
subtitle: i18n.t('servicesScreen.descriptions.amicaleWebsite'),
image: ICON_AMICALE,
onPress: () => this.props.navigation.navigate("amicale-website"),
onPress: () => this.props.navigation.navigate("website", {host: AvailableWebsites.websites.AMICALE, title: i18n.t('screens.amicaleWebsite')}),
},
];
}
@ -287,7 +288,7 @@ class ProfileScreen extends React.Component<Props, State> {
<Button
icon="account-edit"
mode="contained"
onPress={() => this.props.navigation.navigate('amicale-website', {path: this.data.link})}
onPress={() => this.props.navigation.navigate("website", {host: AvailableWebsites.websites.AMICALE, path: this.data.link, title: i18n.t('screens.amicaleWebsite')})}
style={styles.editButton}>
{i18n.t("profileScreen.editInformation")}
</Button>

View file

@ -22,6 +22,7 @@ import LogoutDialog from "../../components/Amicale/LogoutDialog";
import {withCollapsible} from "../../utils/withCollapsible";
import {Collapsible} from "react-navigation-collapsible";
import AsyncStorageManager from "../../managers/AsyncStorageManager";
import AvailableWebsites from "../../constants/AvailableWebsites";
// import DATA from "../dashboard_data.json";
@ -217,7 +218,7 @@ class HomeScreen extends React.Component<Props, State> {
};
onTutorInsaClick = () => {
this.props.navigation.navigate("tutorinsa");
this.props.navigation.navigate("website", {host: AvailableWebsites.websites.TUTOR_INSA, title: "Tutor'INSA"});
};
onMenuClick = () => {

View file

@ -13,6 +13,7 @@ import i18n from 'i18n-js';
import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
import ConnectionManager from "../../managers/ConnectionManager";
import {StackNavigationProp} from "@react-navigation/stack";
import AvailableWebsites from "../../constants/AvailableWebsites";
type Props = {
navigation: StackNavigationProp,
@ -43,6 +44,7 @@ const RU_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/RU.png";
const ROOM_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Salles.png";
const EMAIL_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Bluemind.png";
const ENT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/ENT.png";
const ACCOUNT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Account.png";
class ServicesScreen extends React.Component<Props> {
@ -72,7 +74,7 @@ class ServicesScreen extends React.Component<Props> {
title: i18n.t('screens.amicaleWebsite'),
subtitle: i18n.t('servicesScreen.descriptions.amicaleWebsite'),
image: AMICALE_IMAGE,
onPress: () => nav.navigate("amicale-website"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.AMICALE, title: i18n.t('screens.amicaleWebsite')}),
},
{
title: i18n.t('screens.vote'),
@ -92,19 +94,19 @@ class ServicesScreen extends React.Component<Props> {
title: "Wiketud",
subtitle: i18n.t('servicesScreen.descriptions.wiketud'),
image: WIKETUD_IMAGE,
onPress: () => nav.navigate("wiketud"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.WIKETUD, title: "Wiketud"}),
},
{
title: "Élus Étudiants",
subtitle: i18n.t('servicesScreen.descriptions.elusEtudiants'),
image: EE_IMAGE,
onPress: () => nav.navigate("elus-etudiants"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.ELUS_ETUDIANTS, title: "Élus Étudiants"}),
},
{
title: "Tutor'INSA",
subtitle: i18n.t('servicesScreen.descriptions.tutorInsa'),
image: TUTORINSA_IMAGE,
onPress: () => nav.navigate("tutorinsa"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.TUTOR_INSA, title: "Tutor'INSA"})
},
];
this.insaDataset = [
@ -118,25 +120,31 @@ class ServicesScreen extends React.Component<Props> {
title: i18n.t('screens.availableRooms'),
subtitle: i18n.t('servicesScreen.descriptions.availableRooms'),
image: ROOM_IMAGE,
onPress: () => nav.navigate("available-rooms"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.AVAILABLE_ROOMS, title: i18n.t('screens.availableRooms')}),
},
{
title: i18n.t('screens.bib'),
subtitle: i18n.t('servicesScreen.descriptions.bib'),
image: BIB_IMAGE,
onPress: () => nav.navigate("bib"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.BIB, title: i18n.t('screens.bib')}),
},
{
title: i18n.t('screens.bluemind'),
subtitle: i18n.t('servicesScreen.descriptions.mails'),
image: EMAIL_IMAGE,
onPress: () => nav.navigate("bluemind"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.BLUEMIND, title: i18n.t('screens.bluemind')}),
},
{
title: i18n.t('screens.ent'),
subtitle: i18n.t('servicesScreen.descriptions.ent'),
image: ENT_IMAGE,
onPress: () => nav.navigate("ent"),
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.ENT, title: i18n.t('screens.ent')}),
},
{
title: i18n.t('screens.insaAccount'),
subtitle: i18n.t('servicesScreen.descriptions.insaAccount'),
image: ACCOUNT_IMAGE,
onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.INSA_ACCOUNT, title: i18n.t('screens.insaAccount')}),
},
];
this.finalDataset = [

View file

@ -0,0 +1,109 @@
// @flow
import * as React from 'react';
import {StackNavigationProp} from "@react-navigation/stack";
import WebViewScreen from "../../components/Screens/WebViewScreen";
import AvailableWebsites from "../../constants/AvailableWebsites";
import BasicLoadingScreen from "../../components/Screens/BasicLoadingScreen";
type Props = {
navigation: StackNavigationProp,
route: { params: { host: string, path: string | null, title: string } },
}
class WebsiteScreen extends React.Component<Props> {
fullUrl: string;
injectedJS: { [key: string]: string };
customPaddingFunctions: {[key: string]: (padding: string) => string}
host: string;
constructor(props: Props) {
super(props);
this.props.navigation.addListener('focus', this.onScreenFocus);
this.injectedJS = {};
this.customPaddingFunctions = {};
this.injectedJS[AvailableWebsites.websites.AVAILABLE_ROOMS] =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<style>body,body>.container2{padding-top:0;width:100%}b,body>.container2>h1,body>.container2>h3,br,header{display:none}.table-bordered td,.table-bordered th{border:none;border-right:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.table{padding:0;margin:0;width:200%;max-width:200%;display:block}tbody{display:block;width:100%}thead{display:block;width:100%}.table tbody tr,tbody tr[bgcolor],thead tr{width:100%;display:inline-flex}.table tbody td,.table thead td[colspan]{padding:0;flex:1;height:50px;margin:0}.table tbody td[bgcolor=white],.table thead td,.table>tbody>tr>td:nth-child(1){flex:0 0 150px;height:50px}</style>\'; true;';
this.injectedJS[AvailableWebsites.websites.BIB] =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<style>.hero-unit,.navbar,footer{display:none}.hero-unit-form,.hero-unit2,.hero-unit3{background-color:#fff;box-shadow:none;padding:0;margin:0}.hero-unit-form h4{font-size:2rem;line-height:2rem}.btn{font-size:1.5rem;line-height:1.5rem;padding:20px}.btn-danger{background-image:none;background-color:#be1522}.table{font-size:.8rem}.table td{padding:0;height:18.2333px;border:none;border-bottom:1px solid #c1c1c1}.table td[style="max-width:55px;"]{max-width:110px!important}.table-bordered{min-width:50px}th{height:50px}.table-bordered{border-collapse:collapse}</style>\';' +
'if ($(".hero-unit-form").length > 0 && $("#customBackButton").length === 0)' +
'$(".hero-unit-form").append("' +
'<div style=\'width: 100%; display: flex\'>' +
'<a style=\'margin: auto\' href=\'' + AvailableWebsites.websites.BIB + '\'>' +
'<button id=\'customBackButton\' class=\'btn btn-primary\'>Retour</button>' +
'</a>' +
'</div>");true;';
this.customPaddingFunctions[AvailableWebsites.websites.BLUEMIND] = (padding: string) => {
return (
"$('head').append('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">');" +
"$('.minwidth').css('top', " + padding + ");" +
"$('#mailview-bottom').css('min-height', 500);"
);
};
this.customPaddingFunctions[AvailableWebsites.websites.WIKETUD] = (padding: string) => {
return (
"$('#p-logo-text').css('top', 10 + " + padding + ");" +
"$('#site-navigation h2').css('top', 10 + " + padding + ");" +
"$('#site-tools h2').css('top', 10 + " + padding + ");" +
"$('#user-tools h2').css('top', 10 + " + padding + ");"
);
}
}
onScreenFocus = () => {
this.handleNavigationParams();
};
/**
*
*/
handleNavigationParams() {
if (this.props.route.params != null) {
this.host = this.props.route.params.host;
let path = this.props.route.params.path;
const title = this.props.route.params.title;
if (this.host != null && path != null) {
path = path.replace(this.host, "");
this.fullUrl = this.host + path;
}else
this.fullUrl = this.host;
if (title != null)
this.props.navigation.setOptions({title: title});
}
}
render() {
let injectedJavascript = "";
let customPadding = null;
if (this.host != null && this.injectedJS[this.host] != null)
injectedJavascript = this.injectedJS[this.host];
if (this.host != null && this.customPaddingFunctions[this.host] != null)
customPadding = this.customPaddingFunctions[this.host];
if (this.fullUrl != null) {
return (
<WebViewScreen
{...this.props}
url={this.fullUrl}
customJS={injectedJavascript}
customPaddingFunction={customPadding}
/>
);
} else {
return (
<BasicLoadingScreen/>
);
}
}
}
export default WebsiteScreen;

View file

@ -1,25 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
const URL = 'https://www.amicale-insat.fr/';
/**
* Class defining the app's available rooms screen.
* This screen uses a webview to render the page
*/
export const AmicaleWebsiteScreen = (props: Object) => {
let path = '';
if (props.route.params !== undefined) {
if (props.route.params.path !== undefined && props.route.params.path !== null) {
path = props.route.params.path;
path = path.replace(URL, '');
}
}
return (
<WebViewScreen
{...props}
url={URL + path}/>
);
};

View file

@ -1,45 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
type Props = {
navigation: Object,
}
const ROOM_URL = 'http://planex.insa-toulouse.fr/salles.php';
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile2.css';
/**
* Class defining the app's available rooms screen.
* This screen uses a webview to render the page
*/
export default class AvailableRoomScreen extends React.Component<Props> {
customInjectedJS: string;
/**
* Defines custom injected JavaScript to improve the page display on mobile
*/
constructor() {
super();
this.customInjectedJS =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<link rel="stylesheet" href="' + CUSTOM_CSS_GENERAL + '" type="text/css"/>\';' +
'let header = $(".table tbody tr:first");' +
'$("table").prepend("<thead></thead>");true;' + // Fix for crash on ios
'$("thead").append(header);true;';
}
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
url={ROOM_URL}
customJS={this.customInjectedJS}/>
);
}
}

View file

@ -1,57 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
type Props = {
navigation: Object,
}
const BIB_URL = 'https://bibbox.insa-toulouse.fr/';
const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile.css';
const CUSTOM_CSS_Bib = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customBibMobile.css';
/**
* Class defining the app's Bib screen.
* This screen uses a webview to render the page
*/
export default class AvailableRoomScreen extends React.Component<Props> {
customInjectedJS: string;
customBibInjectedJS: string;
/**
* Defines custom injected JavaScript to improve the page display on mobile
*/
constructor() {
super();
this.customInjectedJS =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<link rel="stylesheet" href="' + CUSTOM_CSS_GENERAL + '" type="text/css"/>\';' +
'let header = $(".table tbody tr:first");' +
'$("table").prepend("<thead></thead>");true;' + // Fix for crash on ios
'$("thead").append(header);true;';
this.customBibInjectedJS =
'document.querySelector(\'head\').innerHTML += \'<meta name="viewport" content="width=device-width, initial-scale=1.0">\';' +
'document.querySelector(\'head\').innerHTML += \'<link rel="stylesheet" href="' + CUSTOM_CSS_Bib + '" type="text/css"/>\';' +
'if ($(".hero-unit-form").length > 0 && $("#customBackButton").length === 0)' +
'$(".hero-unit-form").append("' +
'<div style=\'width: 100%; display: flex\'>' +
'<a style=\'margin: auto\' href=\'' + BIB_URL + '\'>' +
'<button id=\'customBackButton\' class=\'btn btn-primary\'>Retour</button>' +
'</a>' +
'</div>");true;';
}
render() {
const nav = this.props.navigation;
return (
<WebViewScreen
navigation={nav}
url={BIB_URL}
customJS={this.customBibInjectedJS}/>
);
}
}

View file

@ -1,28 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
const URL = 'https://etud-mel.insa-toulouse.fr/webmail/';
const customPadding = (padding: string) => {
return (
"$('head').append('<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">');" +
"$('.minwidth').css('top', " + padding + ");" +
"$('#mailview-bottom').css('min-height', 500);"
);
}
/**
* Class defining the app's available rooms screen.
* This screen uses a webview to render the page
*/
export const BlueMindWebsiteScreen = (props: Object) => {
return (
<WebViewScreen
{...props}
customPaddingFunction={customPadding}
url={URL}/>
);
};

View file

@ -1,18 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
const URL = 'https://ent.insa-toulouse.fr/';
/**
* Class defining the app's available rooms screen.
* This screen uses a webview to render the page
*/
export const ENTWebsiteScreen = (props: Object) => {
return (
<WebViewScreen
{...props}
url={URL}/>
);
};

View file

@ -1,18 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
const URL = 'https://etud.insa-toulouse.fr/~eeinsat/';
/**
* Class defining the app's available rooms screen.
* This screen uses a webview to render the page
*/
export const ElusEtudiantsWebsiteScreen = (props: Object) => {
return (
<WebViewScreen
{...props}
url={URL}/>
);
};

View file

@ -1,18 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
const URL = 'https://www.etud.insa-toulouse.fr/~tutorinsa/';
/**
* Class defining the app's available rooms screen.
* This screen uses a webview to render the page
*/
export const TutorInsaWebsiteScreen = (props: Object) => {
return (
<WebViewScreen
{...props}
url={URL}/>
);
};

View file

@ -1,30 +0,0 @@
// @flow
import * as React from 'react';
import WebViewScreen from "../../../components/Screens/WebViewScreen";
const URL = 'https://wiki.etud.insa-toulouse.fr/';
const customPadding = (padding: string) => {
return (
"$('#p-logo-text').css('top', 10 + " + padding + ");" +
"$('#site-navigation h2').css('top', 10 + " + padding + ");" +
"$('#site-tools h2').css('top', 10 + " + padding + ");" +
"$('#user-tools h2').css('top', 10 + " + padding + ");"
);
}
/**
* Class defining the app's available rooms screen.
* This screen uses a webview to render the page
*/
export const WiketudWebsiteScreen = (props: Object) => {
return (
<WebViewScreen
{...props}
customPaddingFunction={customPadding}
url={URL}/>
);
};

View file

@ -26,7 +26,7 @@
"vote": "Elections",
"scanner": "Scanotron 3000",
"feedback": "Feedback",
"map": "Campus Map"
"insaAccount": "INSA Account"
},
"intro": {
"slideMain": {
@ -427,7 +427,8 @@
"availableRooms": "See how many rooms are free",
"bib": "Book a Bib'Box for project work",
"mails": "Check your INSA mails",
"ent": "See your grades"
"ent": "See your grades",
"insaAccount": "See your information and change your password"
}
},
"planningScreen": {

View file

@ -26,7 +26,7 @@
"vote": "Élections",
"scanner": "Scanotron 3000",
"feedback": "Votre avis",
"map": "Carte du campus"
"insaAccount": "Compte INSA"
},
"intro": {
"slideMain": {
@ -429,7 +429,8 @@
"availableRooms": "Vérifiez les salles disponibles",
"bib": "Réservez une Bib'Box pour les travaux de groupe",
"mails": "Vérifiez vos mails INSA",
"ent": "Retrouvez vos notes"
"ent": "Retrouvez vos notes",
"insaAccount": "Accédez à vos informations et modifiez votre mot de passe"
}
},
"planningScreen": {