Application Android et IOS pour l'amicale des élèves
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.

ServicesScreen.js 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // @flow
  2. import * as React from 'react';
  3. import type {cardList} from "../../components/Lists/CardList/CardList";
  4. import CardList from "../../components/Lists/CardList/CardList";
  5. import CustomTabBar from "../../components/Tabbar/CustomTabBar";
  6. import {withCollapsible} from "../../utils/withCollapsible";
  7. import {Collapsible} from "react-navigation-collapsible";
  8. import {Animated, Image, View} from "react-native";
  9. import {Avatar, Card, Divider, List, TouchableRipple, withTheme} from "react-native-paper";
  10. import type {CustomTheme} from "../../managers/ThemeManager";
  11. import i18n from 'i18n-js';
  12. import MaterialHeaderButtons, {Item} from "../../components/Overrides/CustomHeaderButton";
  13. import ConnectionManager from "../../managers/ConnectionManager";
  14. import {StackNavigationProp} from "@react-navigation/stack";
  15. import {MASCOT_STYLE} from "../../components/Mascot/Mascot";
  16. import MascotPopup from "../../components/Mascot/MascotPopup";
  17. import AsyncStorageManager from "../../managers/AsyncStorageManager";
  18. import ServicesManager from "../../managers/ServicesManager";
  19. type Props = {
  20. navigation: StackNavigationProp,
  21. collapsibleStack: Collapsible,
  22. theme: CustomTheme,
  23. }
  24. type State = {
  25. mascotDialogVisible: boolean,
  26. }
  27. export type listItem = {
  28. title: string,
  29. description: string,
  30. image: string | number,
  31. content: cardList,
  32. }
  33. const AMICALE_LOGO = require("../../../assets/amicale.png");
  34. class ServicesScreen extends React.Component<Props, State> {
  35. amicaleDataset: cardList;
  36. studentsDataset: cardList;
  37. insaDataset: cardList;
  38. finalDataset: Array<listItem>
  39. state = {
  40. mascotDialogVisible: AsyncStorageManager.getInstance().preferences.servicesShowBanner.current === "1"
  41. }
  42. constructor(props) {
  43. super(props);
  44. const services = new ServicesManager(props.navigation);
  45. this.amicaleDataset = services.getAmicaleServices();
  46. this.studentsDataset = services.getStudentServices();
  47. this.insaDataset = services.getINSAServices();
  48. this.finalDataset = [
  49. {
  50. title: i18n.t("screens.services.categories.amicale"),
  51. description: i18n.t("screens.services.more"),
  52. image: AMICALE_LOGO,
  53. content: this.amicaleDataset
  54. },
  55. {
  56. title: i18n.t("screens.services.categories.students"),
  57. description: i18n.t("screens.services.more"),
  58. image: 'account-group',
  59. content: this.studentsDataset
  60. },
  61. {
  62. title: i18n.t("screens.services.categories.insa"),
  63. description: i18n.t("screens.services.more"),
  64. image: 'school',
  65. content: this.insaDataset
  66. },
  67. ];
  68. }
  69. componentDidMount() {
  70. this.props.navigation.setOptions({
  71. headerRight: this.getAboutButton,
  72. });
  73. }
  74. /**
  75. * Callback used when closing the banner.
  76. * This hides the banner and saves to preferences to prevent it from reopening
  77. */
  78. onHideMascotDialog = () => {
  79. this.setState({mascotDialogVisible: false});
  80. AsyncStorageManager.getInstance().savePref(
  81. AsyncStorageManager.getInstance().preferences.servicesShowBanner.key,
  82. '0'
  83. );
  84. };
  85. getAboutButton = () =>
  86. <MaterialHeaderButtons>
  87. <Item title="information" iconName="information" onPress={this.onAboutPress}/>
  88. </MaterialHeaderButtons>;
  89. onAboutPress = () => this.props.navigation.navigate('amicale-contact');
  90. /**
  91. * Gets the list title image for the list.
  92. *
  93. * If the source is a string, we are using an icon.
  94. * If the source is a number, we are using an internal image.
  95. *
  96. * @param props Props to pass to the component
  97. * @param source The source image to display. Can be a string for icons or a number for local images
  98. * @returns {*}
  99. */
  100. getListTitleImage(props, source: string | number) {
  101. if (typeof source === "number")
  102. return <Image
  103. size={48}
  104. source={source}
  105. style={{
  106. width: 48,
  107. height: 48,
  108. }}/>
  109. else
  110. return <Avatar.Icon
  111. {...props}
  112. size={48}
  113. icon={source}
  114. color={this.props.theme.colors.primary}
  115. style={{backgroundColor: 'transparent'}}
  116. />
  117. }
  118. /**
  119. * Redirects to the given route or to the login screen if user is not logged in.
  120. *
  121. * @param route The route to navigate to
  122. */
  123. onAmicaleServicePress(route: string) {
  124. if (ConnectionManager.getInstance().isLoggedIn())
  125. this.props.navigation.navigate(route);
  126. else
  127. this.props.navigation.navigate("login", {nextScreen: route});
  128. }
  129. /**
  130. * A list item showing a list of available services for the current category
  131. *
  132. * @param item
  133. * @returns {*}
  134. */
  135. renderItem = ({item}: { item: listItem }) => {
  136. return (
  137. <TouchableRipple
  138. style={{
  139. margin: 5,
  140. marginBottom: 20,
  141. }}
  142. onPress={() => this.props.navigation.navigate("services-section", {data: item})}
  143. >
  144. <View>
  145. <Card.Title
  146. title={item.title}
  147. subtitle={item.description}
  148. left={(props) => this.getListTitleImage(props, item.image)}
  149. right={(props) => <List.Icon {...props} icon="chevron-right"/>}
  150. />
  151. <CardList
  152. dataset={item.content}
  153. isHorizontal={true}
  154. />
  155. </View>
  156. </TouchableRipple>
  157. );
  158. };
  159. keyExtractor = (item: listItem) => {
  160. return item.title;
  161. }
  162. render() {
  163. const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack;
  164. return (
  165. <View>
  166. <Animated.FlatList
  167. data={this.finalDataset}
  168. renderItem={this.renderItem}
  169. keyExtractor={this.keyExtractor}
  170. onScroll={onScroll}
  171. contentContainerStyle={{
  172. paddingTop: containerPaddingTop,
  173. paddingBottom: CustomTabBar.TAB_BAR_HEIGHT + 20
  174. }}
  175. scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
  176. ItemSeparatorComponent={() => <Divider/>}
  177. />
  178. <MascotPopup
  179. visible={this.state.mascotDialogVisible}
  180. title={i18n.t("screens.services.mascotDialog.title")}
  181. message={i18n.t("screens.services.mascotDialog.message")}
  182. icon={"cloud-question"}
  183. buttons={{
  184. action: null,
  185. cancel: {
  186. message: i18n.t("screens.services.mascotDialog.button"),
  187. icon: "check",
  188. onPress: this.onHideMascotDialog,
  189. }
  190. }}
  191. emotion={MASCOT_STYLE.WINK}
  192. />
  193. </View>
  194. );
  195. }
  196. }
  197. export default withCollapsible(withTheme(ServicesScreen));