Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Adding a category to a Split Bill #27936

Merged
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ad42f5a
re-test
rezkiy37 Sep 20, 2023
d07017b
connect report of participants of MoneyRequestCategoryPage
rezkiy37 Sep 20, 2023
52f20c9
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 20, 2023
16a1bba
attach category to split bill request
rezkiy37 Sep 20, 2023
5f17411
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 21, 2023
576ad93
fix crash when a participant a workspace
rezkiy37 Sep 21, 2023
f4f86d8
fix policy and report props of MoneyRequestConfirmationList
rezkiy37 Sep 21, 2023
e7ba3fc
fix props
rezkiy37 Sep 21, 2023
aa8f4f6
fix adding recently categories
rezkiy37 Sep 21, 2023
495894e
add recently categories for split bills optimistic
rezkiy37 Sep 21, 2023
361b880
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 21, 2023
cd5a6c2
use one withOnyx
rezkiy37 Sep 21, 2023
0857f55
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 22, 2023
57b61e5
add comments
rezkiy37 Sep 22, 2023
a036c4d
move isPolicyExpenseChat to parent
rezkiy37 Sep 22, 2023
ddcf5d6
hack onyx forwarding
rezkiy37 Sep 22, 2023
36b6951
fix props types
rezkiy37 Sep 22, 2023
f6439a9
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 25, 2023
fc7e639
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 26, 2023
0bcda51
unify a fix to get report id on confirm page
rezkiy37 Sep 26, 2023
1602707
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 28, 2023
6b581a9
clarify comment
rezkiy37 Sep 28, 2023
f45ad55
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 28, 2023
d21274f
unify iou report id getter
rezkiy37 Sep 28, 2023
5a5dc17
unify adding a category to recently used
rezkiy37 Sep 28, 2023
43144a9
revert a fix
rezkiy37 Sep 29, 2023
31e4209
extend getIOUReportID
rezkiy37 Sep 29, 2023
0584362
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Sep 29, 2023
3563a7c
fix unit-tests
rezkiy37 Sep 29, 2023
c6d9786
simplify condition
rezkiy37 Sep 29, 2023
2a061f0
Revert "fix unit-tests"
rezkiy37 Sep 29, 2023
b8dcf8d
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Oct 2, 2023
56cfc89
implement buildOptimisticPolicyRecentlyUsedCategories
rezkiy37 Oct 2, 2023
87154dc
remove extra helper
rezkiy37 Oct 2, 2023
586cc49
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Oct 2, 2023
864154c
unify
rezkiy37 Oct 2, 2023
4c3233e
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Oct 3, 2023
733d229
clear category on go back
rezkiy37 Oct 3, 2023
773b8a7
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Oct 4, 2023
df19f03
clear values on start confirm
rezkiy37 Oct 4, 2023
e0193d2
Merge branch 'main' of https://github.com/rezkiy37/Expensify into fix…
rezkiy37 Oct 9, 2023
585d6a2
simplify combining array
rezkiy37 Oct 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/components/MoneyRequestConfirmationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ const propTypes = {
/** Whether the money request is a distance request */
isDistanceRequest: PropTypes.bool,

/** A flag for verifying that the current report is a sub-report of a workspace chat */
isPolicyExpenseChat: PropTypes.bool,

/* Onyx Props */
/** Collection of categories attached to a policy */
policyCategories: PropTypes.objectOf(categoryPropTypes),
Expand Down Expand Up @@ -176,6 +179,7 @@ const defaultProps = {
transaction: {},
mileageRate: {unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate: 0, currency: 'USD'},
isDistanceRequest: false,
isPolicyExpenseChat: false,
};

function MoneyRequestConfirmationList(props) {
Expand All @@ -193,19 +197,16 @@ function MoneyRequestConfirmationList(props) {
const distance = lodashGet(transaction, 'routes.route0.distance', 0);
const shouldCalculateDistanceAmount = props.isDistanceRequest && props.iouAmount === 0;

// A flag for verifying that the current report is a sub-report of a workspace chat
const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(ReportUtils.getReport(props.reportID))), [props.reportID]);

// A flag for showing the categories field
const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories));
const shouldShowCategories = props.isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories));
rezkiy37 marked this conversation as resolved.
Show resolved Hide resolved

// Fetches the first tag list of the policy
const policyTag = PolicyUtils.getTag(props.policyTags);
const policyTagList = lodashGet(policyTag, 'tags', {});
const policyTagListName = lodashGet(policyTag, 'name', translate('common.tag'));
const canUseTags = Permissions.canUseTags(props.betas);
// A flag for showing the tags field
const shouldShowTags = isPolicyExpenseChat && canUseTags && OptionsListUtils.hasEnabledOptions(_.values(policyTagList));
const shouldShowTags = props.isPolicyExpenseChat && canUseTags && OptionsListUtils.hasEnabledOptions(_.values(policyTagList));

// A flag for showing the billable field
const shouldShowBillable = canUseTags && !lodashGet(props.policy, 'disabledFields.defaultBillable', true);
Expand Down
91 changes: 64 additions & 27 deletions src/libs/actions/IOU.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import * as Report from './Report';
import * as NumberUtils from '../NumberUtils';
import ReceiptGeneric from '../../../assets/images/receipt-generic.png';
import * as LocalePhoneNumber from '../LocalePhoneNumber';
import * as Policy from './Policy';

let allReports;
Onyx.connect({
Expand All @@ -44,13 +45,6 @@ Onyx.connect({
},
});

let allRecentlyUsedCategories = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES,
waitForCollectionCallback: true,
callback: (val) => (allRecentlyUsedCategories = val),
});

let allRecentlyUsedTags = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS,
Expand Down Expand Up @@ -137,7 +131,7 @@ function buildOnyxDataForMoneyRequest(
iouAction,
optimisticPersonalDetailListAction,
reportPreviewAction,
optimisticRecentlyUsedCategories,
optimisticPolicyRecentlyUsedCategories,
optimisticPolicyRecentlyUsedTags,
isNewChatReport,
isNewIOUReport,
Expand Down Expand Up @@ -188,11 +182,11 @@ function buildOnyxDataForMoneyRequest(
},
];

if (!_.isEmpty(optimisticRecentlyUsedCategories)) {
if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) {
optimisticData.push({
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`,
value: optimisticRecentlyUsedCategories,
value: optimisticPolicyRecentlyUsedCategories,
});
}

Expand Down Expand Up @@ -477,13 +471,7 @@ function getMoneyRequestInformation(
billable,
);

const uniquePolicyRecentlyUsedCategories = allRecentlyUsedCategories
? _.filter(
allRecentlyUsedCategories[`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`],
(recentlyUsedPolicyCategory) => recentlyUsedPolicyCategory !== category,
)
: [];
const optimisticPolicyRecentlyUsedCategories = [category, ...uniquePolicyRecentlyUsedCategories];
const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category);

const optimisticPolicyRecentlyUsedTags = {};
const policyTags = allPolicyTags[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${iouReport.policyID}`];
Expand Down Expand Up @@ -880,11 +868,12 @@ function requestMoney(
* @param {Number} amount - always in the smallest unit of the currency
* @param {String} comment
* @param {String} currency
* @param {String} category
* @param {String} existingSplitChatReportID - the report ID where the split bill happens, could be a group chat or a workspace chat
*
* @return {Object}
*/
function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingSplitChatReportID = '') {
function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID = '') {
const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin);
const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID));
const existingSplitChatReport =
Expand All @@ -908,6 +897,10 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
'',
'',
`${Localize.translateLocal('iou.splitBill')} ${Localize.translateLocal('common.with')} ${formattedParticipants} [${DateUtils.getDBTime().slice(0, 10)}]`,
undefined,
undefined,
undefined,
category,
);

// Note: The created action must be optimistically generated before the IOU action so there's no chance that the created action appears after the IOU action in the chat
Expand Down Expand Up @@ -1034,9 +1027,12 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco

const hasMultipleParticipants = participants.length > 1;
_.each(participants, (participant) => {
// In case the participant is a worskapce, email & accountID should remain undefined and won't be used in the rest of this code
const email = isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase();
const accountID = isOwnPolicyExpenseChat ? 0 : Number(participant.accountID);
// In a case when a participant is a workspace, even when a current user is not an owner of the workspace
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant);

// In case the participant is a workspace, email & accountID should remain undefined and won't be used in the rest of this code
const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase();
rezkiy37 marked this conversation as resolved.
Show resolved Hide resolved
const accountID = isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID);
if (email === currentUserEmailForIOUSplit) {
return;
}
Expand Down Expand Up @@ -1088,6 +1084,11 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
'',
CONST.IOU.MONEY_REQUEST_TYPE.SPLIT,
splitTransaction.transactionID,
undefined,
undefined,
undefined,
undefined,
category,
);

// STEP 4: Build optimistic reportActions. We need:
Expand Down Expand Up @@ -1128,6 +1129,12 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport);
}

// Add category to optimistic policy recently used categories when a participant is a workspace
let optimisticPolicyRecentlyUsedCategories = [];
if (isPolicyExpenseChat) {
optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category);
}

// STEP 5: Build Onyx Data
const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest(
oneOnOneChatReport,
Expand All @@ -1138,7 +1145,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
oneOnOneIOUAction,
oneOnOnePersonalDetailListAction,
oneOnOneReportPreviewAction,
[],
optimisticPolicyRecentlyUsedCategories,
{},
isNewOneOnOneChatReport,
shouldCreateNewOneOnOneIOUReport,
Expand Down Expand Up @@ -1188,11 +1195,11 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
* @param {Number} amount - always in smallest currency unit
* @param {String} comment
* @param {String} currency
* @param {String} category
* @param {String} existingSplitChatReportID - Either a group DM or a workspace chat
*/
function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingSplitChatReportID = '') {
const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingSplitChatReportID);

function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID = '') {
const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID);
API.write(
'SplitBill',
{
Expand All @@ -1201,6 +1208,7 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount,
splits: JSON.stringify(splits),
currency,
comment,
category,
transactionID: splitData.transactionID,
reportActionID: splitData.reportActionID,
createdReportActionID: splitData.createdReportActionID,
Expand All @@ -1221,9 +1229,10 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount,
* @param {Number} amount - always in smallest currency unit
* @param {String} comment
* @param {String} currency
* @param {String} category
*/
function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency) {
const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency);
function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category) {
const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category);

API.write(
'SplitBillAndOpenReport',
Expand All @@ -1233,6 +1242,7 @@ function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccou
splits: JSON.stringify(splits),
currency,
comment,
category,
transactionID: splitData.transactionID,
reportActionID: splitData.reportActionID,
createdReportActionID: splitData.createdReportActionID,
Expand Down Expand Up @@ -2299,6 +2309,32 @@ function navigateToNextPage(iou, iouType, report, path = '') {
Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType));
}

// route: PropTypes.shape({
// /** Route specific parameters used on this screen via route :iouType/new/category/:reportID? */
// params: PropTypes.shape({
// /** The type of IOU report, i.e. bill, request, send */
// iouType: PropTypes.string,

// /** The report ID of the IOU */
// reportID: PropTypes.string,
// }),
// }).isRequired,

/**
* When the money request or split bill creation flow is initialized via FAB, the reportID is not passed as a navigation
* parameter.
* Gets a report id from the first participant of the IOU object stored in Onyx.
* @param {Object} iou
* @param {Array} iou.participants
* @param {Object} route
* @param {Object} route.params
* @param {String} [route.params.reportID]
* @returns {String}
*/
function getIOUReportID(iou, route) {
return lodashGet(route, 'params.reportID') || lodashGet(iou, 'participants.0.reportID', '');
}

export {
createDistanceRequest,
editMoneyRequest,
Expand Down Expand Up @@ -2329,4 +2365,5 @@ export {
navigateToNextPage,
updateDistanceRequest,
replaceReceipt,
getIOUReportID,
};
24 changes: 24 additions & 0 deletions src/libs/actions/Policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ Onyx.connect({
callback: (val) => (allPersonalDetails = val),
});

let allRecentlyUsedCategories = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES,
waitForCollectionCallback: true,
callback: (val) => (allRecentlyUsedCategories = val),
});

/**
* Stores in Onyx the policy ID of the last workspace that was accessed by the user
* @param {String|null} policyID
Expand Down Expand Up @@ -1168,6 +1175,22 @@ function clearErrors(policyID) {
hideWorkspaceAlertMessage(policyID);
}

/**
* @param {String} policyID
* @param {String} category
* @returns {Object}
*/
function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) {
if (!policyID || !category) {
return [];
}

const policyRecentlyUsedCategories = lodashGet(allRecentlyUsedCategories, `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policyID}`, []);
const uniquePolicyRecentlyUsedCategories = _.filter(policyRecentlyUsedCategories, (recentlyUsedPolicyCategory) => recentlyUsedPolicyCategory !== category);
rezkiy37 marked this conversation as resolved.
Show resolved Hide resolved

return [category, ...uniquePolicyRecentlyUsedCategories];
}

export {
removeMembers,
addMembersToWorkspace,
Expand Down Expand Up @@ -1197,4 +1220,5 @@ export {
setWorkspaceInviteMembersDraft,
clearErrors,
openDraftWorkspaceRequest,
buildOptimisticPolicyRecentlyUsedCategories,
};
26 changes: 18 additions & 8 deletions src/pages/iou/MoneyRequestCategoryPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
import compose from '../../libs/compose';
import ROUTES from '../../ROUTES';
import Navigation from '../../libs/Navigation/Navigation';
import useLocalize from '../../hooks/useLocalize';
Expand Down Expand Up @@ -83,11 +84,20 @@ MoneyRequestCategoryPage.displayName = 'MoneyRequestCategoryPage';
MoneyRequestCategoryPage.propTypes = propTypes;
MoneyRequestCategoryPage.defaultProps = defaultProps;

export default withOnyx({
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`,
},
iou: {
key: ONYXKEYS.IOU,
},
})(MoneyRequestCategoryPage);
export default compose(
withOnyx({
iou: {
key: ONYXKEYS.IOU,
},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
report: {
key: ({route, iou}) => {
const reportID = IOU.getIOUReportID(iou, route);

return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
},
},
}),
)(MoneyRequestCategoryPage);
13 changes: 10 additions & 3 deletions src/pages/iou/MoneyRequestTagPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,21 @@ MoneyRequestTagPage.defaultProps = defaultProps;

export default compose(
withOnyx({
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID')}`,
},
iou: {
key: ONYXKEYS.IOU,
},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
report: {
key: ({route, iou}) => {
const reportID = IOU.getIOUReportID(iou, route);

return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
},
},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
policyTags: {
key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`,
Expand Down
Loading
Loading