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 missing route and infinite route loading when categorizing track distance expense #47977

Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion src/components/TaxPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export default withOnyx<TaxPickerProps, TaxPickerOnyxProps>({
},
transaction: {
key: ({transactionID, action}) => {
if (action === CONST.IOU.ACTION.CREATE || IOUUtils.isMovingTransactionFromTrackExpense(action)) {
if (IOUUtils.shouldUseTransactionDraft(action)) {
return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}` as `${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`;
}
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
Expand Down
34 changes: 34 additions & 0 deletions src/hooks/useFetchRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {isEqual} from 'lodash';
import {useEffect} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import * as IOUUtils from '@libs/IOUUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import * as TransactionAction from '@userActions/Transaction';
import type {IOUAction} from '@src/CONST';
import type {Transaction} from '@src/types/onyx';
import type {WaypointCollection} from '@src/types/onyx/Transaction';
import useNetwork from './useNetwork';
import usePrevious from './usePrevious';

export default function useFetchRoute(transaction: OnyxEntry<Transaction>, waypoints: WaypointCollection | undefined, action: IOUAction) {
const {isOffline} = useNetwork();
const hasRouteError = !!transaction?.errorFields?.route;
const hasRoute = TransactionUtils.hasRoute(transaction);
const isRouteAbsentWithoutErrors = !hasRoute && !hasRouteError;
const isLoadingRoute = transaction?.comment?.isLoading ?? false;
const validatedWaypoints = TransactionUtils.getValidWaypoints(waypoints);
const previousValidatedWaypoints = usePrevious(validatedWaypoints);
const haveValidatedWaypointsChanged = !isEqual(previousValidatedWaypoints, validatedWaypoints);
const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction);
const shouldFetchRoute = isDistanceRequest && (isRouteAbsentWithoutErrors || haveValidatedWaypointsChanged) && !isLoadingRoute && Object.keys(validatedWaypoints).length > 1;

useEffect(() => {
if (isOffline || !shouldFetchRoute || !transaction?.transactionID) {
return;
}

TransactionAction.getRoute(transaction.transactionID, validatedWaypoints, IOUUtils.shouldUseTransactionDraft(action));
}, [shouldFetchRoute, transaction?.transactionID, validatedWaypoints, isOffline, action]);

return {shouldFetchRoute, validatedWaypoints};
}
5 changes: 5 additions & 0 deletions src/libs/IOUUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,16 @@ function isMovingTransactionFromTrackExpense(action?: IOUAction) {
return false;
}

function shouldUseTransactionDraft(action: IOUAction | undefined) {
return action === CONST.IOU.ACTION.CREATE || isMovingTransactionFromTrackExpense(action);
}

export {
calculateAmount,
insertTagIntoTransactionTagsString,
isIOUReportPendingCurrencyConversion,
isMovingTransactionFromTrackExpense,
shouldUseTransactionDraft,
isValidMoneyRequestType,
navigateToStartMoneyRequestStep,
updateIOUOwnerAndTotal,
Expand Down
10 changes: 8 additions & 2 deletions src/libs/actions/TransactionEdit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import ONYXKEYS from '@src/ONYXKEYS';
import type {Transaction} from '@src/types/onyx';

let connectionID: number;

/**
* Makes a backup copy of a transaction object that can be restored when the user cancels editing a transaction.
*/
Expand All @@ -11,6 +13,10 @@
return;
}

// In Strict Mode, the backup logic useEffect is triggered twice on mount. The restore logic is delayed because we need to connect to the onyx first,
// so it's possible that the restore logic is executed after creating the backup for the 2nd time which will completely clear the backup.
// To avoid that, we need to cancel the pending connection.
Onyx.disconnect(connectionID);

Check failure on line 19 in src/libs/actions/TransactionEdit.ts

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'number' is not assignable to parameter of type 'Connection'.
const newTransaction = {
...transaction,
};
Expand All @@ -27,10 +33,10 @@
}

function restoreOriginalTransactionFromBackup(transactionID: string, isDraft: boolean) {
const connection = Onyx.connect({
connectionID = Onyx.connect({

Check failure on line 36 in src/libs/actions/TransactionEdit.ts

View workflow job for this annotation

GitHub Actions / typecheck

Type 'Connection' is not assignable to type 'number'.
key: `${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${transactionID}`,
callback: (backupTransaction) => {
Onyx.disconnect(connection);
Onyx.disconnect(connectionID);

Check failure on line 39 in src/libs/actions/TransactionEdit.ts

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'number' is not assignable to parameter of type 'Connection'.
Copy link
Contributor

Choose a reason for hiding this comment

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

The new Onyx version disconnect function 's param now requires the Connection type, why do we have this change?

 * @param connection Connection object returned by calling `Onyx.connect()`.
 */
declare function disconnect(connection: Connection): void;
/**

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I haven't installed the new onyx. Updated.


// Use set to completely overwrite the original transaction
Onyx.set(`${isDraft ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, backupTransaction ?? null);
Expand Down
3 changes: 3 additions & 0 deletions src/pages/iou/request/step/IOURequestStepConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import MoneyRequestConfirmationList from '@components/MoneyRequestConfirmationLi
import {usePersonalDetails} from '@components/OnyxProvider';
import ScreenWrapper from '@components/ScreenWrapper';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useFetchRoute from '@hooks/useFetchRoute';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
Expand Down Expand Up @@ -159,6 +160,8 @@ function IOURequestStepConfirmation({
const isPolicyExpenseChat = useMemo(() => participants?.some((participant) => participant.isPolicyExpenseChat), [participants]);
const formHasBeenSubmitted = useRef(false);

useFetchRoute(transaction, transaction?.comment?.waypoints, action);

useEffect(() => {
const policyExpenseChat = participants?.find((participant) => participant.isPolicyExpenseChat);
if (policyExpenseChat?.policyID && policy?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD) {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/iou/request/step/IOURequestStepDate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ function IOURequestStepDate({
return;
}

const isTransactionDraft = action === CONST.IOU.ACTION.CREATE || IOUUtils.isMovingTransactionFromTrackExpense(action);
const isTransactionDraft = IOUUtils.shouldUseTransactionDraft(action);

IOU.setMoneyRequestCreated(transaction?.transactionID ?? '-1', newCreated, isTransactionDraft);

Expand Down
2 changes: 1 addition & 1 deletion src/pages/iou/request/step/IOURequestStepDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ function IOURequestStepDescription({
navigateBack();
return;
}
const isTransactionDraft = action === CONST.IOU.ACTION.CREATE || IOUUtils.isMovingTransactionFromTrackExpense(action);
const isTransactionDraft = IOUUtils.shouldUseTransactionDraft(action);

IOU.setMoneyRequestDescription(transaction?.transactionID ?? '-1', newComment, isTransactionDraft);

Expand Down
22 changes: 6 additions & 16 deletions src/pages/iou/request/step/IOURequestStepDistance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import DotIndicatorMessage from '@components/DotIndicatorMessage';
import DraggableList from '@components/DraggableList';
import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
import useFetchRoute from '@hooks/useFetchRoute';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import usePrevious from '@hooks/usePrevious';
import useThemeStyles from '@hooks/useThemeStyles';
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
import * as ErrorUtils from '@libs/ErrorUtils';
import * as IOUUtils from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as ReportUtils from '@libs/ReportUtils';
Expand Down Expand Up @@ -87,6 +89,7 @@ function IOURequestStepDistance({
},
[optimisticWaypoints, transaction],
);
const {shouldFetchRoute, validatedWaypoints} = useFetchRoute(transaction, waypoints, action);
Copy link
Contributor

Choose a reason for hiding this comment

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

Strong reason to believe that this change might've let to the surfacing of the following issue:

which in order to fix we had to extend the logic of useFetchRoute and involve BE. More details in the issue and proposed solution.

const waypointsList = Object.keys(waypoints);
const previousWaypoints = usePrevious(waypoints);
const numberOfWaypoints = Object.keys(waypoints).length;
Expand All @@ -95,12 +98,6 @@ function IOURequestStepDistance({
const isLoadingRoute = transaction?.comment?.isLoading ?? false;
const isLoading = transaction?.isLoading ?? false;
const hasRouteError = !!transaction?.errorFields?.route;
const hasRoute = TransactionUtils.hasRoute(transaction);
const validatedWaypoints = TransactionUtils.getValidWaypoints(waypoints);
const previousValidatedWaypoints = usePrevious(validatedWaypoints);
const haveValidatedWaypointsChanged = !isEqual(previousValidatedWaypoints, validatedWaypoints);
const isRouteAbsentWithoutErrors = !hasRoute && !hasRouteError;
const shouldFetchRoute = (isRouteAbsentWithoutErrors || haveValidatedWaypointsChanged) && !isLoadingRoute && Object.keys(validatedWaypoints).length > 1;
const [shouldShowAtLeastTwoDifferentWaypointsError, setShouldShowAtLeastTwoDifferentWaypointsError] = useState(false);
const isWaypointEmpty = (waypoint?: Waypoint) => {
if (!waypoint) {
Expand Down Expand Up @@ -159,13 +156,6 @@ function IOURequestStepDistance({
return MapboxToken.stop;
}, []);

useEffect(() => {
if (isOffline || !shouldFetchRoute) {
return;
}
TransactionAction.getRoute(transactionID, validatedWaypoints, action === CONST.IOU.ACTION.CREATE);
}, [shouldFetchRoute, transactionID, validatedWaypoints, isOffline, action]);

useEffect(() => {
if (numberOfWaypoints <= numberOfPreviousWaypoints) {
return;
Expand Down Expand Up @@ -199,7 +189,7 @@ function IOURequestStepDistance({
TransactionEdit.removeBackupTransaction(transaction?.transactionID ?? '-1');
return;
}
TransactionEdit.restoreOriginalTransactionFromBackup(transaction?.transactionID ?? '-1', action === CONST.IOU.ACTION.CREATE);
TransactionEdit.restoreOriginalTransactionFromBackup(transaction?.transactionID ?? '-1', IOUUtils.shouldUseTransactionDraft(action));
};
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, []);
Expand Down Expand Up @@ -394,8 +384,8 @@ function IOURequestStepDistance({

setOptimisticWaypoints(newWaypoints);
Promise.all([
TransactionAction.removeWaypoint(transaction, emptyWaypointIndex.toString(), action === CONST.IOU.ACTION.CREATE),
TransactionAction.updateWaypoints(transactionID, newWaypoints, action === CONST.IOU.ACTION.CREATE),
TransactionAction.removeWaypoint(transaction, emptyWaypointIndex.toString(), IOUUtils.shouldUseTransactionDraft(action)),
TransactionAction.updateWaypoints(transactionID, newWaypoints, IOUUtils.shouldUseTransactionDraft(action)),
]).then(() => {
setOptimisticWaypoints(null);
});
Expand Down
9 changes: 5 additions & 4 deletions src/pages/iou/request/step/IOURequestStepWaypoint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as ErrorUtils from '@libs/ErrorUtils';
import * as IOUUtils from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ValidationUtils from '@libs/ValidationUtils';
import * as Modal from '@userActions/Modal';
Expand Down Expand Up @@ -113,13 +114,13 @@ function IOURequestStepWaypoint({
return errors;
};

const saveWaypoint = (waypoint: FormOnyxValues<'waypointForm'>) => Transaction.saveWaypoint(transactionID, pageIndex, waypoint, action === CONST.IOU.ACTION.CREATE);
const saveWaypoint = (waypoint: FormOnyxValues<'waypointForm'>) => Transaction.saveWaypoint(transactionID, pageIndex, waypoint, IOUUtils.shouldUseTransactionDraft(action));

const submit = (values: FormOnyxValues<'waypointForm'>) => {
const waypointValue = values[`waypoint${pageIndex}`] ?? '';
// Allows letting you set a waypoint to an empty value
if (waypointValue === '') {
Transaction.removeWaypoint(transaction, pageIndex, action === CONST.IOU.ACTION.CREATE);
Transaction.removeWaypoint(transaction, pageIndex, IOUUtils.shouldUseTransactionDraft(action));
}

// While the user is offline, the auto-complete address search will not work
Expand All @@ -140,7 +141,7 @@ function IOURequestStepWaypoint({
};

const deleteStopAndHideModal = () => {
Transaction.removeWaypoint(transaction, pageIndex, action === CONST.IOU.ACTION.CREATE);
Transaction.removeWaypoint(transaction, pageIndex, IOUUtils.shouldUseTransactionDraft(action));
setRestoreFocusType(CONST.MODAL.RESTORE_FOCUS_TYPE.DELETE);
setIsDeleteStopModalOpen(false);
goBack();
Expand All @@ -155,7 +156,7 @@ function IOURequestStepWaypoint({
keyForList: `${values.name ?? 'waypoint'}_${Date.now()}`,
};

Transaction.saveWaypoint(transactionID, pageIndex, waypoint, action === CONST.IOU.ACTION.CREATE);
Transaction.saveWaypoint(transactionID, pageIndex, waypoint, IOUUtils.shouldUseTransactionDraft(action));
goBack();
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default function <TProps extends WithFullTransactionOrNotFoundProps<Money
const transactionID = route.params.transactionID ?? -1;
const userAction = 'action' in route.params && route.params.action ? route.params.action : CONST.IOU.ACTION.CREATE;

if (userAction === CONST.IOU.ACTION.CREATE || IOUUtils.isMovingTransactionFromTrackExpense(userAction)) {
if (IOUUtils.shouldUseTransactionDraft(userAction)) {
return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}` as `${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`;
}
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
Expand Down
Loading