diff --git a/src/screens/Amicale/AmicaleContactScreen.js b/src/screens/Amicale/AmicaleContactScreen.tsx similarity index 84% rename from src/screens/Amicale/AmicaleContactScreen.js rename to src/screens/Amicale/AmicaleContactScreen.tsx index e924942..b7f0ae4 100644 --- a/src/screens/Amicale/AmicaleContactScreen.js +++ b/src/screens/Amicale/AmicaleContactScreen.tsx @@ -17,24 +17,18 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {FlatList, Image, Linking, View} from 'react-native'; -import {Card, List, Text, withTheme, Avatar} from 'react-native-paper'; +import {Avatar, Card, List, Text} from 'react-native-paper'; import i18n from 'i18n-js'; -import type {MaterialCommunityIconsGlyphs} from 'react-native-vector-icons/MaterialCommunityIcons'; import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList'; -import AMICALE_LOGO from '../../../assets/amicale.png'; -import type { - CardTitleIconPropsType, - ListIconPropsType, -} from '../../constants/PaperStyles'; + +const AMICALE_LOGO = require('../../../assets/amicale.png'); type DatasetItemType = { - name: string, - email: string, - icon: MaterialCommunityIconsGlyphs, + name: string; + email: string; + icon: string; }; /** @@ -45,7 +39,7 @@ class AmicaleContactScreen extends React.Component { CONTACT_DATASET: Array; constructor() { - super(); + super(null); this.CONTACT_DATASET = [ { name: i18n.t('screens.amicaleAbout.roles.interSchools'), @@ -97,7 +91,13 @@ class AmicaleContactScreen extends React.Component { keyExtractor = (item: DatasetItemType): string => item.email; - getChevronIcon = (iconProps: ListIconPropsType): React.Node => ( + getChevronIcon = (iconProps: { + color: string; + style?: { + marginRight: number; + marginVertical?: number; + }; + }) => ( { /> ); - getRenderItem = ({item}: {item: DatasetItemType}): React.Node => { + getRenderItem = ({item}: {item: DatasetItemType}) => { const onPress = () => { Linking.openURL(`mailto:${item.email}`); }; @@ -113,7 +113,7 @@ class AmicaleContactScreen extends React.Component { ( + left={(iconProps) => ( { ); }; - getScreen = (): React.Node => { + getScreen = () => { return ( { ( + left={(iconProps) => ( )} /> @@ -165,7 +165,7 @@ class AmicaleContactScreen extends React.Component { ); }; - render(): React.Node { + render() { return ( { } } -export default withTheme(AmicaleContactScreen); +export default AmicaleContactScreen; diff --git a/src/screens/Amicale/LoginScreen.js b/src/screens/Amicale/LoginScreen.tsx similarity index 91% rename from src/screens/Amicale/LoginScreen.js rename to src/screens/Amicale/LoginScreen.tsx index 5773425..5da8505 100644 --- a/src/screens/Amicale/LoginScreen.js +++ b/src/screens/Amicale/LoginScreen.tsx @@ -17,8 +17,6 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {Image, KeyboardAvoidingView, StyleSheet, View} from 'react-native'; import { @@ -29,32 +27,33 @@ import { withTheme, } from 'react-native-paper'; import i18n from 'i18n-js'; -import {StackNavigationProp} from '@react-navigation/stack'; +import {StackNavigationProp, StackScreenProps} from '@react-navigation/stack'; import LinearGradient from 'react-native-linear-gradient'; import ConnectionManager from '../../managers/ConnectionManager'; import ErrorDialog from '../../components/Dialogs/ErrorDialog'; -import type {CustomThemeType} from '../../managers/ThemeManager'; import AsyncStorageManager from '../../managers/AsyncStorageManager'; import AvailableWebsites from '../../constants/AvailableWebsites'; import {MASCOT_STYLE} from '../../components/Mascot/Mascot'; import MascotPopup from '../../components/Mascot/MascotPopup'; import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView'; +import {MainStackParamsList} from '../../navigation/MainNavigator'; -type PropsType = { - navigation: StackNavigationProp, - route: {params: {nextScreen: string}}, - theme: CustomThemeType, +type LoginScreenNavigationProp = StackScreenProps; + +type Props = LoginScreenNavigationProp & { + navigation: StackNavigationProp; + theme: ReactNativePaper.Theme; }; type StateType = { - email: string, - password: string, - isEmailValidated: boolean, - isPasswordValidated: boolean, - loading: boolean, - dialogVisible: boolean, - dialogError: number, - mascotDialogVisible: boolean, + email: string; + password: string; + isEmailValidated: boolean; + isPasswordValidated: boolean; + loading: boolean; + dialogVisible: boolean; + dialogError: number; + mascotDialogVisible: boolean; }; const ICON_AMICALE = require('../../../assets/amicale.png'); @@ -82,17 +81,21 @@ const styles = StyleSheet.create({ }, }); -class LoginScreen extends React.Component { +class LoginScreen extends React.Component { onEmailChange: (value: string) => void; onPasswordChange: (value: string) => void; - passwordInputRef: {current: null | TextInput}; + passwordInputRef: { + // @ts-ignore + current: null | TextInput; + }; nextScreen: string | null; - constructor(props: PropsType) { + constructor(props: Props) { super(props); + this.nextScreen = null; this.passwordInputRef = React.createRef(); this.onEmailChange = (value: string) => { this.onInputChange(true, value); @@ -158,8 +161,9 @@ class LoginScreen extends React.Component { * @returns {*} */ onEmailSubmit = () => { - if (this.passwordInputRef.current != null) + if (this.passwordInputRef.current != null) { this.passwordInputRef.current.focus(); + } }; /** @@ -188,7 +192,7 @@ class LoginScreen extends React.Component { * * @returns {*} */ - getFormInput(): React.Node { + getFormInput() { const {email, password} = this.state; return ( @@ -239,7 +243,7 @@ class LoginScreen extends React.Component { * Gets the card containing the input form * @returns {*} */ - getMainCard(): React.Node { + getMainCard() { const {props, state} = this; return ( @@ -248,7 +252,7 @@ class LoginScreen extends React.Component { titleStyle={{color: '#fff'}} subtitle={i18n.t('screens.login.subtitle')} subtitleStyle={{color: '#fff'}} - left={({size}: {size: number}): React.Node => ( + left={({size}) => ( { AsyncStorageManager.PREFERENCES.homeShowMascot.key, false, ); - if (this.nextScreen == null) navigation.goBack(); - else navigation.replace(this.nextScreen); + if (this.nextScreen == null) { + navigation.goBack(); + } else { + navigation.replace(this.nextScreen); + } }; /** * Saves the screen to navigate to after a successful login if one was provided in navigation parameters */ handleNavigationParams() { - const {route} = this.props; - if (route.params != null) { - if (route.params.nextScreen != null) - this.nextScreen = route.params.nextScreen; - else this.nextScreen = null; - } + this.nextScreen = this.props.route.params.nextScreen; } /** @@ -417,7 +419,7 @@ class LoginScreen extends React.Component { return this.isEmailValid() && this.isPasswordValid() && !loading; } - render(): React.Node { + render() { const {mascotDialogVisible, dialogVisible, dialogError} = this.state; return ( { message={i18n.t('screens.login.mascotDialog.message')} icon="help" buttons={{ - action: null, cancel: { message: i18n.t('screens.login.mascotDialog.button'), icon: 'check', diff --git a/src/screens/Amicale/ProfileScreen.js b/src/screens/Amicale/ProfileScreen.tsx similarity index 81% rename from src/screens/Amicale/ProfileScreen.js rename to src/screens/Amicale/ProfileScreen.tsx index b35b401..ac98621 100644 --- a/src/screens/Amicale/ProfileScreen.js +++ b/src/screens/Amicale/ProfileScreen.tsx @@ -17,8 +17,6 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {FlatList, StyleSheet, View} from 'react-native'; import { @@ -38,42 +36,37 @@ import MaterialHeaderButtons, { Item, } from '../../components/Overrides/CustomHeaderButton'; import CardList from '../../components/Lists/CardList/CardList'; -import type {CustomThemeType} from '../../managers/ThemeManager'; import AvailableWebsites from '../../constants/AvailableWebsites'; import Mascot, {MASCOT_STYLE} from '../../components/Mascot/Mascot'; import ServicesManager, {SERVICES_KEY} from '../../managers/ServicesManager'; import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList'; import type {ServiceItemType} from '../../managers/ServicesManager'; -import type { - CardTitleIconPropsType, - ListIconPropsType, -} from '../../constants/PaperStyles'; type PropsType = { - navigation: StackNavigationProp, - theme: CustomThemeType, + navigation: StackNavigationProp; + theme: ReactNativePaper.Theme; }; type StateType = { - dialogVisible: boolean, + dialogVisible: boolean; }; type ClubType = { - id: number, - name: string, - is_manager: boolean, + id: number; + name: string; + is_manager: boolean; }; type ProfileDataType = { - first_name: string, - last_name: string, - email: string, - birthday: string, - phone: string, - branch: string, - link: string, - validity: boolean, - clubs: Array, + first_name: string; + last_name: string; + email: string; + birthday: string; + phone: string; + branch: string; + link: string; + validity: boolean; + clubs: Array; }; const styles = StyleSheet.create({ @@ -89,7 +82,7 @@ const styles = StyleSheet.create({ }); class ProfileScreen extends React.Component { - data: ProfileDataType; + data: ProfileDataType | null; flatListData: Array<{id: string}>; @@ -97,6 +90,7 @@ class ProfileScreen extends React.Component { constructor(props: PropsType) { super(props); + this.data = null; this.flatListData = [{id: '0'}, {id: '1'}, {id: '2'}, {id: '3'}]; const services = new ServicesManager(props.navigation); this.amicaleDataset = services.getAmicaleServices([SERVICES_KEY.PROFILE]); @@ -117,7 +111,7 @@ class ProfileScreen extends React.Component { * * @returns {*} */ - getHeaderButton = (): React.Node => ( + getHeaderButton = () => ( { * @param data The data fetched from the server * @returns {*} */ - getScreen = (data: Array): React.Node => { + getScreen = (data: Array) => { const {dialogVisible} = this.state; - const {navigation} = this.props; - // eslint-disable-next-line prefer-destructuring - if (data[0] != null) this.data = data[0]; - + this.data = data[0]; return ( { data={this.flatListData} /> @@ -154,7 +144,7 @@ class ProfileScreen extends React.Component { ); }; - getRenderItem = ({item}: {item: {id: string}}): React.Node => { + getRenderItem = ({item}: {item: {id: string}}) => { switch (item.id) { case '0': return this.getWelcomeCard(); @@ -172,7 +162,7 @@ class ProfileScreen extends React.Component { * * @returns {*} */ - getServicesList(): React.Node { + getServicesList() { return ; } @@ -181,15 +171,15 @@ class ProfileScreen extends React.Component { * * @returns {*} */ - getWelcomeCard(): React.Node { + getWelcomeCard() { const {navigation} = this.props; return ( ( + left={() => ( { * @param field The field to get the value from * @return {*} */ - static getFieldValue(field: ?string): string { - return field != null ? field : i18n.t('screens.profile.noData'); + static getFieldValue(field?: string): string { + return field ? field : i18n.t('screens.profile.noData'); } /** @@ -244,7 +234,7 @@ class ProfileScreen extends React.Component { * @param icon The icon to use * @return {*} */ - getPersonalListItem(field: ?string, icon: string): React.Node { + getPersonalListItem(field: string | undefined, icon: string) { const {theme} = this.props; const title = field != null ? ProfileScreen.getFieldValue(field) : ':('; const subtitle = field != null ? '' : ProfileScreen.getFieldValue(field); @@ -252,7 +242,7 @@ class ProfileScreen extends React.Component { ( + left={(props) => ( { * * @return {*} */ - getPersonalCard(): React.Node { + getPersonalCard() { const {theme, navigation} = this.props; return ( ( + title={`${this.data?.first_name} ${this.data?.last_name}`} + subtitle={this.data?.email} + left={(iconProps) => ( { {i18n.t('screens.profile.personalInformation')} - {this.getPersonalListItem(this.data.birthday, 'cake-variant')} - {this.getPersonalListItem(this.data.phone, 'phone')} - {this.getPersonalListItem(this.data.email, 'email')} - {this.getPersonalListItem(this.data.branch, 'school')} + {this.getPersonalListItem(this.data?.birthday, 'cake-variant')} + {this.getPersonalListItem(this.data?.phone, 'phone')} + {this.getPersonalListItem(this.data?.email, 'email')} + {this.getPersonalListItem(this.data?.branch, 'school')} @@ -303,7 +293,7 @@ class ProfileScreen extends React.Component { onPress={() => { navigation.navigate('website', { host: AvailableWebsites.websites.AMICALE, - path: this.data.link, + path: this.data?.link, title: i18n.t('screens.websites.amicale'), }); }} @@ -321,14 +311,14 @@ class ProfileScreen extends React.Component { * * @return {*} */ - getClubCard(): React.Node { + getClubCard() { const {theme} = this.props; return ( ( + left={(iconProps) => ( { /> - {this.getClubList(this.data.clubs)} + {this.getClubList(this.data?.clubs)} ); @@ -350,14 +340,14 @@ class ProfileScreen extends React.Component { * * @return {*} */ - getMembershipCar(): React.Node { + getMembershipCar() { const {theme} = this.props; return ( ( + left={(iconProps) => ( { /> - {this.getMembershipItem(this.data.validity)} + {this.getMembershipItem(this.data?.validity === true)} @@ -380,7 +370,7 @@ class ProfileScreen extends React.Component { * * @return {*} */ - getMembershipItem(state: boolean): React.Node { + getMembershipItem(state: boolean) { const {theme} = this.props; return ( { ? i18n.t('screens.profile.membershipPayed') : i18n.t('screens.profile.membershipNotPayed') } - left={(props: ListIconPropsType): React.Node => ( + left={(props) => ( { * @param item The club to render * @return {*} */ - getClubListItem = ({item}: {item: ClubType}): React.Node => { + getClubListItem = ({item}: {item: ClubType}) => { const {theme} = this.props; const onPress = () => { this.openClubDetailsScreen(item.id); }; let description = i18n.t('screens.profile.isMember'); - let icon = (props: ListIconPropsType): React.Node => ( + let icon = (props: { + color: string; + style: { + marginLeft: number; + marginRight: number; + marginVertical?: number; + }; + }) => ( ); if (item.is_manager) { description = i18n.t('screens.profile.isManager'); - icon = (props: ListIconPropsType): React.Node => ( + icon = (props) => ( { * @param list The club list * @return {*} */ - getClubList(list: Array): React.Node { + getClubList(list: Array | undefined) { + if (!list) { + return null; + } + list.sort(this.sortClubList); return ( { navigation.navigate('club-information', {clubId: id}); } - render(): React.Node { + render() { const {navigation} = this.props; return (