-
Notifications
You must be signed in to change notification settings - Fork 3.7k
refactor: PureReportActionItem, add ModifiedExpenseContent and ReimbursementDeQueuedContent #87756
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
Changes from all commits
91de36a
95e063e
3f50c60
28cd321
55ffc9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,7 +77,6 @@ import { | |
| getIOUReportIDFromReportActionPreview, | ||
| getOriginalMessage, | ||
| getPlaidBalanceFailureMessage, | ||
| getReimbursedMessage, | ||
| getRenamedAction, | ||
| getReportActionHtml, | ||
| getReportActionMessage, | ||
|
|
@@ -146,8 +145,11 @@ import ConfirmWhisperContent from './actionContents/ConfirmWhisperContent'; | |
| import FraudAlertContent from './actionContents/FraudAlertContent'; | ||
| import JoinRequestContent from './actionContents/JoinRequestContent'; | ||
| import MentionWhisperContent from './actionContents/MentionWhisperContent'; | ||
| import ModifiedExpenseContent from './actionContents/ModifiedExpenseContent'; | ||
| import PaymentContent from './actionContents/PaymentContent'; | ||
| import PolicyChangeLogContent, {isHandledPolicyChangeLogAction} from './actionContents/PolicyChangeLogContent'; | ||
| import ReimbursedContent from './actionContents/ReimbursedContent'; | ||
| import ReimbursementDeQueuedContent from './actionContents/ReimbursementDeQueuedContent'; | ||
| import ReportMentionWhisperContent from './actionContents/ReportMentionWhisperContent'; | ||
| import SimpleMessageContent, {isSimpleMessageAction} from './actionContents/SimpleMessageContent'; | ||
| import {RestrictedReadOnlyContextMenuActions} from './ContextMenu/ContextMenuActions'; | ||
|
|
@@ -159,7 +161,6 @@ import ReportActionItemBasicMessage from './ReportActionItemBasicMessage'; | |
| import ReportActionItemContentCreated from './ReportActionItemContentCreated'; | ||
| import ReportActionItemDraft from './ReportActionItemDraft'; | ||
| import ReportActionItemGrouped from './ReportActionItemGrouped'; | ||
| import ReportActionItemMessageWithExplain from './ReportActionItemMessageWithExplain'; | ||
| import ReportActionItemSingle from './ReportActionItemSingle'; | ||
| import ReportActionItemThread from './ReportActionItemThread'; | ||
| import TripSummary from './TripSummary'; | ||
|
|
@@ -306,12 +307,6 @@ type PureReportActionItemProps = { | |
| /** What missing payment method does this report action indicate, if any? */ | ||
| missingPaymentMethod?: MissingPaymentMethod | undefined; | ||
|
|
||
| /** Returns the preview message for `REIMBURSEMENT_DEQUEUED` or `REIMBURSEMENT_ACH_CANCELED` action */ | ||
| reimbursementDeQueuedOrCanceledActionMessage?: string; | ||
|
|
||
| /** The report action message when expense has been modified. */ | ||
| modifiedExpenseMessage?: string; | ||
|
|
||
| /** Gets all transactions on an IOU report with a receipt */ | ||
| getTransactionsWithReceipts?: (iouReportID: string | undefined) => OnyxTypes.Transaction[]; | ||
|
|
||
|
|
@@ -406,8 +401,6 @@ function PureReportActionItem({ | |
| isClosedExpenseReportWithNoExpenses, | ||
| isCurrentUserTheOnlyParticipant = () => false, | ||
| missingPaymentMethod, | ||
| reimbursementDeQueuedOrCanceledActionMessage = '', | ||
| modifiedExpenseMessage = '', | ||
| getTransactionsWithReceipts = () => [], | ||
| clearError = () => {}, | ||
| clearAllRelatedReportActionErrors = () => {}, | ||
|
|
@@ -915,12 +908,17 @@ function PureReportActionItem({ | |
| </ReportActionItemBasicMessage> | ||
| ); | ||
| } else if (isReimbursementDeQueuedOrCanceledAction(action)) { | ||
| children = <ReportActionItemBasicMessage message={reimbursementDeQueuedOrCanceledActionMessage} />; | ||
| children = ( | ||
| <ReimbursementDeQueuedContent | ||
| action={action} | ||
| report={report} | ||
| /> | ||
| ); | ||
| } else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIED_EXPENSE) { | ||
| children = ( | ||
| <ReportActionItemMessageWithExplain | ||
| message={modifiedExpenseMessage} | ||
| <ModifiedExpenseContent | ||
| action={action} | ||
| report={report} | ||
| childReport={childReport} | ||
| originalReport={originalReport} | ||
| /> | ||
|
|
@@ -944,7 +942,12 @@ function PureReportActionItem({ | |
| /> | ||
| ); | ||
| } else if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.REIMBURSED)) { | ||
| children = <ReportActionItemBasicMessage message={getReimbursedMessage(translate, action, report, currentUserAccountID)} />; | ||
| children = ( | ||
| <ReimbursedContent | ||
| action={action} | ||
| report={report} | ||
| /> | ||
| ); | ||
| } else if (isSimpleMessageAction(action)) { | ||
| children = <SimpleMessageContent action={action} />; | ||
| } else if (isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) { | ||
|
|
@@ -1023,7 +1026,6 @@ function PureReportActionItem({ | |
| report={report} | ||
| originalReport={originalReport} | ||
| policy={policy} | ||
| currentUserAccountID={currentUserAccountID} | ||
| personalPolicyID={personalPolicyID} | ||
| originalReportID={originalReportID} | ||
| resolveActionableMentionWhisper={resolveActionableMentionWhisper} | ||
|
|
@@ -1188,7 +1190,6 @@ function PureReportActionItem({ | |
| accountIDs={oldestFourAccountIDs} | ||
| onSecondaryInteraction={showPopover} | ||
| isActive={isReportActionActive && !isContextMenuActive} | ||
| currentUserAccountID={currentUserAccountID} | ||
| /> | ||
| </View> | ||
| )} | ||
|
|
@@ -1501,8 +1502,6 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => { | |
| prevProps.isChronosReport === nextProps.isChronosReport && | ||
| prevProps.isClosedExpenseReportWithNoExpenses === nextProps.isClosedExpenseReportWithNoExpenses && | ||
| deepEqual(prevProps.missingPaymentMethod, nextProps.missingPaymentMethod) && | ||
| prevProps.reimbursementDeQueuedOrCanceledActionMessage === nextProps.reimbursementDeQueuedOrCanceledActionMessage && | ||
| prevProps.modifiedExpenseMessage === nextProps.modifiedExpenseMessage && | ||
| prevProps.userBillingFundID === nextProps.userBillingFundID && | ||
|
Comment on lines
1502
to
1505
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
After extracting Useful? React with 👍 / 👎.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The props that bypass the memo (report?.ownerAccountID, report?.policyID, currentUserEmail) are immutable during the component's lifetime, they're set at report creation / login and don't change. The mutable data (policy, policyTags, movedFrom/ToReport) is handled by self-subscription inside the extracted components, which bypasses the memo entirely. The old string comparisons were only catching changes to these self-subscribing values, not to the immutable ones.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Technically there is also another case of change which is the first loading of the data. There can be other cases that could cause a re-render in those circumstances but it might be a good idea to still add the necessary dependencies. WDYT @cristipaval
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than re-add the prop/comparator entry, I pushed the fix to |
||
| deepEqual(prevProps.taskReport, nextProps.taskReport) && | ||
| prevProps.shouldHighlight === nextProps.shouldHighlight && | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import React from 'react'; | ||
| import type {OnyxEntry} from 'react-native-onyx'; | ||
| import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; | ||
| import useLocalize from '@hooks/useLocalize'; | ||
| import useOnyx from '@hooks/useOnyx'; | ||
| import usePolicyForMovingExpenses from '@hooks/usePolicyForMovingExpenses'; | ||
| import {getForReportAction, getMovedReportID} from '@libs/ModifiedExpenseMessage'; | ||
| import ReportActionItemMessageWithExplain from '@pages/inbox/report/ReportActionItemMessageWithExplain'; | ||
| import CONST from '@src/CONST'; | ||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||
| import type {Report, ReportAction} from '@src/types/onyx'; | ||
|
|
||
| type ModifiedExpenseContentProps = { | ||
| action: ReportAction; | ||
| report: OnyxEntry<Report>; | ||
| childReport: OnyxEntry<Report>; | ||
| originalReport: OnyxEntry<Report>; | ||
| }; | ||
|
|
||
| function ModifiedExpenseContent({action, report, childReport, originalReport}: ModifiedExpenseContentProps) { | ||
| const {translate} = useLocalize(); | ||
| const {email: currentUserEmail} = useCurrentUserPersonalDetails(); | ||
| const {policyForMovingExpensesID} = usePolicyForMovingExpenses(); | ||
| const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`); | ||
|
|
||
| // When expense is moved from self-DM to workspace, policyID is temporarily OWNER_EMAIL_FAKE. | ||
| // Fall back to policyForMovingExpensesID (actual destination workspace) for correct tag list. | ||
| const policyIDForTags = report?.policyID === CONST.POLICY.OWNER_EMAIL_FAKE && policyForMovingExpensesID ? policyForMovingExpensesID : report?.policyID; | ||
| const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyIDForTags}`); | ||
| const [movedFromReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(action, CONST.REPORT.MOVE_TYPE.FROM)}`); | ||
| const [movedToReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getMovedReportID(action, CONST.REPORT.MOVE_TYPE.TO)}`); | ||
|
|
||
| const modifiedExpenseMessage = getForReportAction({ | ||
| translate, | ||
| reportAction: action, | ||
| policy, | ||
| movedFromReport, | ||
| movedToReport, | ||
| policyTags: policyTags ?? CONST.POLICY.DEFAULT_TAG_LIST, | ||
| currentUserLogin: currentUserEmail ?? '', | ||
| }); | ||
|
|
||
| return ( | ||
| <ReportActionItemMessageWithExplain | ||
| message={modifiedExpenseMessage} | ||
| action={action} | ||
| childReport={childReport} | ||
| originalReport={originalReport} | ||
| /> | ||
| ); | ||
| } | ||
|
|
||
| ModifiedExpenseContent.displayName = 'ModifiedExpenseContent'; | ||
|
|
||
| export default ModifiedExpenseContent; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import React from 'react'; | ||
| import type {OnyxEntry} from 'react-native-onyx'; | ||
| import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; | ||
| import useLocalize from '@hooks/useLocalize'; | ||
| import {getReimbursedMessage} from '@libs/ReportActionsUtils'; | ||
| import ReportActionItemBasicMessage from '@pages/inbox/report/ReportActionItemBasicMessage'; | ||
| import type {Report, ReportAction} from '@src/types/onyx'; | ||
|
|
||
| type ReimbursedContentProps = { | ||
| action: ReportAction; | ||
| report: OnyxEntry<Report>; | ||
| }; | ||
|
|
||
| function ReimbursedContent({action, report}: ReimbursedContentProps) { | ||
| const {translate} = useLocalize(); | ||
| const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); | ||
| const message = getReimbursedMessage(translate, action, report, currentUserAccountID); | ||
|
|
||
| return <ReportActionItemBasicMessage message={message} />; | ||
| } | ||
|
|
||
| ReimbursedContent.displayName = 'ReimbursedContent'; | ||
|
|
||
| export default ReimbursedContent; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import React from 'react'; | ||
| import type {OnyxEntry} from 'react-native-onyx'; | ||
| import useLocalize from '@hooks/useLocalize'; | ||
| import {getReimbursementDeQueuedOrCanceledActionMessage} from '@libs/ReportUtils'; | ||
| import ReportActionItemBasicMessage from '@pages/inbox/report/ReportActionItemBasicMessage'; | ||
| import type CONST from '@src/CONST'; | ||
| import type {Report, ReportAction} from '@src/types/onyx'; | ||
|
|
||
| type ReimbursementDeQueuedContentProps = { | ||
| action: ReportAction; | ||
| report: OnyxEntry<Report>; | ||
| }; | ||
|
|
||
| function ReimbursementDeQueuedContent({action, report}: ReimbursementDeQueuedContentProps) { | ||
| const {translate} = useLocalize(); | ||
| const message = getReimbursementDeQueuedOrCanceledActionMessage( | ||
| translate, | ||
| action as OnyxEntry<ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_DEQUEUED | typeof CONST.REPORT.ACTIONS.TYPE.REIMBURSEMENT_ACH_CANCELED>>, | ||
| report, | ||
| ); | ||
|
|
||
| return <ReportActionItemBasicMessage message={message} />; | ||
| } | ||
|
|
||
| ReimbursementDeQueuedContent.displayName = 'ReimbursementDeQueuedContent'; | ||
|
|
||
| export default ReimbursementDeQueuedContent; |
Uh oh!
There was an error while loading. Please reload this page.