Skip to content

Commit

Permalink
Merge pull request #17132 from Expensify/cristi_workspaces-in-MoneyRe…
Browse files Browse the repository at this point in the history
…questModal

Workspaces in money request modal
  • Loading branch information
Julesssss authored Apr 14, 2023
2 parents 5c62dce + 9754a32 commit 32b1e01
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import SettlementButton from './SettlementButton';
import ROUTES from '../ROUTES';
import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from './withCurrentUserPersonalDetails';
import * as IOUUtils from '../libs/IOUUtils';
import avatarPropTypes from './avatarPropTypes';
import optionPropTypes from './optionPropTypes';

const propTypes = {
/** Callback to inform parent modal of success */
Expand All @@ -41,20 +41,7 @@ const propTypes = {
iouType: PropTypes.string,

/** Selected participants from MoneyRequestModal with login */
participants: PropTypes.arrayOf(PropTypes.shape({
login: PropTypes.string.isRequired,
alternateText: PropTypes.string,
hasDraftComment: PropTypes.bool,
icons: PropTypes.arrayOf(avatarPropTypes),
searchText: PropTypes.string,
text: PropTypes.string,
keyForList: PropTypes.string,
reportID: PropTypes.string,
// eslint-disable-next-line react/forbid-prop-types
participantsList: PropTypes.arrayOf(PropTypes.object),
payPalMeAddress: PropTypes.string,
phoneNumber: PropTypes.string,
})).isRequired,
participants: PropTypes.arrayOf(optionPropTypes).isRequired,

/** Can the participants be modified or not */
canModifyParticipants: PropTypes.bool,
Expand Down Expand Up @@ -97,7 +84,7 @@ const defaultProps = {
...withCurrentUserPersonalDetailsDefaultProps,
};

class IOUConfirmationList extends Component {
class MoneyRequestConfirmationList extends Component {
constructor(props) {
super(props);

Expand Down Expand Up @@ -194,13 +181,13 @@ class IOUConfirmationList extends Component {
);

sections.push({
title: this.props.translate('iOUConfirmationList.whoPaid'),
title: this.props.translate('moneyRequestConfirmationList.whoPaid'),
data: [formattedMyPersonalDetails],
shouldShow: true,
indexOffset: 0,
isDisabled: true,
}, {
title: this.props.translate('iOUConfirmationList.whoWasThere'),
title: this.props.translate('moneyRequestConfirmationList.whoWasThere'),
data: formattedParticipants,
shouldShow: true,
indexOffset: 1,
Expand Down Expand Up @@ -293,7 +280,7 @@ class IOUConfirmationList extends Component {
onSelectRow={canModifyParticipants ? this.toggleOption : undefined}
onConfirmSelection={this.confirm}
onChangeText={this.props.onUpdateComment}
textInputLabel={this.props.translate('iOUConfirmationList.whatsItFor')}
textInputLabel={this.props.translate('moneyRequestConfirmationList.whatsItFor')}
placeholderText={this.props.translate('common.optional')}
selectedOptions={this.getSelectedOptions()}
canSelectMultipleOptions={canModifyParticipants}
Expand Down Expand Up @@ -327,8 +314,8 @@ class IOUConfirmationList extends Component {
}
}

IOUConfirmationList.propTypes = propTypes;
IOUConfirmationList.defaultProps = defaultProps;
MoneyRequestConfirmationList.propTypes = propTypes;
MoneyRequestConfirmationList.defaultProps = defaultProps;

export default compose(
withLocalize,
Expand All @@ -340,4 +327,4 @@ export default compose(
key: ONYXKEYS.SESSION,
},
}),
)(IOUConfirmationList);
)(MoneyRequestConfirmationList);
4 changes: 4 additions & 0 deletions src/components/optionPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,8 @@ export default PropTypes.shape({

/** If we need to show a brick road indicator or not */
brickRoadIndicator: PropTypes.oneOf([CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, '']),

phoneNumber: PropTypes.string,

payPalMeAddress: PropTypes.string,
});
2 changes: 1 addition & 1 deletion src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ export default {
tfaRequiredTitle: 'Two factor authentication\nrequired',
tfaRequiredDescription: 'Please enter the two-factor authentication code\nwhere you are trying to sign in.',
},
iOUConfirmationList: {
moneyRequestConfirmationList: {
whoPaid: 'Who paid?',
whoWasThere: 'Who was there?',
whatsItFor: 'What\'s it for?',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export default {
tfaRequiredTitle: 'Se requiere autenticación\nde dos factores',
tfaRequiredDescription: 'Por favor, introduce el código de autenticación de dos factores\ndonde estás intentando iniciar sesión.',
},
iOUConfirmationList: {
moneyRequestConfirmationList: {
whoPaid: '¿Quién pago?',
whoWasThere: '¿Quién asistió?',
whatsItFor: '¿Para qué es?',
Expand Down
67 changes: 67 additions & 0 deletions src/libs/OptionsListUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import _ from 'underscore';
import Onyx from 'react-native-onyx';
import lodashOrderBy from 'lodash/orderBy';
import lodashGet from 'lodash/get';
import Str from 'expensify-common/lib/str';
import ONYXKEYS from '../ONYXKEYS';
import CONST from '../CONST';
Expand Down Expand Up @@ -86,6 +87,45 @@ Onyx.connect({
},
});

const policyExpenseReports = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
callback: (report, key) => {
if (!ReportUtils.isPolicyExpenseChat(report)) {
return;
}
policyExpenseReports[key] = report;
},
});

/**
* Get the options for a policy expense report.
* @param {Object} report
* @returns {Array}
*/
function getPolicyExpenseReportOptions(report) {
if (!ReportUtils.isPolicyExpenseChat(report)) {
return [];
}
const filteredPolicyExpenseReports = _.filter(policyExpenseReports, policyExpenseReport => policyExpenseReport.policyID === report.policyID);
return _.map(filteredPolicyExpenseReports, (expenseReport) => {
const policyExpenseChatAvatarSource = lodashGet(policies, [
`${ONYXKEYS.COLLECTION.POLICY}${expenseReport.policyID}`, 'avatar',
]) || ReportUtils.getDefaultWorkspaceAvatar(expenseReport.displayName);
return {
...expenseReport,
keyForList: expenseReport.policyID,
text: expenseReport.displayName,
alternateText: Localize.translateLocal('workspace.common.workspace'),
icons: [{
source: policyExpenseChatAvatarSource,
name: expenseReport.displayName,
type: CONST.ICON_TYPE_WORKSPACE,
}],
};
});
}

/**
* Adds expensify SMS domain (@expensify.sms) if login is a phone number and if it's not included yet
*
Expand Down Expand Up @@ -135,6 +175,31 @@ function getPersonalDetailsForLogins(logins, personalDetails) {
return personalDetailsForLogins;
}

/**
* Get the participant options for a report.
* @param {Object} report
* @param {Array<Object>} personalDetails
* @returns {Array}
*/
function getParticipantsOptions(report, personalDetails) {
const participants = lodashGet(report, 'participants', []);
return _.map(getPersonalDetailsForLogins(participants, personalDetails), details => ({
keyForList: details.login,
login: details.login,
text: details.displayName,
firstName: lodashGet(details, 'firstName', ''),
lastName: lodashGet(details, 'lastName', ''),
alternateText: Str.isSMSLogin(details.login) ? Str.removeSMSDomain(details.login) : details.login,
icons: [{
source: ReportUtils.getAvatar(details.avatar, details.login),
name: details.login,
type: CONST.ICON_TYPE_AVATAR,
}],
payPalMeAddress: lodashGet(details, 'payPalMeAddress', ''),
phoneNumber: lodashGet(details, 'phoneNumber', ''),
}));
}

/**
* Constructs a Set with all possible names (displayName, firstName, lastName, email) for all participants in a report,
* to be used in isSearchStringMatch.
Expand Down Expand Up @@ -828,4 +893,6 @@ export {
getIOUConfirmationOptionsFromParticipants,
getSearchText,
getAllReportErrors,
getPolicyExpenseReportOptions,
getParticipantsOptions,
};
66 changes: 29 additions & 37 deletions src/pages/iou/MoneyRequestModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ import {View} from 'react-native';
import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
import IOUAmountPage from './steps/IOUAmountPage';
import IOUParticipantsPage from './steps/IOUParticipantsPage/IOUParticipantsPage';
import IOUConfirmPage from './steps/IOUConfirmPage';
import MoneyRequestAmountPage from './steps/MoneyRequestAmountPage';
import MoneyRequestParticipantsPage from './steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage';
import MoneyRequestConfirmPage from './steps/MoneyRequestConfirmPage';
import ModalHeader from './ModalHeader';
import styles from '../../styles/styles';
import * as IOU from '../../libs/actions/IOU';
Expand Down Expand Up @@ -99,38 +98,26 @@ const defaultProps = {

// Determines type of step to display within Modal, value provides the title for that page.
const Steps = {
IOUAmount: 'iou.amount',
IOUParticipants: 'iou.participants',
IOUConfirm: 'iou.confirm',
MoneyRequestAmount: 'moneyRequest.amount',
MoneyRequestParticipants: 'moneyRequest.participants',
MoneyRequestConfirm: 'moneyRequest.confirm',
};

const MoneyRequestModal = (props) => {
const reportParticipants = lodashGet(props, 'report.participants', []);
const participantsWithDetails = _.map(OptionsListUtils.getPersonalDetailsForLogins(reportParticipants, props.personalDetails), personalDetails => ({
login: personalDetails.login,
text: personalDetails.displayName,
firstName: lodashGet(personalDetails, 'firstName', ''),
lastName: lodashGet(personalDetails, 'lastName', ''),
alternateText: Str.isSMSLogin(personalDetails.login) ? Str.removeSMSDomain(personalDetails.login) : personalDetails.login,
icons: [{
source: ReportUtils.getAvatar(personalDetails.avatar, personalDetails.login),
name: personalDetails.login,
type: CONST.ICON_TYPE_AVATAR,
}],
keyForList: personalDetails.login,
payPalMeAddress: lodashGet(personalDetails, 'payPalMeAddress', ''),
phoneNumber: lodashGet(personalDetails, 'phoneNumber', ''),
}));

// Skip IOUParticipants step if participants are passed in
const steps = reportParticipants.length ? [Steps.IOUAmount, Steps.IOUConfirm] : [Steps.IOUAmount, Steps.IOUParticipants, Steps.IOUConfirm];
const reportParticipants = lodashGet(props, 'report.participants', []);
const steps = reportParticipants.length ? [Steps.MoneyRequestAmount, Steps.MoneyRequestConfirm] : [Steps.MoneyRequestAmount, Steps.MoneyRequestParticipants, Steps.MoneyRequestConfirm];

const prevCreatingIOUTransactionStatusRef = useRef(lodashGet(props.iou, 'creatingIOUTransaction'));
const prevNetworkStatusRef = useRef(props.network.isOffline);

const [previousStepIndex, setPreviousStepIndex] = useState(0);
const [currentStepIndex, setCurrentStepIndex] = useState(0);
const [participants, setParticipants] = useState(participantsWithDetails);
const [selectedOptions, setSelectedOptions] = useState(
ReportUtils.isPolicyExpenseChat(props.report)
? OptionsListUtils.getPolicyExpenseReportOptions(props.report)
: OptionsListUtils.getParticipantsOptions(props.report, props.personalDetails),
);
const [amount, setAmount] = useState('');
const [comment, setComment] = useState('');

Expand Down Expand Up @@ -237,7 +224,7 @@ const MoneyRequestModal = (props) => {
const amountInDollars = Math.round(amount * 100);
const currency = props.iou.selectedCurrencyCode;
const trimmedComment = comment.trim();
const participant = participants[0];
const participant = selectedOptions[0];

if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) {
IOU.sendMoneyElsewhere(
Expand Down Expand Up @@ -273,7 +260,7 @@ const MoneyRequestModal = (props) => {
participant,
);
}
}, [amount, comment, participants, props.currentUserPersonalDetails.login, props.iou.selectedCurrencyCode, props.report]);
}, [amount, comment, selectedOptions, props.currentUserPersonalDetails.login, props.iou.selectedCurrencyCode, props.report]);

/**
* @param {Array} selectedParticipants
Expand Down Expand Up @@ -309,6 +296,11 @@ const MoneyRequestModal = (props) => {
);
return;
}
if (!selectedParticipants[0].login) {
// TODO - request to the policy expense chat. Not implemented yet!
// Will be implemented here: https://github.com/Expensify/Expensify/issues/270581
return;
}
IOU.requestMoney(
props.report,
Math.round(amount * 100),
Expand All @@ -331,13 +323,13 @@ const MoneyRequestModal = (props) => {
{!didScreenTransitionEnd && <FullScreenLoadingIndicator />}
{didScreenTransitionEnd && (
<>
{currentStep === Steps.IOUAmount && (
{currentStep === Steps.MoneyRequestAmount && (
<AnimatedStep
direction={direction}
style={[styles.flex1, safeAreaPaddingBottomStyle]}
>
{modalHeader}
<IOUAmountPage
<MoneyRequestAmountPage
onStepComplete={(value) => {
setAmount(value);
navigateToNextStep();
Expand All @@ -350,29 +342,29 @@ const MoneyRequestModal = (props) => {
/>
</AnimatedStep>
)}
{currentStep === Steps.IOUParticipants && (
{currentStep === Steps.MoneyRequestParticipants && (
<AnimatedStep
style={[styles.flex1]}
direction={direction}
>
{modalHeader}
<IOUParticipantsPage
participants={participants}
<MoneyRequestParticipantsPage
participants={selectedOptions}
hasMultipleParticipants={props.hasMultipleParticipants}
onAddParticipants={selectedParticipants => setParticipants(selectedParticipants)}
onAddParticipants={setSelectedOptions}
onStepComplete={navigateToNextStep}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
iouType={props.iouType}
/>
</AnimatedStep>
)}
{currentStep === Steps.IOUConfirm && (
{currentStep === Steps.MoneyRequestConfirm && (
<AnimatedStep
style={[styles.flex1, safeAreaPaddingBottomStyle]}
direction={direction}
>
{modalHeader}
<IOUConfirmPage
<MoneyRequestConfirmPage
onConfirm={(selectedParticipants) => {
// TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT
createTransaction(selectedParticipants);
Expand All @@ -384,7 +376,7 @@ const MoneyRequestModal = (props) => {
ReportScrollManager.scrollToBottom();
}}
hasMultipleParticipants={props.hasMultipleParticipants}
participants={_.filter(participants, email => props.currentUserPersonalDetails.login !== email.login)}
participants={_.filter(selectedOptions, email => props.currentUserPersonalDetails.login !== email.login)}
iouAmount={amount}
comment={comment}
onUpdateComment={value => setComment(value)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const defaultProps = {
selectedCurrencyCode: CONST.CURRENCY.USD,
},
};
class IOUAmountPage extends React.Component {
class MoneyRequestAmountPage extends React.Component {
constructor(props) {
super(props);

Expand Down Expand Up @@ -344,12 +344,12 @@ class IOUAmountPage extends React.Component {
}
}

IOUAmountPage.propTypes = propTypes;
IOUAmountPage.defaultProps = defaultProps;
MoneyRequestAmountPage.propTypes = propTypes;
MoneyRequestAmountPage.defaultProps = defaultProps;

export default compose(
withLocalize,
withOnyx({
iou: {key: ONYXKEYS.IOU},
}),
)(IOUAmountPage);
)(MoneyRequestAmountPage);
Loading

0 comments on commit 32b1e01

Please sign in to comment.