forked from vergnet/application-amicale
		
	Update equipment screens to use TypeScript
This commit is contained in:
		
							parent
							
								
									5977ce257b
								
							
						
					
					
						commit
						67cb96dd03
					
				
					 6 changed files with 196 additions and 196 deletions
				
			
		|  | @ -30,7 +30,7 @@ import { | ||||||
| 
 | 
 | ||||||
| type PropsType = { | type PropsType = { | ||||||
|   navigation: StackNavigationProp<any>; |   navigation: StackNavigationProp<any>; | ||||||
|   userDeviceRentDates: [string, string]; |   userDeviceRentDates: [string, string] | null; | ||||||
|   item: DeviceType; |   item: DeviceType; | ||||||
|   height: number; |   height: number; | ||||||
| }; | }; | ||||||
|  | @ -57,7 +57,7 @@ function EquipmentListItem(props: PropsType) { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   let description; |   let description; | ||||||
|   if (isRented) { |   if (isRented && userDeviceRentDates) { | ||||||
|     const start = new Date(userDeviceRentDates[0]); |     const start = new Date(userDeviceRentDates[0]); | ||||||
|     const end = new Date(userDeviceRentDates[1]); |     const end = new Date(userDeviceRentDates[1]); | ||||||
|     if (start.getTime() !== end.getTime()) { |     if (start.getTime() !== end.getTime()) { | ||||||
|  |  | ||||||
|  | @ -1,121 +0,0 @@ | ||||||
| /* |  | ||||||
|  * Copyright (c) 2019 - 2020 Arnaud Vergnet. |  | ||||||
|  * |  | ||||||
|  * This file is part of Campus INSAT. |  | ||||||
|  * |  | ||||||
|  * Campus INSAT is free software: you can redistribute it and/or modify |  | ||||||
|  *  it under the terms of the GNU General Public License as published by |  | ||||||
|  * the Free Software Foundation, either version 3 of the License, or |  | ||||||
|  * (at your option) any later version. |  | ||||||
|  * |  | ||||||
|  * Campus INSAT is distributed in the hope that it will be useful, |  | ||||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the |  | ||||||
|  * GNU General Public License for more details. |  | ||||||
|  * |  | ||||||
|  * You should have received a copy of the GNU General Public License |  | ||||||
|  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
 |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| // @flow
 |  | ||||||
| 
 |  | ||||||
| import * as React from 'react'; |  | ||||||
| import { |  | ||||||
|   Button, |  | ||||||
|   Caption, |  | ||||||
|   Card, |  | ||||||
|   Headline, |  | ||||||
|   Paragraph, |  | ||||||
|   withTheme, |  | ||||||
| } from 'react-native-paper'; |  | ||||||
| import {View} from 'react-native'; |  | ||||||
| import i18n from 'i18n-js'; |  | ||||||
| import type {CustomThemeType} from '../../../managers/ThemeManager'; |  | ||||||
| import type {DeviceType} from './EquipmentListScreen'; |  | ||||||
| import {getRelativeDateString} from '../../../utils/EquipmentBooking'; |  | ||||||
| import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; |  | ||||||
| 
 |  | ||||||
| type PropsType = { |  | ||||||
|   route: { |  | ||||||
|     params?: { |  | ||||||
|       item?: DeviceType, |  | ||||||
|       dates: [string, string], |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|   theme: CustomThemeType, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| class EquipmentConfirmScreen extends React.Component<PropsType> { |  | ||||||
|   item: DeviceType | null; |  | ||||||
| 
 |  | ||||||
|   dates: [string, string] | null; |  | ||||||
| 
 |  | ||||||
|   constructor(props: PropsType) { |  | ||||||
|     super(props); |  | ||||||
|     if (props.route.params != null) { |  | ||||||
|       if (props.route.params.item != null) this.item = props.route.params.item; |  | ||||||
|       else this.item = null; |  | ||||||
|       if (props.route.params.dates != null) |  | ||||||
|         this.dates = props.route.params.dates; |  | ||||||
|       else this.dates = null; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   render(): React.Node { |  | ||||||
|     const {item, dates, props} = this; |  | ||||||
|     if (item != null && dates != null) { |  | ||||||
|       const start = new Date(dates[0]); |  | ||||||
|       const end = new Date(dates[1]); |  | ||||||
|       let buttonText; |  | ||||||
|       if (start == null) buttonText = i18n.t('screens.equipment.booking'); |  | ||||||
|       else if (end != null && start.getTime() !== end.getTime()) |  | ||||||
|         buttonText = i18n.t('screens.equipment.bookingPeriod', { |  | ||||||
|           begin: getRelativeDateString(start), |  | ||||||
|           end: getRelativeDateString(end), |  | ||||||
|         }); |  | ||||||
|       else |  | ||||||
|         buttonText = i18n.t('screens.equipment.bookingDay', { |  | ||||||
|           date: getRelativeDateString(start), |  | ||||||
|         }); |  | ||||||
|       return ( |  | ||||||
|         <CollapsibleScrollView> |  | ||||||
|           <Card style={{margin: 5}}> |  | ||||||
|             <Card.Content> |  | ||||||
|               <View style={{flex: 1}}> |  | ||||||
|                 <View |  | ||||||
|                   style={{ |  | ||||||
|                     marginLeft: 'auto', |  | ||||||
|                     marginRight: 'auto', |  | ||||||
|                     flexDirection: 'row', |  | ||||||
|                     flexWrap: 'wrap', |  | ||||||
|                   }}> |  | ||||||
|                   <Headline style={{textAlign: 'center'}}>{item.name}</Headline> |  | ||||||
|                   <Caption |  | ||||||
|                     style={{ |  | ||||||
|                       textAlign: 'center', |  | ||||||
|                       lineHeight: 35, |  | ||||||
|                       marginLeft: 10, |  | ||||||
|                     }}> |  | ||||||
|                     ({i18n.t('screens.equipment.bail', {cost: item.caution})}) |  | ||||||
|                   </Caption> |  | ||||||
|                 </View> |  | ||||||
|               </View> |  | ||||||
|               <Button |  | ||||||
|                 icon="check-circle-outline" |  | ||||||
|                 color={props.theme.colors.success} |  | ||||||
|                 mode="text"> |  | ||||||
|                 {buttonText} |  | ||||||
|               </Button> |  | ||||||
|               <Paragraph style={{textAlign: 'center'}}> |  | ||||||
|                 {i18n.t('screens.equipment.bookingConfirmedMessage')} |  | ||||||
|               </Paragraph> |  | ||||||
|             </Card.Content> |  | ||||||
|           </Card> |  | ||||||
|         </CollapsibleScrollView> |  | ||||||
|       ); |  | ||||||
|     } |  | ||||||
|     return null; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default withTheme(EquipmentConfirmScreen); |  | ||||||
							
								
								
									
										104
									
								
								src/screens/Amicale/Equipment/EquipmentConfirmScreen.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/screens/Amicale/Equipment/EquipmentConfirmScreen.tsx
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,104 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 - 2020 Arnaud Vergnet. | ||||||
|  |  * | ||||||
|  |  * This file is part of Campus INSAT. | ||||||
|  |  * | ||||||
|  |  * Campus INSAT is free software: you can redistribute it and/or modify | ||||||
|  |  *  it under the terms of the GNU General Public License as published by | ||||||
|  |  * the Free Software Foundation, either version 3 of the License, or | ||||||
|  |  * (at your option) any later version. | ||||||
|  |  * | ||||||
|  |  * Campus INSAT is distributed in the hope that it will be useful, | ||||||
|  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||
|  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||||
|  |  * GNU General Public License for more details. | ||||||
|  |  * | ||||||
|  |  * You should have received a copy of the GNU General Public License | ||||||
|  |  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | import * as React from 'react'; | ||||||
|  | import { | ||||||
|  |   Button, | ||||||
|  |   Caption, | ||||||
|  |   Card, | ||||||
|  |   Headline, | ||||||
|  |   Paragraph, | ||||||
|  |   useTheme, | ||||||
|  | } from 'react-native-paper'; | ||||||
|  | import {View} from 'react-native'; | ||||||
|  | import i18n from 'i18n-js'; | ||||||
|  | import {getRelativeDateString} from '../../../utils/EquipmentBooking'; | ||||||
|  | import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; | ||||||
|  | import {StackScreenProps} from '@react-navigation/stack'; | ||||||
|  | import {MainStackParamsList} from '../../../navigation/MainNavigator'; | ||||||
|  | 
 | ||||||
|  | type EquipmentConfirmScreenNavigationProp = StackScreenProps< | ||||||
|  |   MainStackParamsList, | ||||||
|  |   'equipment-confirm' | ||||||
|  | >; | ||||||
|  | 
 | ||||||
|  | type Props = EquipmentConfirmScreenNavigationProp; | ||||||
|  | 
 | ||||||
|  | function EquipmentConfirmScreen(props: Props) { | ||||||
|  |   const theme = useTheme(); | ||||||
|  |   const item = props.route.params?.item; | ||||||
|  |   const dates = props.route.params?.dates; | ||||||
|  | 
 | ||||||
|  |   if (item != null && dates != null) { | ||||||
|  |     const start = new Date(dates[0]); | ||||||
|  |     const end = new Date(dates[1]); | ||||||
|  |     let buttonText; | ||||||
|  |     if (start == null) { | ||||||
|  |       buttonText = i18n.t('screens.equipment.booking'); | ||||||
|  |     } else if (end != null && start.getTime() !== end.getTime()) { | ||||||
|  |       buttonText = i18n.t('screens.equipment.bookingPeriod', { | ||||||
|  |         begin: getRelativeDateString(start), | ||||||
|  |         end: getRelativeDateString(end), | ||||||
|  |       }); | ||||||
|  |     } else { | ||||||
|  |       buttonText = i18n.t('screens.equipment.bookingDay', { | ||||||
|  |         date: getRelativeDateString(start), | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |     return ( | ||||||
|  |       <CollapsibleScrollView> | ||||||
|  |         <Card style={{margin: 5}}> | ||||||
|  |           <Card.Content> | ||||||
|  |             <View style={{flex: 1}}> | ||||||
|  |               <View | ||||||
|  |                 style={{ | ||||||
|  |                   marginLeft: 'auto', | ||||||
|  |                   marginRight: 'auto', | ||||||
|  |                   flexDirection: 'row', | ||||||
|  |                   flexWrap: 'wrap', | ||||||
|  |                 }}> | ||||||
|  |                 <Headline style={{textAlign: 'center'}}>{item.name}</Headline> | ||||||
|  |                 <Caption | ||||||
|  |                   style={{ | ||||||
|  |                     textAlign: 'center', | ||||||
|  |                     lineHeight: 35, | ||||||
|  |                     marginLeft: 10, | ||||||
|  |                   }}> | ||||||
|  |                   ({i18n.t('screens.equipment.bail', {cost: item.caution})}) | ||||||
|  |                 </Caption> | ||||||
|  |               </View> | ||||||
|  |             </View> | ||||||
|  |             <Button | ||||||
|  |               icon="check-circle-outline" | ||||||
|  |               color={theme.colors.success} | ||||||
|  |               mode="text"> | ||||||
|  |               {buttonText} | ||||||
|  |             </Button> | ||||||
|  |             <Paragraph style={{textAlign: 'center'}}> | ||||||
|  |               {i18n.t('screens.equipment.bookingConfirmedMessage')} | ||||||
|  |             </Paragraph> | ||||||
|  |           </Card.Content> | ||||||
|  |         </Card> | ||||||
|  |       </CollapsibleScrollView> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |   return null; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export default EquipmentConfirmScreen; | ||||||
|  | @ -17,42 +17,38 @@ | ||||||
|  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
 |  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| // @flow
 |  | ||||||
| 
 |  | ||||||
| import * as React from 'react'; | import * as React from 'react'; | ||||||
| import {View} from 'react-native'; | import {View} from 'react-native'; | ||||||
| import {Button, withTheme} from 'react-native-paper'; | import {Button} from 'react-native-paper'; | ||||||
| import {StackNavigationProp} from '@react-navigation/stack'; | import {StackNavigationProp} from '@react-navigation/stack'; | ||||||
| import i18n from 'i18n-js'; | import i18n from 'i18n-js'; | ||||||
| import AuthenticatedScreen from '../../../components/Amicale/AuthenticatedScreen'; | import AuthenticatedScreen from '../../../components/Amicale/AuthenticatedScreen'; | ||||||
| import type {ClubType} from '../Clubs/ClubListScreen'; |  | ||||||
| import EquipmentListItem from '../../../components/Lists/Equipment/EquipmentListItem'; | import EquipmentListItem from '../../../components/Lists/Equipment/EquipmentListItem'; | ||||||
| import MascotPopup from '../../../components/Mascot/MascotPopup'; | import MascotPopup from '../../../components/Mascot/MascotPopup'; | ||||||
| import {MASCOT_STYLE} from '../../../components/Mascot/Mascot'; | import {MASCOT_STYLE} from '../../../components/Mascot/Mascot'; | ||||||
| import AsyncStorageManager from '../../../managers/AsyncStorageManager'; | import AsyncStorageManager from '../../../managers/AsyncStorageManager'; | ||||||
| import CollapsibleFlatList from '../../../components/Collapsible/CollapsibleFlatList'; | import CollapsibleFlatList from '../../../components/Collapsible/CollapsibleFlatList'; | ||||||
| import type {ApiGenericDataType} from '../../../utils/WebData'; |  | ||||||
| 
 | 
 | ||||||
| type PropsType = { | type PropsType = { | ||||||
|   navigation: StackNavigationProp, |   navigation: StackNavigationProp<any>; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| type StateType = { | type StateType = { | ||||||
|   mascotDialogVisible: boolean, |   mascotDialogVisible: boolean; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export type DeviceType = { | export type DeviceType = { | ||||||
|   id: number, |   id: number; | ||||||
|   name: string, |   name: string; | ||||||
|   caution: number, |   caution: number; | ||||||
|   booked_at: Array<{begin: string, end: string}>, |   booked_at: Array<{begin: string; end: string}>; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export type RentedDeviceType = { | export type RentedDeviceType = { | ||||||
|   device_id: number, |   device_id: number; | ||||||
|   device_name: string, |   device_name: string; | ||||||
|   begin: string, |   begin: string; | ||||||
|   end: string, |   end: string; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const LIST_ITEM_HEIGHT = 64; | const LIST_ITEM_HEIGHT = 64; | ||||||
|  | @ -60,12 +56,13 @@ const LIST_ITEM_HEIGHT = 64; | ||||||
| class EquipmentListScreen extends React.Component<PropsType, StateType> { | class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|   userRents: null | Array<RentedDeviceType>; |   userRents: null | Array<RentedDeviceType>; | ||||||
| 
 | 
 | ||||||
|   authRef: {current: null | AuthenticatedScreen}; |   authRef: {current: null | AuthenticatedScreen<any>}; | ||||||
| 
 | 
 | ||||||
|   canRefresh: boolean; |   canRefresh: boolean; | ||||||
| 
 | 
 | ||||||
|   constructor(props: PropsType) { |   constructor(props: PropsType) { | ||||||
|     super(props); |     super(props); | ||||||
|  |     this.userRents = null; | ||||||
|     this.state = { |     this.state = { | ||||||
|       mascotDialogVisible: AsyncStorageManager.getBool( |       mascotDialogVisible: AsyncStorageManager.getBool( | ||||||
|         AsyncStorageManager.PREFERENCES.equipmentShowMascot.key, |         AsyncStorageManager.PREFERENCES.equipmentShowMascot.key, | ||||||
|  | @ -77,12 +74,17 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onScreenFocus = () => { |   onScreenFocus = () => { | ||||||
|     if (this.canRefresh && this.authRef.current != null) |     if ( | ||||||
|  |       this.canRefresh && | ||||||
|  |       this.authRef.current && | ||||||
|  |       this.authRef.current.reload | ||||||
|  |     ) { | ||||||
|       this.authRef.current.reload(); |       this.authRef.current.reload(); | ||||||
|  |     } | ||||||
|     this.canRefresh = true; |     this.canRefresh = true; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   getRenderItem = ({item}: {item: DeviceType}): React.Node => { |   getRenderItem = ({item}: {item: DeviceType}) => { | ||||||
|     const {navigation} = this.props; |     const {navigation} = this.props; | ||||||
|     return ( |     return ( | ||||||
|       <EquipmentListItem |       <EquipmentListItem | ||||||
|  | @ -94,7 +96,7 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   getUserDeviceRentDates(item: DeviceType): [number, number] | null { |   getUserDeviceRentDates(item: DeviceType): [string, string] | null { | ||||||
|     let dates = null; |     let dates = null; | ||||||
|     if (this.userRents != null) { |     if (this.userRents != null) { | ||||||
|       this.userRents.forEach((device: RentedDeviceType) => { |       this.userRents.forEach((device: RentedDeviceType) => { | ||||||
|  | @ -111,7 +113,7 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|    * |    * | ||||||
|    * @returns {*} |    * @returns {*} | ||||||
|    */ |    */ | ||||||
|   getListHeader(): React.Node { |   getListHeader() { | ||||||
|     return ( |     return ( | ||||||
|       <View |       <View | ||||||
|         style={{ |         style={{ | ||||||
|  | @ -133,7 +135,7 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   keyExtractor = (item: ClubType): string => item.id.toString(); |   keyExtractor = (item: DeviceType): string => item.id.toString(); | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Gets the main screen component with the fetched data |    * Gets the main screen component with the fetched data | ||||||
|  | @ -141,15 +143,27 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|    * @param data The data fetched from the server |    * @param data The data fetched from the server | ||||||
|    * @returns {*} |    * @returns {*} | ||||||
|    */ |    */ | ||||||
|   getScreen = (data: Array<ApiGenericDataType | null>): React.Node => { |   getScreen = ( | ||||||
|  |     data: Array< | ||||||
|  |       {devices: Array<DeviceType>} | {locations: Array<RentedDeviceType>} | null | ||||||
|  |     >, | ||||||
|  |   ) => { | ||||||
|     const [allDevices, userRents] = data; |     const [allDevices, userRents] = data; | ||||||
|     if (userRents != null) this.userRents = userRents.locations; |     if (userRents) { | ||||||
|  |       this.userRents = (userRents as { | ||||||
|  |         locations: Array<RentedDeviceType>; | ||||||
|  |       }).locations; | ||||||
|  |     } | ||||||
|     return ( |     return ( | ||||||
|       <CollapsibleFlatList |       <CollapsibleFlatList | ||||||
|         keyExtractor={this.keyExtractor} |         keyExtractor={this.keyExtractor} | ||||||
|         renderItem={this.getRenderItem} |         renderItem={this.getRenderItem} | ||||||
|         ListHeaderComponent={this.getListHeader()} |         ListHeaderComponent={this.getListHeader()} | ||||||
|         data={allDevices != null ? allDevices.devices : null} |         data={ | ||||||
|  |           allDevices | ||||||
|  |             ? (allDevices as {devices: Array<DeviceType>}).devices | ||||||
|  |             : null | ||||||
|  |         } | ||||||
|       /> |       /> | ||||||
|     ); |     ); | ||||||
|   }; |   }; | ||||||
|  | @ -166,7 +180,7 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|     this.setState({mascotDialogVisible: false}); |     this.setState({mascotDialogVisible: false}); | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   render(): React.Node { |   render() { | ||||||
|     const {props, state} = this; |     const {props, state} = this; | ||||||
|     return ( |     return ( | ||||||
|       <View style={{flex: 1}}> |       <View style={{flex: 1}}> | ||||||
|  | @ -193,7 +207,6 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|           message={i18n.t('screens.equipment.mascotDialog.message')} |           message={i18n.t('screens.equipment.mascotDialog.message')} | ||||||
|           icon="vote" |           icon="vote" | ||||||
|           buttons={{ |           buttons={{ | ||||||
|             action: null, |  | ||||||
|             cancel: { |             cancel: { | ||||||
|               message: i18n.t('screens.equipment.mascotDialog.button'), |               message: i18n.t('screens.equipment.mascotDialog.button'), | ||||||
|               icon: 'check', |               icon: 'check', | ||||||
|  | @ -207,4 +220,4 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default withTheme(EquipmentListScreen); | export default EquipmentListScreen; | ||||||
|  | @ -17,8 +17,6 @@ | ||||||
|  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
 |  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
 | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| // @flow
 |  | ||||||
| 
 |  | ||||||
| import * as React from 'react'; | import * as React from 'react'; | ||||||
| import { | import { | ||||||
|   Button, |   Button, | ||||||
|  | @ -28,13 +26,12 @@ import { | ||||||
|   Subheading, |   Subheading, | ||||||
|   withTheme, |   withTheme, | ||||||
| } from 'react-native-paper'; | } from 'react-native-paper'; | ||||||
| import {StackNavigationProp} from '@react-navigation/stack'; | import {StackNavigationProp, StackScreenProps} from '@react-navigation/stack'; | ||||||
| import {BackHandler, View} from 'react-native'; | import {BackHandler, View} from 'react-native'; | ||||||
| import * as Animatable from 'react-native-animatable'; | import * as Animatable from 'react-native-animatable'; | ||||||
| import i18n from 'i18n-js'; | import i18n from 'i18n-js'; | ||||||
| import {CalendarList} from 'react-native-calendars'; | import {CalendarList, PeriodMarking} from 'react-native-calendars'; | ||||||
| import type {DeviceType} from './EquipmentListScreen'; | import type {DeviceType} from './EquipmentListScreen'; | ||||||
| import type {CustomThemeType} from '../../../managers/ThemeManager'; |  | ||||||
| import LoadingConfirmDialog from '../../../components/Dialogs/LoadingConfirmDialog'; | import LoadingConfirmDialog from '../../../components/Dialogs/LoadingConfirmDialog'; | ||||||
| import ErrorDialog from '../../../components/Dialogs/ErrorDialog'; | import ErrorDialog from '../../../components/Dialogs/ErrorDialog'; | ||||||
| import { | import { | ||||||
|  | @ -47,43 +44,46 @@ import { | ||||||
| } from '../../../utils/EquipmentBooking'; | } from '../../../utils/EquipmentBooking'; | ||||||
| import ConnectionManager from '../../../managers/ConnectionManager'; | import ConnectionManager from '../../../managers/ConnectionManager'; | ||||||
| import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; | import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView'; | ||||||
|  | import {MainStackParamsList} from '../../../navigation/MainNavigator'; | ||||||
| 
 | 
 | ||||||
| type PropsType = { | type EquipmentRentScreenNavigationProp = StackScreenProps< | ||||||
|   navigation: StackNavigationProp, |   MainStackParamsList, | ||||||
|   route: { |   'equipment-rent' | ||||||
|     params?: { | >; | ||||||
|       item?: DeviceType, | 
 | ||||||
|     }, | type Props = EquipmentRentScreenNavigationProp & { | ||||||
|   }, |   navigation: StackNavigationProp<any>; | ||||||
|   theme: CustomThemeType, |   theme: ReactNativePaper.Theme; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export type MarkedDatesObjectType = { | export type MarkedDatesObjectType = { | ||||||
|   [key: string]: {startingDay: boolean, endingDay: boolean, color: string}, |   [key: string]: PeriodMarking; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| type StateType = { | type StateType = { | ||||||
|   dialogVisible: boolean, |   dialogVisible: boolean; | ||||||
|   errorDialogVisible: boolean, |   errorDialogVisible: boolean; | ||||||
|   markedDates: MarkedDatesObjectType, |   markedDates: MarkedDatesObjectType; | ||||||
|   currentError: number, |   currentError: number; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class EquipmentRentScreen extends React.Component<PropsType, StateType> { | class EquipmentRentScreen extends React.Component<Props, StateType> { | ||||||
|   item: DeviceType | null; |   item: DeviceType | null; | ||||||
| 
 | 
 | ||||||
|   bookedDates: Array<string>; |   bookedDates: Array<string>; | ||||||
| 
 | 
 | ||||||
|   bookRef: {current: null | Animatable.View}; |   bookRef: {current: null | (Animatable.View & View)}; | ||||||
| 
 | 
 | ||||||
|   canBookEquipment: boolean; |   canBookEquipment: boolean; | ||||||
| 
 | 
 | ||||||
|   lockedDates: { |   lockedDates: { | ||||||
|     [key: string]: {startingDay: boolean, endingDay: boolean, color: string}, |     [key: string]: PeriodMarking; | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   constructor(props: PropsType) { |   constructor(props: Props) { | ||||||
|     super(props); |     super(props); | ||||||
|  |     this.item = null; | ||||||
|  |     this.lockedDates = {}; | ||||||
|     this.state = { |     this.state = { | ||||||
|       dialogVisible: false, |       dialogVisible: false, | ||||||
|       errorDialogVisible: false, |       errorDialogVisible: false, | ||||||
|  | @ -95,13 +95,16 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|     this.canBookEquipment = false; |     this.canBookEquipment = false; | ||||||
|     this.bookedDates = []; |     this.bookedDates = []; | ||||||
|     if (props.route.params != null) { |     if (props.route.params != null) { | ||||||
|       if (props.route.params.item != null) this.item = props.route.params.item; |       if (props.route.params.item != null) { | ||||||
|       else this.item = null; |         this.item = props.route.params.item; | ||||||
|  |       } else { | ||||||
|  |         this.item = null; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|     const {item} = this; |     const {item} = this; | ||||||
|     if (item != null) { |     if (item != null) { | ||||||
|       this.lockedDates = {}; |       this.lockedDates = {}; | ||||||
|       item.booked_at.forEach((date: {begin: string, end: string}) => { |       item.booked_at.forEach((date: {begin: string; end: string}) => { | ||||||
|         const range = getValidRange( |         const range = getValidRange( | ||||||
|           new Date(date.begin), |           new Date(date.begin), | ||||||
|           new Date(date.end), |           new Date(date.end), | ||||||
|  | @ -211,11 +214,11 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|    * @param day The day selected |    * @param day The day selected | ||||||
|    */ |    */ | ||||||
|   selectNewDate = (day: { |   selectNewDate = (day: { | ||||||
|     dateString: string, |     dateString: string; | ||||||
|     day: number, |     day: number; | ||||||
|     month: number, |     month: number; | ||||||
|     timestamp: number, |     timestamp: number; | ||||||
|     year: number, |     year: number; | ||||||
|   }) => { |   }) => { | ||||||
|     const selected = new Date(day.dateString); |     const selected = new Date(day.dateString); | ||||||
|     const start = this.getBookStartDate(); |     const start = this.getBookStartDate(); | ||||||
|  | @ -229,7 +232,9 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|       } else if (this.bookedDates.length === 1) { |       } else if (this.bookedDates.length === 1) { | ||||||
|         this.updateSelectionRange(start, selected); |         this.updateSelectionRange(start, selected); | ||||||
|         this.enableBooking(); |         this.enableBooking(); | ||||||
|       } else this.resetSelection(); |       } else { | ||||||
|  |         this.resetSelection(); | ||||||
|  |       } | ||||||
|       this.updateMarkedSelection(); |       this.updateMarkedSelection(); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
|  | @ -249,7 +254,7 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|    * Shows the book button by plying a fade animation |    * Shows the book button by plying a fade animation | ||||||
|    */ |    */ | ||||||
|   showBookButton() { |   showBookButton() { | ||||||
|     if (this.bookRef.current != null) { |     if (this.bookRef.current && this.bookRef.current.fadeInUp) { | ||||||
|       this.bookRef.current.fadeInUp(500); |       this.bookRef.current.fadeInUp(500); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -258,7 +263,7 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|    * Hides the book button by plying a fade animation |    * Hides the book button by plying a fade animation | ||||||
|    */ |    */ | ||||||
|   hideBookButton() { |   hideBookButton() { | ||||||
|     if (this.bookRef.current != null) { |     if (this.bookRef.current && this.bookRef.current.fadeOutDown) { | ||||||
|       this.bookRef.current.fadeOutDown(500); |       this.bookRef.current.fadeOutDown(500); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -271,7 +276,9 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   resetSelection() { |   resetSelection() { | ||||||
|     if (this.canBookEquipment) this.hideBookButton(); |     if (this.canBookEquipment) { | ||||||
|  |       this.hideBookButton(); | ||||||
|  |     } | ||||||
|     this.canBookEquipment = false; |     this.canBookEquipment = false; | ||||||
|     this.bookedDates = []; |     this.bookedDates = []; | ||||||
|   } |   } | ||||||
|  | @ -287,21 +294,23 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   render(): React.Node { |   render() { | ||||||
|     const {item, props, state} = this; |     const {item, props, state} = this; | ||||||
|     const start = this.getBookStartDate(); |     const start = this.getBookStartDate(); | ||||||
|     const end = this.getBookEndDate(); |     const end = this.getBookEndDate(); | ||||||
|     let subHeadingText; |     let subHeadingText; | ||||||
|     if (start == null) subHeadingText = i18n.t('screens.equipment.booking'); |     if (start == null) { | ||||||
|     else if (end != null && start.getTime() !== end.getTime()) |       subHeadingText = i18n.t('screens.equipment.booking'); | ||||||
|  |     } else if (end != null && start.getTime() !== end.getTime()) { | ||||||
|       subHeadingText = i18n.t('screens.equipment.bookingPeriod', { |       subHeadingText = i18n.t('screens.equipment.bookingPeriod', { | ||||||
|         begin: getRelativeDateString(start), |         begin: getRelativeDateString(start), | ||||||
|         end: getRelativeDateString(end), |         end: getRelativeDateString(end), | ||||||
|       }); |       }); | ||||||
|     else |     } else { | ||||||
|       subHeadingText = i18n.t('screens.equipment.bookingDay', { |       subHeadingText = i18n.t('screens.equipment.bookingDay', { | ||||||
|         date: getRelativeDateString(start), |         date: getRelativeDateString(start), | ||||||
|       }); |       }); | ||||||
|  |     } | ||||||
|     if (item != null) { |     if (item != null) { | ||||||
|       const isAvailable = isEquipmentAvailable(item); |       const isAvailable = isEquipmentAvailable(item); | ||||||
|       const firstAvailability = getFirstEquipmentAvailability(item); |       const firstAvailability = getFirstEquipmentAvailability(item); | ||||||
|  | @ -369,12 +378,10 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> { | ||||||
|               onDayPress={this.selectNewDate} |               onDayPress={this.selectNewDate} | ||||||
|               // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
 |               // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
 | ||||||
|               firstDay={1} |               firstDay={1} | ||||||
|               // Disable all touch events for disabled days. can be override with disableTouchEvent in markedDates
 |  | ||||||
|               disableAllTouchEventsForDisabledDays |  | ||||||
|               // Hide month navigation arrows.
 |               // Hide month navigation arrows.
 | ||||||
|               hideArrows={false} |               hideArrows={false} | ||||||
|               // Date marking style [simple/period/multi-dot/custom]. Default = 'simple'
 |               // Date marking style [simple/period/multi-dot/custom]. Default = 'simple'
 | ||||||
|               markingType="period" |               markingType={'period'} | ||||||
|               markedDates={{...this.lockedDates, ...state.markedDates}} |               markedDates={{...this.lockedDates, ...state.markedDates}} | ||||||
|               theme={{ |               theme={{ | ||||||
|                 backgroundColor: props.theme.colors.agendaBackgroundColor, |                 backgroundColor: props.theme.colors.agendaBackgroundColor, | ||||||
|  | @ -21,6 +21,7 @@ import i18n from 'i18n-js'; | ||||||
| import type {DeviceType} from '../screens/Amicale/Equipment/EquipmentListScreen'; | import type {DeviceType} from '../screens/Amicale/Equipment/EquipmentListScreen'; | ||||||
| import DateManager from '../managers/DateManager'; | import DateManager from '../managers/DateManager'; | ||||||
| import type {MarkedDatesObjectType} from '../screens/Amicale/Equipment/EquipmentRentScreen'; | import type {MarkedDatesObjectType} from '../screens/Amicale/Equipment/EquipmentRentScreen'; | ||||||
|  | import {PeriodMarking} from 'react-native-calendars'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Gets the current day at midnight |  * Gets the current day at midnight | ||||||
|  | @ -189,11 +190,7 @@ export function generateMarkedDates( | ||||||
|   range: Array<string>, |   range: Array<string>, | ||||||
| ): MarkedDatesObjectType { | ): MarkedDatesObjectType { | ||||||
|   const markedDates: { |   const markedDates: { | ||||||
|     [key: string]: { |     [key: string]: PeriodMarking; | ||||||
|       startingDay: boolean; |  | ||||||
|       endingDay: boolean; |  | ||||||
|       color: string; |  | ||||||
|     }; |  | ||||||
|   } = {}; |   } = {}; | ||||||
|   for (let i = 0; i < range.length; i += 1) { |   for (let i = 0; i < range.length; i += 1) { | ||||||
|     const isStart = i === 0; |     const isStart = i === 0; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue