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