Fix eslint errors

First files rewritten to match the new eslint config
This commit is contained in:
Arnaud Vergnet 2020-08-01 20:59:59 +02:00
parent b596f68abe
commit be1f61b671
4 changed files with 415 additions and 381 deletions

205
App.js
View file

@ -1,36 +1,36 @@
// @flow
import * as React from 'react';
import {LogBox, Platform, SafeAreaView, StatusBar, View} from 'react-native';
import LocaleManager from './src/managers/LocaleManager';
import AsyncStorageManager from "./src/managers/AsyncStorageManager";
import CustomIntroSlider from "./src/components/Overrides/CustomIntroSlider";
import type {CustomTheme} from "./src/managers/ThemeManager";
import ThemeManager from './src/managers/ThemeManager';
import {LogBox, Platform, SafeAreaView, View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import MainNavigator from './src/navigation/MainNavigator';
import {Provider as PaperProvider} from 'react-native-paper';
import AprilFoolsManager from "./src/managers/AprilFoolsManager";
import Update from "./src/constants/Update";
import ConnectionManager from "./src/managers/ConnectionManager";
import URLHandler from "./src/utils/URLHandler";
import {setSafeBounceHeight} from "react-navigation-collapsible";
import SplashScreen from 'react-native-splash-screen'
import {OverflowMenuProvider} from "react-navigation-header-buttons";
import {setSafeBounceHeight} from 'react-navigation-collapsible';
import SplashScreen from 'react-native-splash-screen';
import {OverflowMenuProvider} from 'react-navigation-header-buttons';
import LocaleManager from './src/managers/LocaleManager';
import AsyncStorageManager from './src/managers/AsyncStorageManager';
import CustomIntroSlider from './src/components/Overrides/CustomIntroSlider';
import type {CustomTheme} from './src/managers/ThemeManager';
import ThemeManager from './src/managers/ThemeManager';
import MainNavigator from './src/navigation/MainNavigator';
import AprilFoolsManager from './src/managers/AprilFoolsManager';
import Update from './src/constants/Update';
import ConnectionManager from './src/managers/ConnectionManager';
import type {ParsedUrlDataType} from './src/utils/URLHandler';
import URLHandler from './src/utils/URLHandler';
import {setupStatusBar} from './src/utils/Utils';
// Native optimizations https://reactnavigation.org/docs/react-native-screens
// Crashes app when navigating away from webview on android 9+
// enableScreens(true);
LogBox.ignoreLogs([ // collapsible headers cause this warning, just ignore as it is not an issue
LogBox.ignoreLogs([
// collapsible headers cause this warning, just ignore as it is not an issue
'Non-serializable values were found in the navigation state',
'Cannot update a component from inside the function body of a different component',
]);
type Props = {};
type State = {
type StateType = {
isLoading: boolean,
showIntro: boolean,
showUpdate: boolean,
@ -38,27 +38,24 @@ type State = {
currentTheme: CustomTheme | null,
};
export default class App extends React.Component<Props, State> {
export default class App extends React.Component<null, StateType> {
navigatorRef: {current: null | NavigationContainer};
state = {
defaultHomeRoute: string | null;
defaultHomeData: {[key: string]: string};
urlHandler: URLHandler;
constructor() {
super();
this.state = {
isLoading: true,
showIntro: true,
showUpdate: true,
showAprilFools: false,
currentTheme: null,
};
navigatorRef: { current: null | NavigationContainer };
defaultHomeRoute: string | null;
defaultHomeData: { [key: string]: any }
createDrawerNavigator: () => React.Node;
urlHandler: URLHandler;
constructor() {
super();
LocaleManager.initTranslations();
this.navigatorRef = React.createRef();
this.defaultHomeRoute = null;
@ -66,7 +63,7 @@ export default class App extends React.Component<Props, State> {
this.urlHandler = new URLHandler(this.onInitialURLParsed, this.onDetectURL);
this.urlHandler.listen();
setSafeBounceHeight(Platform.OS === 'ios' ? 100 : 20);
this.loadAssetsAsync().then(() => {
this.loadAssetsAsync().finally(() => {
this.onLoadFinished();
});
}
@ -77,7 +74,7 @@ export default class App extends React.Component<Props, State> {
*
* @param parsedData The data parsed from the url
*/
onInitialURLParsed = (parsedData: { route: string, data: { [key: string]: any } }) => {
onInitialURLParsed = (parsedData: ParsedUrlDataType) => {
this.defaultHomeRoute = parsedData.route;
this.defaultHomeData = parsedData.data;
};
@ -88,12 +85,13 @@ export default class App extends React.Component<Props, State> {
*
* @param parsedData The data parsed from the url
*/
onDetectURL = (parsedData: { route: string, data: { [key: string]: any } }) => {
onDetectURL = (parsedData: ParsedUrlDataType) => {
// Navigate to nested navigator and pass data to the index screen
if (this.navigatorRef.current != null) {
this.navigatorRef.current.navigate('home', {
const nav = this.navigatorRef.current;
if (nav != null) {
nav.navigate('home', {
screen: 'index',
params: {nextScreen: parsedData.route, data: parsedData.data}
params: {nextScreen: parsedData.route, data: parsedData.data},
});
}
};
@ -103,25 +101,11 @@ export default class App extends React.Component<Props, State> {
*/
onUpdateTheme = () => {
this.setState({
currentTheme: ThemeManager.getCurrentTheme()
currentTheme: ThemeManager.getCurrentTheme(),
});
this.setupStatusBar();
setupStatusBar();
};
/**
* Updates status bar content color if on iOS only,
* as the android status bar is always set to black.
*/
setupStatusBar() {
if (ThemeManager.getNightMode()) {
StatusBar.setBarStyle('light-content', true);
} else {
StatusBar.setBarStyle('dark-content', true);
}
if (Platform.OS === "android")
StatusBar.setBackgroundColor(ThemeManager.getCurrentTheme().colors.surface, true);
}
/**
* Callback when user ends the intro. Save in preferences to avoid showing back the introSlides
*/
@ -131,11 +115,49 @@ export default class App extends React.Component<Props, State> {
showUpdate: false,
showAprilFools: false,
});
AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.showIntro.key, false);
AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.updateNumber.key, Update.number);
AsyncStorageManager.set(AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key, false);
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.showIntro.key,
false,
);
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.updateNumber.key,
Update.number,
);
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key,
false,
);
};
/**
* Async loading is done, finish processing startup data
*/
onLoadFinished() {
// Only show intro if this is the first time starting the app
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
// Status bar goes dark if set too fast on ios
if (Platform.OS === 'ios') setTimeout(setupStatusBar, 1000);
else setupStatusBar();
this.setState({
isLoading: false,
currentTheme: ThemeManager.getCurrentTheme(),
showIntro: AsyncStorageManager.getBool(
AsyncStorageManager.PREFERENCES.showIntro.key,
),
showUpdate:
AsyncStorageManager.getNumber(
AsyncStorageManager.PREFERENCES.updateNumber.key,
) !== Update.number,
showAprilFools:
AprilFoolsManager.getInstance().isAprilFoolsEnabled() &&
AsyncStorageManager.getBool(
AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key,
),
});
SplashScreen.hide();
}
/**
* Loads every async data
*
@ -143,58 +165,38 @@ export default class App extends React.Component<Props, State> {
*/
loadAssetsAsync = async () => {
await AsyncStorageManager.getInstance().loadPreferences();
try {
await ConnectionManager.getInstance().recoverLogin();
} catch (e) {
}
}
/**
* Async loading is done, finish processing startup data
*/
onLoadFinished() {
// Only show intro if this is the first time starting the app
this.createDrawerNavigator = () => <MainNavigator
defaultHomeRoute={this.defaultHomeRoute}
defaultHomeData={this.defaultHomeData}
/>;
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
// Status bar goes dark if set too fast on ios
if (Platform.OS === 'ios')
setTimeout(this.setupStatusBar, 1000);
else
this.setupStatusBar();
this.setState({
isLoading: false,
currentTheme: ThemeManager.getCurrentTheme(),
showIntro: AsyncStorageManager.getBool(AsyncStorageManager.PREFERENCES.showIntro.key),
showUpdate: AsyncStorageManager.getNumber(AsyncStorageManager.PREFERENCES.updateNumber.key)
!== Update.number,
showAprilFools: AprilFoolsManager.getInstance().isAprilFoolsEnabled()
&& AsyncStorageManager.getBool(AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key),
});
SplashScreen.hide();
}
};
/**
* Renders the app based on loading state
*/
render() {
if (this.state.isLoading) {
render(): React.Node {
const {state} = this;
if (state.isLoading) {
return null;
} else if (this.state.showIntro || this.state.showUpdate || this.state.showAprilFools) {
return <CustomIntroSlider
onDone={this.onIntroDone}
isUpdate={this.state.showUpdate && !this.state.showIntro}
isAprilFools={this.state.showAprilFools && !this.state.showIntro}
/>;
} else {
}
if (state.showIntro || state.showUpdate || state.showAprilFools) {
return (
<PaperProvider theme={this.state.currentTheme}>
<CustomIntroSlider
onDone={this.onIntroDone}
isUpdate={state.showUpdate && !state.showIntro}
isAprilFools={state.showAprilFools && !state.showIntro}
/>
);
}
return (
<PaperProvider theme={state.currentTheme}>
<OverflowMenuProvider>
<View style={{backgroundColor: ThemeManager.getCurrentTheme().colors.background, flex: 1}}>
<View
style={{
backgroundColor: ThemeManager.getCurrentTheme().colors.background,
flex: 1,
}}>
<SafeAreaView style={{flex: 1}}>
<NavigationContainer theme={this.state.currentTheme} ref={this.navigatorRef}>
<NavigationContainer
theme={state.currentTheme}
ref={this.navigatorRef}>
<MainNavigator
defaultHomeRoute={this.defaultHomeRoute}
defaultHomeData={this.defaultHomeData}
@ -206,5 +208,4 @@ export default class App extends React.Component<Props, State> {
</PaperProvider>
);
}
}
}

View file

@ -1,21 +1,15 @@
// @flow
import type {ServiceItem} from "./ServicesManager";
import ServicesManager from "./ServicesManager";
import {StackNavigationProp} from "@react-navigation/stack";
import {getSublistWithIds} from "../utils/Utils";
import AsyncStorageManager from "./AsyncStorageManager";
import type {ServiceItem} from './ServicesManager';
import ServicesManager from './ServicesManager';
import {getSublistWithIds} from '../utils/Utils';
import AsyncStorageManager from './AsyncStorageManager';
export default class DashboardManager extends ServicesManager {
constructor(nav: StackNavigationProp) {
super(nav)
}
getCurrentDashboard(): Array<ServiceItem> {
const dashboardIdList = AsyncStorageManager
.getObject(AsyncStorageManager.PREFERENCES.dashboardItems.key);
getCurrentDashboard(): Array<ServiceItem | null> {
const dashboardIdList = AsyncStorageManager.getObject(
AsyncStorageManager.PREFERENCES.dashboardItems.key,
);
const allDatasets = [
...this.amicaleDataset,
...this.studentsDataset,

View file

@ -2,23 +2,40 @@
import {Linking} from 'react-native';
export type ParsedUrlDataType = {
route: string,
data: {[key: string]: string},
};
export type ParsedUrlCallbackType = (parsedData: ParsedUrlDataType) => void;
type RawParsedUrlDataType = {
path: string,
queryParams: {[key: string]: string},
};
/**
* Class use to handle depp links scanned or clicked.
*/
export default class URLHandler {
static SCHEME = 'campus-insat://'; // Urls beginning with this string will be opened in the app
static SCHEME = "campus-insat://"; // Urls beginning with this string will be opened in the app
static CLUB_INFO_URL_PATH = 'club';
static CLUB_INFO_URL_PATH = "club";
static EVENT_INFO_URL_PATH = "event";
static EVENT_INFO_URL_PATH = 'event';
static CLUB_INFO_ROUTE = "club-information";
static EVENT_INFO_ROUTE = "planning-information";
static CLUB_INFO_ROUTE = 'club-information';
onInitialURLParsed: Function;
onDetectURL: Function;
static EVENT_INFO_ROUTE = 'planning-information';
constructor(onInitialURLParsed: Function, onDetectURL: Function) {
onInitialURLParsed: ParsedUrlCallbackType;
onDetectURL: ParsedUrlCallbackType;
constructor(
onInitialURLParsed: ParsedUrlCallbackType,
onDetectURL: ParsedUrlCallbackType,
) {
this.onInitialURLParsed = onInitialURLParsed;
this.onDetectURL = onDetectURL;
}
@ -29,45 +46,47 @@ export default class URLHandler {
* @param url The url to parse
* @returns {{path: string, queryParams: {}}}
*/
static parseUrl(url: string) {
let params = {};
let path = "";
let temp = url.replace(URLHandler.SCHEME, "");
if (temp != null) {
let array = temp.split("?");
if (array != null && array.length > 0) {
path = array[0];
static parseUrl(url: string): RawParsedUrlDataType | null {
let parsedData: RawParsedUrlDataType | null = null;
const urlNoScheme = url.replace(URLHandler.SCHEME, '');
if (urlNoScheme != null) {
const params = {};
const [path, fullParamsString] = urlNoScheme.split('?');
if (fullParamsString != null) {
const paramsStringArray = fullParamsString.split('&');
paramsStringArray.forEach((paramString: string) => {
const [key, value] = paramString.split('=');
if (value != null) {
params[key] = value;
}
if (array != null && array.length > 1) {
let tempParams = array[1].split("&");
for (let i = 0; i < tempParams.length; i++) {
let paramsArray = tempParams[i].split("=");
if (paramsArray.length > 1) {
params[paramsArray[0]] = paramsArray[1];
});
}
if (path != null) parsedData = {path, queryParams: params};
}
}
}
return {path: path, queryParams: params};
return parsedData;
}
/**
* Gets routing data corresponding to the given url.
* If the url does not match any existing route, null will be returned.
*
* @param path Url path
* @param queryParams Url parameters
* @param rawParsedUrlData The data just parsed
* @returns {null}
*/
static getUrlData({path, queryParams}: { path: string, queryParams: { [key: string]: string } }) {
let data = null;
if (path !== null) {
static getUrlData(
rawParsedUrlData: RawParsedUrlDataType | null,
): ParsedUrlDataType | null {
let parsedData: null | ParsedUrlDataType = null;
if (rawParsedUrlData != null) {
const {path} = rawParsedUrlData;
const {queryParams} = rawParsedUrlData;
if (URLHandler.isClubInformationLink(path))
data = URLHandler.generateClubInformationData(queryParams);
parsedData = URLHandler.generateClubInformationData(queryParams);
else if (URLHandler.isPlanningInformationLink(path))
data = URLHandler.generatePlanningInformationData(queryParams);
parsedData = URLHandler.generatePlanningInformationData(queryParams);
}
return data;
return parsedData;
}
/**
@ -76,7 +95,7 @@ export default class URLHandler {
* @param url The url to check
* @returns {boolean}
*/
static isUrlValid(url: string) {
static isUrlValid(url: string): boolean {
return this.getUrlData(URLHandler.parseUrl(url)) !== null;
}
@ -86,7 +105,7 @@ export default class URLHandler {
* @param path The url to check
* @returns {boolean}
*/
static isClubInformationLink(path: string) {
static isClubInformationLink(path: string): boolean {
return path === URLHandler.CLUB_INFO_URL_PATH;
}
@ -96,7 +115,7 @@ export default class URLHandler {
* @param path The url to check
* @returns {boolean}
*/
static isPlanningInformationLink(path: string) {
static isPlanningInformationLink(path: string): boolean {
return path === URLHandler.EVENT_INFO_URL_PATH;
}
@ -106,12 +125,16 @@ export default class URLHandler {
* @param params Url parameters to convert
* @returns {null|{route: string, data: {clubId: number}}}
*/
static generateClubInformationData(params: Object): Object | null {
if (params !== undefined && params.id !== undefined) {
let id = parseInt(params.id);
if (!isNaN(id)) {
return {route: URLHandler.CLUB_INFO_ROUTE, data: {clubId: id}};
}
static generateClubInformationData(params: {
[key: string]: string,
}): ParsedUrlDataType | null {
if (params.id != null) {
const id = parseInt(params.id, 10);
if (!Number.isNaN(id))
return {
route: URLHandler.CLUB_INFO_ROUTE,
data: {clubId: id.toString()},
};
}
return null;
}
@ -122,11 +145,16 @@ export default class URLHandler {
* @param params Url parameters to convert
* @returns {null|{route: string, data: {clubId: number}}}
*/
static generatePlanningInformationData(params: Object): Object | null {
if (params !== undefined && params.id !== undefined) {
let id = parseInt(params.id);
if (!isNaN(id)) {
return {route: URLHandler.EVENT_INFO_ROUTE, data: {eventId: id}};
static generatePlanningInformationData(params: {
[key: string]: string,
}): ParsedUrlDataType | null {
if (params.id != null) {
const id = parseInt(params.id, 10);
if (!Number.isNaN(id)) {
return {
route: URLHandler.EVENT_INFO_ROUTE,
data: {eventId: id.toString()},
};
}
}
return null;
@ -151,11 +179,10 @@ export default class URLHandler {
*
* @param url The url detected
*/
onUrl = ({url}: { url: string }) => {
onUrl = ({url}: {url: string}) => {
if (url != null) {
let data = URLHandler.getUrlData(URLHandler.parseUrl(url));
if (data !== null)
this.onDetectURL(data);
const data = URLHandler.getUrlData(URLHandler.parseUrl(url));
if (data != null) this.onDetectURL(data);
}
};
@ -166,10 +193,8 @@ export default class URLHandler {
*/
onInitialUrl = (url: ?string) => {
if (url != null) {
let data = URLHandler.getUrlData(URLHandler.parseUrl(url));
if (data !== null)
this.onInitialURLParsed(data);
const data = URLHandler.getUrlData(URLHandler.parseUrl(url));
if (data != null) this.onInitialURLParsed(data);
}
};
}

View file

@ -1,5 +1,7 @@
// @flow
import {Platform, StatusBar} from 'react-native';
import ThemeManager from '../managers/ThemeManager';
/**
* Gets a sublist of the given list with items of the given ids only
@ -10,28 +12,40 @@
* @param originalList The original list
* @returns {[]}
*/
export function getSublistWithIds(
export function getSublistWithIds<T>(
idList: Array<string>,
originalList: Array<{ key: string, [key: string]: any }>
): Array<{ key: string, [key: string]: any }> {
let subList = [];
for (let i = 0; i < subList.length; i++) {
originalList: Array<{key: string, ...T}>,
): Array<{key: string, ...T} | null> {
const subList = [];
for (let i = 0; i < idList.length; i += 1) {
subList.push(null);
}
let itemsAdded = 0;
for (let i = 0; i < originalList.length; i++) {
for (let i = 0; i < originalList.length; i += 1) {
const item = originalList[i];
if (idList.includes(item.key)) {
subList[idList.indexOf(item.key)] = item;
itemsAdded++;
if (itemsAdded === idList.length)
break;
itemsAdded += 1;
if (itemsAdded === idList.length) break;
}
}
for (let i = 0; i < subList.length; i++) {
if (subList[i] == null)
subList.splice(i, 1);
}
return subList;
}
/**
* Updates status bar content color if on iOS only,
* as the android status bar is always set to black.
*/
export function setupStatusBar() {
if (ThemeManager.getNightMode()) {
StatusBar.setBarStyle('light-content', true);
} else {
StatusBar.setBarStyle('dark-content', true);
}
if (Platform.OS === 'android') {
StatusBar.setBackgroundColor(
ThemeManager.getCurrentTheme().colors.surface,
true,
);
}
}