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.

EquipmentListScreen.tsx 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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 React, { useRef, useState } from 'react';
  20. import { StyleSheet, View } from 'react-native';
  21. import { Button } from 'react-native-paper';
  22. import i18n from 'i18n-js';
  23. import EquipmentListItem from '../../../components/Lists/Equipment/EquipmentListItem';
  24. import MascotPopup from '../../../components/Mascot/MascotPopup';
  25. import { MASCOT_STYLE } from '../../../components/Mascot/Mascot';
  26. import GENERAL_STYLES from '../../../constants/Styles';
  27. import { ApiRejectType } from '../../../utils/WebData';
  28. import WebSectionList from '../../../components/Screens/WebSectionList';
  29. import { useAuthenticatedRequest } from '../../../context/loginContext';
  30. export type DeviceType = {
  31. id: number;
  32. name: string;
  33. caution: number;
  34. booked_at: Array<{ begin: string; end: string }>;
  35. };
  36. export type RentedDeviceType = {
  37. device_id: number;
  38. device_name: string;
  39. begin: string;
  40. end: string;
  41. };
  42. type ResponseType = {
  43. devices: Array<DeviceType>;
  44. locations?: Array<RentedDeviceType>;
  45. };
  46. const LIST_ITEM_HEIGHT = 64;
  47. const styles = StyleSheet.create({
  48. headerContainer: {
  49. width: '100%',
  50. marginTop: 10,
  51. marginBottom: 10,
  52. },
  53. });
  54. function EquipmentListScreen() {
  55. const userRents = useRef<undefined | Array<RentedDeviceType>>();
  56. const [mascotDialogVisible, setMascotDialogVisible] =
  57. useState<undefined | boolean>(undefined);
  58. const requestAll =
  59. useAuthenticatedRequest<{ devices: Array<DeviceType> }>('location/all');
  60. const requestOwn =
  61. useAuthenticatedRequest<{
  62. locations: Array<RentedDeviceType>;
  63. }>('location/my');
  64. const getRenderItem = ({ item }: { item: DeviceType }) => {
  65. return (
  66. <EquipmentListItem
  67. item={item}
  68. userDeviceRentDates={getUserDeviceRentDates(item)}
  69. height={LIST_ITEM_HEIGHT}
  70. />
  71. );
  72. };
  73. const getUserDeviceRentDates = (
  74. item: DeviceType
  75. ): [string, string] | null => {
  76. let dates = null;
  77. if (userRents.current) {
  78. userRents.current.forEach((device: RentedDeviceType) => {
  79. if (item.id === device.device_id) {
  80. dates = [device.begin, device.end];
  81. }
  82. });
  83. }
  84. return dates;
  85. };
  86. const getListHeader = () => {
  87. return (
  88. <View style={styles.headerContainer}>
  89. <Button
  90. mode="contained"
  91. icon="help-circle"
  92. onPress={showMascotDialog}
  93. style={GENERAL_STYLES.centerHorizontal}
  94. >
  95. {i18n.t('screens.equipment.mascotDialog.title')}
  96. </Button>
  97. </View>
  98. );
  99. };
  100. const keyExtractor = (item: DeviceType): string => item.id.toString();
  101. const createDataset = (data: ResponseType | undefined) => {
  102. if (data) {
  103. if (data.locations) {
  104. userRents.current = data.locations;
  105. }
  106. return [{ title: '', data: data.devices }];
  107. } else {
  108. return [];
  109. }
  110. };
  111. const showMascotDialog = () => setMascotDialogVisible(true);
  112. const hideMascotDialog = () => setMascotDialogVisible(false);
  113. const request = () => {
  114. return new Promise(
  115. (
  116. resolve: (data: ResponseType) => void,
  117. reject: (error: ApiRejectType) => void
  118. ) => {
  119. requestAll()
  120. .then((devicesData) => {
  121. requestOwn()
  122. .then((rentsData) => {
  123. resolve({
  124. devices: devicesData.devices,
  125. locations: rentsData.locations,
  126. });
  127. })
  128. .catch(() =>
  129. resolve({
  130. devices: devicesData.devices,
  131. })
  132. );
  133. })
  134. .catch(reject);
  135. }
  136. );
  137. };
  138. return (
  139. <View style={GENERAL_STYLES.flex}>
  140. <WebSectionList
  141. request={request}
  142. createDataset={createDataset}
  143. keyExtractor={keyExtractor}
  144. renderItem={getRenderItem}
  145. renderListHeaderComponent={getListHeader}
  146. />
  147. <MascotPopup
  148. visible={mascotDialogVisible}
  149. title={i18n.t('screens.equipment.mascotDialog.title')}
  150. message={i18n.t('screens.equipment.mascotDialog.message')}
  151. icon="vote"
  152. buttons={{
  153. cancel: {
  154. message: i18n.t('screens.equipment.mascotDialog.button'),
  155. icon: 'check',
  156. onPress: hideMascotDialog,
  157. },
  158. }}
  159. emotion={MASCOT_STYLE.WINK}
  160. />
  161. </View>
  162. );
  163. }
  164. export default EquipmentListScreen;