@cometchat/chat-uikit-react-native
Version:
Ready-to-use Chat UI Components for React Native
364 lines (343 loc) • 10 kB
JavaScript
import React from "react";
import PropTypes from "prop-types";
import {
StyleSheet,
Text,
TouchableHighlight,
View,
Appearance,
} from "react-native";
import DateTimePicker from "@react-native-community/datetimepicker";
import Modal from "./Modal";
import { isIphoneX } from "./utils";
import DateTime from "../luxon/src/datetime";
export const BACKGROUND_COLOR_LIGHT = "white";
export const BACKGROUND_COLOR_DARK = "#0E0E0E";
export const BORDER_COLOR = "#d5d5d5";
export const BORDER_COLOR_DARK = "#272729";
export const BORDER_RADIUS = 13;
export const BUTTON_FONT_WEIGHT = "normal";
export const BUTTON_FONT_COLOR = "#007ff9";
export const BUTTON_FONT_SIZE = 20;
export const HIGHLIGHT_COLOR_DARK = "#444444";
export const HIGHLIGHT_COLOR_LIGHT = "#ebebeb";
export class DateTimePickerModal extends React.PureComponent {
static propTypes = {
buttonTextColorIOS: PropTypes.string,
cancelButtonTestID: PropTypes.string,
confirmButtonTestID: PropTypes.string,
cancelTextIOS: PropTypes.string,
confirmTextIOS: PropTypes.string,
customCancelButtonIOS: PropTypes.elementType,
customConfirmButtonIOS: PropTypes.elementType,
customHeaderIOS: PropTypes.elementType,
customPickerIOS: PropTypes.elementType,
date: PropTypes.instanceOf(Date),
modalPropsIOS: PropTypes.any,
modalStyleIOS: PropTypes.any,
isDarkModeEnabled: PropTypes.bool,
isVisible: PropTypes.bool,
pickerContainerStyleIOS: PropTypes.any,
pickerStyleIOS: PropTypes.any,
backdropStyleIOS: PropTypes.any,
pickerComponentStyleIOS: PropTypes.any,
onCancel: PropTypes.func.isRequired,
onConfirm: PropTypes.func.isRequired,
onChange: PropTypes.func,
onHide: PropTypes.func,
maximumDate: PropTypes.instanceOf(Date),
minimumDate: PropTypes.instanceOf(Date),
};
static defaultProps = {
cancelTextIOS: "Cancel",
confirmTextIOS: "Confirm",
modalPropsIOS: {},
date: new Date(),
isDarkModeEnabled: undefined,
isVisible: false,
pickerContainerStyleIOS: {},
pickerStyleIOS: {},
backdropStyleIOS: {},
pickerComponentStyleIOS: {},
};
state = {
currentDate: this.props.date,
isPickerVisible: this.props.isVisible,
};
didPressConfirm = false;
static getDerivedStateFromProps(props, state) {
if (props.isVisible && !state.isPickerVisible) {
return { currentDate: props.date, isPickerVisible: true };
}
return null;
}
handleCancel = () => {
this.didPressConfirm = false;
this.props.onCancel();
};
handleConfirm = () => {
this.didPressConfirm = true;
this.props.onConfirm(this.state.currentDate);
};
handleHide = () => {
const { onHide } = this.props;
if (onHide) {
onHide(this.didPressConfirm, this.state.currentDate);
}
this.setState({ isPickerVisible: false });
};
handleChange = (event, date) => {
console.log('handleChange',event.timeStamp,DateTime.fromJSDate(date).toFormat("HH:mm:ss"));
if (this.props.onChange) {
this.props.onChange(date);
}
this.setState({ currentDate: new Date(date) });
};
render() {
const {
cancelButtonTestID,
confirmButtonTestID,
cancelTextIOS,
confirmTextIOS,
customCancelButtonIOS,
customConfirmButtonIOS,
customHeaderIOS,
customPickerIOS,
date,
display,
isDarkModeEnabled,
isVisible,
modalStyleIOS,
modalPropsIOS,
pickerContainerStyleIOS,
pickerStyleIOS,
pickerComponentStyleIOS,
onCancel,
onConfirm,
onChange,
onHide,
backdropStyleIOS,
buttonTextColorIOS,
...otherProps
} = this.props;
const isAppearanceModuleAvailable = !!(
Appearance && Appearance.getColorScheme
);
const _isDarkModeEnabled =
isDarkModeEnabled === undefined && isAppearanceModuleAvailable
? Appearance.getColorScheme() === "dark"
: isDarkModeEnabled || false;
const ConfirmButtonComponent = customConfirmButtonIOS || ConfirmButton;
const CancelButtonComponent = customCancelButtonIOS || CancelButton;
const PickerComponent = customPickerIOS || DateTimePicker;
const HeaderComponent = customHeaderIOS;
const themedContainerStyle = _isDarkModeEnabled
? pickerStyles.containerDark
: pickerStyles.containerLight;
return (
<Modal
isVisible={isVisible}
contentStyle={[pickerStyles.modal, modalStyleIOS]}
onBackdropPress={this.handleCancel}
onHide={this.handleHide}
backdropStyle={backdropStyleIOS}
{...modalPropsIOS}
>
<View
style={[
pickerStyles.container,
themedContainerStyle,
pickerContainerStyleIOS,
]}
>
{HeaderComponent && <HeaderComponent />}
{!HeaderComponent && display === "inline" && (
<View style={pickerStyles.headerFiller} />
)}
<View
style={[
display === "inline"
? pickerStyles.pickerInline
: pickerStyles.pickerSpinner,
pickerStyleIOS,
]}
>
<PickerComponent
display={display || "spinner"}
{...otherProps}
value={this.state.currentDate}
onChange={this.handleChange}
// Recent versions @react-native-community/datetimepicker (at least starting with 6.7.0)
// have a peculiar iOS behaviour where sometimes, for example in react-native Modal,
// the inline picker is not rendered correctly if in datetime mode. Explicitly setting the height
// of the native picker to 370 fixes this issue. This is dependent on the other styles applied to the picker
// and may need to be adjusted if the other styles are changed.
style={[
{
height:
!customPickerIOS &&
otherProps.mode === "datetime" &&
display === "inline"
? 380
: undefined,
},
pickerComponentStyleIOS,
]}
/>
</View>
<ConfirmButtonComponent
confirmButtonTestID={confirmButtonTestID}
isDarkModeEnabled={_isDarkModeEnabled}
onPress={this.handleConfirm}
label={confirmTextIOS}
buttonTextColorIOS={buttonTextColorIOS}
/>
</View>
<CancelButtonComponent
cancelButtonTestID={cancelButtonTestID}
isDarkModeEnabled={_isDarkModeEnabled}
onPress={this.handleCancel}
label={cancelTextIOS}
buttonTextColorIOS={buttonTextColorIOS}
/>
</Modal>
);
}
}
const pickerStyles = StyleSheet.create({
modal: {
justifyContent: "flex-end",
margin: 10,
marginBottom: isIphoneX() ? 34 : 10,
},
container: {
borderRadius: BORDER_RADIUS,
marginBottom: 8,
overflow: "hidden",
},
pickerSpinner: {
marginBottom: 8,
},
pickerInline: {
paddingHorizontal: 12,
paddingTop: 14,
},
containerLight: {
backgroundColor: BACKGROUND_COLOR_LIGHT,
},
containerDark: {
backgroundColor: BACKGROUND_COLOR_DARK,
},
});
export const ConfirmButton = ({
isDarkModeEnabled,
confirmButtonTestID,
onPress,
label,
buttonTextColorIOS,
style = confirmButtonStyles,
}) => {
const themedButtonStyle = isDarkModeEnabled
? confirmButtonStyles.buttonDark
: confirmButtonStyles.buttonLight;
const underlayColor = isDarkModeEnabled
? HIGHLIGHT_COLOR_DARK
: HIGHLIGHT_COLOR_LIGHT;
return (
<TouchableHighlight
testID={confirmButtonTestID}
style={[themedButtonStyle, style.button]}
underlayColor={underlayColor}
onPress={onPress}
accessible={true}
accessibilityRole="button"
accessibilityLabel={label}
>
<Text
style={[
style.text,
buttonTextColorIOS && { color: buttonTextColorIOS },
]}
>
{label}
</Text>
</TouchableHighlight>
);
};
export const confirmButtonStyles = StyleSheet.create({
button: {
borderTopWidth: StyleSheet.hairlineWidth,
backgroundColor: "transparent",
height: 57,
justifyContent: "center",
},
buttonLight: {
borderColor: BORDER_COLOR,
},
buttonDark: {
borderColor: BORDER_COLOR_DARK,
},
text: {
textAlign: "center",
color: BUTTON_FONT_COLOR,
fontSize: BUTTON_FONT_SIZE,
fontWeight: BUTTON_FONT_WEIGHT,
backgroundColor: "transparent",
},
});
export const CancelButton = ({
cancelButtonTestID,
isDarkModeEnabled,
onPress,
label,
buttonTextColorIOS,
style = cancelButtonStyles,
}) => {
const themedButtonStyle = isDarkModeEnabled
? cancelButtonStyles.buttonDark
: cancelButtonStyles.buttonLight;
const underlayColor = isDarkModeEnabled
? HIGHLIGHT_COLOR_DARK
: HIGHLIGHT_COLOR_LIGHT;
return (
<TouchableHighlight
testID={cancelButtonTestID}
style={[themedButtonStyle, style.button]}
underlayColor={underlayColor}
onPress={onPress}
accessible={true}
accessibilityRole="button"
accessibilityLabel={label}
>
<Text
style={[
style.text,
buttonTextColorIOS && { color: buttonTextColorIOS },
]}
>
{label}
</Text>
</TouchableHighlight>
);
};
export const cancelButtonStyles = StyleSheet.create({
button: {
borderRadius: BORDER_RADIUS,
height: 57,
justifyContent: "center",
},
buttonLight: {
backgroundColor: BACKGROUND_COLOR_LIGHT,
},
buttonDark: {
backgroundColor: BACKGROUND_COLOR_DARK,
},
text: {
padding: 10,
textAlign: "center",
color: BUTTON_FONT_COLOR,
fontSize: BUTTON_FONT_SIZE,
fontWeight: "600",
backgroundColor: "transparent",
},
});