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.

PlanningScreen.js 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // @flow
  2. import * as React from 'react';
  3. import {BackHandler, View} from 'react-native';
  4. import i18n from "i18n-js";
  5. import {LocaleConfig} from 'react-native-calendars';
  6. import {readData} from "../../utils/WebData";
  7. import type {eventObject} from "../../utils/Planning";
  8. import {
  9. generateEventAgenda,
  10. getCurrentDateString,
  11. getDateOnlyString,
  12. getFormattedEventTime,
  13. } from '../../utils/Planning';
  14. import {Avatar, Divider, List} from 'react-native-paper';
  15. import CustomAgenda from "../../components/Overrides/CustomAgenda";
  16. import {StackNavigationProp} from "@react-navigation/stack";
  17. LocaleConfig.locales['fr'] = {
  18. monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
  19. monthNamesShort: ['Janv.', 'Févr.', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil.', 'Août', 'Sept.', 'Oct.', 'Nov.', 'Déc.'],
  20. dayNames: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
  21. dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
  22. today: 'Aujourd\'hui'
  23. };
  24. type Props = {
  25. navigation: StackNavigationProp,
  26. }
  27. type State = {
  28. refreshing: boolean,
  29. agendaItems: Object,
  30. calendarShowing: boolean,
  31. };
  32. const FETCH_URL = "https://www.amicale-insat.fr/api/event/list";
  33. const AGENDA_MONTH_SPAN = 3;
  34. /**
  35. * Class defining the app's planning screen
  36. */
  37. class PlanningScreen extends React.Component<Props, State> {
  38. agendaRef: Object;
  39. lastRefresh: Date;
  40. minTimeBetweenRefresh = 60;
  41. state = {
  42. refreshing: false,
  43. agendaItems: {},
  44. calendarShowing: false,
  45. };
  46. currentDate = getDateOnlyString(getCurrentDateString());
  47. constructor(props: any) {
  48. super(props);
  49. if (i18n.currentLocale().startsWith("fr")) {
  50. LocaleConfig.defaultLocale = 'fr';
  51. }
  52. }
  53. /**
  54. * Captures focus and blur events to hook on android back button
  55. */
  56. componentDidMount() {
  57. this.onRefresh();
  58. this.props.navigation.addListener(
  59. 'focus',
  60. () =>
  61. BackHandler.addEventListener(
  62. 'hardwareBackPress',
  63. this.onBackButtonPressAndroid
  64. )
  65. );
  66. this.props.navigation.addListener(
  67. 'blur',
  68. () =>
  69. BackHandler.removeEventListener(
  70. 'hardwareBackPress',
  71. this.onBackButtonPressAndroid
  72. )
  73. );
  74. }
  75. /**
  76. * Overrides default android back button behaviour to close the calendar if it was open.
  77. *
  78. * @return {boolean}
  79. */
  80. onBackButtonPressAndroid = () => {
  81. if (this.state.calendarShowing) {
  82. this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
  83. return true;
  84. } else {
  85. return false;
  86. }
  87. };
  88. /**
  89. * Function used to check if a row has changed
  90. *
  91. * @param r1
  92. * @param r2
  93. * @return {boolean}
  94. */
  95. rowHasChanged(r1: Object, r2: Object) {
  96. return false;
  97. // if (r1 !== undefined && r2 !== undefined)
  98. // return r1.title !== r2.title;
  99. // else return !(r1 === undefined && r2 === undefined);
  100. }
  101. /**
  102. * Refreshes data and shows an animation while doing it
  103. */
  104. onRefresh = () => {
  105. let canRefresh;
  106. if (this.lastRefresh !== undefined)
  107. canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
  108. else
  109. canRefresh = true;
  110. if (canRefresh) {
  111. this.setState({refreshing: true});
  112. readData(FETCH_URL)
  113. .then((fetchedData) => {
  114. this.setState({
  115. refreshing: false,
  116. agendaItems: generateEventAgenda(fetchedData, AGENDA_MONTH_SPAN)
  117. });
  118. this.lastRefresh = new Date();
  119. })
  120. .catch(() => {
  121. this.setState({
  122. refreshing: false,
  123. });
  124. });
  125. }
  126. };
  127. /**
  128. * Callback used when receiving the agenda ref
  129. *
  130. * @param ref
  131. */
  132. onAgendaRef = (ref: Object) => {
  133. this.agendaRef = ref;
  134. }
  135. /**
  136. * Callback used when a button is pressed to toggle the calendar
  137. *
  138. * @param isCalendarOpened True is the calendar is already open, false otherwise
  139. */
  140. onCalendarToggled = (isCalendarOpened: boolean) => {
  141. this.setState({calendarShowing: isCalendarOpened});
  142. }
  143. /**
  144. * Gets an event render item
  145. *
  146. * @param item The current event to render
  147. * @return {*}
  148. */
  149. getRenderItem = (item: eventObject) => {
  150. const onPress = this.props.navigation.navigate.bind(this, 'planning-information', {data: item});
  151. if (item.logo !== null) {
  152. return (
  153. <View>
  154. <Divider/>
  155. <List.Item
  156. title={item.title}
  157. description={getFormattedEventTime(item["date_begin"], item["date_end"])}
  158. left={() => <Avatar.Image
  159. source={{uri: item.logo}}
  160. style={{backgroundColor: 'transparent'}}
  161. />}
  162. onPress={onPress}
  163. />
  164. </View>
  165. );
  166. } else {
  167. return (
  168. <View>
  169. <Divider/>
  170. <List.Item
  171. title={item.title}
  172. description={getFormattedEventTime(item["date_begin"], item["date_end"])}
  173. onPress={onPress}
  174. />
  175. </View>
  176. );
  177. }
  178. }
  179. /**
  180. * Gets an empty render item for an empty date
  181. *
  182. * @return {*}
  183. */
  184. getRenderEmptyDate = () => <Divider/>;
  185. render() {
  186. return (
  187. <CustomAgenda
  188. {...this.props}
  189. // the list of items that have to be displayed in agenda. If you want to render item as empty date
  190. // the value of date key kas to be an empty array []. If there exists no value for date key it is
  191. // considered that the date in question is not yet loaded
  192. items={this.state.agendaItems}
  193. // initially selected day
  194. selected={this.currentDate}
  195. // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
  196. minDate={this.currentDate}
  197. // Max amount of months allowed to scroll to the past. Default = 50
  198. pastScrollRange={1}
  199. // Max amount of months allowed to scroll to the future. Default = 50
  200. futureScrollRange={AGENDA_MONTH_SPAN}
  201. // If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
  202. onRefresh={this.onRefresh}
  203. // callback that fires when the calendar is opened or closed
  204. onCalendarToggled={this.onCalendarToggled}
  205. // Set this true while waiting for new data from a refresh
  206. refreshing={this.state.refreshing}
  207. renderItem={this.getRenderItem}
  208. renderEmptyDate={this.getRenderEmptyDate}
  209. rowHasChanged={this.rowHasChanged}
  210. // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
  211. firstDay={1}
  212. // ref to this agenda in order to handle back button event
  213. onRef={this.onAgendaRef}
  214. />
  215. );
  216. }
  217. }
  218. export default PlanningScreen;