Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // @flow
  2. import * as React from 'react';
  3. import {BackHandler, Image} from 'react-native';
  4. import {H3, Text, View} from 'native-base';
  5. import i18n from "i18n-js";
  6. import ThemeManager from "../utils/ThemeManager";
  7. import {Agenda, LocaleConfig} from 'react-native-calendars';
  8. import Touchable from 'react-native-platform-touchable';
  9. import WebDataManager from "../utils/WebDataManager";
  10. import PlanningEventManager from '../utils/PlanningEventManager';
  11. LocaleConfig.locales['fr'] = {
  12. monthNames: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
  13. monthNamesShort: ['Janv.', 'Févr.', 'Mars', 'Avril', 'Mai', 'Juin', 'Juil.', 'Août', 'Sept.', 'Oct.', 'Nov.', 'Déc.'],
  14. dayNames: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
  15. dayNamesShort: ['Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam'],
  16. today: 'Aujourd\'hui'
  17. };
  18. type Props = {
  19. navigation: Object,
  20. }
  21. type State = {
  22. refreshing: boolean,
  23. agendaItems: Object,
  24. calendarShowing: boolean,
  25. };
  26. const FETCH_URL = "https://amicale-insat.fr/event/json/list";
  27. const AGENDA_MONTH_SPAN = 6;
  28. /**
  29. * Class defining the app's planning screen
  30. */
  31. export default class PlanningScreen extends React.Component<Props, State> {
  32. agendaRef: Agenda;
  33. webDataManager: WebDataManager;
  34. lastRefresh: Date;
  35. minTimeBetweenRefresh = 60;
  36. didFocusSubscription: Function;
  37. willBlurSubscription: Function;
  38. state = {
  39. refreshing: false,
  40. agendaItems: {},
  41. calendarShowing: false,
  42. };
  43. onRefresh: Function;
  44. onCalendarToggled: Function;
  45. getRenderItem: Function;
  46. getRenderEmptyDate: Function;
  47. onAgendaRef: Function;
  48. onCalendarToggled: Function;
  49. onBackButtonPressAndroid: Function;
  50. currentDate = this.getCurrentDate();
  51. constructor(props: any) {
  52. super(props);
  53. this.webDataManager = new WebDataManager(FETCH_URL);
  54. this.didFocusSubscription = props.navigation.addListener(
  55. 'didFocus',
  56. () =>
  57. BackHandler.addEventListener(
  58. 'hardwareBackPress',
  59. this.onBackButtonPressAndroid
  60. )
  61. );
  62. if (i18n.currentLocale().startsWith("fr")) {
  63. LocaleConfig.defaultLocale = 'fr';
  64. }
  65. // Create references for functions required in the render function
  66. this.onRefresh = this.onRefresh.bind(this);
  67. this.onCalendarToggled = this.onCalendarToggled.bind(this);
  68. this.getRenderItem = this.getRenderItem.bind(this);
  69. this.getRenderEmptyDate = this.getRenderEmptyDate.bind(this);
  70. this.onAgendaRef = this.onAgendaRef.bind(this);
  71. this.onCalendarToggled = this.onCalendarToggled.bind(this);
  72. this.onBackButtonPressAndroid = this.onBackButtonPressAndroid.bind(this);
  73. }
  74. shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
  75. return nextState.refreshing === false && this.state.refreshing === true ||
  76. nextState.agendaItems !== this.state.agendaItems ||
  77. nextState.calendarShowing !== this.state.calendarShowing;
  78. }
  79. componentDidMount() {
  80. this.onRefresh();
  81. this.willBlurSubscription = this.props.navigation.addListener(
  82. 'willBlur',
  83. () =>
  84. BackHandler.removeEventListener(
  85. 'hardwareBackPress',
  86. this.onBackButtonPressAndroid
  87. )
  88. );
  89. }
  90. onBackButtonPressAndroid() {
  91. if (this.state.calendarShowing) {
  92. this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
  93. return true;
  94. } else {
  95. return false;
  96. }
  97. };
  98. componentWillUnmount() {
  99. this.didFocusSubscription && this.didFocusSubscription.remove();
  100. this.willBlurSubscription && this.willBlurSubscription.remove();
  101. }
  102. getCurrentDate() {
  103. let today = new Date();
  104. return this.getFormattedDate(today);
  105. }
  106. getFormattedDate(date: Date) {
  107. let dd = String(date.getDate()).padStart(2, '0');
  108. let mm = String(date.getMonth() + 1).padStart(2, '0'); //January is 0!
  109. let yyyy = date.getFullYear();
  110. return yyyy + '-' + mm + '-' + dd;
  111. }
  112. generateEmptyCalendar() {
  113. let end = new Date(new Date().setMonth(new Date().getMonth() + AGENDA_MONTH_SPAN + 1));
  114. let daysOfYear = {};
  115. for (let d = new Date(2019, 8, 1); d <= end; d.setDate(d.getDate() + 1)) {
  116. daysOfYear[this.getFormattedDate(new Date(d))] = []
  117. }
  118. return daysOfYear;
  119. }
  120. getRenderItem(item: Object) {
  121. return (
  122. <Touchable
  123. style={{
  124. backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
  125. borderRadius: 10,
  126. marginRight: 10,
  127. marginTop: 17,
  128. }}
  129. onPress={() => this.props.navigation.navigate('PlanningDisplayScreen', {data: item})}>
  130. <View style={{
  131. padding: 10,
  132. flex: 1,
  133. flexDirection: 'row'
  134. }}>
  135. <View style={{
  136. width: item.logo !== null ? '70%' : '100%',
  137. }}>
  138. <Text style={{
  139. color: ThemeManager.getCurrentThemeVariables().listNoteColor,
  140. marginTop: 5,
  141. marginBottom: 10
  142. }}>
  143. {PlanningEventManager.getFormattedTime(item)}
  144. </Text>
  145. <H3 style={{marginBottom: 10}}>{item.title}</H3>
  146. </View>
  147. <View style={{
  148. width: item.logo !== null ? '30%' : 0,
  149. height: 80
  150. }}>
  151. {item.logo !== null ?
  152. <Image source={{uri: item.logo}}
  153. style={{
  154. flex: 1,
  155. resizeMode: "contain"
  156. }}/>
  157. : <View/>}
  158. </View>
  159. </View>
  160. </Touchable>
  161. );
  162. }
  163. getRenderEmptyDate() {
  164. return (
  165. <View style={{
  166. padding: 10,
  167. flex: 1,
  168. }}>
  169. <View style={{
  170. width: '100%',
  171. height: 1,
  172. backgroundColor: ThemeManager.getCurrentThemeVariables().agendaEmptyLine,
  173. marginTop: 'auto',
  174. marginBottom: 'auto',
  175. }}/>
  176. </View>
  177. );
  178. }
  179. rowHasChanged(r1: Object, r2: Object) {
  180. if (r1 !== undefined && r2 !== undefined)
  181. return r1.title !== r2.title;
  182. else return !(r1 === undefined && r2 === undefined);
  183. }
  184. /**
  185. * Refresh data and show a toast if any error occurred
  186. * @private
  187. */
  188. onRefresh = () => {
  189. let canRefresh;
  190. if (this.lastRefresh !== undefined)
  191. canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
  192. else
  193. canRefresh = true;
  194. if (canRefresh) {
  195. this.setState({refreshing: true});
  196. this.webDataManager.readData()
  197. .then((fetchedData) => {
  198. this.setState({
  199. refreshing: false,
  200. });
  201. this.generateEventAgenda(fetchedData);
  202. this.lastRefresh = new Date();
  203. })
  204. .catch((err) => {
  205. this.setState({
  206. refreshing: false,
  207. });
  208. // console.log(err);
  209. });
  210. }
  211. };
  212. generateEventAgenda(eventList: Array<Object>) {
  213. let agendaItems = this.generateEmptyCalendar();
  214. for (let i = 0; i < eventList.length; i++) {
  215. if (agendaItems[PlanningEventManager.getEventStartDate(eventList[i])] !== undefined) {
  216. this.pushEventInOrder(agendaItems, eventList[i], PlanningEventManager.getEventStartDate(eventList[i]));
  217. }
  218. }
  219. this.setState({agendaItems: agendaItems})
  220. }
  221. pushEventInOrder(agendaItems: Object, event: Object, startDate: string) {
  222. if (agendaItems[startDate].length === 0)
  223. agendaItems[startDate].push(event);
  224. else {
  225. for (let i = 0; i < agendaItems[startDate].length; i++) {
  226. if (PlanningEventManager.isEventBefore(event, agendaItems[startDate][i])) {
  227. agendaItems[startDate].splice(i, 0, event);
  228. break;
  229. } else if (i === agendaItems[startDate].length - 1) {
  230. agendaItems[startDate].push(event);
  231. break;
  232. }
  233. }
  234. }
  235. }
  236. onAgendaRef(ref: Agenda) {
  237. this.agendaRef = ref;
  238. }
  239. onCalendarToggled(isCalendarOpened: boolean) {
  240. this.setState({calendarShowing: isCalendarOpened});
  241. }
  242. render() {
  243. // console.log("rendering PlanningScreen");
  244. return (
  245. <Agenda
  246. // the list of items that have to be displayed in agenda. If you want to render item as empty date
  247. // the value of date key kas to be an empty array []. If there exists no value for date key it is
  248. // considered that the date in question is not yet loaded
  249. items={this.state.agendaItems}
  250. // initially selected day
  251. selected={this.currentDate}
  252. // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
  253. minDate={this.currentDate}
  254. // Max amount of months allowed to scroll to the past. Default = 50
  255. pastScrollRange={1}
  256. // Max amount of months allowed to scroll to the future. Default = 50
  257. futureScrollRange={AGENDA_MONTH_SPAN}
  258. // If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
  259. onRefresh={this.onRefresh}
  260. // callback that fires when the calendar is opened or closed
  261. onCalendarToggled={this.onCalendarToggled}
  262. // Set this true while waiting for new data from a refresh
  263. refreshing={this.state.refreshing}
  264. renderItem={this.getRenderItem}
  265. renderEmptyDate={this.getRenderEmptyDate}
  266. rowHasChanged={this.rowHasChanged}
  267. // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
  268. firstDay={1}
  269. // ref to this agenda in order to handle back button event
  270. ref={this.onAgendaRef}
  271. // agenda theme
  272. theme={{
  273. backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor,
  274. calendarBackground: ThemeManager.getCurrentThemeVariables().containerBgColor,
  275. textSectionTitleColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
  276. selectedDayBackgroundColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
  277. selectedDayTextColor: '#ffffff',
  278. todayTextColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
  279. dayTextColor: ThemeManager.getCurrentThemeVariables().textColor,
  280. textDisabledColor: ThemeManager.getCurrentThemeVariables().textDisabledColor,
  281. dotColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
  282. selectedDotColor: '#ffffff',
  283. arrowColor: 'orange',
  284. monthTextColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
  285. indicatorColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
  286. textDayFontWeight: '300',
  287. textMonthFontWeight: 'bold',
  288. textDayHeaderFontWeight: '300',
  289. textDayFontSize: 16,
  290. textMonthFontSize: 16,
  291. textDayHeaderFontSize: 16,
  292. agendaDayTextColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
  293. agendaDayNumColor: ThemeManager.getCurrentThemeVariables().listNoteColor,
  294. agendaTodayColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
  295. agendaKnobColor: ThemeManager.getCurrentThemeVariables().brandPrimary,
  296. }}
  297. />
  298. );
  299. }
  300. }