Skip to content

Commit 1abbf42

Browse files
authored
Merge pull request #40840 from allroundexperts/feat-40668
Update logic for categorising expenses
2 parents 4c03f95 + 9fce2e8 commit 1abbf42

File tree

6 files changed

+133
-80
lines changed

6 files changed

+133
-80
lines changed

src/CONST.ts

+21
Original file line numberDiff line numberDiff line change
@@ -1619,6 +1619,27 @@ const CONST = {
16191619
DISABLE: 'disable',
16201620
ENABLE: 'enable',
16211621
},
1622+
DEFAULT_CATEGORIES: [
1623+
'Advertising',
1624+
'Benefits',
1625+
'Car',
1626+
'Equipment',
1627+
'Fees',
1628+
'Home Office',
1629+
'Insurance',
1630+
'Interest',
1631+
'Labor',
1632+
'Maintenance',
1633+
'Materials',
1634+
'Meals and Entertainment',
1635+
'Office Supplies',
1636+
'Other',
1637+
'Professional Services',
1638+
'Rent',
1639+
'Taxes',
1640+
'Travel',
1641+
'Utilities',
1642+
],
16221643
OWNERSHIP_ERRORS: {
16231644
NO_BILLING_CARD: 'noBillingCard',
16241645
AMOUNT_OWED: 'amountOwed',

src/libs/ReportUtils.ts

+29-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import type {EmptyObject} from '@src/types/utils/EmptyObject';
5555
import {isEmptyObject} from '@src/types/utils/EmptyObject';
5656
import type IconAsset from '@src/types/utils/IconAsset';
5757
import * as IOU from './actions/IOU';
58+
import * as PolicyActions from './actions/Policy';
5859
import * as store from './actions/ReimbursementAccount/store';
5960
import * as CurrencyUtils from './CurrencyUtils';
6061
import DateUtils from './DateUtils';
@@ -6116,7 +6117,34 @@ function createDraftTransactionAndNavigateToParticipantSelector(transactionID: s
61166117
mccGroup,
61176118
} as Transaction);
61186119

6119-
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.SUBMIT, transactionID, reportID, undefined, actionName));
6120+
const filteredPolicies = Object.values(allPolicies ?? {}).filter(
6121+
(policy) => policy?.type !== CONST.POLICY.TYPE.PERSONAL && policy?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
6122+
);
6123+
6124+
if (actionName === CONST.IOU.ACTION.SUBMIT || (allPolicies && filteredPolicies.length > 0)) {
6125+
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(CONST.IOU.TYPE.SUBMIT, transactionID, reportID, undefined, actionName));
6126+
return;
6127+
}
6128+
6129+
const {expenseChatReportID, policyID, policyName} = PolicyActions.createWorkspace();
6130+
const isCategorizing = actionName === CONST.IOU.ACTION.CATEGORIZE;
6131+
6132+
IOU.setMoneyRequestParticipants(transactionID, [
6133+
{
6134+
selected: true,
6135+
accountID: 0,
6136+
isPolicyExpenseChat: true,
6137+
reportID: expenseChatReportID,
6138+
policyID,
6139+
searchText: policyName,
6140+
},
6141+
]);
6142+
const iouConfirmationPageRoute = ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(actionName, CONST.IOU.TYPE.SUBMIT, transactionID, expenseChatReportID);
6143+
if (isCategorizing) {
6144+
Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CATEGORY.getRoute(actionName, CONST.IOU.TYPE.SUBMIT, transactionID, expenseChatReportID, iouConfirmationPageRoute));
6145+
} else {
6146+
Navigation.navigate(iouConfirmationPageRoute);
6147+
}
61206148
}
61216149

61226150
/**

src/libs/actions/Policy.ts

+80-42
Original file line numberDiff line numberDiff line change
@@ -2075,6 +2075,69 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol
20752075
Onyx.update(optimisticData);
20762076
}
20772077

2078+
function buildOptimisticPolicyCategories(policyID: string, categories: readonly string[]) {
2079+
const optimisticCategoryMap = categories.reduce(
2080+
(acc, category) => ({
2081+
...acc,
2082+
[category]: {
2083+
name: category,
2084+
enabled: true,
2085+
errors: null,
2086+
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
2087+
},
2088+
}),
2089+
{},
2090+
);
2091+
2092+
const successCategoryMap = categories.reduce(
2093+
(acc, category) => ({
2094+
...acc,
2095+
[category]: {
2096+
errors: null,
2097+
pendingAction: null,
2098+
},
2099+
}),
2100+
{},
2101+
);
2102+
2103+
const failureCategoryMap = categories.reduce(
2104+
(acc, category) => ({
2105+
...acc,
2106+
[category]: {
2107+
errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.createFailureMessage'),
2108+
pendingAction: null,
2109+
},
2110+
}),
2111+
{},
2112+
);
2113+
2114+
const onyxData: OnyxData = {
2115+
optimisticData: [
2116+
{
2117+
onyxMethod: Onyx.METHOD.MERGE,
2118+
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
2119+
value: optimisticCategoryMap,
2120+
},
2121+
],
2122+
successData: [
2123+
{
2124+
onyxMethod: Onyx.METHOD.MERGE,
2125+
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
2126+
value: successCategoryMap,
2127+
},
2128+
],
2129+
failureData: [
2130+
{
2131+
onyxMethod: Onyx.METHOD.MERGE,
2132+
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
2133+
value: failureCategoryMap,
2134+
},
2135+
],
2136+
};
2137+
2138+
return onyxData;
2139+
}
2140+
20782141
/**
20792142
* Optimistically creates a new workspace and default workspace chats
20802143
*
@@ -2083,7 +2146,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol
20832146
* @param [policyName] custom policy name we will use for created workspace
20842147
* @param [policyID] custom policy id we will use for created workspace
20852148
*/
2086-
function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', policyID = generatePolicyID()): string {
2149+
function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', policyID = generatePolicyID()): CreateWorkspaceParams {
20872150
const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail);
20882151

20892152
const {customUnits, customUnitID, customUnitRateID, outputCurrency} = buildOptimisticCustomUnits();
@@ -2103,6 +2166,8 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName
21032166
expenseCreatedReportActionID,
21042167
} = ReportUtils.buildOptimisticWorkspaceChats(policyID, workspaceName);
21052168

2169+
const optimisticCategoriesData = buildOptimisticPolicyCategories(policyID, CONST.POLICY.DEFAULT_CATEGORIES);
2170+
21062171
const optimisticData: OnyxUpdate[] = [
21072172
{
21082173
onyxMethod: Onyx.METHOD.SET,
@@ -2293,6 +2358,18 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName
22932358
},
22942359
];
22952360

2361+
if (optimisticCategoriesData.optimisticData) {
2362+
optimisticData.push(...optimisticCategoriesData.optimisticData);
2363+
}
2364+
2365+
if (optimisticCategoriesData.failureData) {
2366+
failureData.push(...optimisticCategoriesData.failureData);
2367+
}
2368+
2369+
if (optimisticCategoriesData.successData) {
2370+
successData.push(...optimisticCategoriesData.successData);
2371+
}
2372+
22962373
const params: CreateWorkspaceParams = {
22972374
policyID,
22982375
announceChatReportID,
@@ -2311,7 +2388,7 @@ function createWorkspace(policyOwnerEmail = '', makeMeAdmin = false, policyName
23112388

23122389
API.write(WRITE_COMMANDS.CREATE_WORKSPACE, params, {optimisticData, successData, failureData});
23132390

2314-
return adminsChatReportID;
2391+
return params;
23152392
}
23162393

23172394
function openWorkspaceReimburseView(policyID: string) {
@@ -3085,46 +3162,7 @@ function setWorkspaceCategoryEnabled(policyID: string, categoriesToUpdate: Recor
30853162
}
30863163

30873164
function createPolicyCategory(policyID: string, categoryName: string) {
3088-
const onyxData: OnyxData = {
3089-
optimisticData: [
3090-
{
3091-
onyxMethod: Onyx.METHOD.MERGE,
3092-
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
3093-
value: {
3094-
[categoryName]: {
3095-
name: categoryName,
3096-
enabled: true,
3097-
errors: null,
3098-
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3099-
},
3100-
},
3101-
},
3102-
],
3103-
successData: [
3104-
{
3105-
onyxMethod: Onyx.METHOD.MERGE,
3106-
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
3107-
value: {
3108-
[categoryName]: {
3109-
errors: null,
3110-
pendingAction: null,
3111-
},
3112-
},
3113-
},
3114-
],
3115-
failureData: [
3116-
{
3117-
onyxMethod: Onyx.METHOD.MERGE,
3118-
key: `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`,
3119-
value: {
3120-
[categoryName]: {
3121-
errors: ErrorUtils.getMicroSecondOnyxError('workspace.categories.createFailureMessage'),
3122-
pendingAction: null,
3123-
},
3124-
},
3125-
},
3126-
],
3127-
};
3165+
const onyxData = buildOptimisticPolicyCategories(policyID, [categoryName]);
31283166

31293167
const parameters = {
31303168
policyID,

src/pages/OnboardingWork/BaseOnboardingWork.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function BaseOnboardingWork({currentUserPersonalDetails, shouldUseNativeStyles,
4343

4444
const work = values.work.trim();
4545

46-
const adminsChatReportID = Policy.createWorkspace(undefined, true, work);
46+
const {adminsChatReportID} = Policy.createWorkspace(undefined, true, work);
4747

4848
Report.completeOnboarding(
4949
onboardingPurposeSelected,

src/pages/iou/request/MoneyTemporaryForRefactorRequestParticipantsSelector.js

-34
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import lodashEvery from 'lodash/every';
21
import lodashGet from 'lodash/get';
32
import lodashIsEqual from 'lodash/isEqual';
43
import lodashMap from 'lodash/map';
@@ -9,11 +8,8 @@ import lodashValues from 'lodash/values';
98
import PropTypes from 'prop-types';
109
import React, {memo, useCallback, useEffect, useMemo} from 'react';
1110
import {useOnyx} from 'react-native-onyx';
12-
import BlockingView from '@components/BlockingViews/BlockingView';
1311
import Button from '@components/Button';
1412
import FormHelpMessage from '@components/FormHelpMessage';
15-
import * as Illustrations from '@components/Icon/Illustrations';
16-
import OfflineIndicator from '@components/OfflineIndicator';
1713
import {usePersonalDetails} from '@components/OnyxProvider';
1814
import {useOptionsList} from '@components/OptionListContextProvider';
1915
import ReferralProgramCTA from '@components/ReferralProgramCTA';
@@ -26,15 +22,11 @@ import useNetwork from '@hooks/useNetwork';
2622
import usePermissions from '@hooks/usePermissions';
2723
import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus';
2824
import useThemeStyles from '@hooks/useThemeStyles';
29-
import useWindowDimensions from '@hooks/useWindowDimensions';
3025
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
31-
import Navigation from '@libs/Navigation/Navigation';
3226
import * as OptionsListUtils from '@libs/OptionsListUtils';
33-
import variables from '@styles/variables';
3427
import * as Report from '@userActions/Report';
3528
import CONST from '@src/CONST';
3629
import ONYXKEYS from '@src/ONYXKEYS';
37-
import ROUTES from '@src/ROUTES';
3830

3931
const propTypes = {
4032
/** Callback to request parent modal to go to next step, which should be split */
@@ -87,7 +79,6 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
8779
const offlineMessage = isOffline ? [`${translate('common.youAppearToBeOffline')} ${translate('search.resultsAreLimited')}`, {isTranslated: true}] : '';
8880

8981
const maxParticipantsReached = participants.length === CONST.REPORT.MAXIMUM_PARTICIPANTS;
90-
const {isSmallScreenWidth} = useWindowDimensions();
9182

9283
const isIOUSplit = iouType === CONST.IOU.TYPE.SPLIT;
9384
const isCategorizeOrShareAction = [CONST.IOU.ACTION.CATEGORIZE, CONST.IOU.ACTION.SHARE].includes(action);
@@ -335,31 +326,6 @@ function MoneyTemporaryForRefactorRequestParticipantsSelector({participants, onF
335326
);
336327
}, [handleConfirmSelection, participants.length, isDismissed, referralContentType, shouldShowSplitBillErrorMessage, styles, translate]);
337328

338-
const renderEmptyWorkspaceView = () => (
339-
<>
340-
<BlockingView
341-
icon={Illustrations.TeleScope}
342-
iconWidth={variables.emptyWorkspaceIconWidth}
343-
iconHeight={variables.emptyWorkspaceIconHeight}
344-
title={translate('workspace.emptyWorkspace.notFound')}
345-
shouldShowLink={false}
346-
/>
347-
<Button
348-
success
349-
large
350-
text={translate('footer.learnMore')}
351-
onPress={() => Navigation.navigate(ROUTES.SETTINGS_WORKSPACES)}
352-
style={[styles.mh5, styles.mb5]}
353-
/>
354-
{isSmallScreenWidth && <OfflineIndicator />}
355-
</>
356-
);
357-
358-
const isAllSectionsEmpty = lodashEvery(sections, (section) => section.data.length === 0);
359-
if (isCategorizeOrShareAction && isAllSectionsEmpty && didScreenTransitionEnd && debouncedSearchTerm.trim() === '' && areOptionsInitialized) {
360-
return renderEmptyWorkspaceView();
361-
}
362-
363329
return (
364330
<SelectionList
365331
onConfirm={handleConfirmSelection}

src/pages/iou/request/step/IOURequestStepConfirmation.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ function IOURequestStepConfirmation({
8282
const requestType = TransactionUtils.getRequestType(transaction);
8383

8484
const headerTitle = useMemo(() => {
85-
if (isSharingTrackExpense) {
85+
if (isCategorizingTrackExpense) {
8686
return translate('iou.categorize');
8787
}
8888
if (isSubmittingFromTrackExpense) {
8989
return translate('iou.submitExpense');
9090
}
91-
if (isCategorizingTrackExpense) {
91+
if (isSharingTrackExpense) {
9292
return translate('iou.share');
9393
}
9494
if (iouType === CONST.IOU.TYPE.SPLIT) {

0 commit comments

Comments
 (0)