Skip to content
1 change: 1 addition & 0 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const CONST = {
},
MODAL: {
MODAL_TYPE: {
CONFIRM: 'confirm',
CENTERED: 'centered',
BOTTOM_DOCKED: 'bottom_docked',
POPOVER: 'popover',
Expand Down
90 changes: 90 additions & 0 deletions src/components/ConfirmModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React from 'react';
import {
TouchableOpacity, Text, View,
} from 'react-native';
import PropTypes from 'prop-types';
import Header from './Header';
import Modal from './Modal';
import styles from '../styles/styles';
import CONST from '../CONST';
import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';

const propTypes = {
/** Title of the modal */
title: PropTypes.string.isRequired,

/** A callback to call when the form has been submitted */
onConfirm: PropTypes.func.isRequired,

/** A callback to call when the form has been closed */
onCancel: PropTypes.func.isRequired,

/** Modal visibility */
isVisible: PropTypes.bool.isRequired,

/** Confirm button text */
confirmText: PropTypes.string,

/** Cancel button text */
cancelText: PropTypes.string,

/** Modal content text */
prompt: PropTypes.string,

...windowDimensionsPropTypes,
};

const defaultProps = {
confirmText: 'Yes',
cancelText: 'No',
prompt: '',
};

const ConfirmModal = props => (
<Modal
onSubmit={props.onConfirm}
onClose={props.onCancel}
isVisible={props.isVisible}
type={props.isSmallScreenWidth
? CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED
: CONST.MODAL.MODAL_TYPE.CONFIRM}
>
<View style={styles.m5}>
<View style={[styles.flexRow, styles.mb4]}>
<Header title={props.title} />
</View>

<Text style={styles.textP}>
{props.prompt}
</Text>

<TouchableOpacity
style={[styles.button, styles.buttonSuccess, styles.mt4]}
onPress={props.onConfirm}
>
<Text
style={[
styles.buttonText,
styles.buttonSuccessText,
]}
>
{props.confirmText}
</Text>
</TouchableOpacity>

<TouchableOpacity
style={[styles.button, styles.mt3]}
onPress={props.onCancel}
>
<Text style={styles.buttonText}>
{props.cancelText}
</Text>
</TouchableOpacity>
</View>
</Modal>
);

ConfirmModal.propTypes = propTypes;
ConfirmModal.defaultProps = defaultProps;
ConfirmModal.displayName = 'ConfirmModal';
export default withWindowDimensions(ConfirmModal);
1 change: 1 addition & 0 deletions src/components/Modal/ModalPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const propTypes = {

// Style of modal to display
type: PropTypes.oneOf([
CONST.MODAL.MODAL_TYPE.CONFIRM,
CONST.MODAL.MODAL_TYPE.CENTERED,
CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED,
CONST.MODAL.MODAL_TYPE.POPOVER,
Expand Down
45 changes: 10 additions & 35 deletions src/components/UpdateAppModal/BaseUpdateAppModal.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import React, {PureComponent} from 'react';
import {
TouchableOpacity, Text,
} from 'react-native';
import HeaderWithCloseButton from '../HeaderWithCloseButton';
import Modal from '../Modal';
import styles from '../../styles/styles';
import {propTypes, defaultProps} from './UpdateAppModalPropTypes';
import ConfirmModal from '../ConfirmModal';

class BaseUpdateAppModal extends PureComponent {
constructor(props) {
Expand All @@ -29,36 +24,16 @@ class BaseUpdateAppModal extends PureComponent {
render() {
return (
<>
<Modal
onSubmit={this.submitAndClose}
onClose={() => this.setState({isModalOpen: false})}
<ConfirmModal
title="Update App"
isVisible={this.state.isModalOpen}
>
<HeaderWithCloseButton
title="Update App"
onCloseButtonPress={() => this.setState({isModalOpen: false})}
/>
<Text style={[styles.textLabel, styles.p4]}>
A new version of Expensify.cash is available.
Update now or restart the app at a later time to download the latest changes.
</Text>
{this.props.onSubmit && (
<TouchableOpacity
style={[styles.button, styles.buttonSuccess, styles.buttonConfirm]}
onPress={this.submitAndClose}
>
<Text
style={[
styles.buttonText,
styles.buttonSuccessText,
styles.buttonConfirmText,
]}
>
Update App
</Text>
</TouchableOpacity>
)}
</Modal>
onConfirm={this.submitAndClose}
onCancel={() => this.setState({isModalOpen: false})}
prompt="A new version of Expensify.cash is available.
Update now or restart the app at a later time to download the latest changes."
confirmText="Update App"
cancelText="Cancel"
/>
</>
);
}
Expand Down
30 changes: 30 additions & 0 deletions src/styles/getModalStyles.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,36 @@ export default (type, windowDimensions, popoverAnchorPosition = {}) => {
let shouldAddTopSafeAreaPadding = false;

switch (type) {
case CONST.MODAL.MODAL_TYPE.CONFIRM:
// A confirm modal is one that has a visible backdrop
// and can be dismissed by clicking outside of the modal.
modalStyle = {
...modalStyle,
...{
alignItems: 'center',
},
};
modalContainerStyle = {
// Shadow Styles
shadowColor: colors.black,
shadowOffset: {
width: 0,
height: 0,
},
shadowOpacity: 0.1,
shadowRadius: 5,

borderRadius: 12,
overflow: 'hidden',
width: variables.sideBarWidth,
};

// setting this to undefined we effectively disable the
// ability to swipe our modal
swipeDirection = undefined;
animationIn = 'fadeIn';
animationOut = 'fadeOut';
break;
case CONST.MODAL.MODAL_TYPE.CENTERED:
// A centered modal is one that has a visible backdrop
// and can be dismissed by clicking outside of the modal.
Expand Down
8 changes: 8 additions & 0 deletions src/styles/utilities/spacing.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ export default {
margin: 8,
},

m4: {
margin: 16,
},

m5: {
margin: 20,
},

mh1: {
marginHorizontal: 4,
},
Expand Down