forked from vergnet/application-amicale
Improved flow typing
This commit is contained in:
parent
7f24eb77ac
commit
dc3aed8bda
6 changed files with 103 additions and 83 deletions
|
@ -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<Props> {
|
||||
|
||||
|
||||
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;
|
||||
|
|
|
@ -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<Props> {
|
||||
|
||||
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<Props> {
|
|||
getCategoriesRender(categories: Array<number | null>) {
|
||||
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(
|
||||
<Chip
|
||||
style={{marginRight: 5, marginBottom: 5}}
|
||||
|
@ -46,6 +47,7 @@ class ClubListItem extends React.Component<Props> {
|
|||
|
||||
render() {
|
||||
const categoriesRender = this.getCategoriesRender.bind(this, this.props.item.category);
|
||||
const colors = this.props.theme.colors;
|
||||
return (
|
||||
<List.Item
|
||||
title={this.props.item.name}
|
||||
|
@ -65,7 +67,7 @@ class ClubListItem extends React.Component<Props> {
|
|||
}}
|
||||
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,
|
||||
|
|
|
@ -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<Props, State> {
|
||||
|
||||
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<Props, State> {
|
|||
|| (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 (
|
||||
<GroupListItem
|
||||
height={LIST_ITEM_HEIGHT}
|
||||
item={item}
|
||||
onPress={onPress}
|
||||
onStartPress={onStartPress}/>
|
||||
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<Props, State> {
|
|||
: null}
|
||||
unmountWhenCollapsed={true}// Only render list if expanded for increased performance
|
||||
>
|
||||
{/*$FlowFixMe*/}
|
||||
<FlatList
|
||||
data={item.content}
|
||||
extraData={this.props.currentSearchString}
|
||||
renderItem={this.renderItem}
|
||||
keyExtractor={this.keyExtractor}
|
||||
listKey={item.id}
|
||||
listKey={item.id.toString()}
|
||||
// Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
|
||||
getItemLayout={this.itemLayout} // Broken with search
|
||||
removeClippedSubviews={true}
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import {IconButton, List, withTheme} from 'react-native-paper';
|
||||
import type {CustomTheme} from "../../../managers/ThemeManager";
|
||||
import type {group} from "../../../screens/Planex/GroupSelectionScreen";
|
||||
|
||||
type Props = {
|
||||
theme: Object,
|
||||
onPress: Function,
|
||||
onStartPress: Function,
|
||||
item: Object,
|
||||
theme: CustomTheme,
|
||||
onPress: () => void,
|
||||
onStarPress: () => void,
|
||||
item: group,
|
||||
height: number,
|
||||
}
|
||||
|
||||
|
@ -17,11 +19,8 @@ type State = {
|
|||
|
||||
class GroupListItem extends React.Component<Props, State> {
|
||||
|
||||
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<Props, State> {
|
|||
|
||||
onStarPress = () => {
|
||||
this.setState({isFav: !this.state.isFav});
|
||||
this.props.onStartPress();
|
||||
this.props.onStarPress();
|
||||
}
|
||||
|
||||
render() {
|
||||
const colors = this.props.theme.colors;
|
||||
return (
|
||||
<List.Item
|
||||
title={this.props.item.name}
|
||||
|
@ -51,7 +51,7 @@ class GroupListItem extends React.Component<Props, State> {
|
|||
icon={"star"}
|
||||
onPress={this.onStarPress}
|
||||
color={this.state.isFav
|
||||
? this.props.theme.colors.tetrisScore
|
||||
? colors.tetrisScore
|
||||
: props.color}
|
||||
/>}
|
||||
style={{
|
||||
|
|
|
@ -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<string>,
|
||||
};
|
||||
|
||||
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<Props, State> {
|
|||
currentSearchString: '',
|
||||
};
|
||||
|
||||
colors: Object;
|
||||
|
||||
categories: Array<Object>;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.colors = props.theme.colors;
|
||||
}
|
||||
categories: Array<category>;
|
||||
|
||||
/**
|
||||
* Creates the header content
|
||||
|
@ -88,19 +99,25 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
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<category>, clubs: Array<club>} | 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
|
||||
<Animated.FlatList
|
||||
data={data[0].clubs}
|
||||
data={clubList}
|
||||
keyExtractor={this.keyExtractor}
|
||||
renderItem={this.getRenderItem}
|
||||
ListHeaderComponent={this.getListHeader()}
|
||||
|
@ -138,7 +155,7 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
})
|
||||
}
|
||||
|
||||
getChipRender = (category: Object, key: string) => {
|
||||
getChipRender = (category: category, key: string) => {
|
||||
const onPress = this.onChipSelect.bind(this, category.id);
|
||||
return <Chip
|
||||
selected={isItemInCategoryFilter(this.state.currentlySelectedCategories, [category.id])}
|
||||
|
@ -165,7 +182,7 @@ class ClubListScreen extends React.Component<Props, State> {
|
|||
}
|
||||
};
|
||||
|
||||
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<Props, State> {
|
|||
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<Props, State> {
|
|||
*
|
||||
* @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<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withCollapsible(withTheme(ClubListScreen));
|
||||
export default withCollapsible(ClubListScreen);
|
||||
|
|
|
@ -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<group>,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
navigation: Object,
|
||||
route: Object,
|
||||
theme: Object,
|
||||
navigation: StackNavigationProp,
|
||||
}
|
||||
|
||||
type State = {
|
||||
currentSearchString: string,
|
||||
favoriteGroups: Array<Object>,
|
||||
favoriteGroups: Array<group>,
|
||||
};
|
||||
|
||||
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<Props, State> {
|
||||
|
||||
constructor(props) {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentSearchString: '',
|
||||
|
@ -88,18 +99,18 @@ class GroupSelectionScreen extends React.Component<Props, State> {
|
|||
*
|
||||
* @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<Props, State> {
|
|||
return isFav;
|
||||
}
|
||||
|
||||
removeGroupFromFavorites(favorites: Array<Object>, group: Object) {
|
||||
removeGroupFromFavorites(favorites: Array<group>, 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<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
addGroupToFavorites(favorites: Array<Object>, group: Object) {
|
||||
addGroupToFavorites(favorites: Array<group>, 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<Props, State> {
|
|||
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<Props, State> {
|
|||
* @param item The article to render
|
||||
* @return {*}
|
||||
*/
|
||||
renderItem = ({item}: Object) => {
|
||||
renderItem = ({item}: { item: groupCategory }) => {
|
||||
if (this.shouldDisplayAccordion(item)) {
|
||||
return (
|
||||
<GroupListAccordion
|
||||
|
@ -170,18 +181,18 @@ class GroupSelectionScreen extends React.Component<Props, State> {
|
|||
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<Props, State> {
|
|||
* @param fetchedData
|
||||
* @return {*}
|
||||
* */
|
||||
createDataset = (fetchedData: Object) => {
|
||||
createDataset = (fetchedData: { [key: string]: groupCategory }) => {
|
||||
return [
|
||||
{
|
||||
title: '',
|
||||
|
@ -219,4 +230,4 @@ class GroupSelectionScreen extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withTheme(GroupSelectionScreen);
|
||||
export default GroupSelectionScreen;
|
||||
|
|
Loading…
Reference in a new issue