From dc3aed8bdacb2d234b88bac760d08cacf96b5c81 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Mon, 20 Apr 2020 09:29:21 +0200 Subject: [PATCH] Improved flow typing --- src/components/Lists/Clubs/ClubListHeader.js | 12 +--- src/components/Lists/Clubs/ClubListItem.js | 18 +++--- .../Lists/PlanexGroups/GroupListAccordion.js | 28 ++++----- .../Lists/PlanexGroups/GroupListItem.js | 18 +++--- src/screens/Amicale/Clubs/ClubListScreen.js | 59 ++++++++++++------- src/screens/Planex/GroupSelectionScreen.js | 51 +++++++++------- 6 files changed, 103 insertions(+), 83 deletions(-) diff --git a/src/components/Lists/Clubs/ClubListHeader.js b/src/components/Lists/Clubs/ClubListHeader.js index edb91b3..7028742 100644 --- a/src/components/Lists/Clubs/ClubListHeader.js +++ b/src/components/Lists/Clubs/ClubListHeader.js @@ -1,7 +1,7 @@ // @flow import * as React from 'react'; -import {Card, List, Text, withTheme} from 'react-native-paper'; +import {Card, List, Text} from 'react-native-paper'; import {StyleSheet, View} from "react-native"; import i18n from 'i18n-js'; import AnimatedAccordion from "../../Animations/AnimatedAccordion"; @@ -13,14 +13,6 @@ type Props = { class ClubListHeader extends React.Component { - - colors: Object; - - constructor(props) { - super(props); - this.colors = props.theme.colors; - } - getCategoriesRender() { let final = []; for (let i = 0; i < this.props.categories.length; i++) { @@ -67,4 +59,4 @@ const styles = StyleSheet.create({ }, }); -export default withTheme(ClubListHeader); +export default ClubListHeader; diff --git a/src/components/Lists/Clubs/ClubListItem.js b/src/components/Lists/Clubs/ClubListItem.js index a72ed8a..2231e77 100644 --- a/src/components/Lists/Clubs/ClubListItem.js +++ b/src/components/Lists/Clubs/ClubListItem.js @@ -3,22 +3,23 @@ import * as React from 'react'; import {Avatar, Chip, List, withTheme} from 'react-native-paper'; import {View} from "react-native"; +import type {category, club} from "../../../screens/Amicale/Clubs/ClubListScreen"; +import type {CustomTheme} from "../../../managers/ThemeManager"; type Props = { - onPress: Function, - categoryTranslator: Function, - item: Object, + onPress: () => void, + categoryTranslator: (id: number) => category, + item: club, height: number, + theme: CustomTheme, } class ClubListItem extends React.Component { - colors: Object; hasManagers: boolean; constructor(props) { super(props); - this.colors = props.theme.colors; this.hasManagers = props.item.responsibles.length > 0; } @@ -29,8 +30,8 @@ class ClubListItem extends React.Component { getCategoriesRender(categories: Array) { let final = []; for (let i = 0; i < categories.length; i++) { - if (categories[i] !== null){ - const category = this.props.categoryTranslator(categories[i]); + if (categories[i] !== null) { + const category: category = this.props.categoryTranslator(categories[i]); final.push( { render() { const categoriesRender = this.getCategoriesRender.bind(this, this.props.item.category); + const colors = this.props.theme.colors; return ( { }} size={48} icon={this.hasManagers ? "check-circle-outline" : "alert-circle-outline"} - color={this.hasManagers ? this.colors.success : this.colors.primary} + color={this.hasManagers ? colors.success : colors.primary} />} style={{ height: this.props.height, diff --git a/src/components/Lists/PlanexGroups/GroupListAccordion.js b/src/components/Lists/PlanexGroups/GroupListAccordion.js index bf3875c..552f4c4 100644 --- a/src/components/Lists/PlanexGroups/GroupListAccordion.js +++ b/src/components/Lists/PlanexGroups/GroupListAccordion.js @@ -4,18 +4,19 @@ import * as React from 'react'; import {List, withTheme} from 'react-native-paper'; import {FlatList, View} from "react-native"; import {stringMatchQuery} from "../../../utils/Search"; -import * as Animatable from "react-native-animatable"; import GroupListItem from "./GroupListItem"; import AnimatedAccordion from "../../Animations/AnimatedAccordion"; +import type {group, groupCategory} from "../../../screens/Planex/GroupSelectionScreen"; +import type {CustomTheme} from "../../../managers/ThemeManager"; type Props = { - item: Object, - onGroupPress: Function, - onFavoritePress: Function, + item: groupCategory, + onGroupPress: (group) => void, + onFavoritePress: (group) => void, currentSearchString: string, favoriteNumber: number, height: number, - theme: Object, + theme: CustomTheme, } type State = { @@ -23,18 +24,14 @@ type State = { } const LIST_ITEM_HEIGHT = 64; -const AnimatedListIcon = Animatable.createAnimatableComponent(List.Icon); class GroupListAccordion extends React.Component { - chevronRef: Object; - constructor(props) { super(props); this.state = { expanded: props.item.id === "0", } - this.chevronRef = React.createRef(); } shouldComponentUpdate(nextProps: Props, nextSate: State) { @@ -47,24 +44,24 @@ class GroupListAccordion extends React.Component { || (nextProps.item.content.length !== this.props.item.content.length); } - keyExtractor = (item: Object) => item.id.toString(); + keyExtractor = (item: group) => item.id.toString(); - renderItem = ({item}: Object) => { + renderItem = ({item}: {item: group}) => { if (stringMatchQuery(item.name, this.props.currentSearchString)) { const onPress = () => this.props.onGroupPress(item); - const onStartPress = () => this.props.onFavoritePress(item); + const onStarPress = () => this.props.onFavoritePress(item); return ( + onStarPress={onStarPress}/> ); } else return null; } - itemLayout = (data: Object, index: number) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index}); + itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index}); render() { const item = this.props.item; @@ -86,12 +83,13 @@ class GroupListAccordion extends React.Component { : null} unmountWhenCollapsed={true}// Only render list if expanded for increased performance > + {/*$FlowFixMe*/} void, + onStarPress: () => void, + item: group, height: number, } @@ -17,11 +19,8 @@ type State = { class GroupListItem extends React.Component { - colors: Object; - constructor(props) { super(props); - this.colors = props.theme.colors; this.state = { isFav: (props.item.isFav !== undefined && props.item.isFav), } @@ -33,10 +32,11 @@ class GroupListItem extends React.Component { onStarPress = () => { this.setState({isFav: !this.state.isFav}); - this.props.onStartPress(); + this.props.onStarPress(); } render() { + const colors = this.props.theme.colors; return ( { icon={"star"} onPress={this.onStarPress} color={this.state.isFav - ? this.props.theme.colors.tetrisScore + ? colors.tetrisScore : props.color} />} style={{ diff --git a/src/screens/Amicale/Clubs/ClubListScreen.js b/src/screens/Amicale/Clubs/ClubListScreen.js index 6255c1d..be3146a 100644 --- a/src/screens/Amicale/Clubs/ClubListScreen.js +++ b/src/screens/Amicale/Clubs/ClubListScreen.js @@ -2,7 +2,7 @@ import * as React from 'react'; import {Animated, Platform} from "react-native"; -import {Chip, Searchbar, withTheme} from 'react-native-paper'; +import {Chip, Searchbar} from 'react-native-paper'; import AuthenticatedScreen from "../../../components/Amicale/AuthenticatedScreen"; import i18n from "i18n-js"; import ClubListItem from "../../../components/Lists/Clubs/ClubListItem"; @@ -10,11 +10,29 @@ import {isItemInCategoryFilter, stringMatchQuery} from "../../../utils/Search"; import ClubListHeader from "../../../components/Lists/Clubs/ClubListHeader"; import MaterialHeaderButtons, {Item} from "../../../components/Overrides/CustomHeaderButton"; import {withCollapsible} from "../../../utils/withCollapsible"; +import {StackNavigationProp} from "@react-navigation/stack"; +import type {CustomTheme} from "../../../managers/ThemeManager"; +import {Collapsible} from "react-navigation-collapsible"; + +export type category = { + id: number, + name: string, +}; + +export type club = { + id: number, + name: string, + description: string, + logo: string, + email:string, + category: [number, number], + responsibles: Array, +}; type Props = { - navigation: Object, - theme: Object, - collapsibleStack: Object, + navigation: StackNavigationProp, + theme: CustomTheme, + collapsibleStack: Collapsible, } type State = { @@ -31,14 +49,7 @@ class ClubListScreen extends React.Component { currentSearchString: '', }; - colors: Object; - - categories: Array; - - constructor(props) { - super(props); - this.colors = props.theme.colors; - } + categories: Array; /** * Creates the header content @@ -88,19 +99,25 @@ class ClubListScreen extends React.Component { this.updateFilteredData(str, null); }; - keyExtractor = (item: Object) => { + keyExtractor = (item: club) => { return item.id.toString(); }; itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index}); - getScreen = (data: Object) => { - this.categories = data[0].categories; + getScreen = (data: Array<{categories: Array, clubs: Array} | null>) => { + let categoryList = []; + let clubList = []; + if (data[0] != null) { + categoryList = data[0].categories; + clubList = data[0].clubs; + } + this.categories = categoryList; const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack; return ( //$FlowFixMe { }) } - getChipRender = (category: Object, key: string) => { + getChipRender = (category: category, key: string) => { const onPress = this.onChipSelect.bind(this, category.id); return { } }; - shouldRenderItem(item) { + shouldRenderItem(item: club) { let shouldRender = this.state.currentlySelectedCategories.length === 0 || isItemInCategoryFilter(this.state.currentlySelectedCategories, item.category); if (shouldRender) @@ -173,7 +190,7 @@ class ClubListScreen extends React.Component { return shouldRender; } - getRenderItem = ({item}: Object) => { + getRenderItem = ({item}: {item: club}) => { const onPress = this.onListItemPress.bind(this, item); if (this.shouldRenderItem(item)) { return ( @@ -194,7 +211,7 @@ class ClubListScreen extends React.Component { * * @param item The article pressed */ - onListItemPress(item: Object) { + onListItemPress(item: club) { this.props.navigation.navigate("club-information", {data: item, categories: this.categories}); } @@ -215,4 +232,4 @@ class ClubListScreen extends React.Component { } } -export default withCollapsible(withTheme(ClubListScreen)); +export default withCollapsible(ClubListScreen); diff --git a/src/screens/Planex/GroupSelectionScreen.js b/src/screens/Planex/GroupSelectionScreen.js index b3dda9f..f522b95 100644 --- a/src/screens/Planex/GroupSelectionScreen.js +++ b/src/screens/Planex/GroupSelectionScreen.js @@ -3,26 +3,37 @@ import * as React from 'react'; import {Platform} from "react-native"; import i18n from "i18n-js"; -import {Searchbar, withTheme} from "react-native-paper"; +import {Searchbar} from "react-native-paper"; import {stringMatchQuery} from "../../utils/Search"; import WebSectionList from "../../components/Screens/WebSectionList"; import GroupListAccordion from "../../components/Lists/PlanexGroups/GroupListAccordion"; import AsyncStorageManager from "../../managers/AsyncStorageManager"; +import {StackNavigationProp} from "@react-navigation/stack"; const LIST_ITEM_HEIGHT = 70; +export type group = { + name: string, + id: number, + isFav: boolean, +}; + +export type groupCategory = { + name: string, + id: number, + content: Array, +}; + type Props = { - navigation: Object, - route: Object, - theme: Object, + navigation: StackNavigationProp, } type State = { currentSearchString: string, - favoriteGroups: Array, + favoriteGroups: Array, }; -function sortName(a, b) { +function sortName(a: group | groupCategory, b: group | groupCategory) { if (a.name.toLowerCase() < b.name.toLowerCase()) return -1; if (a.name.toLowerCase() > b.name.toLowerCase()) @@ -38,7 +49,7 @@ const REPLACE_REGEX = /_/g; */ class GroupSelectionScreen extends React.Component { - constructor(props) { + constructor(props: Props) { super(props); this.state = { currentSearchString: '', @@ -88,18 +99,18 @@ class GroupSelectionScreen extends React.Component { * * @param item The article pressed */ - onListItemPress = (item: Object) => { + onListItemPress = (item: group) => { this.props.navigation.navigate("planex", { screen: "index", params: {group: item} }); }; - onListFavoritePress = (item: Object) => { + onListFavoritePress = (item: group) => { this.updateGroupFavorites(item); }; - isGroupInFavorites(group: Object) { + isGroupInFavorites(group: group) { let isFav = false; for (let i = 0; i < this.state.favoriteGroups.length; i++) { if (group.id === this.state.favoriteGroups[i].id) { @@ -110,7 +121,7 @@ class GroupSelectionScreen extends React.Component { return isFav; } - removeGroupFromFavorites(favorites: Array, group: Object) { + removeGroupFromFavorites(favorites: Array, group: group) { for (let i = 0; i < favorites.length; i++) { if (group.id === favorites[i].id) { favorites.splice(i, 1); @@ -119,13 +130,13 @@ class GroupSelectionScreen extends React.Component { } } - addGroupToFavorites(favorites: Array, group: Object) { + addGroupToFavorites(favorites: Array, group: group) { group.isFav = true; favorites.push(group); favorites.sort(sortName); } - updateGroupFavorites(group: Object) { + updateGroupFavorites(group: group) { let newFavorites = [...this.state.favoriteGroups] if (this.isGroupInFavorites(group)) this.removeGroupFromFavorites(newFavorites, group); @@ -137,7 +148,7 @@ class GroupSelectionScreen extends React.Component { JSON.stringify(newFavorites)); } - shouldDisplayAccordion(item: Object) { + shouldDisplayAccordion(item: groupCategory) { let shouldDisplay = false; for (let i = 0; i < item.content.length; i++) { if (stringMatchQuery(item.content[i].name, this.state.currentSearchString)) { @@ -154,7 +165,7 @@ class GroupSelectionScreen extends React.Component { * @param item The article to render * @return {*} */ - renderItem = ({item}: Object) => { + renderItem = ({item}: { item: groupCategory }) => { if (this.shouldDisplayAccordion(item)) { return ( { return null; }; - generateData(fetchedData: Object) { + generateData(fetchedData: { [key: string]: groupCategory }) { let data = []; for (let key in fetchedData) { this.formatGroups(fetchedData[key]); data.push(fetchedData[key]); } data.sort(sortName); - data.unshift({name: "FAVORITES", id: "0", content: this.state.favoriteGroups}); + data.unshift({name: "FAVORITES", id: 0, content: this.state.favoriteGroups}); return data; } - formatGroups(item: Object) { + formatGroups(item: groupCategory) { for (let i = 0; i < item.content.length; i++) { item.content[i].name = item.content[i].name.replace(REPLACE_REGEX, " ") item.content[i].isFav = this.isGroupInFavorites(item.content[i]); @@ -194,7 +205,7 @@ class GroupSelectionScreen extends React.Component { * @param fetchedData * @return {*} * */ - createDataset = (fetchedData: Object) => { + createDataset = (fetchedData: { [key: string]: groupCategory }) => { return [ { title: '', @@ -219,4 +230,4 @@ class GroupSelectionScreen extends React.Component { } } -export default withTheme(GroupSelectionScreen); +export default GroupSelectionScreen;