diff --git a/src/components/Lists/Clubs/ClubListItem.tsx b/src/components/Lists/Clubs/ClubListItem.tsx index ad60cdf..87bae5b 100644 --- a/src/components/Lists/Clubs/ClubListItem.tsx +++ b/src/components/Lists/Clubs/ClubListItem.tsx @@ -27,7 +27,7 @@ import type { type PropsType = { onPress: () => void; - categoryTranslator: (id: number) => ClubCategoryType; + categoryTranslator: (id: number) => ClubCategoryType | null; item: ClubType; height: number; theme: ReactNativePaper.Theme; @@ -50,14 +50,16 @@ class ClubListItem extends React.Component { const final: Array = []; categories.forEach((cat: number | null) => { if (cat != null) { - const category: ClubCategoryType = props.categoryTranslator(cat); - final.push( - - {category.name} - , - ); + const category = props.categoryTranslator(cat); + if (category) { + final.push( + + {category.name} + , + ); + } } }); return {final}; diff --git a/src/screens/Amicale/Clubs/ClubAboutScreen.js b/src/screens/Amicale/Clubs/ClubAboutScreen.js deleted file mode 100644 index 30c73cf..0000000 --- a/src/screens/Amicale/Clubs/ClubAboutScreen.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2019 - 2020 Arnaud Vergnet. - * - * This file is part of Campus INSAT. - * - * Campus INSAT is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Campus INSAT is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Campus INSAT. If not, see . - */ - -// @flow - -import * as React from 'react'; -import {Image, View} from 'react-native'; -import {Card, Avatar, Text, withTheme} from 'react-native-paper'; -import i18n from 'i18n-js'; -import Autolink from 'react-native-autolink'; -import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; -import AMICALE_ICON from '../../../../assets/amicale.png'; -import type {CardTitleIconPropsType} from '../../../constants/PaperStyles'; - -const CONTACT_LINK = 'clubs@amicale-insat.fr'; - -// eslint-disable-next-line react/prefer-stateless-function -class ClubAboutScreen extends React.Component { - render(): React.Node { - return ( - - - - - {i18n.t('screens.clubs.about.text')} - - ( - - )} - /> - - {i18n.t('screens.clubs.about.message')} - - - - - ); - } -} - -export default withTheme(ClubAboutScreen); diff --git a/src/screens/Amicale/Clubs/ClubAboutScreen.tsx b/src/screens/Amicale/Clubs/ClubAboutScreen.tsx new file mode 100644 index 0000000..3164432 --- /dev/null +++ b/src/screens/Amicale/Clubs/ClubAboutScreen.tsx @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019 - 2020 Arnaud Vergnet. + * + * This file is part of Campus INSAT. + * + * Campus INSAT is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Campus INSAT is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Campus INSAT. If not, see . + */ + +import * as React from 'react'; +import {Image, View} from 'react-native'; +import {Card, Avatar, Text} from 'react-native-paper'; +import i18n from 'i18n-js'; +import Autolink from 'react-native-autolink'; +import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; +const AMICALE_ICON = require('../../../../assets/amicale.png'); + +const CONTACT_LINK = 'clubs@amicale-insat.fr'; + +function ClubAboutScreen() { + return ( + + + + + {i18n.t('screens.clubs.about.text')} + + ( + + )} + /> + + {i18n.t('screens.clubs.about.message')} + text={CONTACT_LINK} component={Text} /> + + + + ); +} + +export default ClubAboutScreen; diff --git a/src/screens/Amicale/Clubs/ClubDisplayScreen.js b/src/screens/Amicale/Clubs/ClubDisplayScreen.tsx similarity index 80% rename from src/screens/Amicale/Clubs/ClubDisplayScreen.js rename to src/screens/Amicale/Clubs/ClubDisplayScreen.tsx index f1aa770..43be895 100644 --- a/src/screens/Amicale/Clubs/ClubDisplayScreen.js +++ b/src/screens/Amicale/Clubs/ClubDisplayScreen.tsx @@ -17,8 +17,6 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {Linking, View} from 'react-native'; import { @@ -35,24 +33,20 @@ import AuthenticatedScreen from '../../../components/Amicale/AuthenticatedScreen import CustomHTML from '../../../components/Overrides/CustomHTML'; import CustomTabBar from '../../../components/Tabbar/CustomTabBar'; import type {ClubCategoryType, ClubType} from './ClubListScreen'; -import type {CustomThemeType} from '../../../managers/ThemeManager'; import {ERROR_TYPE} from '../../../utils/WebData'; import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; -import type {ApiGenericDataType} from '../../../utils/WebData'; -import type {CardTitleIconPropsType} from '../../../constants/PaperStyles'; import ImageGalleryButton from '../../../components/Media/ImageGalleryButton'; type PropsType = { - navigation: StackNavigationProp, + navigation: StackNavigationProp; route: { params?: { - data?: ClubType, - categories?: Array, - clubId?: number, - }, - ... - }, - theme: CustomThemeType, + data?: ClubType; + categories?: Array; + clubId?: number; + }; + }; + theme: ReactNativePaper.Theme; }; const AMICALE_MAIL = 'clubs@amicale-insat.fr'; @@ -73,21 +67,20 @@ class ClubDisplayScreen extends React.Component { constructor(props: PropsType) { super(props); - if (props.route.params != null) { - if ( - props.route.params.data != null && - props.route.params.categories != null - ) { - this.displayData = props.route.params.data; - this.categories = props.route.params.categories; - this.clubId = props.route.params.data.id; - this.shouldFetchData = false; - } else if (props.route.params.clubId != null) { - this.displayData = null; - this.categories = null; - this.clubId = props.route.params.clubId; - this.shouldFetchData = true; - } + this.displayData = null; + this.categories = null; + this.clubId = props.route.params?.clubId ? props.route.params.clubId : 0; + this.shouldFetchData = true; + + if ( + props.route.params && + props.route.params.data && + props.route.params.categories + ) { + this.displayData = props.route.params.data; + this.categories = props.route.params.categories; + this.clubId = props.route.params.data.id; + this.shouldFetchData = false; } } @@ -101,7 +94,9 @@ class ClubDisplayScreen extends React.Component { let categoryName = ''; if (this.categories !== null) { this.categories.forEach((item: ClubCategoryType) => { - if (id === item.id) categoryName = item.name; + if (id === item.id) { + categoryName = item.name; + } }); } return categoryName; @@ -113,10 +108,12 @@ class ClubDisplayScreen extends React.Component { * @param categories The categories to display (max 2) * @returns {null|*} */ - getCategoriesRender(categories: Array): React.Node { - if (this.categories == null) return null; + getCategoriesRender(categories: Array) { + if (this.categories == null) { + return null; + } - const final = []; + const final: Array = []; categories.forEach((cat: number | null) => { if (cat != null) { final.push( @@ -136,9 +133,9 @@ class ClubDisplayScreen extends React.Component { * @param email The club contact email * @returns {*} */ - getManagersRender(managers: Array, email: string | null): React.Node { + getManagersRender(managers: Array, email: string | null) { const {props} = this; - const managersListView = []; + const managersListView: Array = []; managers.forEach((item: string) => { managersListView.push({item}); }); @@ -153,7 +150,7 @@ class ClubDisplayScreen extends React.Component { ? i18n.t('screens.clubs.managersSubtitle') : i18n.t('screens.clubs.managersUnavailable') } - left={(iconProps: CardTitleIconPropsType): React.Node => ( + left={(iconProps) => ( { * @param hasManagers True if the club has managers * @returns {*} */ - static getEmailButton( - email: string | null, - hasManagers: boolean, - ): React.Node { + static getEmailButton(email: string | null, hasManagers: boolean) { const destinationEmail = email != null && hasManagers ? email : AMICALE_MAIL; const text = @@ -206,20 +200,15 @@ class ClubDisplayScreen extends React.Component { ); } - getScreen = (response: Array): React.Node => { - const {navigation} = this.props; - let data: ClubType | null = null; - if (response[0] != null) { - [data] = response; - this.updateHeaderTitle(data); - } + getScreen = (response: Array) => { + let data: ClubType | null = response[0]; if (data != null) { + this.updateHeaderTitle(data); return ( {this.getCategoriesRender(data.category)} {data.logo !== null ? ( { props.navigation.setOptions({title: data.name}); } - render(): React.Node { + render() { const {props} = this; - if (this.shouldFetchData) + if (this.shouldFetchData) { return ( { ]} /> ); + } return this.getScreen([this.displayData]); } } diff --git a/src/screens/Amicale/Clubs/ClubListScreen.js b/src/screens/Amicale/Clubs/ClubListScreen.tsx similarity index 85% rename from src/screens/Amicale/Clubs/ClubListScreen.js rename to src/screens/Amicale/Clubs/ClubListScreen.tsx index d3a1968..7663bac 100644 --- a/src/screens/Amicale/Clubs/ClubListScreen.js +++ b/src/screens/Amicale/Clubs/ClubListScreen.tsx @@ -17,8 +17,6 @@ * along with Campus INSAT. If not, see . */ -// @flow - import * as React from 'react'; import {Platform} from 'react-native'; import {Searchbar} from 'react-native-paper'; @@ -34,27 +32,27 @@ import MaterialHeaderButtons, { import CollapsibleFlatList from '../../../components/Collapsible/CollapsibleFlatList'; export type ClubCategoryType = { - id: number, - name: string, + id: number; + name: string; }; export type ClubType = { - id: number, - name: string, - description: string, - logo: string, - email: string | null, - category: Array, - responsibles: Array, + id: number; + name: string; + description: string; + logo: string; + email: string | null; + category: Array; + responsibles: Array; }; type PropsType = { - navigation: StackNavigationProp, + navigation: StackNavigationProp; }; type StateType = { - currentlySelectedCategories: Array, - currentSearchString: string, + currentlySelectedCategories: Array; + currentSearchString: string; }; const LIST_ITEM_HEIGHT = 96; @@ -62,8 +60,9 @@ const LIST_ITEM_HEIGHT = 96; class ClubListScreen extends React.Component { categories: Array; - constructor() { - super(); + constructor(props: PropsType) { + super(props); + this.categories = []; this.state = { currentlySelectedCategories: [], currentSearchString: '', @@ -114,7 +113,7 @@ class ClubListScreen extends React.Component { * * @return {*} */ - getSearchBar = (): React.Node => { + getSearchBar = () => { return ( { * Gets the header button * @return {*} */ - getHeaderButtons = (): React.Node => { + getHeaderButtons = () => { const onPress = () => { const {props} = this; props.navigation.navigate('club-about'); @@ -145,12 +144,12 @@ class ClubListScreen extends React.Component { getScreen = ( data: Array<{ - categories: Array, - clubs: Array, + categories: Array; + clubs: Array; } | null>, - ): React.Node => { - let categoryList = []; - let clubList = []; + ) => { + let categoryList: Array = []; + let clubList: Array = []; if (data[0] != null) { categoryList = data[0].categories; clubList = data[0].clubs; @@ -174,7 +173,7 @@ class ClubListScreen extends React.Component { * * @returns {*} */ - getListHeader(): React.Node { + getListHeader() { const {state} = this; return ( { getCategoryOfId = (id: number): ClubCategoryType | null => { let cat = null; this.categories.forEach((item: ClubCategoryType) => { - if (id === item.id) cat = item; + if (id === item.id) { + cat = item; + } }); return cat; }; - getRenderItem = ({item}: {item: ClubType}): React.Node => { + getRenderItem = ({item}: {item: ClubType}) => { const onPress = () => { this.onListItemPress(item); }; @@ -219,9 +220,9 @@ class ClubListScreen extends React.Component { keyExtractor = (item: ClubType): string => item.id.toString(); itemLayout = ( - data: {...}, + data: Array | null | undefined, index: number, - ): {length: number, offset: number, index: number} => ({ + ): {length: number; offset: number; index: number} => ({ length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index, @@ -240,17 +241,23 @@ class ClubListScreen extends React.Component { const {state} = this; const newCategoriesState = [...state.currentlySelectedCategories]; let newStrState = state.currentSearchString; - if (filterStr !== null) newStrState = filterStr; + if (filterStr !== null) { + newStrState = filterStr; + } if (categoryId !== null) { const index = newCategoriesState.indexOf(categoryId); - if (index === -1) newCategoriesState.push(categoryId); - else newCategoriesState.splice(index, 1); + if (index === -1) { + newCategoriesState.push(categoryId); + } else { + newCategoriesState.splice(index, 1); + } } - if (filterStr !== null || categoryId !== null) + if (filterStr !== null || categoryId !== null) { this.setState({ currentSearchString: newStrState, currentlySelectedCategories: newCategoriesState, }); + } } /** @@ -264,12 +271,13 @@ class ClubListScreen extends React.Component { let shouldRender = state.currentlySelectedCategories.length === 0 || isItemInCategoryFilter(state.currentlySelectedCategories, item.category); - if (shouldRender) + if (shouldRender) { shouldRender = stringMatchQuery(item.name, state.currentSearchString); + } return shouldRender; } - render(): React.Node { + render() { const {props} = this; return (