Skip to content

Commit

Permalink
Merge pull request #29309 from BeeMargarida/feat/28767-next-steps
Browse files Browse the repository at this point in the history
[NoQA] feat: show next steps for draft reports
  • Loading branch information
mountiny authored Oct 19, 2023
2 parents 20cd522 + fdc60fb commit fd04739
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 40 deletions.
1 change: 1 addition & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ const ONYXKEYS = {
TRANSACTION: 'transactions_',
SPLIT_TRANSACTION_DRAFT: 'splitTransactionDraft_',
PRIVATE_NOTES_DRAFT: 'privateNotesDraft_',
NEXT_STEP: 'reportNextStep_',

// Manual request tab selector
SELECTED_TAB: 'selectedTab_',
Expand Down
100 changes: 60 additions & 40 deletions src/components/MoneyReportHeader.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {useMemo} from 'react';
import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
import {View} from 'react-native';
import PropTypes from 'prop-types';
Expand All @@ -15,11 +16,13 @@ import Navigation from '../libs/Navigation/Navigation';
import ROUTES from '../ROUTES';
import ONYXKEYS from '../ONYXKEYS';
import CONST from '../CONST';
import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar';
import SettlementButton from './SettlementButton';
import Button from './Button';
import * as IOU from '../libs/actions/IOU';
import * as CurrencyUtils from '../libs/CurrencyUtils';
import reportPropTypes from '../pages/reportPropTypes';
import nextStepPropTypes from '../pages/nextStepPropTypes';

const propTypes = {
/** The report currently being looked at */
Expand All @@ -40,6 +43,9 @@ const propTypes = {
/** The chat report this report is linked to */
chatReport: reportPropTypes,

/** The next step for the report */
nextStep: nextStepPropTypes,

/** Personal details so we can get the ones for the report participants */
personalDetails: PropTypes.objectOf(participantPropTypes).isRequired,

Expand All @@ -54,13 +60,14 @@ const propTypes = {

const defaultProps = {
chatReport: {},
nextStep: {},
session: {
email: null,
},
policy: {},
};

function MoneyReportHeader({session, personalDetails, policy, chatReport, report: moneyRequestReport, isSmallScreenWidth}) {
function MoneyReportHeader({session, personalDetails, policy, chatReport, nextStep, report: moneyRequestReport, isSmallScreenWidth}) {
const {translate} = useLocalize();
const reimbursableTotal = ReportUtils.getMoneyRequestReimbursableTotal(moneyRequestReport);
const isApproved = ReportUtils.isReportApproved(moneyRequestReport);
Expand All @@ -81,9 +88,11 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
return isManager && !isDraft && !isApproved && !isSettled;
}, [policyType, isManager, isDraft, isApproved, isSettled]);
const shouldShowSubmitButton = isDraft && reimbursableTotal !== 0;
const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton;
const shouldShowNextSteps = isDraft && nextStep && (!_.isEmpty(nextStep.message) || !_.isEmpty(nextStep.expenseMessage));
const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextSteps;
const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport);
const formattedAmount = CurrencyUtils.convertToDisplayString(reimbursableTotal, moneyRequestReport.currency);
const isMoreContentShown = shouldShowNextSteps || (shouldShowAnyButton && isSmallScreenWidth);

return (
<View style={[styles.pt0]}>
Expand All @@ -96,7 +105,8 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
personalDetails={personalDetails}
shouldShowBackButton={isSmallScreenWidth}
onBackButtonPress={() => Navigation.goBack(ROUTES.HOME, false, true)}
shouldShowBorderBottom={!shouldShowAnyButton || !isSmallScreenWidth}
// Shows border if no buttons or next steps are showing below the header
shouldShowBorderBottom={!(shouldShowAnyButton && isSmallScreenWidth) && !(shouldShowNextSteps && !isSmallScreenWidth)}
>
{shouldShowSettlementButton && !isSmallScreenWidth && (
<View style={styles.pv2}>
Expand Down Expand Up @@ -141,43 +151,50 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
</View>
)}
</HeaderWithBackButton>
{shouldShowSettlementButton && isSmallScreenWidth && (
<View style={[styles.ph5, styles.pb2, isSmallScreenWidth && styles.borderBottom]}>
<SettlementButton
currency={moneyRequestReport.currency}
policyID={moneyRequestReport.policyID}
chatReportID={moneyRequestReport.chatReportID}
iouReport={moneyRequestReport}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)}
enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS}
addBankAccountRoute={bankAccountRoute}
shouldShowPaymentOptions
formattedAmount={formattedAmount}
/>
</View>
)}
{shouldShowApproveButton && isSmallScreenWidth && (
<View style={[styles.ph5, styles.pb2, isSmallScreenWidth && styles.borderBottom]}>
<Button
success
medium
text={translate('iou.approve')}
style={[styles.w100, styles.pr0]}
onPress={() => IOU.approveMoneyRequest(moneyRequestReport)}
/>
</View>
)}
{shouldShowSubmitButton && isSmallScreenWidth && (
<View style={[styles.ph5, styles.pb2, isSmallScreenWidth && styles.borderBottom]}>
<Button
medium
success={chatReport.isOwnPolicyExpenseChat}
text={translate('common.submit')}
style={[styles.w100, styles.pr0]}
onPress={() => IOU.submitReport(moneyRequestReport)}
/>
</View>
)}
<View style={isMoreContentShown ? [styles.dFlex, styles.flexColumn, styles.borderBottom] : []}>
{shouldShowNextSteps && (
<View style={[styles.ph5, styles.pb2]}>
<MoneyReportHeaderStatusBar nextStep={nextStep} />
</View>
)}
{shouldShowSettlementButton && isSmallScreenWidth && (
<View style={[styles.ph5, styles.pb2]}>
<SettlementButton
currency={moneyRequestReport.currency}
policyID={moneyRequestReport.policyID}
chatReportID={moneyRequestReport.chatReportID}
iouReport={moneyRequestReport}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)}
enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS}
addBankAccountRoute={bankAccountRoute}
shouldShowPaymentOptions
formattedAmount={formattedAmount}
/>
</View>
)}
{shouldShowApproveButton && isSmallScreenWidth && (
<View style={[styles.ph5, styles.pb2]}>
<Button
success
medium
text={translate('iou.approve')}
style={[styles.w100, styles.pr0]}
onPress={() => IOU.approveMoneyRequest(moneyRequestReport)}
/>
</View>
)}
{shouldShowSubmitButton && isSmallScreenWidth && (
<View style={[styles.ph5, styles.pb2]}>
<Button
medium
success={chatReport.isOwnPolicyExpenseChat}
text={translate('common.submit')}
style={[styles.w100, styles.pr0]}
onPress={() => IOU.submitReport(moneyRequestReport)}
/>
</View>
)}
</View>
</View>
);
}
Expand All @@ -192,6 +209,9 @@ export default compose(
chatReport: {
key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`,
},
nextStep: {
key: ({report}) => `${ONYXKEYS.COLLECTION.NEXT_STEP}${report.reportID}`,
},
session: {
key: ONYXKEYS.SESSION,
},
Expand Down
43 changes: 43 additions & 0 deletions src/components/MoneyReportHeaderStatusBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, {useMemo} from 'react';
import {Text, View} from 'react-native';
import _ from 'underscore';
import styles from '../styles/styles';
import * as NextStepUtils from '../libs/NextStepUtils';
import useLocalize from '../hooks/useLocalize';
import nextStepPropTypes from '../pages/nextStepPropTypes';
import RenderHTML from './RenderHTML';

const propTypes = {
/** The next step for the report */
nextStep: nextStepPropTypes,
};

const defaultProps = {
nextStep: {},
};

function MoneyReportHeaderStatusBar({nextStep}) {
const {translate} = useLocalize();

const messageContent = useMemo(() => {
const messageArray = _.isEmpty(nextStep.expenseMessage) ? nextStep.message : nextStep.expenseMessage;
return NextStepUtils.parseMessage(messageArray);
}, [nextStep.expenseMessage, nextStep.message]);

return (
<View style={[styles.dFlex, styles.flexRow, styles.alignItemsCenter, styles.overflowHidden, styles.w100]}>
<View style={styles.moneyRequestHeaderStatusBarBadge}>
<Text style={[styles.textStrong, styles.textLabel]}>{translate('iou.nextSteps')}</Text>
</View>
<View style={[styles.dFlex, styles.flexRow, styles.flexShrink1]}>
<RenderHTML html={messageContent} />
</View>
</View>
);
}

MoneyReportHeaderStatusBar.displayName = 'MoneyReportHeaderStatusBar';
MoneyReportHeaderStatusBar.propTypes = propTypes;
MoneyReportHeaderStatusBar.defaultProps = defaultProps;

export default MoneyReportHeaderStatusBar;
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ export default {
settledElsewhere: 'Paid elsewhere',
settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => `Pay ${formattedAmount} with Expensify`,
payElsewhere: 'Pay elsewhere',
nextSteps: 'Next Steps',
requestAmount: ({amount}: RequestAmountParams) => `request ${amount}`,
requestedAmount: ({formattedAmount, comment}: RequestedAmountMessageParams) => `requested ${formattedAmount}${comment ? ` for ${comment}` : ''}`,
splitAmount: ({amount}: SplitAmountParams) => `split ${amount}`,
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ export default {
settledElsewhere: 'Pagado de otra forma',
settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => `Pagar ${formattedAmount} con Expensify`,
payElsewhere: 'Pagar de otra forma',
nextSteps: 'Pasos Siguientes',
requestAmount: ({amount}: RequestAmountParams) => `solicitar ${amount}`,
requestedAmount: ({formattedAmount, comment}: RequestedAmountMessageParams) => `solicité ${formattedAmount}${comment ? ` para ${comment}` : ''}`,
splitAmount: ({amount}: SplitAmountParams) => `dividir ${amount}`,
Expand Down
19 changes: 19 additions & 0 deletions src/libs/NextStepUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import _ from 'underscore';
import Str from 'expensify-common/lib/str';

function parseMessage(messageToParse) {
let nextStepHTML = '';

_.each(messageToParse, (part) => {
const tagType = part.type || 'span';
nextStepHTML += `<${tagType}>${Str.safeEscape(part.text)}</${tagType}>`;
});

return nextStepHTML
.replace(/%expenses/g, 'this expense')
.replace(/%Expenses/g, 'This expense')
.replace(/%tobe/g, 'is');
}

// eslint-disable-next-line import/prefer-default-export
export {parseMessage};
48 changes: 48 additions & 0 deletions src/pages/nextStepPropTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import PropTypes from 'prop-types';

const messagePropType = PropTypes.shape({
text: PropTypes.string,
type: PropTypes.string,
action: PropTypes.string,
});

export default PropTypes.shape({
/** The message parts of the next step */
message: PropTypes.arrayOf(messagePropType),

/** The title for the next step */
title: PropTypes.string,

/** Whether the user should take some sort of action in order to unblock the report */
requiresUserAction: PropTypes.bool,

/** The type of next step */
type: PropTypes.oneOf(['neutral', 'alert', null]),

/** If the "Undo submit" button should be visible */
showUndoSubmit: PropTypes.bool,

/** Deprecated - If the next step should be displayed on mobile, related to OldApp */
showForMobile: PropTypes.bool,

/** If the next step should be displayed at the expense level */
showForExpense: PropTypes.bool,

/** An optional alternate message to display on expenses instead of what is provided in the "message" field */
expenseMessage: PropTypes.arrayOf(messagePropType),

/** The next person in the approval chain of the report */
nextReceiver: PropTypes.string,

/** An array of buttons to be displayed next to the next step */
buttons: PropTypes.arrayOf(
PropTypes.shape({
text: PropTypes.string,
tooltip: PropTypes.string,
disabled: PropTypes.bool,
hidden: PropTypes.bool,
// eslint-disable-next-line react/forbid-prop-types
data: PropTypes.array,
}),
),
});

0 comments on commit fd04739

Please sign in to comment.