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.

GroupSelectionScreen.js 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // @flow
  2. import * as React from 'react';
  3. import {Platform} from "react-native";
  4. import i18n from "i18n-js";
  5. import {Searchbar} from "react-native-paper";
  6. import {stringMatchQuery} from "../../utils/Search";
  7. import WebSectionList from "../../components/Screens/WebSectionList";
  8. import GroupListAccordion from "../../components/Lists/PlanexGroups/GroupListAccordion";
  9. import AsyncStorageManager from "../../managers/AsyncStorageManager";
  10. import {StackNavigationProp} from "@react-navigation/stack";
  11. const LIST_ITEM_HEIGHT = 70;
  12. export type group = {
  13. name: string,
  14. id: number,
  15. isFav: boolean,
  16. };
  17. export type groupCategory = {
  18. name: string,
  19. id: number,
  20. content: Array<group>,
  21. };
  22. type Props = {
  23. navigation: StackNavigationProp,
  24. }
  25. type State = {
  26. currentSearchString: string,
  27. favoriteGroups: Array<group>,
  28. };
  29. function sortName(a: group | groupCategory, b: group | groupCategory) {
  30. if (a.name.toLowerCase() < b.name.toLowerCase())
  31. return -1;
  32. if (a.name.toLowerCase() > b.name.toLowerCase())
  33. return 1;
  34. return 0;
  35. }
  36. const GROUPS_URL = 'http://planex.insa-toulouse.fr/wsAdeGrp.php?projectId=1';
  37. const REPLACE_REGEX = /_/g;
  38. /**
  39. * Class defining planex group selection screen.
  40. */
  41. class GroupSelectionScreen extends React.Component<Props, State> {
  42. constructor(props: Props) {
  43. super(props);
  44. this.state = {
  45. currentSearchString: '',
  46. favoriteGroups: JSON.parse(AsyncStorageManager.getInstance().preferences.planexFavoriteGroups.current),
  47. };
  48. }
  49. /**
  50. * Creates the header content
  51. */
  52. componentDidMount() {
  53. this.props.navigation.setOptions({
  54. headerTitle: this.getSearchBar,
  55. headerBackTitleVisible: false,
  56. headerTitleContainerStyle: Platform.OS === 'ios' ?
  57. {marginHorizontal: 0, width: '70%'} :
  58. {marginHorizontal: 0, right: 50, left: 50},
  59. });
  60. }
  61. /**
  62. * Gets the header search bar
  63. *
  64. * @return {*}
  65. */
  66. getSearchBar = () => {
  67. return (
  68. <Searchbar
  69. placeholder={i18n.t('proximoScreen.search')}
  70. onChangeText={this.onSearchStringChange}
  71. />
  72. );
  73. };
  74. /**
  75. * Callback used when the search changes
  76. *
  77. * @param str The new search string
  78. */
  79. onSearchStringChange = (str: string) => {
  80. this.setState({currentSearchString: str})
  81. };
  82. /**
  83. * Callback used when clicking an article in the list.
  84. * It opens the modal to show detailed information about the article
  85. *
  86. * @param item The article pressed
  87. */
  88. onListItemPress = (item: group) => {
  89. this.props.navigation.navigate("planex", {
  90. screen: "index",
  91. params: {group: item}
  92. });
  93. };
  94. /**
  95. * Callback used when the user clicks on the favorite button
  96. *
  97. * @param item The item to add/remove from favorites
  98. */
  99. onListFavoritePress = (item: group) => {
  100. this.updateGroupFavorites(item);
  101. };
  102. /**
  103. * Checks if the given group is in the favorites list
  104. *
  105. * @param group The group to check
  106. * @returns {boolean}
  107. */
  108. isGroupInFavorites(group: group) {
  109. let isFav = false;
  110. for (let i = 0; i < this.state.favoriteGroups.length; i++) {
  111. if (group.id === this.state.favoriteGroups[i].id) {
  112. isFav = true;
  113. break;
  114. }
  115. }
  116. return isFav;
  117. }
  118. /**
  119. * Removes the given group from the given array
  120. *
  121. * @param favorites The array containing favorites groups
  122. * @param group The group to remove from the array
  123. */
  124. removeGroupFromFavorites(favorites: Array<group>, group: group) {
  125. for (let i = 0; i < favorites.length; i++) {
  126. if (group.id === favorites[i].id) {
  127. favorites.splice(i, 1);
  128. break;
  129. }
  130. }
  131. }
  132. /**
  133. * Adds the given group to the given array
  134. *
  135. * @param favorites The array containing favorites groups
  136. * @param group The group to add to the array
  137. */
  138. addGroupToFavorites(favorites: Array<group>, group: group) {
  139. group.isFav = true;
  140. favorites.push(group);
  141. favorites.sort(sortName);
  142. }
  143. /**
  144. * Adds or removes the given group to the favorites list, depending on whether it is already in it or not.
  145. * Favorites are then saved in user preferences
  146. *
  147. * @param group The group to add/remove to favorites
  148. */
  149. updateGroupFavorites(group: group) {
  150. let newFavorites = [...this.state.favoriteGroups]
  151. if (this.isGroupInFavorites(group))
  152. this.removeGroupFromFavorites(newFavorites, group);
  153. else
  154. this.addGroupToFavorites(newFavorites, group);
  155. this.setState({favoriteGroups: newFavorites})
  156. AsyncStorageManager.getInstance().savePref(
  157. AsyncStorageManager.getInstance().preferences.planexFavoriteGroups.key,
  158. JSON.stringify(newFavorites));
  159. }
  160. /**
  161. * Checks whether to display the given group category, depending on user search query
  162. *
  163. * @param item The group category
  164. * @returns {boolean}
  165. */
  166. shouldDisplayAccordion(item: groupCategory) {
  167. let shouldDisplay = false;
  168. for (let i = 0; i < item.content.length; i++) {
  169. if (stringMatchQuery(item.content[i].name, this.state.currentSearchString)) {
  170. shouldDisplay = true;
  171. break;
  172. }
  173. }
  174. return shouldDisplay;
  175. }
  176. /**
  177. * Gets a render item for the given article
  178. *
  179. * @param item The article to render
  180. * @return {*}
  181. */
  182. renderItem = ({item}: { item: groupCategory }) => {
  183. if (this.shouldDisplayAccordion(item)) {
  184. return (
  185. <GroupListAccordion
  186. item={item}
  187. onGroupPress={this.onListItemPress}
  188. onFavoritePress={this.onListFavoritePress}
  189. currentSearchString={this.state.currentSearchString}
  190. favoriteNumber={this.state.favoriteGroups.length}
  191. height={LIST_ITEM_HEIGHT}
  192. />
  193. );
  194. } else
  195. return null;
  196. };
  197. /**
  198. * Generates the dataset to be used in the FlatList.
  199. * This improves formatting of group names, sorts alphabetically the categories, and adds favorites at the top.
  200. *
  201. * @param fetchedData The raw data fetched from the server
  202. * @returns {[]}
  203. */
  204. generateData(fetchedData: { [key: string]: groupCategory }) {
  205. let data = [];
  206. for (let key in fetchedData) {
  207. this.formatGroups(fetchedData[key]);
  208. data.push(fetchedData[key]);
  209. }
  210. data.sort(sortName);
  211. data.unshift({name: i18n.t("planexScreen.favorites"), id: 0, content: this.state.favoriteGroups});
  212. return data;
  213. }
  214. /**
  215. * Replaces underscore by spaces and sets the favorite state of every group in the given category
  216. *
  217. * @param item The category containing groups to format
  218. */
  219. formatGroups(item: groupCategory) {
  220. for (let i = 0; i < item.content.length; i++) {
  221. item.content[i].name = item.content[i].name.replace(REPLACE_REGEX, " ")
  222. item.content[i].isFav = this.isGroupInFavorites(item.content[i]);
  223. }
  224. }
  225. /**
  226. * Creates the dataset to be used in the FlatList
  227. *
  228. * @param fetchedData
  229. * @return {*}
  230. * */
  231. createDataset = (fetchedData: { [key: string]: groupCategory }) => {
  232. return [
  233. {
  234. title: '',
  235. data: this.generateData(fetchedData)
  236. }
  237. ];
  238. }
  239. render() {
  240. return (
  241. <WebSectionList
  242. {...this.props}
  243. createDataset={this.createDataset}
  244. autoRefreshTime={0}
  245. refreshOnFocus={false}
  246. fetchUrl={GROUPS_URL}
  247. renderItem={this.renderItem}
  248. updateData={this.state.currentSearchString + this.state.favoriteGroups.length}
  249. itemHeight={LIST_ITEM_HEIGHT}
  250. />
  251. );
  252. }
  253. }
  254. export default GroupSelectionScreen;