Improved doc and typing, improved API connection handling

This commit is contained in:
Arnaud Vergnet 2020-07-01 13:14:17 +02:00
parent 3f14f7bb96
commit b813aa0b83
6 changed files with 138 additions and 76 deletions

View file

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

View file

@ -1,14 +1,13 @@
// @flow // @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 { export default class AprilFoolsManager {
static instance: AprilFoolsManager | null = null; static instance: AprilFoolsManager | null = null;
aprilFoolsEnabled: boolean;
static fakeMachineNumber = [ static fakeMachineNumber = [
"", "",
"cos(ln(1))", "cos(ln(1))",
@ -24,6 +23,7 @@ export default class AprilFoolsManager {
"1×10¹+1×10⁰", "1×10¹+1×10⁰",
"Re(√192e^(iπ/6))", "Re(√192e^(iπ/6))",
]; ];
aprilFoolsEnabled: boolean;
constructor() { constructor() {
let today = new Date(); let today = new Date();
@ -40,7 +40,13 @@ export default class AprilFoolsManager {
AprilFoolsManager.instance; 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(4, 0, {name: "Coq au vin"});
menu[1]["dishes"].splice(2, 0, {name: "Bat'Soupe"}); menu[1]["dishes"].splice(2, 0, {name: "Bat'Soupe"});
menu[1]["dishes"].splice(1, 0, {name: "Pave de loup"}); menu[1]["dishes"].splice(1, 0, {name: "Pave de loup"});
@ -49,16 +55,26 @@ export default class AprilFoolsManager {
return menu; 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]; let second = dryers[1];
dryers.splice(1, 1); dryers.splice(1, 1);
dryers.push(second); 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 first = washers[0];
let second = washers[1]; let second = washers[1];
let fifth = washers[4]; let fifth = washers[4];
@ -67,14 +83,25 @@ export default class AprilFoolsManager {
washers.splice(4, 1, ninth); washers.splice(4, 1, ninth);
washers.splice(1, 1, first); washers.splice(1, 1, first);
washers.splice(0, 1, fifth); 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) { static getProxiwashMachineDisplayNumber(number: number) {
return AprilFoolsManager.fakeMachineNumber[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) { static getAprilFoolsTheme(currentTheme: Object) {
return { return {
...currentTheme, ...currentTheme,

View file

@ -23,15 +23,13 @@ export default class ConnectionManager {
#email: string; #email: string;
#token: string | null; #token: string | null;
listeners: Array<Function>;
constructor() { constructor() {
this.#token = null; 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} * @returns {ConnectionManager}
*/ */
static getInstance(): ConnectionManager { static getInstance(): ConnectionManager {
@ -40,21 +38,20 @@ export default class ConnectionManager {
ConnectionManager.instance; ConnectionManager.instance;
} }
getToken() { /**
* Gets the current token
*
* @returns {string | null}
*/
getToken(): string | null {
return this.#token; return this.#token;
} }
onLoginStateChange(newState: boolean) { /**
for (let i = 0; i < this.listeners.length; i++) { * Tries to recover login token from the secure keychain
if (this.listeners[i] !== undefined) *
this.listeners[i](newState); * @returns {Promise<R>}
} */
}
addLoginStateListener(listener: Function) {
this.listeners.push(listener);
}
async recoverLogin() { async recoverLogin() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (this.getToken() !== null) if (this.getToken() !== null)
@ -64,7 +61,6 @@ export default class ConnectionManager {
.then((data) => { .then((data) => {
if (data) { if (data) {
this.#token = data.password; this.#token = data.password;
this.onLoginStateChange(true);
resolve(this.#token); resolve(this.#token);
} else } else
reject(false); reject(false);
@ -76,17 +72,28 @@ export default class ConnectionManager {
}); });
} }
/**
* Check if the user has a valid token
*
* @returns {boolean}
*/
isLoggedIn() { isLoggedIn() {
return this.getToken() !== null; 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) { async saveLogin(email: string, token: string) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
Keychain.setInternetCredentials(SERVER_NAME, 'token', token) Keychain.setInternetCredentials(SERVER_NAME, 'token', token)
.then(() => { .then(() => {
this.#token = token; this.#token = token;
this.#email = email; this.#email = email;
this.onLoginStateChange(true);
resolve(true); resolve(true);
}) })
.catch(() => { .catch(() => {
@ -95,12 +102,16 @@ export default class ConnectionManager {
}); });
} }
/**
* Deletes the login token from the keychain
*
* @returns {Promise<R>}
*/
async disconnect() { async disconnect() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
Keychain.resetInternetCredentials(SERVER_NAME) Keychain.resetInternetCredentials(SERVER_NAME)
.then(() => { .then(() => {
this.#token = null; this.#token = null;
this.onLoginStateChange(false);
resolve(true); resolve(true);
}) })
.catch(() => { .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) { async connect(email: string, password: string) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const data = { const data = {
@ -117,19 +138,28 @@ export default class ConnectionManager {
}; };
apiRequest(AUTH_PATH, 'POST', data) apiRequest(AUTH_PATH, 'POST', data)
.then((response) => { .then((response) => {
this.saveLogin(email, response.token) if (this.isConnectionResponseValid(response)) {
.then(() => { this.saveLogin(email, response.token)
resolve(true); .then(() => {
}) resolve(true);
.catch(() => { })
reject(ERROR_TYPE.TOKEN_SAVE); .catch(() => {
}); reject(ERROR_TYPE.TOKEN_SAVE);
});
} else
reject(ERROR_TYPE.SERVER_ERROR);
}) })
.catch((error) => reject(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); let valid = isResponseValid(response);
if (valid && response.error === ERROR_TYPE.SUCCESS) if (valid && response.error === ERROR_TYPE.SUCCESS)
@ -140,6 +170,13 @@ export default class ConnectionManager {
return valid; 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) { async authenticatedRequest(path: string, params: Object) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (this.getToken() !== null) { if (this.getToken() !== null) {

View file

@ -45,6 +45,10 @@ export default class DateManager {
DateManager.instance; DateManager.instance;
} }
static isWeekend(date: Date) {
return date.getDay() === 6 || date.getDay() === 0;
}
/** /**
* Gets a translated string representing the given date. * 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(); 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.translations = {fr, en};
i18n.locale = RNLocalize.findBestAvailableLanguage(["en", "fr"]).languageTag; 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 // Tetris
tetrisBackground: string, tetrisBackground: string,
tetrisBorder:string, tetrisBorder: string,
tetrisScore:string, tetrisScore: string,
tetrisI : string, tetrisI: string,
tetrisO : string, tetrisO: string,
tetrisT : string, tetrisT: string,
tetrisS : string, tetrisS: string,
tetrisZ : string, tetrisZ: string,
tetrisJ : string, tetrisJ: string,
tetrisL : string, tetrisL: string,
}, },
} }
@ -116,16 +116,16 @@ export default class ThemeManager {
tutorinsaColor: '#f93943', tutorinsaColor: '#f93943',
// Tetris // Tetris
tetrisBackground:'#e6e6e6', tetrisBackground: '#e6e6e6',
tetrisBorder:'#2f2f2f', tetrisBorder: '#2f2f2f',
tetrisScore:'#e2bd33', tetrisScore: '#e2bd33',
tetrisI : '#3cd9e6', tetrisI: '#3cd9e6',
tetrisO : '#ffdd00', tetrisO: '#ffdd00',
tetrisT : '#a716e5', tetrisT: '#a716e5',
tetrisS : '#09c528', tetrisS: '#09c528',
tetrisZ : '#ff0009', tetrisZ: '#ff0009',
tetrisJ : '#2a67e3', tetrisJ: '#2a67e3',
tetrisL : '#da742d', tetrisL: '#da742d',
}, },
}; };
} }
@ -176,16 +176,16 @@ export default class ThemeManager {
tutorinsaColor: '#f93943', tutorinsaColor: '#f93943',
// Tetris // Tetris
tetrisBackground:'#2c2c2c', tetrisBackground: '#2c2c2c',
tetrisBorder:'#1b1b1b', tetrisBorder: '#1b1b1b',
tetrisScore:'#e2d707', tetrisScore: '#e2d707',
tetrisI : '#30b3be', tetrisI: '#30b3be',
tetrisO : '#c1a700', tetrisO: '#c1a700',
tetrisT : '#9114c7', tetrisT: '#9114c7',
tetrisS : '#08a121', tetrisS: '#08a121',
tetrisZ : '#b50008', tetrisZ: '#b50008',
tetrisJ : '#0f37b9', tetrisJ: '#0f37b9',
tetrisL : '#b96226', tetrisL: '#b96226',
}, },
}; };
} }