Skip to content

Commit d41b087

Browse files
authored
Merge pull request Expensify#87142 from TaduJR/fix-Add-updated-automatic/scan-flow-to-native-share-sheet-creation-flow
fix: Add updated automatic/scan flow to native share sheet creation flow
2 parents 3d9b33b + 186209d commit d41b087

1 file changed

Lines changed: 87 additions & 21 deletions

File tree

src/pages/Share/SubmitDetailsPage.tsx

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {StackScreenProps} from '@react-navigation/stack';
22
import {hasSeenTourSelector} from '@selectors/Onboarding';
33
import {validTransactionDraftsSelector} from '@selectors/TransactionDraft';
4-
import React, {useEffect, useState} from 'react';
4+
import React, {useCallback, useEffect, useMemo, useState} from 'react';
55
import {View} from 'react-native';
66
import type {OnyxEntry} from 'react-native-onyx';
77
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
@@ -11,6 +11,7 @@ import MoneyRequestConfirmationList from '@components/MoneyRequestConfirmationLi
1111
import ScreenWrapper from '@components/ScreenWrapper';
1212
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
1313
import useLocalize from '@hooks/useLocalize';
14+
import useNetwork from '@hooks/useNetwork';
1415
import useOnyx from '@hooks/useOnyx';
1516
import usePermissions from '@hooks/usePermissions';
1617
import usePersonalPolicy from '@hooks/usePersonalPolicy';
@@ -19,7 +20,15 @@ import useReportAttributes from '@hooks/useReportAttributes';
1920
import useReportIsArchived from '@hooks/useReportIsArchived';
2021
import useThemeStyles from '@hooks/useThemeStyles';
2122
import type {GpsPoint} from '@libs/actions/IOU';
22-
import {getIOURequestPolicyID, getMoneyRequestParticipantsFromReport, initMoneyRequest, updateLastLocationPermissionPrompt} from '@libs/actions/IOU';
23+
import {
24+
getIOURequestPolicyID,
25+
getMoneyRequestParticipantsFromReport,
26+
initMoneyRequest,
27+
setMoneyRequestBillable,
28+
setMoneyRequestReimbursable,
29+
updateLastLocationPermissionPrompt,
30+
} from '@libs/actions/IOU';
31+
import {setMoneyRequestReceipt} from '@libs/actions/IOU/Receipt';
2332
import {requestMoney, trackExpense} from '@libs/actions/IOU/TrackExpense';
2433
import DateUtils from '@libs/DateUtils';
2534
import {getFileName, readFileAsync} from '@libs/fileDownload/FileUtils';
@@ -30,10 +39,11 @@ import navigateAfterInteraction from '@libs/Navigation/navigateAfterInteraction'
3039
import Navigation from '@libs/Navigation/Navigation';
3140
import type {ShareNavigatorParamList} from '@libs/Navigation/types';
3241
import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils';
33-
import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil} from '@libs/PolicyUtils';
42+
import {hasOnlyPersonalPolicies as hasOnlyPersonalPoliciesUtil, isPaidGroupPolicy} from '@libs/PolicyUtils';
3443
import {shouldValidateFile} from '@libs/ReceiptUtils';
3544
import {getReportOrDraftReport, isSelfDM} from '@libs/ReportUtils';
3645
import {getDefaultTaxCode, getTaxValue} from '@libs/TransactionUtils';
46+
import DraftWorkspaceOpener from '@pages/iou/request/step/confirmation/DraftWorkspaceOpener';
3747
import CONST from '@src/CONST';
3848
import ONYXKEYS from '@src/ONYXKEYS';
3949
import type SCREENS from '@src/SCREENS';
@@ -107,7 +117,7 @@ function SubmitDetailsPage({
107117
reportID: reportOrAccountID,
108118
policy,
109119
personalPolicy,
110-
currentIouRequestType: CONST.IOU.REQUEST_TYPE.SCAN,
120+
currentIouRequestType: transaction?.iouRequestType,
111121
newIouRequestType: CONST.IOU.REQUEST_TYPE.SCAN,
112122
report,
113123
parentReport,
@@ -120,13 +130,53 @@ function SubmitDetailsPage({
120130
// eslint-disable-next-line react-hooks/exhaustive-deps
121131
}, [reportOrAccountID, policy, personalPolicy, report, parentReport, currentDate, currentUserPersonalDetails, hasOnlyPersonalPolicies]);
122132

133+
// Set receipt on the transaction draft so isScanRequest() returns true and
134+
// compact mode, "Automatic" labels, and receipt image rendering all work correctly
135+
const receiptSource = currentAttachment?.content ?? fileUri;
136+
const receiptFileName = getFileName(currentAttachment?.content ?? '') || fileName;
137+
const receiptFileType = currentAttachment?.mimeType ?? fileType;
138+
139+
useEffect(() => {
140+
if (!receiptSource) {
141+
return;
142+
}
143+
setMoneyRequestReceipt(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, receiptSource, receiptFileName, true, receiptFileType);
144+
}, [receiptSource, receiptFileName, receiptFileType]);
145+
123146
const selectedParticipants = unknownUserDetails ? [unknownUserDetails] : getMoneyRequestParticipantsFromReport(report, currentUserPersonalDetails.accountID);
124147
const participants = selectedParticipants.map((participant) => {
125148
const privateIsArchived = privateIsArchivedMap[`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${participant.reportID}`];
126149
return participant?.accountID
127150
? getParticipantsOption(participant, personalDetails)
128151
: getReportOption(participant, privateIsArchived, policy, personalDetails, conciergeReportID, reportAttributesDerived);
129152
});
153+
154+
const isPolicyExpenseChat = useMemo(() => participants?.some((participant) => participant.isPolicyExpenseChat), [participants]);
155+
const policyExpenseChatPolicyID = participants?.find((participant) => participant.isPolicyExpenseChat)?.policyID;
156+
const senderPolicyID = participants?.find((participant) => !!participant && 'isSender' in participant && participant.isSender)?.policyID;
157+
const iouType = isSelfDM(report) ? CONST.IOU.TYPE.TRACK : CONST.IOU.TYPE.SUBMIT;
158+
const {isOffline} = useNetwork();
159+
const isCreatingTrackExpense = iouType === CONST.IOU.TYPE.TRACK;
160+
161+
// Initialize billable/reimbursable from policy defaults (mirrors IOURequestStepConfirmation)
162+
const defaultBillable = !!policy?.defaultBillable;
163+
useEffect(() => {
164+
setMoneyRequestBillable(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, defaultBillable);
165+
}, [defaultBillable]);
166+
167+
useEffect(() => {
168+
const defaultReimbursable = (isPolicyExpenseChat && isPaidGroupPolicy(policy)) || isCreatingTrackExpense ? (policy?.defaultReimbursable ?? true) : true;
169+
setMoneyRequestReimbursable(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, defaultReimbursable);
170+
}, [policy, isPolicyExpenseChat, isCreatingTrackExpense]);
171+
172+
const setBillable = useCallback((billable: boolean) => {
173+
setMoneyRequestBillable(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, billable);
174+
}, []);
175+
176+
const setReimbursable = useCallback((reimbursable: boolean) => {
177+
setMoneyRequestReimbursable(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, reimbursable);
178+
}, []);
179+
130180
const trimmedComment = transaction?.comment?.comment?.trim() ?? '';
131181
const transactionAmount = transaction?.amount ?? 0;
132182
const transactionTaxAmount = transaction?.taxAmount ?? 0;
@@ -224,12 +274,7 @@ function SubmitDetailsPage({
224274
}
225275
};
226276

227-
const onSuccess = (file: File, locationPermissionGranted?: boolean) => {
228-
const participant = selectedParticipants.at(0);
229-
if (!participant) {
230-
return;
231-
}
232-
277+
const onSuccess = (participant: Participant, file: File, locationPermissionGranted?: boolean) => {
233278
const receipt: Receipt = file;
234279
receipt.state = file && CONST.IOU.RECEIPT_STATE.SCAN_READY;
235280
if (locationPermissionGranted) {
@@ -250,7 +295,7 @@ function SubmitDetailsPage({
250295
finishRequestAndNavigate(participant, receipt);
251296
};
252297

253-
const onConfirm = (gpsRequired?: boolean) => {
298+
const onConfirm = (listOfParticipants?: Participant[], gpsRequired?: boolean) => {
254299
const shouldStartLocationPermissionFlow =
255300
gpsRequired &&
256301
(!lastLocationPermissionPrompt ||
@@ -265,43 +310,64 @@ function SubmitDetailsPage({
265310
return;
266311
}
267312

313+
const participant = listOfParticipants?.at(0) ?? selectedParticipants.at(0);
314+
if (!participant) {
315+
return;
316+
}
317+
268318
readFileAsync(
269-
fileUri,
270-
fileName,
271-
(file) => onSuccess(file, shouldStartLocationPermissionFlow),
319+
receiptSource,
320+
receiptFileName,
321+
(file) => onSuccess(participant, file, shouldStartLocationPermissionFlow),
272322
() => {},
273-
fileType,
323+
receiptFileType,
274324
);
275325
};
276326

277327
return (
278328
<ScreenWrapper testID="SubmitDetailsPage">
279329
<FullPageNotFoundView shouldShow={!reportOrAccountID}>
330+
<DraftWorkspaceOpener
331+
isCreatingTrackExpense={isCreatingTrackExpense}
332+
policyID={policy?.id}
333+
policyPendingAction={policy?.pendingAction}
334+
policyExpenseChatPolicyID={policyExpenseChatPolicyID}
335+
senderPolicyID={senderPolicyID}
336+
isOffline={isOffline}
337+
/>
280338
<HeaderWithBackButton
281-
title={translate('common.details')}
339+
title={translate('iou.confirmDetails')}
282340
onBackButtonPress={() => Navigation.goBack()}
283341
/>
284342
<LocationPermissionModal
285343
startPermissionFlow={startLocationPermissionFlow}
286344
resetPermissionFlow={() => setStartLocationPermissionFlow(false)}
287-
onGrant={onConfirm}
345+
onGrant={() => onConfirm(undefined, true)}
288346
onDeny={() => {
289347
updateLastLocationPermissionPrompt();
290348
setStartLocationPermissionFlow(false);
291349
navigateAfterInteraction(() => {
292-
onConfirm(false);
350+
onConfirm(undefined, false);
293351
});
294352
}}
295353
/>
296354
<View style={[styles.containerWithSpaceBetween, styles.pointerEventsBoxNone]}>
297355
<MoneyRequestConfirmationList
298356
transaction={transaction}
299357
selectedParticipants={participants}
300-
onConfirm={() => onConfirm(true)}
301-
receiptPath={fileUri}
302-
receiptFilename={getFileName(fileName)}
358+
iouType={iouType}
359+
onToggleBillable={setBillable}
360+
onToggleReimbursable={setReimbursable}
361+
isPolicyExpenseChat={isPolicyExpenseChat}
362+
policyID={policy?.id}
363+
onConfirm={(updatedParticipants) => onConfirm(updatedParticipants, true)}
364+
receiptPath={receiptSource}
365+
receiptFilename={receiptFileName}
303366
reportID={reportOrAccountID}
304367
shouldShowSmartScanFields={false}
368+
shouldDisplayReceipt
369+
isReceiptEditable
370+
action={CONST.IOU.ACTION.CREATE}
305371
onPDFLoadError={() => {
306372
if (errorTitle) {
307373
return;

0 commit comments

Comments
 (0)