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.

EquipmentListScreen.tsx 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import * as React from 'react';
  20. import {View} from 'react-native';
  21. import {Button} from 'react-native-paper';
  22. import {StackNavigationProp} from '@react-navigation/stack';
  23. import i18n from 'i18n-js';
  24. import AuthenticatedScreen from '../../../components/Amicale/AuthenticatedScreen';
  25. import EquipmentListItem from '../../../components/Lists/Equipment/EquipmentListItem';
  26. import MascotPopup from '../../../components/Mascot/MascotPopup';
  27. import {MASCOT_STYLE} from '../../../components/Mascot/Mascot';
  28. import AsyncStorageManager from '../../../managers/AsyncStorageManager';
  29. import CollapsibleFlatList from '../../../components/Collapsible/CollapsibleFlatList';
  30. type PropsType = {
  31. navigation: StackNavigationProp<any>;
  32. };
  33. type StateType = {
  34. mascotDialogVisible: boolean;
  35. };
  36. export type DeviceType = {
  37. id: number;
  38. name: string;
  39. caution: number;
  40. booked_at: Array<{begin: string; end: string}>;
  41. };
  42. export type RentedDeviceType = {
  43. device_id: number;
  44. device_name: string;
  45. begin: string;
  46. end: string;
  47. };
  48. const LIST_ITEM_HEIGHT = 64;
  49. class EquipmentListScreen extends React.Component<PropsType, StateType> {
  50. userRents: null | Array<RentedDeviceType>;
  51. authRef: {current: null | AuthenticatedScreen<any>};
  52. canRefresh: boolean;
  53. constructor(props: PropsType) {
  54. super(props);
  55. this.userRents = null;
  56. this.state = {
  57. mascotDialogVisible: AsyncStorageManager.getBool(
  58. AsyncStorageManager.PREFERENCES.equipmentShowMascot.key,
  59. ),
  60. };
  61. this.canRefresh = false;
  62. this.authRef = React.createRef();
  63. props.navigation.addListener('focus', this.onScreenFocus);
  64. }
  65. onScreenFocus = () => {
  66. if (
  67. this.canRefresh &&
  68. this.authRef.current &&
  69. this.authRef.current.reload
  70. ) {
  71. this.authRef.current.reload();
  72. }
  73. this.canRefresh = true;
  74. };
  75. getRenderItem = ({item}: {item: DeviceType}) => {
  76. const {navigation} = this.props;
  77. return (
  78. <EquipmentListItem
  79. navigation={navigation}
  80. item={item}
  81. userDeviceRentDates={this.getUserDeviceRentDates(item)}
  82. height={LIST_ITEM_HEIGHT}
  83. />
  84. );
  85. };
  86. getUserDeviceRentDates(item: DeviceType): [string, string] | null {
  87. let dates = null;
  88. if (this.userRents != null) {
  89. this.userRents.forEach((device: RentedDeviceType) => {
  90. if (item.id === device.device_id) {
  91. dates = [device.begin, device.end];
  92. }
  93. });
  94. }
  95. return dates;
  96. }
  97. /**
  98. * Gets the list header, with explains this screen's purpose
  99. *
  100. * @returns {*}
  101. */
  102. getListHeader() {
  103. return (
  104. <View
  105. style={{
  106. width: '100%',
  107. marginTop: 10,
  108. marginBottom: 10,
  109. }}>
  110. <Button
  111. mode="contained"
  112. icon="help-circle"
  113. onPress={this.showMascotDialog}
  114. style={{
  115. marginRight: 'auto',
  116. marginLeft: 'auto',
  117. }}>
  118. {i18n.t('screens.equipment.mascotDialog.title')}
  119. </Button>
  120. </View>
  121. );
  122. }
  123. keyExtractor = (item: DeviceType): string => item.id.toString();
  124. /**
  125. * Gets the main screen component with the fetched data
  126. *
  127. * @param data The data fetched from the server
  128. * @returns {*}
  129. */
  130. getScreen = (
  131. data: Array<
  132. {devices: Array<DeviceType>} | {locations: Array<RentedDeviceType>} | null
  133. >,
  134. ) => {
  135. const [allDevices, userRents] = data;
  136. if (userRents) {
  137. this.userRents = (userRents as {
  138. locations: Array<RentedDeviceType>;
  139. }).locations;
  140. }
  141. return (
  142. <CollapsibleFlatList
  143. keyExtractor={this.keyExtractor}
  144. renderItem={this.getRenderItem}
  145. ListHeaderComponent={this.getListHeader()}
  146. data={
  147. allDevices
  148. ? (allDevices as {devices: Array<DeviceType>}).devices
  149. : null
  150. }
  151. />
  152. );
  153. };
  154. showMascotDialog = () => {
  155. this.setState({mascotDialogVisible: true});
  156. };
  157. hideMascotDialog = () => {
  158. AsyncStorageManager.set(
  159. AsyncStorageManager.PREFERENCES.equipmentShowMascot.key,
  160. false,
  161. );
  162. this.setState({mascotDialogVisible: false});
  163. };
  164. render() {
  165. const {props, state} = this;
  166. return (
  167. <View style={{flex: 1}}>
  168. <AuthenticatedScreen
  169. navigation={props.navigation}
  170. ref={this.authRef}
  171. requests={[
  172. {
  173. link: 'location/all',
  174. params: {},
  175. mandatory: true,
  176. },
  177. {
  178. link: 'location/my',
  179. params: {},
  180. mandatory: false,
  181. },
  182. ]}
  183. renderFunction={this.getScreen}
  184. />
  185. <MascotPopup
  186. visible={state.mascotDialogVisible}
  187. title={i18n.t('screens.equipment.mascotDialog.title')}
  188. message={i18n.t('screens.equipment.mascotDialog.message')}
  189. icon="vote"
  190. buttons={{
  191. cancel: {
  192. message: i18n.t('screens.equipment.mascotDialog.button'),
  193. icon: 'check',
  194. onPress: this.hideMascotDialog,
  195. },
  196. }}
  197. emotion={MASCOT_STYLE.WINK}
  198. />
  199. </View>
  200. );
  201. }
  202. }
  203. export default EquipmentListScreen;