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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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, 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 AvailableWebsites from "../../constants/AvailableWebsites";
  16. import {MASCOT_STYLE} from "../../components/Mascot/Mascot";
  17. import MascotPopup from "../../components/Mascot/MascotPopup";
  18. import AsyncStorageManager from "../../managers/AsyncStorageManager";
  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. const CLUBS_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Clubs.png";
  35. const PROFILE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/ProfilAmicaliste.png";
  36. const EQUIPMENT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Materiel.png";
  37. const VOTE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Vote.png";
  38. const AMICALE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/WebsiteAmicale.png";
  39. const PROXIMO_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Proximo.png"
  40. const WIKETUD_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Wiketud.png";
  41. const EE_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/EEC.png";
  42. const TUTORINSA_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/TutorINSA.png";
  43. const BIB_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Bib.png";
  44. const RU_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/RU.png";
  45. const ROOM_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Salles.png";
  46. const EMAIL_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Bluemind.png";
  47. const ENT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/ENT.png";
  48. const ACCOUNT_IMAGE = "https://etud.insa-toulouse.fr/~amicale_app/images/Account.png";
  49. class ServicesScreen extends React.Component<Props, State> {
  50. amicaleDataset: cardList;
  51. studentsDataset: cardList;
  52. insaDataset: cardList;
  53. finalDataset: Array<listItem>
  54. state = {
  55. mascotDialogVisible: AsyncStorageManager.getInstance().preferences.servicesShowBanner.current === "1"
  56. }
  57. constructor(props) {
  58. super(props);
  59. const nav = props.navigation;
  60. this.amicaleDataset = [
  61. {
  62. title: i18n.t('screens.clubs.title'),
  63. subtitle: i18n.t('screens.services.descriptions.clubs'),
  64. image: CLUBS_IMAGE,
  65. onPress: () => this.onAmicaleServicePress("club-list"),
  66. },
  67. {
  68. title: i18n.t('screens.profile.title'),
  69. subtitle: i18n.t('screens.services.descriptions.profile'),
  70. image: PROFILE_IMAGE,
  71. onPress: () => this.onAmicaleServicePress("profile"),
  72. },
  73. {
  74. title: i18n.t('screens.equipment.title'),
  75. subtitle: i18n.t('screens.services.descriptions.equipment'),
  76. image: EQUIPMENT_IMAGE,
  77. onPress: () => this.onAmicaleServicePress("equipment-list"),
  78. },
  79. {
  80. title: i18n.t('screens.websites.amicale'),
  81. subtitle: i18n.t('screens.services.descriptions.amicaleWebsite'),
  82. image: AMICALE_IMAGE,
  83. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.AMICALE, title: i18n.t('screens.websites.amicale')}),
  84. },
  85. {
  86. title: i18n.t('screens.vote.title'),
  87. subtitle: i18n.t('screens.services.descriptions.vote'),
  88. image: VOTE_IMAGE,
  89. onPress: () => this.onAmicaleServicePress("vote"),
  90. },
  91. ];
  92. this.studentsDataset = [
  93. {
  94. title: i18n.t('screens.proximo.title'),
  95. subtitle: i18n.t('screens.services.descriptions.proximo'),
  96. image: PROXIMO_IMAGE,
  97. onPress: () => nav.navigate("proximo"),
  98. },
  99. {
  100. title: "Wiketud",
  101. subtitle: i18n.t('screens.services.descriptions.wiketud'),
  102. image: WIKETUD_IMAGE,
  103. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.WIKETUD, title: "Wiketud"}),
  104. },
  105. {
  106. title: "Élus Étudiants",
  107. subtitle: i18n.t('screens.services.descriptions.elusEtudiants'),
  108. image: EE_IMAGE,
  109. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.ELUS_ETUDIANTS, title: "Élus Étudiants"}),
  110. },
  111. {
  112. title: "Tutor'INSA",
  113. subtitle: i18n.t('screens.services.descriptions.tutorInsa'),
  114. image: TUTORINSA_IMAGE,
  115. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.TUTOR_INSA, title: "Tutor'INSA"})
  116. },
  117. ];
  118. this.insaDataset = [
  119. {
  120. title: i18n.t('screens.menu.title'),
  121. subtitle: i18n.t('screens.services.descriptions.self'),
  122. image: RU_IMAGE,
  123. onPress: () => nav.navigate("self-menu"),
  124. },
  125. {
  126. title: i18n.t('screens.websites.rooms'),
  127. subtitle: i18n.t('screens.services.descriptions.availableRooms'),
  128. image: ROOM_IMAGE,
  129. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.AVAILABLE_ROOMS, title: i18n.t('screens.websites.rooms')}),
  130. },
  131. {
  132. title: i18n.t('screens.websites.bib'),
  133. subtitle: i18n.t('screens.services.descriptions.bib'),
  134. image: BIB_IMAGE,
  135. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.BIB, title: i18n.t('screens.websites.bib')}),
  136. },
  137. {
  138. title: i18n.t('screens.websites.mails'),
  139. subtitle: i18n.t('screens.services.descriptions.mails'),
  140. image: EMAIL_IMAGE,
  141. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.BLUEMIND, title: i18n.t('screens.websites.mails')}),
  142. },
  143. {
  144. title: i18n.t('screens.websites.ent'),
  145. subtitle: i18n.t('screens.services.descriptions.ent'),
  146. image: ENT_IMAGE,
  147. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.ENT, title: i18n.t('screens.websites.ent')}),
  148. },
  149. {
  150. title: i18n.t('screens.insaAccount.title'),
  151. subtitle: i18n.t('screens.services.descriptions.insaAccount'),
  152. image: ACCOUNT_IMAGE,
  153. onPress: () => nav.navigate("website", {host: AvailableWebsites.websites.INSA_ACCOUNT, title: i18n.t('screens.insaAccount.title')}),
  154. },
  155. ];
  156. this.finalDataset = [
  157. {
  158. title: i18n.t("screens.services.categories.amicale"),
  159. description: i18n.t("screens.services.more"),
  160. image: AMICALE_LOGO,
  161. content: this.amicaleDataset
  162. },
  163. {
  164. title: i18n.t("screens.services.categories.students"),
  165. description: i18n.t("screens.services.more"),
  166. image: 'account-group',
  167. content: this.studentsDataset
  168. },
  169. {
  170. title: i18n.t("screens.services.categories.insa"),
  171. description: i18n.t("screens.services.more"),
  172. image: 'school',
  173. content: this.insaDataset
  174. },
  175. ];
  176. }
  177. componentDidMount() {
  178. this.props.navigation.setOptions({
  179. headerRight: this.getAboutButton,
  180. });
  181. }
  182. /**
  183. * Callback used when closing the banner.
  184. * This hides the banner and saves to preferences to prevent it from reopening
  185. */
  186. onHideMascotDialog = () => {
  187. this.setState({mascotDialogVisible: false});
  188. AsyncStorageManager.getInstance().savePref(
  189. AsyncStorageManager.getInstance().preferences.servicesShowBanner.key,
  190. '0'
  191. );
  192. };
  193. getAboutButton = () =>
  194. <MaterialHeaderButtons>
  195. <Item title="information" iconName="information" onPress={this.onAboutPress}/>
  196. </MaterialHeaderButtons>;
  197. onAboutPress = () => this.props.navigation.navigate('amicale-contact');
  198. /**
  199. * Gets the list title image for the list.
  200. *
  201. * If the source is a string, we are using an icon.
  202. * If the source is a number, we are using an internal image.
  203. *
  204. * @param props Props to pass to the component
  205. * @param source The source image to display. Can be a string for icons or a number for local images
  206. * @returns {*}
  207. */
  208. getListTitleImage(props, source: string | number) {
  209. if (typeof source === "number")
  210. return <Avatar.Image
  211. {...props}
  212. size={48}
  213. source={source}
  214. style={{backgroundColor: 'transparent'}}
  215. />
  216. else
  217. return <Avatar.Icon
  218. {...props}
  219. size={48}
  220. icon={source}
  221. color={this.props.theme.colors.primary}
  222. style={{backgroundColor: 'transparent'}}
  223. />
  224. }
  225. /**
  226. * Redirects to the given route or to the login screen if user is not logged in.
  227. *
  228. * @param route The route to navigate to
  229. */
  230. onAmicaleServicePress(route: string) {
  231. if (ConnectionManager.getInstance().isLoggedIn())
  232. this.props.navigation.navigate(route);
  233. else
  234. this.props.navigation.navigate("login", {nextScreen: route});
  235. }
  236. /**
  237. * A list item showing a list of available services for the current category
  238. *
  239. * @param item
  240. * @returns {*}
  241. */
  242. renderItem = ({item}: { item: listItem }) => {
  243. return (
  244. <TouchableRipple
  245. style={{
  246. margin: 5,
  247. marginBottom: 20,
  248. }}
  249. onPress={() => this.props.navigation.navigate("services-section", {data: item})}
  250. >
  251. <View>
  252. <Card.Title
  253. title={item.title}
  254. subtitle={item.description}
  255. left={(props) => this.getListTitleImage(props, item.image)}
  256. right={(props) => <List.Icon {...props} icon="chevron-right"/>}
  257. />
  258. <CardList
  259. dataset={item.content}
  260. isHorizontal={true}
  261. />
  262. </View>
  263. </TouchableRipple>
  264. );
  265. };
  266. keyExtractor = (item: listItem) => {
  267. return item.title;
  268. }
  269. render() {
  270. const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack;
  271. return (
  272. <View>
  273. <Animated.FlatList
  274. data={this.finalDataset}
  275. renderItem={this.renderItem}
  276. keyExtractor={this.keyExtractor}
  277. onScroll={onScroll}
  278. contentContainerStyle={{
  279. paddingTop: containerPaddingTop,
  280. paddingBottom: CustomTabBar.TAB_BAR_HEIGHT + 20
  281. }}
  282. scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
  283. ItemSeparatorComponent={() => <Divider/>}
  284. />
  285. <MascotPopup
  286. visible={this.state.mascotDialogVisible}
  287. title={i18n.t("screens.services.mascotDialog.title")}
  288. message={i18n.t("screens.services.mascotDialog.message")}
  289. icon={"cloud-question"}
  290. buttons={{
  291. action: null,
  292. cancel: {
  293. message: i18n.t("screens.services.mascotDialog.button"),
  294. icon: "check",
  295. onPress: this.onHideMascotDialog,
  296. }
  297. }}
  298. emotion={MASCOT_STYLE.WINK}
  299. />
  300. </View>
  301. );
  302. }
  303. }
  304. export default withCollapsible(withTheme(ServicesScreen));