Skip to content

Commit 017e381

Browse files
authored
Merge pull request Expensify#64390 from ishpaul777/feat/update-auto-submit-optimistic-flow
update optimistic autosubmit flow
2 parents 83ae1c8 + 719ada1 commit 017e381

9 files changed

Lines changed: 57 additions & 27 deletions

File tree

src/CONST/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ const CONST = {
627627
},
628628
BETAS: {
629629
ALL: 'all',
630-
AUTO_SUBMIT: 'autoSubmit',
630+
ASAP_SUBMIT: 'asapSubmit',
631631
DEFAULT_ROOMS: 'defaultRooms',
632632
P2P_DISTANCE_REQUESTS: 'p2pDistanceRequests',
633633
SPOTNANA_TRAVEL: 'spotnanaTravel',

src/ONYXKEYS.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,12 @@ const ONYXKEYS = {
164164
NVP_DISMISSED_REFERRAL_BANNERS: 'nvp_dismissedReferralBanners',
165165

166166
/**
167-
* This NVP contains if user has ever seen the instant submit explanation modal and user intent to not show the instant submit explanation modal again
167+
* This NVP contains if user has ever seen the ASAP submit explanation modal and user intent to not show the ASAP submit explanation modal again
168168
* undefined : user has never seen the modal
169169
* false : user has seen the modal but has not chosen "do not show again"
170170
* true : user has seen the modal and does not want to see it again
171171
*/
172-
NVP_DISMISSED_INSTANT_SUBMIT_EXPLANATION: 'nvp_dismissedInstantSubmitExplanation',
172+
NVP_DISMISSED_ASAP_SUBMIT_EXPLANATION: 'nvp_dismissedASAPSubmitExplanation',
173173

174174
/** This NVP contains the training modals the user denied showing again */
175175
NVP_HAS_SEEN_TRACK_TRAINING: 'nvp_hasSeenTrackTraining',
@@ -1069,7 +1069,7 @@ type OnyxValuesMapping = {
10691069
[ONYXKEYS.NVP_RECENT_ATTENDEES]: Attendee[];
10701070
[ONYXKEYS.NVP_TRY_FOCUS_MODE]: boolean;
10711071
[ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION]: boolean;
1072-
[ONYXKEYS.NVP_DISMISSED_INSTANT_SUBMIT_EXPLANATION]: boolean;
1072+
[ONYXKEYS.NVP_DISMISSED_ASAP_SUBMIT_EXPLANATION]: boolean;
10731073
[ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: OnyxTypes.LastPaymentMethod;
10741074
[ONYXKEYS.NVP_LAST_LOCATION_PERMISSION_PROMPT]: string;
10751075
[ONYXKEYS.LAST_EXPORT_METHOD]: OnyxTypes.LastExportMethod;

src/components/AutoSubmitModal.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import useStyleUtils from '@hooks/useStyleUtils';
66
import useThemeStyles from '@hooks/useThemeStyles';
77
import colors from '@styles/theme/colors';
88
import variables from '@styles/variables';
9-
import {dismissInstantSubmitExplanation} from '@userActions/User';
9+
import {dismissASAPSubmitExplanation} from '@userActions/User';
1010
import CONST from '@src/CONST';
1111
import type {TranslationPaths} from '@src/languages/types';
1212
import ONYXKEYS from '@src/ONYXKEYS';
@@ -29,17 +29,17 @@ const menuSections = [
2929
];
3030

3131
function AutoSubmitModal() {
32-
const [dismissedInstantSubmitExplanation] = useOnyx(ONYXKEYS.NVP_DISMISSED_INSTANT_SUBMIT_EXPLANATION, {canBeMissing: true});
32+
const [dismissedASAPSubmitExplanation] = useOnyx(ONYXKEYS.NVP_DISMISSED_ASAP_SUBMIT_EXPLANATION, {canBeMissing: true});
3333
const {translate} = useLocalize();
3434
const styles = useThemeStyles();
3535
const StyleUtils = useStyleUtils();
3636

3737
const onClose = useCallback((willShowAgain: boolean) => {
3838
InteractionManager.runAfterInteractions(() => {
3939
if (!willShowAgain) {
40-
dismissInstantSubmitExplanation(true);
40+
dismissASAPSubmitExplanation(true);
4141
} else {
42-
dismissInstantSubmitExplanation(false);
42+
dismissASAPSubmitExplanation(false);
4343
}
4444
});
4545
}, []);
@@ -58,7 +58,7 @@ function AutoSubmitModal() {
5858
illustrationInnerContainerStyle={[styles.alignItemsCenter, styles.justifyContentCenter, StyleUtils.getBackgroundColorStyle(colors.green700), styles.p8]}
5959
modalInnerContainerStyle={styles.pt0}
6060
illustrationOuterContainerStyle={styles.p0}
61-
shouldShowDismissModalOption={dismissedInstantSubmitExplanation === false}
61+
shouldShowDismissModalOption={dismissedASAPSubmitExplanation === false}
6262
onConfirm={onClose}
6363
titleStyles={[styles.mb1]}
6464
contentInnerContainerStyles={[styles.mb5]}

src/libs/NextStepUtils.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
55
import type {ValueOf} from 'type-fest';
66
import CONST from '@src/CONST';
77
import ONYXKEYS from '@src/ONYXKEYS';
8-
import type {Policy, Report, ReportNextStep, TransactionViolations} from '@src/types/onyx';
8+
import type {Beta, Policy, Report, ReportNextStep, TransactionViolations} from '@src/types/onyx';
99
import type {Message} from '@src/types/onyx/ReportNextStep';
1010
import type DeepValueOf from '@src/types/utils/DeepValueOf';
1111
import EmailUtils from './EmailUtils';
12+
import Permissions from './Permissions';
1213
import {getLoginsByAccountIDs, getPersonalDetailsByIDs} from './PersonalDetailsUtils';
1314
import {getApprovalWorkflow, getCorrectedAutoReportingFrequency, getReimburserAccountID} from './PolicyUtils';
1415
import {
@@ -42,6 +43,12 @@ Onyx.connect({
4243
callback: (value) => (allPolicies = value),
4344
});
4445

46+
let allBetas: OnyxEntry<Beta[]>;
47+
Onyx.connect({
48+
key: ONYXKEYS.BETAS,
49+
callback: (value) => (allBetas = value),
50+
});
51+
4552
let transactionViolations: OnyxCollection<TransactionViolations>;
4653
Onyx.connect({
4754
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
@@ -142,7 +149,9 @@ function buildNextStep(
142149
const {harvesting, autoReportingOffset} = policy;
143150
const autoReportingFrequency = getCorrectedAutoReportingFrequency(policy);
144151
const hasViolations = hasViolationsReportUtils(report?.reportID, transactionViolations);
145-
const shouldShowFixMessage = hasViolations && autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT;
152+
const isASAPSubmitBetaEnabled = Permissions.isBetaEnabled(CONST.BETAS.ASAP_SUBMIT, allBetas);
153+
const isInstantSubmitEnabled = autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT;
154+
const shouldShowFixMessage = hasViolations && isInstantSubmitEnabled && !isASAPSubmitBetaEnabled;
146155
const [policyOwnerPersonalDetails, ownerPersonalDetails] = getPersonalDetailsByIDs({
147156
accountIDs: [policy.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID, ownerAccountID],
148157
currentUserAccountID,
@@ -200,7 +209,7 @@ function buildNextStep(
200209
switch (predictedNextStatus) {
201210
// Generates an optimistic nextStep once a report has been opened
202211
case CONST.REPORT.STATUS_NUM.OPEN:
203-
if (shouldFixViolations) {
212+
if ((isASAPSubmitBetaEnabled && hasViolations && isInstantSubmitEnabled) || shouldFixViolations) {
204213
optimisticNextStep = {
205214
type,
206215
icon: CONST.NEXT_STEP.ICONS.HOURGLASS,

src/libs/ReportUtils.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5929,6 +5929,13 @@ function buildOptimisticInvoiceReport(
59295929
* @param policy
59305930
*/
59315931
function getExpenseReportStateAndStatus(policy: OnyxEntry<Policy>, isEmptyOptimisticReport = false) {
5932+
const isASAPSubmitBetaEnabled = Permissions.isBetaEnabled(CONST.BETAS.ASAP_SUBMIT, allBetas);
5933+
if (isASAPSubmitBetaEnabled) {
5934+
return {
5935+
stateNum: CONST.REPORT.STATE_NUM.OPEN,
5936+
statusNum: CONST.REPORT.STATUS_NUM.OPEN,
5937+
};
5938+
}
59325939
const isInstantSubmitEnabledLocal = isInstantSubmitEnabled(policy);
59335940
const isSubmitAndCloseLocal = isSubmitAndClose(policy);
59345941
const arePaymentsDisabled = policy?.reimbursementChoice === CONST.POLICY.REIMBURSEMENT_CHOICES.REIMBURSEMENT_NO;
@@ -9675,8 +9682,9 @@ function hasMissingPaymentMethod(userWallet: OnyxEntry<UserWallet>, iouReportID:
96759682
* - we have one, but it's waiting on the payee adding a bank account
96769683
* - we have one, but we can't add more transactions to it due to: report is approved or settled
96779684
*/
9678-
function shouldCreateNewMoneyRequestReport(existingIOUReport: OnyxInputOrEntry<Report> | undefined, chatReport: OnyxInputOrEntry<Report>): boolean {
9679-
return !existingIOUReport || hasIOUWaitingOnCurrentUserBankAccount(chatReport) || !canAddTransaction(existingIOUReport);
9685+
function shouldCreateNewMoneyRequestReport(existingIOUReport: OnyxInputOrEntry<Report> | undefined, chatReport: OnyxInputOrEntry<Report>, isScanRequest: boolean): boolean {
9686+
const isASAPSubmitBetaEnabled = Permissions.isBetaEnabled(CONST.BETAS.ASAP_SUBMIT, allBetas);
9687+
return !existingIOUReport || hasIOUWaitingOnCurrentUserBankAccount(chatReport) || !canAddTransaction(existingIOUReport) || (isScanRequest && isASAPSubmitBetaEnabled);
96809688
}
96819689

96829690
function getTripIDFromTransactionParentReportID(transactionParentReportID: string | undefined): string | undefined {

src/libs/TransactionUtils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ function isDistanceRequest(transaction: OnyxEntry<Transaction>): boolean {
144144
return type === CONST.TRANSACTION.TYPE.CUSTOM_UNIT && customUnitName === CONST.CUSTOM_UNITS.NAME_DISTANCE;
145145
}
146146

147-
function isScanRequest(transaction: OnyxEntry<Transaction>): boolean {
147+
function isScanRequest(transaction: OnyxEntry<Transaction> | Partial<Transaction>): boolean {
148148
// This is used during the expense creation flow before the transaction has been saved to the server
149149
if (lodashHas(transaction, 'iouRequestType')) {
150150
return transaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.SCAN;

src/libs/__mocks__/Permissions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@ import type Beta from '@src/types/onyx/Beta';
1010

1111
export default {
1212
...jest.requireActual<typeof Permissions>('../Permissions'),
13-
isBetaEnabled: (beta: Beta, betas: Beta[]) => betas.includes(beta),
13+
isBetaEnabled: (beta: Beta, betas: Beta[]) => !!betas?.includes(beta),
1414
};

src/libs/actions/IOU.ts

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {getManagerMcTestParticipant, getPersonalDetailsForAccountIDs} from '@lib
6464
import Parser from '@libs/Parser';
6565
import {getCustomUnitID} from '@libs/PerDiemRequestUtils';
6666
import Performance from '@libs/Performance';
67+
import Permissions from '@libs/Permissions';
6768
import {getAccountIDsByLogins} from '@libs/PersonalDetailsUtils';
6869
import {addSMSDomainIfPhoneNumber} from '@libs/PhoneNumber';
6970
import {
@@ -662,6 +663,12 @@ type GetSearchOnyxUpdateParams = {
662663
transactionThreadReportID: string | undefined;
663664
};
664665

666+
let allBetas: OnyxEntry<OnyxTypes.Beta[]>;
667+
Onyx.connect({
668+
key: ONYXKEYS.BETAS,
669+
callback: (value) => (allBetas = value),
670+
});
671+
665672
let allTransactions: NonNullable<OnyxCollection<OnyxTypes.Transaction>> = {};
666673
Onyx.connect({
667674
key: ONYXKEYS.COLLECTION.TRANSACTION,
@@ -1394,6 +1401,7 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR
13941401

13951402
const isScanRequest = isScanRequestTransactionUtils(transaction);
13961403
const isPerDiemRequest = isPerDiemRequestTransactionUtils(transaction);
1404+
const isASAPSubmitBetaEnabled = Permissions.isBetaEnabled(CONST.BETAS.ASAP_SUBMIT, allBetas);
13971405
const outstandingChildRequest = getOutstandingChildRequest(iou.report);
13981406
const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null]));
13991407
const isMoneyRequestToManagerMcTest = isTestTransactionReport(iou.report);
@@ -1424,7 +1432,8 @@ function buildOnyxDataForMoneyRequest(moneyRequestParams: BuildOnyxDataForMoneyR
14241432
...chat.report,
14251433
lastReadTime: DateUtils.getDBTime(),
14261434
...(shouldCreateNewMoneyRequestReport ? {lastVisibleActionCreated: chat.reportPreviewAction.created} : {}),
1427-
iouReportID: iou.report.reportID,
1435+
// do not update iouReportID if auto submit beta is enabled and it is a scan request
1436+
...(isASAPSubmitBetaEnabled && isScanRequest ? {} : {iouReportID: iou.report.reportID}),
14281437
...outstandingChildRequest,
14291438
...(isNewChatReport ? {pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}} : {}),
14301439
},
@@ -2411,6 +2420,7 @@ function buildOnyxDataForTrackExpense({
24112420
const {policy, tagList: policyTagList, categories: policyCategories} = policyParams;
24122421

24132422
const isScanRequest = isScanRequestTransactionUtils(transaction);
2423+
const isASAPSubmitBetaEnabled = Permissions.isBetaEnabled(CONST.BETAS.ASAP_SUBMIT, allBetas);
24142424
const isDistanceRequest = isDistanceRequestTransactionUtils(transaction);
24152425
const clearedPendingFields = Object.fromEntries(Object.keys(transaction.pendingFields ?? {}).map((key) => [key, null]));
24162426

@@ -2437,7 +2447,8 @@ function buildOnyxDataForTrackExpense({
24372447
lastMessageText: getReportActionText(iouAction),
24382448
lastMessageHtml: getReportActionHtml(iouAction),
24392449
lastReadTime: DateUtils.getDBTime(),
2440-
iouReportID: iouReport?.reportID,
2450+
// do not update iouReportID if auto submit beta is enabled and it is a scan request
2451+
iouReportID: isASAPSubmitBetaEnabled && isScanRequest ? null : iouReport?.reportID,
24412452
lastVisibleActionCreated: shouldCreateNewMoneyRequestReport ? reportPreviewAction?.created : chatReport.lastVisibleActionCreated,
24422453
},
24432454
},
@@ -3317,7 +3328,8 @@ function getMoneyRequestInformation(moneyRequestInformation: MoneyRequestInforma
33173328
iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null;
33183329
}
33193330

3320-
const shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport);
3331+
const isScanRequest = isScanRequestTransactionUtils({amount, receipt});
3332+
const shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport, isScanRequest);
33213333

33223334
if (!iouReport || shouldCreateNewMoneyRequestReport) {
33233335
iouReport = isPolicyExpenseChat
@@ -3576,7 +3588,7 @@ function getPerDiemExpenseInformation(perDiemExpenseInformation: PerDiemExpenseI
35763588
iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null;
35773589
}
35783590

3579-
const shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport);
3591+
const shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport, false);
35803592

35813593
if (!iouReport || shouldCreateNewMoneyRequestReport) {
35823594
iouReport = isPolicyExpenseChat
@@ -3787,8 +3799,8 @@ function getTrackExpenseInformation(params: GetTrackExpenseInformationParams): T
37873799
} else {
37883800
iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${chatReport.iouReportID}`] ?? null;
37893801
}
3790-
3791-
shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport);
3802+
const isScanRequest = isScanRequestTransactionUtils({amount, receipt});
3803+
shouldCreateNewMoneyRequestReport = shouldCreateNewMoneyRequestReportReportUtils(iouReport, chatReport, isScanRequest);
37923804
if (!iouReport || shouldCreateNewMoneyRequestReport) {
37933805
iouReport = buildOptimisticExpenseReport(chatReport.reportID, chatReport.policyID, payeeAccountID, amount, currency, amount);
37943806
} else {
@@ -6189,7 +6201,8 @@ function createSplitsAndOnyxData({
61896201

61906202
// STEP 2: Get existing IOU/Expense report and update its total OR build a new optimistic one
61916203
let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null;
6192-
const shouldCreateNewOneOnOneIOUReport = shouldCreateNewMoneyRequestReportReportUtils(oneOnOneIOUReport, oneOnOneChatReport);
6204+
const isScanRequest = isScanRequestTransactionUtils(splitTransaction);
6205+
const shouldCreateNewOneOnOneIOUReport = shouldCreateNewMoneyRequestReportReportUtils(oneOnOneIOUReport, oneOnOneChatReport, isScanRequest);
61936206

61946207
if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) {
61956208
oneOnOneIOUReport = isOwnPolicyExpenseChat
@@ -7010,7 +7023,7 @@ function completeSplitBill(
70107023
}
70117024

70127025
let oneOnOneIOUReport: OneOnOneIOUReport = oneOnOneChatReport?.iouReportID ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`] : null;
7013-
const shouldCreateNewOneOnOneIOUReport = shouldCreateNewMoneyRequestReportReportUtils(oneOnOneIOUReport, oneOnOneChatReport);
7026+
const shouldCreateNewOneOnOneIOUReport = shouldCreateNewMoneyRequestReportReportUtils(oneOnOneIOUReport, oneOnOneChatReport, false);
70147027

70157028
if (!oneOnOneIOUReport || shouldCreateNewOneOnOneIOUReport) {
70167029
oneOnOneIOUReport = isPolicyExpenseChat

src/libs/actions/User.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,8 +1382,8 @@ function dismissTrackTrainingModal() {
13821382
* Dismiss the Auto-Submit explanation modal
13831383
* @param shouldDismiss Whether the user selected "Don't show again"
13841384
*/
1385-
function dismissInstantSubmitExplanation(shouldDismiss: boolean) {
1386-
Onyx.merge(ONYXKEYS.NVP_DISMISSED_INSTANT_SUBMIT_EXPLANATION, shouldDismiss);
1385+
function dismissASAPSubmitExplanation(shouldDismiss: boolean) {
1386+
Onyx.merge(ONYXKEYS.NVP_DISMISSED_ASAP_SUBMIT_EXPLANATION, shouldDismiss);
13871387
}
13881388

13891389
function requestRefund() {
@@ -1445,7 +1445,7 @@ export {
14451445
closeAccount,
14461446
dismissReferralBanner,
14471447
dismissTrackTrainingModal,
1448-
dismissInstantSubmitExplanation,
1448+
dismissASAPSubmitExplanation,
14491449
resendValidateCode,
14501450
requestContactMethodValidateCode,
14511451
updateNewsletterSubscription,

0 commit comments

Comments
 (0)