Skip to content

Commit

Permalink
Merge pull request #18143 from Expensify/jules-iouPreview-showForBill…
Browse files Browse the repository at this point in the history
…Split

Enable IOUPreview for bill splits
  • Loading branch information
luacmartins authored May 5, 2023
2 parents bf36fa9 + 721d353 commit 689be6c
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 118 deletions.
7 changes: 4 additions & 3 deletions src/components/MoneyRequestConfirmationList.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
import _ from 'underscore';
import styles from '../styles/styles';
import * as OptionsListUtils from '../libs/OptionsListUtils';
Expand Down Expand Up @@ -105,10 +106,10 @@ class MoneyRequestConfirmationList extends Component {
*/
getSplitOrRequestOptions() {
return [{
text: this.props.translate(
this.props.hasMultipleParticipants ? 'iou.split' : 'iou.request',
text: Str.recapitalize(this.props.translate(
this.props.hasMultipleParticipants ? 'iou.splitAmount' : 'iou.requestAmount',
{amount: CurrencyUtils.convertToDisplayString(this.props.iouAmount, this.props.iou.selectedCurrencyCode)},
),
)),
value: this.props.hasMultipleParticipants ? CONST.IOU.MONEY_REQUEST_TYPE.SPLIT : CONST.IOU.MONEY_REQUEST_TYPE.REQUEST,
}];
}
Expand Down
29 changes: 17 additions & 12 deletions src/components/ReportActionItem/IOUAction.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const propTypes = {
/** The ID of the associated chatReport */
chatReportID: PropTypes.string.isRequired,

/** The ID of the associated request report */
requestReportID: PropTypes.string.isRequired,

/** Is this IOUACTION the most recent? */
isMostRecentIOUReportAction: PropTypes.bool.isRequired,

Expand Down Expand Up @@ -66,14 +69,16 @@ const defaultProps = {
};

const IOUAction = (props) => {
const launchDetailsModal = () => {
Navigation.navigate(ROUTES.getIouDetailsRoute(props.chatReportID, props.action.originalMessage.IOUReportID));
const hasMultipleParticipants = props.chatReport.participants.length > 1;
const onIOUPreviewPressed = () => {
if (hasMultipleParticipants) {
Navigation.navigate(ROUTES.getReportParticipantsRoute(props.chatReportID));
} else {
Navigation.navigate(ROUTES.getIouDetailsRoute(props.chatReportID, props.action.originalMessage.IOUReportID));
}
};

const shouldShowIOUPreview = (
props.isMostRecentIOUReportAction
&& Boolean(props.action.originalMessage.IOUReportID)
&& props.chatReport.hasOutstandingIOU) || props.action.originalMessage.type === 'pay';
const shouldShowIOUPreview = props.isMostRecentIOUReportAction || props.action.originalMessage.type === 'pay';

let shouldShowPendingConversionMessage = false;
if (
Expand All @@ -93,21 +98,21 @@ const IOUAction = (props) => {
action={props.action}
chatReportID={props.chatReportID}
contextMenuAnchor={props.contextMenuAnchor}
shouldAllowViewDetails={Boolean(props.action.originalMessage.IOUReportID)}
onViewDetailsPressed={launchDetailsModal}
onViewDetailsPressed={onIOUPreviewPressed}
checkIfContextMenuActive={props.checkIfContextMenuActive}
isHovered={props.isHovered}
/>
{shouldShowIOUPreview && (
<IOUPreview
iouReportID={props.action.originalMessage.IOUReportID.toString()}
iouReportID={props.requestReportID}
chatReportID={props.chatReportID}
isBillSplit={hasMultipleParticipants}
action={props.action}
contextMenuAnchor={props.contextMenuAnchor}
checkIfContextMenuActive={props.checkIfContextMenuActive}
shouldShowPendingConversionMessage={shouldShowPendingConversionMessage}
onPayButtonPressed={launchDetailsModal}
onPreviewPressed={launchDetailsModal}
onPayButtonPressed={onIOUPreviewPressed}
onPreviewPressed={onIOUPreviewPressed}
containerStyles={[
styles.cursorPointer,
props.isHovered
Expand All @@ -131,7 +136,7 @@ export default compose(
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`,
},
iouReport: {
key: ({action}) => `${ONYXKEYS.COLLECTION.REPORT}${action.originalMessage.IOUReportID}`,
key: ({requestReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`,
},
reportActions: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`,
Expand Down
83 changes: 28 additions & 55 deletions src/components/ReportActionItem/IOUPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
Pressable,
} from 'react-native';
import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import _ from 'underscore';
Expand All @@ -26,7 +25,7 @@ import ControlSelection from '../../libs/ControlSelection';
import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
import {showContextMenuForReport} from '../ShowContextMenuContext';
import * as ReportUtils from '../../libs/ReportUtils';
import * as OptionsListUtils from '../../libs/OptionsListUtils';
import Button from '../Button';
import * as CurrencyUtils from '../../libs/CurrencyUtils';

Expand Down Expand Up @@ -80,16 +79,12 @@ const propTypes = {
hasOutstandingIOU: PropTypes.bool,
}),

/** True if this is this IOU is a split instead of a 1:1 request */
isBillSplit: PropTypes.bool.isRequired,

/** True if the IOU Preview card is hovered */
isHovered: PropTypes.bool,

/** All of the personal details for everyone */
personalDetails: PropTypes.objectOf(PropTypes.shape({

/** This is either the user's full name, or their login if full name is an empty string */
displayName: PropTypes.string.isRequired,
})),

/** Session info for the currently logged in user. */
session: PropTypes.shape({
/** Currently logged in user email */
Expand Down Expand Up @@ -122,7 +117,6 @@ const defaultProps = {
walletTerms: {},
pendingAction: null,
isHovered: false,
personalDetails: {},
session: {
email: null,
},
Expand All @@ -137,30 +131,21 @@ const IOUPreview = (props) => {
if (props.iouReport.total === 0) {
return null;
}

const sessionEmail = lodashGet(props.session, 'email', null);
const managerEmail = props.iouReport.managerEmail || '';
const ownerEmail = props.iouReport.ownerEmail || '';

// When displaying within a IOUDetailsModal we cannot guarentee that participants are included in the originalMessage data
// Because an IOUPreview of type split can never be rendered within the IOUDetailsModal, manually building the email array is only needed for non-billSplit ious
const participantEmails = props.isBillSplit ? props.action.originalMessage.participants : [managerEmail, ownerEmail];
const participantAvatars = OptionsListUtils.getAvatarsForLogins(participantEmails);

// Pay button should only be visible to the manager of the report.
const isCurrentUserManager = managerEmail === sessionEmail;

const managerName = ReportUtils.getDisplayNameForParticipant(managerEmail, true);
const ownerName = ReportUtils.getDisplayNameForParticipant(ownerEmail, true);
const managerAvatar = {
source: ReportUtils.getAvatar(lodashGet(props.personalDetails, [managerEmail, 'avatar']), managerEmail),
type: CONST.ICON_TYPE_AVATAR,
name: managerEmail,
};
const ownerAvatar = {
source: ReportUtils.getAvatar(lodashGet(props.personalDetails, [ownerEmail, 'avatar']), ownerEmail),
type: CONST.ICON_TYPE_AVATAR,
name: ownerEmail,
};
const cachedTotal = props.iouReport.total && props.iouReport.currency
? CurrencyUtils.convertToDisplayString(props.iouReport.total, props.iouReport.currency)
: '';
const avatarTooltip = [Str.removeSMSDomain(managerEmail), Str.removeSMSDomain(ownerEmail)];
// Get request formatting options, as long as currency is provided
const requestAmount = props.isBillSplit ? props.action.originalMessage.amount : props.iouReport.total;
const requestCurrency = props.isBillSplit ? lodashGet(props.action, 'originalMessage.currency', CONST.CURRENCY.USD) : props.iouReport.currency;

const showContextMenu = (event) => {
// Use action and shouldHidePayButton props to check if we are in IOUDetailsModal,
Expand Down Expand Up @@ -191,51 +176,42 @@ const IOUPreview = (props) => {
needsOffscreenAlphaCompositing
>
<View style={[styles.iouPreviewBox, ...props.containerStyles]}>
<Text>
{props.isBillSplit ? props.translate('iou.split') : props.translate('iou.cash')}
</Text>
<View style={[styles.flexRow]}>
<View style={[styles.flex1, styles.flexRow, styles.alignItemsCenter]}>
<Text style={styles.h1}>
{cachedTotal}
{CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency)}
</Text>
{!props.iouReport.hasOutstandingIOU && (
{!props.iouReport.hasOutstandingIOU && !props.isBillSplit && (
<View style={styles.iouPreviewBoxCheckmark}>
<Icon src={Expensicons.Checkmark} fill={themeColors.iconSuccessFill} />
</View>
)}
</View>
<View style={styles.iouPreviewBoxAvatar}>
<MultipleAvatars
icons={[managerAvatar, ownerAvatar]}
icons={participantAvatars}
secondAvatarStyle={[
styles.secondAvatarInline,
props.isHovered
? styles.iouPreviewBoxAvatarHover
: undefined,
]}
avatarTooltips={avatarTooltip}
avatarTooltips={participantEmails}
/>
</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>
{props.shouldShowPendingConversionMessage && (
<Text style={[styles.textLabel, styles.colorMuted]}>
{props.translate('iou.pendingConversionMessage')}
</Text>
)}
</>
)}

{!isCurrentUserManager && props.shouldShowPendingConversionMessage && (
<Text style={[styles.textLabel, styles.colorMuted]}>
{props.translate('iou.pendingConversionMessage')}
</Text>
)}

<Text>{lodashGet(props.action, 'originalMessage.comment', '')}</Text>

{(isCurrentUserManager
&& !props.shouldHidePayButton
&& props.iouReport.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && (
Expand Down Expand Up @@ -278,9 +254,6 @@ IOUPreview.displayName = 'IOUPreview';
export default compose(
withLocalize,
withOnyx({
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS,
},
iouReport: {
key: ({iouReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`,
},
Expand Down
26 changes: 6 additions & 20 deletions src/components/ReportActionItem/IOUQuote.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import Text from '../Text';
import Icon from '../Icon';
import * as Expensicons from '../Icon/Expensicons';
import styles from '../../styles/styles';
import themeColors from '../../styles/themes/default';
import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
import withLocalize, {withLocalizePropTypes} from '../withLocalize';
import ControlSelection from '../../libs/ControlSelection';
Expand All @@ -25,9 +24,6 @@ const propTypes = {
/** Popover context menu anchor, used for showing context menu */
contextMenuAnchor: PropTypes.shape({current: PropTypes.elementType}),

/** Whether it is allowed to view details. */
shouldAllowViewDetails: PropTypes.bool,

/** Callback invoked when View Details is pressed */
onViewDetailsPressed: PropTypes.func,

Expand All @@ -42,7 +38,6 @@ const propTypes = {

const defaultProps = {
contextMenuAnchor: null,
shouldAllowViewDetails: false,
isHovered: false,
onViewDetailsPressed: () => {},
checkIfContextMenuActive: () => {},
Expand All @@ -53,9 +48,7 @@ const IOUQuote = props => (
{_.map(props.action.message, (fragment, index) => (
<Pressable
key={`iouQuote-${props.action.reportActionID}-${index}`}
onPress={props.shouldAllowViewDetails
? props.onViewDetailsPressed
: () => {}}
onPress={props.onViewDetailsPressed}
onPressIn={() => DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
onPressOut={() => ControlSelection.unblock()}
onLongPress={event => showContextMenuForReport(
Expand All @@ -65,27 +58,20 @@ const IOUQuote = props => (
props.action,
props.checkIfContextMenuActive,
)}
style={[styles.flexRow, styles.justifyContentBetween,
props.shouldAllowViewDetails
? undefined
: styles.cursorDefault,
]}
focusable={props.shouldAllowViewDetails}
style={[styles.flexRow, styles.justifyContentBetween]}
focusable
>
<Text style={[styles.flex1, styles.mr2]}>
<Text style={props.shouldAllowViewDetails && styles.chatItemMessageLink}>
<Text style={styles.chatItemMessageLink}>
{/* Get first word of IOU message */}
{fragment.text.split(' ')[0]}
</Text>
<Text style={[styles.chatItemMessage, props.shouldAllowViewDetails
? styles.cursorPointer
: styles.cursorDefault]}
>
<Text style={[styles.chatItemMessage, styles.cursorPointer]}>
{/* Get remainder of IOU message */}
{fragment.text.substring(fragment.text.indexOf(' '))}
</Text>
</Text>
<Icon src={Expensicons.ArrowRight} fill={props.shouldAllowViewDetails ? StyleUtils.getIconFillColor(getButtonState(props.isHovered)) : themeColors.transparent} />
<Icon src={Expensicons.ArrowRight} fill={StyleUtils.getIconFillColor(getButtonState(props.isHovered))} />
</Pressable>
))}
</View>
Expand Down
10 changes: 3 additions & 7 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ export default {
iou: {
amount: 'Amount',
cash: 'Cash',
split: 'Split',
participants: 'Participants',
splitBill: 'Split bill',
requestMoney: 'Request money',
Expand All @@ -317,13 +318,8 @@ export default {
settleExpensify: 'Pay with Expensify',
settleElsewhere: 'I\'ll settle up elsewhere',
settlePaypalMe: 'Pay with PayPal.me',
request: ({amount}) => `Request ${amount}`,
youowe: ({owner}) => `You owe ${owner}`,
youpaid: ({owner}) => `You paid ${owner}`,
owesyou: ({manager}) => `${manager} owes you`,
paidyou: ({manager}) => `${manager} paid you`,
split: ({amount}) => `Split ${amount}`,
send: ({amount}) => `Send ${amount}`,
requestAmount: ({amount}) => `request ${amount}`,
splitAmount: ({amount}) => `split ${amount}`,
noReimbursableExpenses: 'This report has an invalid amount',
pendingConversionMessage: 'Total will update when you\'re back online',
error: {
Expand Down
10 changes: 3 additions & 7 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ export default {
iou: {
amount: 'Importe',
cash: 'Efectivo',
split: 'Dividir',
participants: 'Participantes',
splitBill: 'Dividir factura',
requestMoney: 'Pedir dinero',
Expand All @@ -316,13 +317,8 @@ export default {
settleExpensify: 'Pagar con Expensify',
settleElsewhere: 'Voy a pagar de otra forma',
settlePaypalMe: 'Pagar con PayPal.me',
request: ({amount}) => `Solicitar ${amount}`,
youowe: ({owner}) => `Le debes a ${owner}`,
youpaid: ({owner}) => `Le pagaste a ${owner}`,
owesyou: ({manager}) => `${manager} te debe`,
paidyou: ({manager}) => `${manager} te pagó`,
split: ({amount}) => `Dividir ${amount}`,
send: ({amount}) => `Enviar ${amount}`,
requestAmount: ({amount}) => `solicitar ${amount}`,
splitAmount: ({amount}) => `dividir ${amount}`,
noReimbursableExpenses: 'El monto de este informe es inválido',
pendingConversionMessage: 'El total se actualizará cuando estés online',
error: {
Expand Down
Loading

0 comments on commit 689be6c

Please sign in to comment.