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

fix: Closing receipt view using device navigation redirects user to expense report #35497

Merged
merged 19 commits into from
Mar 8, 2024
Merged
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,10 @@ const ROUTES = {
getRoute: (contentType: string, backTo?: string) => getUrlWithBackToParam(`referral/${contentType}`, backTo),
},
PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational',
TRANSACTION_RECEIPT: {
route: 'r/:reportID/transaction/:transactionID/receipt',
getRoute: (reportID: string, transactionID: string) => `r/${reportID}/transaction/${transactionID}/receipt` as const,
},
} as const;

/**
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ const SCREENS = {
GET_ASSISTANCE: 'GetAssistance',
REFERRAL_DETAILS: 'Referral_Details',
KEYBOARD_SHORTCUTS: 'KeyboardShortcuts',
TRANSACTION_RECEIPT: 'TransactionReceipt',
} as const;

type Screen = DeepValueOf<typeof SCREENS>;
Expand Down
2 changes: 1 addition & 1 deletion src/components/AttachmentModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ function AttachmentModal({
const deleteAndCloseModal = useCallback(() => {
IOU.detachReceipt(transaction?.transactionID ?? '');
setIsDeleteReceiptConfirmModalVisible(false);
Navigation.dismissModal(report?.reportID);
Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID ?? ''));
}, [transaction, report]);

const isValidFile = useCallback((fileObject: FileObject) => {
Expand Down
3 changes: 1 addition & 2 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,9 @@ function MoneyRequestView({
thumbnail={receiptURIs?.thumbnail}
image={receiptURIs?.image}
isLocalFile={receiptURIs?.isLocalFile}
filename={receiptURIs?.filename}
transaction={transaction}
enablePreviewModal
canEditReceipt={canEditReceipt}
filename={receiptURIs?.filename}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I updated

/>
)}
</View>
Expand Down
43 changes: 10 additions & 33 deletions src/components/ReportActionItem/ReportActionItemImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import type {ReactElement} from 'react';
import type {ImageSourcePropType, ViewStyle} from 'react-native';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import AttachmentModal from '@components/AttachmentModal';
import EReceiptThumbnail from '@components/EReceiptThumbnail';
import * as Expensicons from '@components/Icon/Expensicons';
import Image from '@components/Image';
Expand All @@ -14,10 +13,12 @@ import {ShowContextMenuContext} from '@components/ShowContextMenuContext';
import ThumbnailImage from '@components/ThumbnailImage';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import * as TransactionUtils from '@libs/TransactionUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {Transaction} from '@src/types/onyx';

type ReportActionItemImageProps = {
Expand All @@ -36,9 +37,6 @@ type ReportActionItemImageProps = {
/** whether thumbnail is refer the local file or not */
isLocalFile?: boolean;

/** whether the receipt can be replaced */
canEditReceipt?: boolean;

/** Filename of attachment */
filename?: string;

Expand All @@ -52,16 +50,7 @@ type ReportActionItemImageProps = {
* and optional preview modal as well.
*/

function ReportActionItemImage({
thumbnail,
image,
enablePreviewModal = false,
transaction,
canEditReceipt = false,
isLocalFile = false,
filename,
isSingleImage = true,
}: ReportActionItemImageProps) {
function ReportActionItemImage({thumbnail, image, enablePreviewModal = false, transaction, isLocalFile = false, filename, isSingleImage = true}: ReportActionItemImageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const attachmentModalSource = tryResolveUrlFromApiRoot(image ?? '');
Expand Down Expand Up @@ -118,26 +107,14 @@ function ReportActionItemImage({
return (
<ShowContextMenuContext.Consumer>
{({report}) => (
<AttachmentModal
source={attachmentModalSource}
isAuthTokenRequired={!isLocalFile}
report={report}
isReceiptAttachment
canEditReceipt={canEditReceipt}
allowDownload={!isEReceipt}
originalFileName={filename}
<PressableWithoutFocus
style={[styles.w100, styles.h100, styles.noOutline as ViewStyle]}
onPress={() => Navigation.navigate(ROUTES.TRANSACTION_RECEIPT.getRoute(report?.reportID ?? '', transaction?.transactionID ?? ''))}
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
accessibilityRole={CONST.ROLE.BUTTON}
>
{({show}) => (
<PressableWithoutFocus
style={[styles.w100, styles.h100, styles.noOutline as ViewStyle]}
onPress={show}
accessibilityRole={CONST.ROLE.BUTTON}
accessibilityLabel={translate('accessibilityHints.viewAttachment')}
>
{receiptImageComponent}
</PressableWithoutFocus>
)}
</AttachmentModal>
{receiptImageComponent}
</PressableWithoutFocus>
)}
</ShowContextMenuContext.Consumer>
);
Expand Down
11 changes: 11 additions & 0 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const loadConciergePage = () => require('../../../pages/ConciergePage').default
const loadProfileAvatar = () => require('../../../pages/settings/Profile/ProfileAvatar').default as React.ComponentType;
const loadWorkspaceAvatar = () => require('../../../pages/workspace/WorkspaceAvatar').default as React.ComponentType;
const loadReportAvatar = () => require('../../../pages/ReportAvatar').default as React.ComponentType;
const loadReceiptView = () => require('../../../pages/TransactionReceiptPage').default as React.ComponentType;
const loadWorkspaceJoinUser = () => require('@pages/workspace/WorkspaceJoinUserPage').default as React.ComponentType;

let timezone: Timezone | null;
Expand Down Expand Up @@ -363,8 +364,18 @@ function AuthScreens({session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = f
headerShown: false,
presentation: 'transparentModal',
}}
listeners={modalScreenListeners}
getComponent={loadWorkspaceJoinUser}
/>
<RootStack.Screen
name={SCREENS.TRANSACTION_RECEIPT}
options={{
headerShown: false,
presentation: 'transparentModal',
}}
getComponent={loadReceiptView}
listeners={modalScreenListeners}
/>
</RootStack.Navigator>
</View>
);
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.PROFILE_AVATAR]: ROUTES.PROFILE_AVATAR.route,
[SCREENS.WORKSPACE_AVATAR]: ROUTES.WORKSPACE_AVATAR.route,
[SCREENS.REPORT_AVATAR]: ROUTES.REPORT_AVATAR.route,
[SCREENS.TRANSACTION_RECEIPT]: ROUTES.TRANSACTION_RECEIPT.route,
[SCREENS.WORKSPACE_JOIN_USER]: ROUTES.WORKSPACE_JOIN_USER.route,

// Sidebar
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,10 @@ type AuthScreensParamList = SharedScreensParamList & {
[NAVIGATORS.RIGHT_MODAL_NAVIGATOR]: NavigatorScreenParams<RightModalNavigatorParamList>;
[NAVIGATORS.FULL_SCREEN_NAVIGATOR]: NavigatorScreenParams<FullScreenNavigatorParamList>;
[SCREENS.DESKTOP_SIGN_IN_REDIRECT]: undefined;
[SCREENS.TRANSACTION_RECEIPT]: {
reportID: string;
transactionID: string;
};
};

type RootStackParamList = PublicScreensParamList & AuthScreensParamList;
Expand Down
79 changes: 79 additions & 0 deletions src/pages/TransactionReceiptPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useEffect} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import AttachmentModal from '@components/AttachmentModal';
import Navigation from '@libs/Navigation/Navigation';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import * as ReceiptUtils from '@libs/ReceiptUtils';
import * as ReportActionUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
import * as ReportActions from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {Report, ReportMetadata, Transaction} from '@src/types/onyx';

type TransactionReceiptOnyxProps = {
report: OnyxEntry<Report>;
transaction: OnyxEntry<Transaction>;
reportMetadata: OnyxEntry<ReportMetadata>;
};

type TransactionReceiptProps = TransactionReceiptOnyxProps & StackScreenProps<AuthScreensParamList, typeof SCREENS.TRANSACTION_RECEIPT>;

function TransactionReceipt({transaction, report, reportMetadata = {isLoadingInitialReportActions: true}, route}: TransactionReceiptProps) {
const receiptURIs = ReceiptUtils.getThumbnailAndImageURIs(transaction);

const imageSource = tryResolveUrlFromApiRoot(receiptURIs.image);

const isLocalFile = receiptURIs.isLocalFile;

const parentReportAction = ReportActionUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? '');
const canEditReceipt = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.RECEIPT);
const isEReceipt = transaction && TransactionUtils.hasEReceipt(transaction);

useEffect(() => {
if (report && transaction) {
return;
}
ReportActions.openReport(route.params.reportID);
// I'm disabling the warning, as it expects to use exhaustive deps, even though we want this useEffect to run only on the first render.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<AttachmentModal
source={imageSource}
isAuthTokenRequired={!isLocalFile}
report={report}
isReceiptAttachment
canEditReceipt={canEditReceipt}
allowDownload={!isEReceipt}
originalFileName={receiptURIs?.filename}
defaultOpen
onModalClose={() => {
Navigation.goBack(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report?.reportID ?? ''));
}}
isLoading={!transaction && reportMetadata?.isLoadingInitialReportActions}
shouldShowNotFoundPage={(report?.parentReportID ?? '') !== transaction?.reportID}
Copy link
Contributor

@shubham1206agra shubham1206agra Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tienifr Is there a special reason to add this condition here (shouldShowNotFoundPage)?

This line is causing bugs in self DM track expense.

/>
);
}

TransactionReceipt.displayName = 'TransactionReceipt';

export default withOnyx<TransactionReceiptProps, TransactionReceiptOnyxProps>({
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID ?? '0'}`,
},
transaction: {
key: ({route}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${route.params.transactionID ?? '0'}`,
},
reportMetadata: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${route.params.reportID ?? '0'}`,
},
})(TransactionReceipt);
Loading