Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
788 changes: 788 additions & 0 deletions patches/react-native-onyx+3.0.89.patch

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/components/GPSTripStateChecker/index.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function GPSTripStateChecker() {
useEffect(() => {
async function handleGpsTripInProgressOnAppRestart() {
await checkAndCleanGpsNotification();
const gpsTrip = await OnyxUtils.get(ONYXKEYS.GPS_DRAFT_DETAILS);
const gpsTrip = OnyxUtils.get(ONYXKEYS.GPS_DRAFT_DETAILS);

if (!gpsTrip?.isTracking) {
const isBackgroundTaskRunning = await hasStartedLocationUpdatesAsync(BACKGROUND_LOCATION_TRACKING_TASK_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ function useUpdateGpsTripOnReconnect({gpsPoints}: {gpsPoints: GPSPoint[][]}) {
const waypointAddresses = (await Promise.all(waypointUpdates)).filter((waypoints) => !!waypoints.point.address);

// To avoid race conditions, we need to get the latest gpsDraftDetails, because reverse geocoding may even take a few seconds
const gpsDraftDetailsPromiseResult = await OnyxUtils.get(ONYXKEYS.GPS_DRAFT_DETAILS).catch(() => undefined);
const latestGpsDraftDetails = gpsDraftDetailsPromiseResult;
const latestGpsDraftDetails = OnyxUtils.get(ONYXKEYS.GPS_DRAFT_DETAILS) ?? undefined;

const latestGpsPoints = getGpsPoints(latestGpsDraftDetails) ?? gpsPoints;
const newGpsPoints = [...latestGpsPoints];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,10 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps)
parentReportAction={parentReportAction}
parentReportActionForTransactionThread={EmptyParentReportActionForTransactionThread}
report={reportStable}
transactionThreadReport={transactionThreadReport}
transactionThreadReportID={transactionThreadReport?.reportID}
transactionThreadPolicyID={transactionThreadReport?.policyID}
transactionThreadParentReportActionID={transactionThreadReport?.parentReportActionID}
transactionThreadParentReportID={transactionThreadReport?.parentReportID}
chatReport={chatReport}
displayAsGroup={displayAsGroup}
shouldDisplayNewMarker={reportAction.reportActionID === unreadMarkerReportActionID}
Expand All @@ -609,7 +612,10 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps)
reportStable,
chatReport,
isOffline,
transactionThreadReport,
transactionThreadReport?.reportID,
transactionThreadReport?.policyID,
transactionThreadReport?.parentReportActionID,
transactionThreadReport?.parentReportID,
unreadMarkerReportActionID,
firstVisibleReportActionID,
linkedReportActionID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ function MoneyRequestReportView({report, reportLoadingState, shouldDisplayReport
<Animated.View style={styles.wideRHPMoneyRequestReceiptViewContainer}>
<ScrollView contentContainerStyle={styles.wideRHPMoneyRequestReceiptViewScrollViewContainer}>
<MoneyRequestReceiptView
report={transactionThreadReport}
reportID={transactionThreadReport?.reportID}
fillSpace
isDisplayedInWideRHP
hasParentPendingAction={!!reportPendingAction}
Expand Down
61 changes: 13 additions & 48 deletions src/components/Navigation/NavigationTabBar/InboxTabButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import {PressableWithFeedback} from '@components/Pressable';

import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useRootNavigationState from '@hooks/useRootNavigationState';
import {useSidebarOrderedReportsState} from '@hooks/useSidebarOrderedReports';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
Expand All @@ -18,12 +16,11 @@ import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
import type {Report, ReportActions} from '@src/types/onyx';

import type {OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';

import React from 'react';
import OnyxUtils from 'react-native-onyx/dist/OnyxUtils';

import getLastRoute from './getLastRoute';
import NAVIGATION_TABS from './NAVIGATION_TABS';
Expand Down Expand Up @@ -54,71 +51,39 @@ type InboxTabButtonProps = {
isWideLayout: boolean;
};

function doesLastReportExistSelector(report: OnyxEntry<Report>) {
return !!report?.reportID;
}

function makeDoesLastReportActionExistSelector(actionID: string | undefined) {
return (reportActions: OnyxEntry<ReportActions>) => {
const reportAction = actionID ? reportActions?.[actionID] : undefined;
return !!reportAction && !isDeletedAction(reportAction);
};
}

type WideInboxTabButtonProps = {
selectedTab: ValueOf<typeof NAVIGATION_TABS>;
statusIndicatorColor: string | undefined;
accessibilityLabel: string;
};

// The last-viewed report deep link only exists in the wide layout, so the report and report-action
// Onyx subscriptions live here and are only created when the wide layout is rendered. In the narrow
// layout tapping Inbox always routes to ROUTES.INBOX, so these subscriptions are never set up.
// The last-viewed report deep link only exists in the wide layout. In the narrow layout tapping
// Inbox always routes to ROUTES.INBOX.
function WideInboxTabButton({selectedTab, statusIndicatorColor, accessibilityLabel}: WideInboxTabButtonProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Inbox']);

const lastReportRouteReportID = useRootNavigationState((rootState) => {
if (!rootState) {
return undefined;
}
const route = getLastRoute(rootState, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, SCREENS.REPORT);
return getStringParam(route?.params, 'reportID');
});

const lastReportRouteReportActionID = useRootNavigationState((rootState) => {
if (!rootState) {
return undefined;
}
const route = getLastRoute(rootState, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, SCREENS.REPORT);
return getStringParam(route?.params, 'reportActionID');
});

const [doesLastReportExist] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${lastReportRouteReportID}`, {selector: doesLastReportExistSelector}, [lastReportRouteReportID]);

const doesLastReportActionExistSelector = makeDoesLastReportActionExistSelector(lastReportRouteReportActionID);
const [doesLastReportActionExist] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${lastReportRouteReportID}`, {selector: doesLastReportActionExistSelector}, [
lastReportRouteReportID,
lastReportRouteReportActionID,
]);

const navigateToChats = () => {
if (selectedTab === NAVIGATION_TABS.INBOX) {
return;
}

startNavigateToInboxTabSpan({isWideLayout: true});

if (doesLastReportExist) {
// Fetch route params on-demand to avoid storing the full route object in render-time state
const rootState = navigationRef.getRootState();
const lastRoute = rootState ? getLastRoute(rootState, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, SCREENS.REPORT) : undefined;
if (lastRoute) {
const reportID = getStringParam(lastRoute.params, 'reportID');
// Fetch route params on-demand to avoid storing the full route object in render-time state
const rootState = navigationRef.getRootState();
const lastRoute = rootState ? getLastRoute(rootState, NAVIGATORS.REPORTS_SPLIT_NAVIGATOR, SCREENS.REPORT) : undefined;
if (lastRoute) {
const reportID = getStringParam(lastRoute.params, 'reportID');
const doesLastReportExist = !!OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT}${reportID}` as const)?.reportID;
if (doesLastReportExist) {
const reportActionID = getStringParam(lastRoute.params, 'reportActionID');
const referrer = getStringParam(lastRoute.params, 'referrer');
const backTo = getStringParam(lastRoute.params, 'backTo');
const reportActions = OnyxUtils.get(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}` as const);
const reportAction = reportActionID ? reportActions?.[reportActionID] : undefined;
const doesLastReportActionExist = !!reportAction && !isDeletedAction(reportAction);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(reportID, doesLastReportActionExist ? reportActionID : undefined, referrer, backTo));
return;
}
Expand Down
14 changes: 11 additions & 3 deletions src/components/ReportActionItem/MoneyRequestReceiptView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
import ReceiptAudit, {ReceiptAuditMessages} from '@components/ReceiptAudit';
import ReceiptEmptyState from '@components/ReceiptEmptyState';
import ReceiptHoverZoom from '@components/ReceiptHoverZoom';
import {useSearchResultsContext} from '@components/Search/SearchContext';
import Tooltip from '@components/Tooltip';

import useActiveRoute from '@hooks/useActiveRoute';
Expand Down Expand Up @@ -88,14 +89,17 @@ import {conciergePersonalDetailSelector, personalDetailsSelector} from '@selecto
import mapValues from 'lodash/mapValues';
import React, {useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
// Use the original useOnyx hook to get the real-time data from Onyx and not from the snapshot
// eslint-disable-next-line no-restricted-imports
import {useOnyx as originalUseOnyx} from 'react-native-onyx';

import HoveredDistanceEReceipt from './HoveredDistanceEReceipt';
import {isElementHovered, resetButtonHoverState} from './receiptHoverUtils';
import ReportActionItemImage from './ReportActionItemImage';

type MoneyRequestReceiptViewProps = {
/** The report currently being looked at */
report: OnyxEntry<OnyxTypes.Report>;
/** The ID of the report currently being looked at */
reportID: string | undefined;

/** Whether we should show Money Request with disabled all fields */
readonly?: boolean;
Expand Down Expand Up @@ -129,14 +133,18 @@ const receiptImageViolationNames = new Set<OnyxTypes.ViolationName>([
const receiptFieldViolationNames = new Set<OnyxTypes.ViolationName>([CONST.VIOLATIONS.MODIFIED_AMOUNT, CONST.VIOLATIONS.MODIFIED_DATE]);

function MoneyRequestReceiptView({
report,
reportID,
readonly = false,
updatedTransaction,
fillSpace = false,
mergeTransactionID,
isDisplayedInWideRHP = false,
hasParentPendingAction = false,
}: MoneyRequestReceiptViewProps) {
// Real-time data from Onyx first, then the search-results snapshot for reports that only exist there (e.g. the merge-from-search flow).
const [reportFromOnyx] = originalUseOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(reportID)}`);
const {currentSearchResults} = useSearchResultsContext();
const report = reportFromOnyx ?? (reportID ? currentSearchResults?.data[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] : undefined);
const styles = useThemeStyles();
const {translate} = useLocalize();
const {convertToDisplayString} = useCurrencyListActions();
Expand Down
Loading
Loading