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 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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, {SERVICES_CATEGORIES_KEY} 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. class ServicesScreen extends React.Component<Props, State> {
  34. finalDataset: Array<listItem>
  35. state = {
  36. mascotDialogVisible: AsyncStorageManager.getInstance().preferences.servicesShowBanner.current === "1"
  37. }
  38. constructor(props) {
  39. super(props);
  40. const services = new ServicesManager(props.navigation);
  41. this.finalDataset = services.getCategories([SERVICES_CATEGORIES_KEY.SPECIAL])
  42. }
  43. componentDidMount() {
  44. this.props.navigation.setOptions({
  45. headerRight: this.getAboutButton,
  46. });
  47. }
  48. /**
  49. * Callback used when closing the banner.
  50. * This hides the banner and saves to preferences to prevent it from reopening
  51. */
  52. onHideMascotDialog = () => {
  53. this.setState({mascotDialogVisible: false});
  54. AsyncStorageManager.getInstance().savePref(
  55. AsyncStorageManager.getInstance().preferences.servicesShowBanner.key,
  56. '0'
  57. );
  58. };
  59. getAboutButton = () =>
  60. <MaterialHeaderButtons>
  61. <Item title="information" iconName="information" onPress={this.onAboutPress}/>
  62. </MaterialHeaderButtons>;
  63. onAboutPress = () => this.props.navigation.navigate('amicale-contact');
  64. /**
  65. * Gets the list title image for the list.
  66. *
  67. * If the source is a string, we are using an icon.
  68. * If the source is a number, we are using an internal image.
  69. *
  70. * @param props Props to pass to the component
  71. * @param source The source image to display. Can be a string for icons or a number for local images
  72. * @returns {*}
  73. */
  74. getListTitleImage(props, source: string | number) {
  75. if (typeof source === "number")
  76. return <Image
  77. size={48}
  78. source={source}
  79. style={{
  80. width: 48,
  81. height: 48,
  82. }}/>
  83. else
  84. return <Avatar.Icon
  85. {...props}
  86. size={48}
  87. icon={source}
  88. color={this.props.theme.colors.primary}
  89. style={{backgroundColor: 'transparent'}}
  90. />
  91. }
  92. /**
  93. * Redirects to the given route or to the login screen if user is not logged in.
  94. *
  95. * @param route The route to navigate to
  96. */
  97. onAmicaleServicePress(route: string) {
  98. if (ConnectionManager.getInstance().isLoggedIn())
  99. this.props.navigation.navigate(route);
  100. else
  101. this.props.navigation.navigate("login", {nextScreen: route});
  102. }
  103. /**
  104. * A list item showing a list of available services for the current category
  105. *
  106. * @param item
  107. * @returns {*}
  108. */
  109. renderItem = ({item}: { item: listItem }) => {
  110. return (
  111. <TouchableRipple
  112. style={{
  113. margin: 5,
  114. marginBottom: 20,
  115. }}
  116. onPress={() => this.props.navigation.navigate("services-section", {data: item})}
  117. >
  118. <View>
  119. <Card.Title
  120. title={item.title}
  121. subtitle={item.description}
  122. left={(props) => this.getListTitleImage(props, item.image)}
  123. right={(props) => <List.Icon {...props} icon="chevron-right"/>}
  124. />
  125. <CardList
  126. dataset={item.content}
  127. isHorizontal={true}
  128. />
  129. </View>
  130. </TouchableRipple>
  131. );
  132. };
  133. keyExtractor = (item: listItem) => {
  134. return item.title;
  135. }
  136. render() {
  137. const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack;
  138. return (
  139. <View>
  140. <Animated.FlatList
  141. data={this.finalDataset}
  142. renderItem={this.renderItem}
  143. keyExtractor={this.keyExtractor}
  144. onScroll={onScroll}
  145. contentContainerStyle={{
  146. paddingTop: containerPaddingTop,
  147. paddingBottom: CustomTabBar.TAB_BAR_HEIGHT + 20
  148. }}
  149. scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
  150. ItemSeparatorComponent={() => <Divider/>}
  151. />
  152. <MascotPopup
  153. visible={this.state.mascotDialogVisible}
  154. title={i18n.t("screens.services.mascotDialog.title")}
  155. message={i18n.t("screens.services.mascotDialog.message")}
  156. icon={"cloud-question"}
  157. buttons={{
  158. action: null,
  159. cancel: {
  160. message: i18n.t("screens.services.mascotDialog.button"),
  161. icon: "check",
  162. onPress: this.onHideMascotDialog,
  163. }
  164. }}
  165. emotion={MASCOT_STYLE.WINK}
  166. />
  167. </View>
  168. );
  169. }
  170. }
  171. export default withCollapsible(withTheme(ServicesScreen));