Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ClubListScreen.js 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // @flow
  2. import * as React from 'react';
  3. import {FlatList, Platform} from "react-native";
  4. import {Chip, Searchbar, withTheme} from 'react-native-paper';
  5. import AuthenticatedScreen from "../../../components/Amicale/AuthenticatedScreen";
  6. import i18n from "i18n-js";
  7. import ClubListItem from "../../../components/Lists/ClubListItem";
  8. import {isItemInCategoryFilter, stringMatchQuery} from "../../../utils/Search";
  9. import ClubListHeader from "../../../components/Lists/ClubListHeader";
  10. import HeaderButton from "../../../components/Custom/HeaderButton";
  11. type Props = {
  12. navigation: Object,
  13. theme: Object,
  14. }
  15. type State = {
  16. currentlySelectedCategories: Array<string>,
  17. currentSearchString: string,
  18. }
  19. const LIST_ITEM_HEIGHT = 96;
  20. class ClubListScreen extends React.Component<Props, State> {
  21. state = {
  22. currentlySelectedCategories: [],
  23. currentSearchString: '',
  24. };
  25. colors: Object;
  26. categories: Array<Object>;
  27. constructor(props) {
  28. super(props);
  29. this.colors = props.theme.colors;
  30. }
  31. /**
  32. * Creates the header content
  33. */
  34. componentDidMount() {
  35. this.props.navigation.setOptions({
  36. headerTitle: this.getSearchBar,
  37. headerRight: this.getHeaderButtons,
  38. headerBackTitleVisible: false,
  39. headerTitleContainerStyle: Platform.OS === 'ios' ?
  40. {marginHorizontal: 0, width: '70%'} :
  41. {marginHorizontal: 0, right: 50, left: 50},
  42. });
  43. }
  44. /**
  45. * Gets the header search bar
  46. *
  47. * @return {*}
  48. */
  49. getSearchBar = () => {
  50. return (
  51. <Searchbar
  52. placeholder={i18n.t('proximoScreen.search')}
  53. onChangeText={this.onSearchStringChange}
  54. />
  55. );
  56. };
  57. /**
  58. * Gets the header button
  59. * @return {*}
  60. */
  61. getHeaderButtons = () => {
  62. const onPress = () => this.props.navigation.navigate("club-about");
  63. return <HeaderButton icon={'information'} onPress={onPress}/>;
  64. };
  65. /**
  66. * Callback used when the search changes
  67. *
  68. * @param str The new search string
  69. */
  70. onSearchStringChange = (str: string) => {
  71. this.updateFilteredData(str, null);
  72. };
  73. keyExtractor = (item: Object) => {
  74. return item.id.toString();
  75. };
  76. itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
  77. getScreen = (data: Object) => {
  78. this.categories = data[0].categories;
  79. return (
  80. //$FlowFixMe
  81. <FlatList
  82. data={data[0].clubs}
  83. keyExtractor={this.keyExtractor}
  84. renderItem={this.getRenderItem}
  85. ListHeaderComponent={this.getListHeader()}
  86. // Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
  87. removeClippedSubviews={true}
  88. getItemLayout={this.itemLayout}
  89. />
  90. )
  91. };
  92. onChipSelect(id: string) {
  93. this.updateFilteredData(null, id);
  94. }
  95. updateFilteredData(filterStr: string | null, categoryId: string | null) {
  96. let newCategoriesState = [...this.state.currentlySelectedCategories];
  97. let newStrState = this.state.currentSearchString;
  98. if (filterStr !== null)
  99. newStrState = filterStr;
  100. if (categoryId !== null) {
  101. let index = newCategoriesState.indexOf(categoryId);
  102. if (index === -1)
  103. newCategoriesState.push(categoryId);
  104. else
  105. newCategoriesState.splice(index, 1);
  106. }
  107. if (filterStr !== null || categoryId !== null)
  108. this.setState({
  109. currentSearchString: newStrState,
  110. currentlySelectedCategories: newCategoriesState,
  111. })
  112. }
  113. getChipRender = (category: Object, key: string) => {
  114. const onPress = this.onChipSelect.bind(this, category.id);
  115. return <Chip
  116. selected={isItemInCategoryFilter(this.state.currentlySelectedCategories, [category.id])}
  117. mode={'outlined'}
  118. onPress={onPress}
  119. style={{marginRight: 5, marginBottom: 5}}
  120. key={key}
  121. >
  122. {category.name}
  123. </Chip>;
  124. };
  125. getListHeader() {
  126. return <ClubListHeader
  127. categories={this.categories}
  128. categoryRender={this.getChipRender}
  129. />;
  130. }
  131. getCategoryOfId = (id: number) => {
  132. for (let i = 0; i < this.categories.length; i++) {
  133. if (id === this.categories[i].id)
  134. return this.categories[i];
  135. }
  136. };
  137. shouldRenderItem(item) {
  138. let shouldRender = this.state.currentlySelectedCategories.length === 0
  139. || isItemInCategoryFilter(this.state.currentlySelectedCategories, item.category);
  140. if (shouldRender)
  141. shouldRender = stringMatchQuery(item.name, this.state.currentSearchString);
  142. return shouldRender;
  143. }
  144. getRenderItem = ({item}: Object) => {
  145. const onPress = this.onListItemPress.bind(this, item);
  146. if (this.shouldRenderItem(item)) {
  147. return (
  148. <ClubListItem
  149. categoryTranslator={this.getCategoryOfId}
  150. item={item}
  151. onPress={onPress}
  152. height={LIST_ITEM_HEIGHT}
  153. />
  154. );
  155. } else
  156. return null;
  157. };
  158. /**
  159. * Callback used when clicking an article in the list.
  160. * It opens the modal to show detailed information about the article
  161. *
  162. * @param item The article pressed
  163. */
  164. onListItemPress(item: Object) {
  165. this.props.navigation.navigate("club-information", {data: item, categories: this.categories});
  166. }
  167. render() {
  168. return (
  169. <AuthenticatedScreen
  170. {...this.props}
  171. links={[
  172. {
  173. link: 'clubs/list',
  174. mandatory: true,
  175. }
  176. ]}
  177. renderFunction={this.getScreen}
  178. />
  179. );
  180. }
  181. }
  182. export default withTheme(ClubListScreen);