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

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