Compare commits
3 commits
98168b560b
...
d622a2f77a
| Author | SHA1 | Date | |
|---|---|---|---|
| d622a2f77a | |||
| b813aa0b83 | |||
| 3f14f7bb96 |
25 changed files with 295 additions and 353 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"/>
|
||||
|
|
|
|||
13
src/constants/AvailableWebsites.js
Normal file
13
src/constants/AvailableWebsites.js
Normal 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/",
|
||||
},
|
||||
}
|
||||
|
|
@ -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'))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 = () => {
|
||||
|
|
|
|||
|
|
@ -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 = [
|
||||
|
|
|
|||
109
src/screens/Services/WebsiteScreen.js
Normal file
109
src/screens/Services/WebsiteScreen.js
Normal 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;
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -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}/>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue