From 53beacb9856ba7e094bc661bd313c1b0dfa330a9 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 16 Dec 2024 12:03:23 +0800 Subject: [PATCH 1/4] add a new discard confirmation modal when going back from a page with unsaved changes --- src/hooks/useBeforeRemove.tsx | 3 +- src/languages/en.ts | 5 ++ src/languages/es.ts | 5 ++ .../Navigators/RightModalNavigator.tsx | 4 ++ .../step/DiscardChangesConfirmation.tsx | 52 +++++++++++++++++++ .../step/IOURequestStepDescription.tsx | 20 ++++++- .../request/step/IOURequestStepMerchant.tsx | 23 +++++++- 7 files changed, 108 insertions(+), 4 deletions(-) create mode 100644 src/pages/iou/request/step/DiscardChangesConfirmation.tsx diff --git a/src/hooks/useBeforeRemove.tsx b/src/hooks/useBeforeRemove.tsx index 91d1b93a41cc..78a95b4974d4 100644 --- a/src/hooks/useBeforeRemove.tsx +++ b/src/hooks/useBeforeRemove.tsx @@ -1,7 +1,8 @@ import {useNavigation} from '@react-navigation/native'; +import type {EventListenerCallback, EventMapCore, NavigationState} from '@react-navigation/native'; import {useEffect} from 'react'; -const useBeforeRemove = (onBeforeRemove: () => void) => { +const useBeforeRemove = (onBeforeRemove: EventListenerCallback, 'beforeRemove'>) => { const navigation = useNavigation(); useEffect(() => { diff --git a/src/languages/en.ts b/src/languages/en.ts index 66a83e719377..4f33dc5c6dd0 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -5497,6 +5497,11 @@ const translations = { part3: '\nand more!', }, }, + discardChangesConfirmation: { + title: 'Discard changes?', + body: 'Are you sure you want to discard the changes you made?', + confirmText: 'Discard changes', + }, }; export default translations satisfies TranslationDeepObject; diff --git a/src/languages/es.ts b/src/languages/es.ts index 9c2b8a90f312..d983ba7b9525 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6017,6 +6017,11 @@ const translations = { part3: '\ny mucho más!', }, }, + discardChangesConfirmation: { + title: '¿Descartar cambios?', + body: '¿Estás seguro de que quieres descartar los cambios que hiciste?', + confirmText: 'Descartar cambios', + }, }; export default translations satisfies TranslationDeepObject; diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index c996f380e98c..91533e66b5f0 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -13,6 +13,7 @@ import useSideModalStackScreenOptions from '@libs/Navigation/AppNavigator/useSid import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {AuthScreensParamList, RightModalNavigatorParamList} from '@navigation/types'; +import CONST from '@src/CONST'; import NAVIGATORS from '@src/NAVIGATORS'; import SCREENS from '@src/SCREENS'; import Overlay from './Overlay'; @@ -53,6 +54,9 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) { } isExecutingRef.current = true; navigation.goBack(); + setTimeout(() => { + isExecutingRef.current = false; + }, CONST.ANIMATED_TRANSITION); }} /> )} diff --git a/src/pages/iou/request/step/DiscardChangesConfirmation.tsx b/src/pages/iou/request/step/DiscardChangesConfirmation.tsx new file mode 100644 index 000000000000..317547632a29 --- /dev/null +++ b/src/pages/iou/request/step/DiscardChangesConfirmation.tsx @@ -0,0 +1,52 @@ +import {useNavigation} from '@react-navigation/native'; +import type {NavigationAction} from '@react-navigation/native'; +import React, {memo, useCallback, useRef, useState} from 'react'; +import ConfirmModal from '@components/ConfirmModal'; +import useBeforeRemove from '@hooks/useBeforeRemove'; +import useLocalize from '@hooks/useLocalize'; + +type DiscardChangesConfirmationProps = { + getHasUnsavedChanges: () => boolean; +}; + +function DiscardChangesConfirmation({getHasUnsavedChanges}: DiscardChangesConfirmationProps) { + const navigation = useNavigation(); + const {translate} = useLocalize(); + const [isVisible, setIsVisible] = useState(false); + const blockedNavigationAction = useRef(); + + useBeforeRemove( + useCallback( + (e) => { + if (!getHasUnsavedChanges()) { + return; + } + + e.preventDefault(); + blockedNavigationAction.current = e.data.action; + setIsVisible(true); + }, + [getHasUnsavedChanges], + ), + ); + + return ( + { + setIsVisible(false); + if (blockedNavigationAction.current) { + navigation.dispatch(blockedNavigationAction.current); + } + }} + onCancel={() => setIsVisible(false)} + /> + ); +} + +export default memo(DiscardChangesConfirmation); diff --git a/src/pages/iou/request/step/IOURequestStepDescription.tsx b/src/pages/iou/request/step/IOURequestStepDescription.tsx index a39261f08b8c..67850e709874 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.tsx +++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx @@ -1,5 +1,5 @@ import lodashIsEmpty from 'lodash/isEmpty'; -import React, {useCallback} from 'react'; +import React, {useCallback, useRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; @@ -23,6 +23,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/MoneyRequestDescriptionForm'; import type * as OnyxTypes from '@src/types/onyx'; +import DiscardChangesConfirmation from './DiscardChangesConfirmation'; import StepScreenWrapper from './StepScreenWrapper'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; @@ -73,6 +74,8 @@ function IOURequestStepDescription({ // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value const isEditingSplitBill = iouType === CONST.IOU.TYPE.SPLIT && action === CONST.IOU.ACTION.EDIT; const currentDescription = isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction?.comment?.comment ?? '' : transaction?.comment?.comment ?? ''; + const descriptionRef = useRef(currentDescription); + const isSavedRef = useRef(false); /** * @returns - An object containing the errors for each inputID @@ -98,7 +101,12 @@ function IOURequestStepDescription({ Navigation.goBack(backTo); }; + const updateDescriptionRef = (value: string) => { + descriptionRef.current = value; + }; + const updateComment = (value: FormOnyxValues) => { + isSavedRef.current = true; const newComment = value.moneyRequestComment.trim(); // Only update comment if it has changed @@ -151,10 +159,12 @@ function IOURequestStepDescription({ > + { + if (isSavedRef.current) { + return false; + } + return descriptionRef.current !== currentDescription; + }} + /> ); } diff --git a/src/pages/iou/request/step/IOURequestStepMerchant.tsx b/src/pages/iou/request/step/IOURequestStepMerchant.tsx index 80720b1cbf1c..a3389ea4f65b 100644 --- a/src/pages/iou/request/step/IOURequestStepMerchant.tsx +++ b/src/pages/iou/request/step/IOURequestStepMerchant.tsx @@ -1,4 +1,4 @@ -import React, {useCallback} from 'react'; +import React, {useCallback, useRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; @@ -18,6 +18,7 @@ import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/MoneyRequestMerchantForm'; import type * as OnyxTypes from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import DiscardChangesConfirmation from './DiscardChangesConfirmation'; import StepScreenWrapper from './StepScreenWrapper'; import type {WithFullTransactionOrNotFoundProps} from './withFullTransactionOrNotFound'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; @@ -62,6 +63,9 @@ function IOURequestStepMerchant({ const isEditingSplitBill = iouType === CONST.IOU.TYPE.SPLIT && isEditing; const merchant = ReportUtils.getTransactionDetails(isEditingSplitBill && !isEmptyObject(splitDraftTransaction) ? splitDraftTransaction : transaction)?.merchant; const isEmptyMerchant = merchant === '' || merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT; + const initialMerchant = isEmptyMerchant ? '' : merchant; + const merchantRef = useRef(initialMerchant); + const isSavedRef = useRef(false); const isMerchantRequired = ReportUtils.isPolicyExpenseChat(report) || ReportUtils.isExpenseRequest(report) || transaction?.participants?.some((participant) => !!participant.isPolicyExpenseChat); @@ -83,7 +87,12 @@ function IOURequestStepMerchant({ [isMerchantRequired, translate], ); + const updateMerchantRef = (value: string) => { + merchantRef.current = value; + }; + const updateMerchant = (value: FormOnyxValues) => { + isSavedRef.current = true; const newMerchant = value.moneyRequestMerchant?.trim(); // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value @@ -124,10 +133,12 @@ function IOURequestStepMerchant({ > + { + if (isSavedRef.current) { + return false; + } + return merchantRef.current !== initialMerchant; + }} + /> ); } From a47801783e2a6ab2dd282c35e3dfdb6c75510730 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 16 Dec 2024 12:50:06 +0800 Subject: [PATCH 2/4] migrate to useOnyx --- .../step/IOURequestStepDescription.tsx | 100 +++++------------- .../request/step/IOURequestStepMerchant.tsx | 54 ++-------- 2 files changed, 38 insertions(+), 116 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepDescription.tsx b/src/pages/iou/request/step/IOURequestStepDescription.tsx index 67850e709874..e9aedcf22a58 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.tsx +++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx @@ -1,14 +1,15 @@ import lodashIsEmpty from 'lodash/isEmpty'; -import React, {useCallback, useRef} from 'react'; +import React, {useCallback, useMemo, useRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import TextInput from '@components/TextInput'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as IOUUtils from '@libs/IOUUtils'; @@ -29,45 +30,38 @@ import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -type IOURequestStepDescriptionOnyxProps = { - /** The draft transaction that holds data to be persisted on the current transaction */ - splitDraftTransaction: OnyxEntry; - - /** The policy of the report */ - policy: OnyxEntry; - - /** Collection of categories attached to a policy */ - policyCategories: OnyxEntry; - - /** Collection of tags attached to a policy */ - policyTags: OnyxEntry; - - /** The actions from the parent report */ - reportActions: OnyxEntry; - - /** Session info for the currently logged in user. */ - session: OnyxEntry; +type IOURequestStepDescriptionProps = WithWritableReportOrNotFoundProps & { + /** Holds data related to Expense view state, rather than the underlying Expense data. */ + transaction: OnyxEntry; }; -type IOURequestStepDescriptionProps = IOURequestStepDescriptionOnyxProps & - WithWritableReportOrNotFoundProps & { - /** Holds data related to Expense view state, rather than the underlying Expense data. */ - transaction: OnyxEntry; - }; - function IOURequestStepDescription({ route: { - params: {action, iouType, reportID, backTo, reportActionID}, + params: {action, iouType, reportID, backTo, reportActionID, transactionID}, }, transaction, - splitDraftTransaction, - policy, - policyTags, - policyCategories, - reportActions, - session, report, }: IOURequestStepDescriptionProps) { + const policy = usePolicy(report?.policyID); + const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID || '-1'}`); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID || '-1'}`); + const reportActionsReportID = useMemo(() => { + let actionsReportID = '-1'; + if (action === CONST.IOU.ACTION.EDIT) { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + actionsReportID = iouType === CONST.IOU.TYPE.SPLIT ? report?.reportID || '-1' : report?.parentReportID || '-1'; + } + return actionsReportID; + }, [action, iouType, report?.reportID, report?.parentReportID]); + const [reportAction] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportActionsReportID}`, { + canEvict: false, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + selector: (reportActions) => reportActions?.[report?.parentReportActionID || reportActionID], + }); + const [session] = useOnyx(ONYXKEYS.SESSION); const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(true); @@ -132,8 +126,6 @@ function IOURequestStepDescription({ navigateBack(); }; - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- nullish coalescing doesn't achieve the same result in this case - const reportAction = reportActions?.[report?.parentReportActionID || reportActionID] ?? null; const isEditing = action === CONST.IOU.ACTION.EDIT; const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); @@ -191,44 +183,8 @@ function IOURequestStepDescription({ IOURequestStepDescription.displayName = 'IOURequestStepDescription'; -const IOURequestStepDescriptionWithOnyx = withOnyx({ - splitDraftTransaction: { - key: ({route}) => { - const transactionID = route?.params.transactionID ?? -1; - return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; - }, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '-1'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '-1'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '-1'}`, - }, - reportActions: { - key: ({ - report, - route: { - params: {action, iouType}, - }, - }) => { - let reportID = '-1'; - if (action === CONST.IOU.ACTION.EDIT) { - reportID = iouType === CONST.IOU.TYPE.SPLIT ? report?.reportID ?? '-1' : report?.parentReportID ?? '-1'; - } - return `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; - }, - canEvict: false, - }, - session: { - key: ONYXKEYS.SESSION, - }, -})(IOURequestStepDescription); - // eslint-disable-next-line rulesdir/no-negated-variables -const IOURequestStepDescriptionWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepDescriptionWithOnyx); +const IOURequestStepDescriptionWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepDescription); // eslint-disable-next-line rulesdir/no-negated-variables const IOURequestStepDescriptionWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepDescriptionWithFullTransactionOrNotFound); diff --git a/src/pages/iou/request/step/IOURequestStepMerchant.tsx b/src/pages/iou/request/step/IOURequestStepMerchant.tsx index a3389ea4f65b..1331b82128de 100644 --- a/src/pages/iou/request/step/IOURequestStepMerchant.tsx +++ b/src/pages/iou/request/step/IOURequestStepMerchant.tsx @@ -1,13 +1,13 @@ import React, {useCallback, useRef} from 'react'; import {View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import TextInput from '@components/TextInput'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; @@ -16,7 +16,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/MoneyRequestMerchantForm'; -import type * as OnyxTypes from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import DiscardChangesConfirmation from './DiscardChangesConfirmation'; import StepScreenWrapper from './StepScreenWrapper'; @@ -25,22 +24,7 @@ import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -type IOURequestStepMerchantOnyxProps = { - /** The draft transaction that holds data to be persisted on the current transaction */ - splitDraftTransaction: OnyxEntry; - - /** The policy of the report */ - policy: OnyxEntry; - - /** Collection of categories attached to a policy */ - policyCategories: OnyxEntry; - - /** Collection of tags attached to a policy */ - policyTags: OnyxEntry; -}; - -type IOURequestStepMerchantProps = IOURequestStepMerchantOnyxProps & - WithWritableReportOrNotFoundProps & +type IOURequestStepMerchantProps = WithWritableReportOrNotFoundProps & WithFullTransactionOrNotFoundProps; function IOURequestStepMerchant({ @@ -48,12 +32,14 @@ function IOURequestStepMerchant({ params: {transactionID, reportID, backTo, action, iouType}, }, transaction, - splitDraftTransaction, - policy, - policyTags, - policyCategories, report, }: IOURequestStepMerchantProps) { + const policy = usePolicy(report?.policyID); + const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID || '-1'}`); + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID || '-1'}`); const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); @@ -161,24 +147,4 @@ function IOURequestStepMerchant({ IOURequestStepMerchant.displayName = 'IOURequestStepMerchant'; -export default withWritableReportOrNotFound( - withFullTransactionOrNotFound( - withOnyx({ - splitDraftTransaction: { - key: ({route}) => { - const transactionID = route.params.transactionID ?? -1; - return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; - }, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '-1'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '-1'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '-1'}`, - }, - })(IOURequestStepMerchant), - ), -); +export default withWritableReportOrNotFound(withFullTransactionOrNotFound(IOURequestStepMerchant)); From d72f8a03bc43151e2a8839b5ce1fe0aa091a69a9 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Mon, 23 Dec 2024 18:59:08 +0700 Subject: [PATCH 3/4] lint --- .../step/IOURequestStepDescription.tsx | 21 ++++++++++--------- .../request/step/IOURequestStepMerchant.tsx | 6 ++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/pages/iou/request/step/IOURequestStepDescription.tsx b/src/pages/iou/request/step/IOURequestStepDescription.tsx index e9aedcf22a58..f4a8ee827ff1 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.tsx +++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx @@ -44,15 +44,12 @@ function IOURequestStepDescription({ }: IOURequestStepDescriptionProps) { const policy = usePolicy(report?.policyID); const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID || '-1'}`); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID || '-1'}`); + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID}`); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`); const reportActionsReportID = useMemo(() => { - let actionsReportID = '-1'; + let actionsReportID; if (action === CONST.IOU.ACTION.EDIT) { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - actionsReportID = iouType === CONST.IOU.TYPE.SPLIT ? report?.reportID || '-1' : report?.parentReportID || '-1'; + actionsReportID = iouType === CONST.IOU.TYPE.SPLIT ? report?.reportID : report?.parentReportID; } return actionsReportID; }, [action, iouType, report?.reportID, report?.parentReportID]); @@ -100,6 +97,10 @@ function IOURequestStepDescription({ }; const updateComment = (value: FormOnyxValues) => { + if (!transaction?.transactionID) { + return; + } + isSavedRef.current = true; const newComment = value.moneyRequestComment.trim(); @@ -111,16 +112,16 @@ function IOURequestStepDescription({ // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value if (isEditingSplitBill) { - IOU.setDraftSplitTransaction(transaction?.transactionID ?? '-1', {comment: newComment}); + IOU.setDraftSplitTransaction(transaction?.transactionID, {comment: newComment}); navigateBack(); return; } const isTransactionDraft = IOUUtils.shouldUseTransactionDraft(action); - IOU.setMoneyRequestDescription(transaction?.transactionID ?? '-1', newComment, isTransactionDraft); + IOU.setMoneyRequestDescription(transaction?.transactionID, newComment, isTransactionDraft); if (action === CONST.IOU.ACTION.EDIT) { - IOU.updateMoneyRequestDescription(transaction?.transactionID ?? '-1', reportID, newComment, policy, policyTags, policyCategories); + IOU.updateMoneyRequestDescription(transaction?.transactionID, reportID, newComment, policy, policyTags, policyCategories); } navigateBack(); diff --git a/src/pages/iou/request/step/IOURequestStepMerchant.tsx b/src/pages/iou/request/step/IOURequestStepMerchant.tsx index 1331b82128de..ac6035725106 100644 --- a/src/pages/iou/request/step/IOURequestStepMerchant.tsx +++ b/src/pages/iou/request/step/IOURequestStepMerchant.tsx @@ -36,10 +36,8 @@ function IOURequestStepMerchant({ }: IOURequestStepMerchantProps) { const policy = usePolicy(report?.policyID); const [splitDraftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID || '-1'}`); - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID || '-1'}`); + const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID}`); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`); const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); From 93328ea8b0dc1880041b6277c219c0c4379cad35 Mon Sep 17 00:00:00 2001 From: Bernhard Owen Josephus Date: Tue, 24 Dec 2024 12:58:38 +0700 Subject: [PATCH 4/4] add comment --- src/hooks/useBeforeRemove.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/useBeforeRemove.tsx b/src/hooks/useBeforeRemove.tsx index 78a95b4974d4..835d5a30babe 100644 --- a/src/hooks/useBeforeRemove.tsx +++ b/src/hooks/useBeforeRemove.tsx @@ -2,6 +2,7 @@ import {useNavigation} from '@react-navigation/native'; import type {EventListenerCallback, EventMapCore, NavigationState} from '@react-navigation/native'; import {useEffect} from 'react'; +// beforeRemove have some limitations. When the react-navigation is upgraded to 7.x, update this to use usePreventRemove hook. const useBeforeRemove = (onBeforeRemove: EventListenerCallback, 'beforeRemove'>) => { const navigation = useNavigation();