Skip to content

Commit

Permalink
Merge pull request #10578 from Expensify/francois-redBrickRoadWalletT…
Browse files Browse the repository at this point in the history
…erms

Add offline behavior and error handling for `AcceptWalletTerms`
  • Loading branch information
MariaHCD authored Sep 9, 2022
2 parents 679be43 + 5c81a0f commit 3cb5dbf
Show file tree
Hide file tree
Showing 19 changed files with 188 additions and 63 deletions.
11 changes: 11 additions & 0 deletions src/components/AvatarWithIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import bankAccountPropTypes from './bankAccountPropTypes';
import cardPropTypes from './cardPropTypes';
import userWalletPropTypes from '../pages/EnablePayments/userWalletPropTypes';
import {fullPolicyPropTypes} from '../pages/workspace/withFullPolicy';
import walletTermsPropTypes from '../pages/EnablePayments/walletTermsPropTypes';
import * as PolicyUtils from '../libs/PolicyUtils';
import * as PaymentMethods from '../libs/actions/PaymentMethods';

Expand Down Expand Up @@ -39,6 +40,9 @@ const propTypes = {

/** The user's wallet (coming from Onyx) */
userWallet: userWalletPropTypes,

/** Information about the user accepting the terms for payments */
walletTerms: walletTermsPropTypes,
};

const defaultProps = {
Expand All @@ -49,6 +53,7 @@ const defaultProps = {
bankAccountList: {},
cardList: {},
userWallet: {},
walletTerms: {},
};

const AvatarWithIndicator = (props) => {
Expand All @@ -73,6 +78,9 @@ const AvatarWithIndicator = (props) => {
() => _.some(cleanPolicies, PolicyUtils.hasPolicyError),
() => _.some(cleanPolicies, PolicyUtils.hasCustomUnitsError),
() => _.some(cleanPolicyMembers, PolicyUtils.hasPolicyMemberError),

// Wallet term errors that are not caused by an IOU (we show the red brick indicator for those in the LHN instead)
() => !_.isEmpty(props.walletTerms.errors) && !props.walletTerms.chatReportID,
];
const shouldShowIndicator = _.some(errorCheckingMethods, errorCheckingMethod => errorCheckingMethod());

Expand Down Expand Up @@ -112,4 +120,7 @@ export default withOnyx({
userWallet: {
key: ONYXKEYS.USER_WALLET,
},
walletTerms: {
key: ONYXKEYS.WALLET_TERMS,
},
})(AvatarWithIndicator);
2 changes: 2 additions & 0 deletions src/components/KYCWall/BaseKYCWall.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as PaymentMethods from '../../libs/actions/PaymentMethods';
import ONYXKEYS from '../../ONYXKEYS';
import Log from '../../libs/Log';
import {propTypes, defaultProps} from './kycWallPropTypes';
import * as Wallet from '../../libs/actions/Wallet';

// This component allows us to block various actions by forcing the user to first add a default payment method and successfully make it through our Know Your Customer flow
// before continuing to take whatever action they originally intended to take. It requires a button as a child and a native event so we can get the coordinates and use it
Expand All @@ -35,6 +36,7 @@ class KYCWall extends React.Component {
if (this.props.shouldListenForResize) {
this.dimensionsSubscription = Dimensions.addEventListener('change', this.setMenuPosition);
}
Wallet.setKYCWallSourceChatReportID(this.props.chatReportID);
}

componentWillUnmount() {
Expand Down
6 changes: 5 additions & 1 deletion src/components/KYCWall/kycWallPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@ const propTypes = {
isDisabled: PropTypes.bool,

/** The user's wallet */
userWallet: PropTypes.objectOf(userWalletPropTypes),
userWallet: userWalletPropTypes,

/** When the button is opened via an IOU, ID for the chatReport that the IOU is linked to */
chatReportID: PropTypes.number,
};

const defaultProps = {
userWallet: {},
popoverPlacement: 'top',
shouldListenForResize: false,
isDisabled: false,
chatReportID: 0,
};

export {propTypes, defaultProps};
106 changes: 62 additions & 44 deletions src/components/ReportActionItem/IOUPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import Icon from '../Icon';
import CONST from '../../CONST';
import * as Expensicons from '../Icon/Expensicons';
import Text from '../Text';
import * as PaymentMethods from '../../libs/actions/PaymentMethods';
import OfflineWithFeedback from '../OfflineWithFeedback';
import walletTermsPropTypes from '../../pages/EnablePayments/walletTermsPropTypes';

const propTypes = {
/** Additional logic for displaying the pay button */
Expand Down Expand Up @@ -75,6 +78,9 @@ const propTypes = {
email: PropTypes.string,
}).isRequired,

/** Information about the user accepting the terms for payments */
walletTerms: walletTermsPropTypes,

...withLocalizePropTypes,
};

Expand All @@ -84,6 +90,7 @@ const defaultProps = {
onPayButtonPressed: null,
onPreviewPressed: () => {},
containerStyles: [],
walletTerms: {},
};

const IOUPreview = (props) => {
Expand Down Expand Up @@ -124,10 +131,18 @@ const IOUPreview = (props) => {
{reportIsLoading
? <ActivityIndicator style={styles.iouPreviewBoxLoading} color={themeColors.text} />
: (
<View>
<View style={styles.flexRow}>
<View style={styles.flex1}>
<View style={styles.flexRow}>
<OfflineWithFeedback
pendingAction={CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}
errors={props.walletTerms.errors}
onClose={() => {
PaymentMethods.clearWalletTermsError();
Report.clearIOUError(props.chatReportID);
}}
errorRowStyles={[styles.mbn1]}
>
<View>
<View style={styles.flexRow}>
<View style={[styles.flex1, styles.flexRow]}>
<Text style={styles.h1}>
{cachedTotal}
</Text>
Expand All @@ -137,48 +152,48 @@ const IOUPreview = (props) => {
</View>
)}
</View>
<View style={styles.iouPreviewBoxAvatar}>
<MultipleAvatars
icons={[managerAvatar, ownerAvatar]}
secondAvatarStyle={[styles.secondAvatarInline]}
avatarTooltips={avatarTooltip}
/>
</View>
</View>
<View style={styles.iouPreviewBoxAvatar}>
<MultipleAvatars
icons={[managerAvatar, ownerAvatar]}
secondAvatarStyle={[styles.secondAvatarInline]}
avatarTooltips={avatarTooltip}
/>
</View>
</View>
{isCurrentUserManager
? (
<Text>
{props.iouReport.hasOutstandingIOU
? props.translate('iou.youowe', {owner: ownerName})
: props.translate('iou.youpaid', {owner: ownerName})}
</Text>
)
: (
<Text>
{props.iouReport.hasOutstandingIOU
? props.translate('iou.owesyou', {manager: managerName})
: props.translate('iou.paidyou', {manager: managerName})}
</Text>
)}
{(isCurrentUserManager
&& !props.shouldHidePayButton
&& props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && (
<TouchableOpacity
style={[styles.buttonSmall, styles.buttonSuccess, styles.mt4]}
onPress={props.onPayButtonPressed}
>
<Text
style={[
styles.buttonSmallText,
styles.buttonSuccessText,
]}
{isCurrentUserManager
? (
<Text>
{props.iouReport.hasOutstandingIOU
? props.translate('iou.youowe', {owner: ownerName})
: props.translate('iou.youpaid', {owner: ownerName})}
</Text>
)
: (
<Text>
{props.iouReport.hasOutstandingIOU
? props.translate('iou.owesyou', {manager: managerName})
: props.translate('iou.paidyou', {manager: managerName})}
</Text>
)}
{(isCurrentUserManager
&& !props.shouldHidePayButton
&& props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && (
<TouchableOpacity
style={[styles.buttonSmall, styles.buttonSuccess, styles.mt4]}
onPress={props.onPayButtonPressed}
>
{props.translate('iou.pay')}
</Text>
</TouchableOpacity>
))}
</View>
<Text
style={[
styles.buttonSmallText,
styles.buttonSuccessText,
]}
>
{props.translate('iou.pay')}
</Text>
</TouchableOpacity>
))}
</View>
</OfflineWithFeedback>
)}
</View>
</TouchableWithoutFeedback>
Expand All @@ -201,5 +216,8 @@ export default compose(
session: {
key: ONYXKEYS.SESSION,
},
walletTerms: {
key: ONYXKEYS.WALLET_TERMS,
},
}),
)(IOUPreview);
5 changes: 5 additions & 0 deletions src/components/SettlementButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ const propTypes = {
/** Information about the network */
network: networkPropTypes.isRequired,

/** When the button is opened via an IOU, ID for the chatReport that the IOU is linked to */
chatReportID: PropTypes.number,

...withLocalizePropTypes,
};

const defaultProps = {
currency: CONST.CURRENCY.USD,
shouldShowPaypal: false,
chatReportID: 0,
};

class SettlementButton extends React.Component {
Expand Down Expand Up @@ -80,6 +84,7 @@ class SettlementButton extends React.Component {
addBankAccountRoute={this.props.addBankAccountRoute}
addDebitCardRoute={this.props.addDebitCardRoute}
isDisabled={this.props.network.isOffline}
chatReportID={this.props.chatReportID}
>
{triggerKYCFlow => (
<ButtonWithMenu
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,8 @@ export default {
activatedTitle: 'Wallet activated!',
activatedMessage: 'Congrats, your wallet is set up and ready to make payments.',
checkBackLater: 'We\'re still reviewing your information. Please check back later.',
continueToPayment: 'Continue to payment',
continueToTransfer: 'Continue to transfer',
},
companyStep: {
headerTitle: 'Company information',
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,8 @@ export default {
activatedTitle: '¡Billetera activada!',
activatedMessage: 'Felicidades, tu Billetera está configurada y lista para hacer pagos.',
checkBackLater: 'Todavía estamos revisando tu información. Por favor, vuelva más tarde.',
continueToPayment: 'Continuar al pago',
continueToTransfer: 'Continuar a la transferencia',
},
companyStep: {
headerTitle: 'Información de la empresa',
Expand Down
8 changes: 8 additions & 0 deletions src/libs/actions/PaymentMethods.js
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,13 @@ function clearWalletError() {
Onyx.merge(ONYXKEYS.USER_WALLET, {errors: null});
}

/**
* Clear any error(s) related to the user's wallet terms
*/
function clearWalletTermsError() {
Onyx.merge(ONYXKEYS.WALLET_TERMS, {errors: null});
}

function deletePaymentCard(fundID) {
API.write('DeletePaymentCard', {
fundID,
Expand Down Expand Up @@ -355,4 +362,5 @@ export {
clearDeletePaymentMethodError,
clearAddPaymentMethodError,
clearWalletError,
clearWalletTermsError,
};
10 changes: 10 additions & 0 deletions src/libs/actions/Report.js
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,15 @@ function viewNewReportAction(reportID, action) {
});
}

/**
* Clear the errors associated with the IOUs of a given report.
*
* @param {Number} reportID
*/
function clearIOUError(reportID) {
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {errorFields: {iou: null}});
}

// We are using this map to ensure actions are only handled once
const handledReportActions = {};
Onyx.connect({
Expand Down Expand Up @@ -1636,4 +1645,5 @@ export {
buildOptimisticCreatedReportAction,
updatePolicyRoomName,
clearPolicyRoomNameErrors,
clearIOUError,
};
13 changes: 12 additions & 1 deletion src/libs/actions/Wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ function setWalletShouldShowFailedKYC(shouldShowFailedKYC) {
Onyx.merge(ONYXKEYS.USER_WALLET, {shouldShowFailedKYC});
}

/**
* Save the ID of the chat whose IOU triggered showing the KYC wall.
*
* @param {Number} chatReportID
*/
function setKYCWallSourceChatReportID(chatReportID) {
Onyx.merge(ONYXKEYS.WALLET_TERMS, {chatReportID});
}

/**
* Transforms a list of Idology errors to a translated displayable error string.
* @param {Array} idologyErrors
Expand Down Expand Up @@ -452,6 +461,7 @@ function verifyIdentity(parameters) {
*
* @param {Object} parameters
* @param {Boolean} parameters.hasAcceptedTerms
* @param {Number} parameters.chatReportID When accepting the terms of wallet to pay an IOU, indicates the parent chat ID of the IOU
*/
function acceptWalletTerms(parameters) {
const optimisticData = [
Expand Down Expand Up @@ -485,7 +495,7 @@ function acceptWalletTerms(parameters) {
},
];

API.write('AcceptWalletTerms', {hasAcceptedTerms: parameters.hasAcceptedTerms}, {optimisticData, successData, failureData});
API.write('AcceptWalletTerms', {hasAcceptedTerms: parameters.hasAcceptedTerms, reportID: parameters.chatReportID}, {optimisticData, successData, failureData});
}

/**
Expand Down Expand Up @@ -542,4 +552,5 @@ export {
updatePersonalDetails,
verifyIdentity,
acceptWalletTerms,
setKYCWallSourceChatReportID,
};
Loading

0 comments on commit 3cb5dbf

Please sign in to comment.