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

Add One Transaction Report View #36934

Merged
merged 51 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
53ada16
report action utils functions
NikkiWines Feb 7, 2024
df1b56c
report utils functions for one transaction report
NikkiWines Feb 7, 2024
b841b6a
hide background for money requests on a single transaction report
NikkiWines Feb 7, 2024
7ec2e5c
update css style for money request
NikkiWines Feb 7, 2024
353b740
update report actions items to retrieve transaction thread report det…
NikkiWines Feb 9, 2024
42adcea
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Feb 9, 2024
66f498b
use undefined instead of {}
NikkiWines Feb 9, 2024
de66987
check prevProps
NikkiWines Feb 9, 2024
74a42f6
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Feb 20, 2024
1bf4c04
simplify transactionThreadReportActions display
NikkiWines Feb 20, 2024
6153bab
minor style and lint updates
NikkiWines Feb 21, 2024
d436ffe
use simplified report icons when applicable
NikkiWines Feb 21, 2024
b722725
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Feb 22, 2024
b13fc4b
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Feb 26, 2024
452d012
add transactionThreadReportID to report structure for onyx and props
NikkiWines Feb 27, 2024
cac6d81
simplify transactionThreadReportID logic to use value returned in the…
NikkiWines Feb 27, 2024
6a08ba5
minor style
NikkiWines Feb 27, 2024
1674735
don't show report if transaction thread and expense report have the s…
NikkiWines Feb 27, 2024
f3f5e52
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Feb 27, 2024
90bc361
update default value for transactionThreadReportActions key
NikkiWines Feb 28, 2024
0f21504
update utils files to no longer reference report.transactionThreadRep…
NikkiWines Mar 6, 2024
4bb0313
use general report and reportActions onyx keys instead of relying on …
NikkiWines Mar 6, 2024
35d0264
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 6, 2024
c941d23
update getOneTransactionReportID to take in only reportActions
NikkiWines Mar 7, 2024
2a02be8
fix some malformed logic
NikkiWines Mar 7, 2024
b5ae144
ensure we don't show outdated UI due to removed IOU requests
NikkiWines Mar 7, 2024
f6cfcb3
use transaction currency instead of checking between transactionThrea…
NikkiWines Mar 7, 2024
0140912
merge main and address conflicts from ts migrations for ReportActionItem
NikkiWines Mar 8, 2024
db05afc
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 8, 2024
c274090
style and ts updates
NikkiWines Mar 8, 2024
618b5ac
minor style
NikkiWines Mar 8, 2024
31cf018
adjust currency and filtering combined reportActions logic
NikkiWines Mar 9, 2024
6b2d28a
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 11, 2024
1b27a33
minor adjustments and stylistic changes
NikkiWines Mar 11, 2024
d36bc98
ts fixes
NikkiWines Mar 11, 2024
686a2dc
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 11, 2024
7994917
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 14, 2024
1003a1f
get transactionThreadReportActions in ReportActionsView instead of Re…
NikkiWines Mar 15, 2024
de600c8
pass transactionThreadReport and reportActions for report to reportAc…
NikkiWines Mar 15, 2024
034b93f
lint / style
NikkiWines Mar 15, 2024
716023c
supress incorrect linter error
NikkiWines Mar 20, 2024
3b88172
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 20, 2024
45c7fc1
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 21, 2024
f9f3607
update reportActionsView to account for getting newer and older repor…
NikkiWines Mar 22, 2024
e3be337
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 26, 2024
1090c5b
type resolution
NikkiWines Mar 26, 2024
a4926d3
updates to one-transaction utils functions
NikkiWines Mar 28, 2024
7dd2384
use reportActionsByReport, and some minor stylistic updates
NikkiWines Mar 28, 2024
fec3aa3
pass transactionThreadReportID from ReportScreen
NikkiWines Mar 28, 2024
5438f69
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 28, 2024
1aac6e0
Merge branch 'main' of github.com:Expensify/App into nikki-one-transa…
NikkiWines Mar 28, 2024
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
10 changes: 7 additions & 3 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ type MoneyRequestViewPropsWithoutTransaction = MoneyRequestViewOnyxPropsWithoutT

/** Whether we should display the horizontal rule below the component */
shouldShowHorizontalRule: boolean;

/** Whether we should display the animated banner above the component */
shouldShowAnimatedBackground: boolean;
};

type MoneyRequestViewProps = MoneyRequestViewTransactionOnyxProps & MoneyRequestViewPropsWithoutTransaction;
Expand All @@ -84,6 +87,7 @@ function MoneyRequestView({
policyTagList,
policy,
transactionViolations,
shouldShowAnimatedBackground,
}: MoneyRequestViewProps) {
const theme = useTheme();
const styles = useThemeStyles();
Expand Down Expand Up @@ -237,9 +241,9 @@ function MoneyRequestView({
);

return (
<View style={[StyleUtils.getReportWelcomeContainerStyle(isSmallScreenWidth)]}>
<AnimatedEmptyStateBackground />
<View style={[StyleUtils.getReportWelcomeTopMarginStyle(isSmallScreenWidth)]}>
<View style={[StyleUtils.getReportWelcomeContainerStyle(isSmallScreenWidth, true, shouldShowAnimatedBackground)]}>
{shouldShowAnimatedBackground && <AnimatedEmptyStateBackground />}
<View style={shouldShowAnimatedBackground && [StyleUtils.getReportWelcomeTopMarginStyle(isSmallScreenWidth, true)]}>
{/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */}
{(showMapAsImage || hasReceipt) && (
<OfflineWithFeedback
Expand Down
30 changes: 30 additions & 0 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,35 @@ function isTransactionThread(parentReportAction: OnyxEntry<ReportAction> | Empty
);
}

/**
* Returns the reportID for the transaction thread associated with a report by iterating over the reportActions and identifying the IOU report actions with a childReportID. Returns a reportID if there is exactly one transaction thread for the report, and null otherwise.
*/
function getOneTransactionThreadReportID(reportActions: OnyxEntry<ReportActions> | ReportAction[]): string | null {
const reportActionsArray = Object.values(reportActions ?? {});

if (!reportActionsArray.length) {
return null;
}

// Get all IOU report actions for the report.
const iouRequestTypes: Array<ValueOf<typeof CONST.IOU.REPORT_ACTION_TYPE>> = [CONST.IOU.REPORT_ACTION_TYPE.CREATE, CONST.IOU.REPORT_ACTION_TYPE.SPLIT, CONST.IOU.REPORT_ACTION_TYPE.PAY];
const iouRequestActions = reportActionsArray.filter(
(action) =>
action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU &&
(iouRequestTypes.includes(action.originalMessage.type) ?? []) &&
action.childReportID &&
action.originalMessage.IOUTransactionID,
tgolen marked this conversation as resolved.
Show resolved Hide resolved
);

// If we don't have any IOU request actions, or we have more than one IOU request actions, this isn't a oneTransaction report
if (!iouRequestActions.length || iouRequestActions.length > 1) {
return null;
}

// Ensure we have a childReportID associated with the IOU report action
return iouRequestActions[0].childReportID ?? null;
}

/**
* Sort an array of reportActions by their created timestamp first, and reportActionID second
* This gives us a stable order even in the case of multiple reportActions created on the same millisecond
Expand Down Expand Up @@ -1035,6 +1064,7 @@ function getReportActionMessageText(reportAction: OnyxEntry<ReportAction> | Empt

export {
extractLinksFromMessageHtml,
getOneTransactionThreadReportID,
getAllReportActions,
getIOUReportIDFromReportActionPreview,
getLastClosedReportAction,
Expand Down
32 changes: 32 additions & 0 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,23 @@ function isMoneyRequestReport(reportOrID: OnyxEntry<Report> | EmptyObject | stri
return isIOUReport(report) || isExpenseReport(report);
}

/**
* Checks if a report has only one transaction associated with it
*/
function isOneTransactionReport(reportID: string): boolean {
const reportActions = reportActionsByReport?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? ([] as ReportAction[]);
return ReportActionsUtils.getOneTransactionThreadReportID(reportActions) !== null;
}

/**
* Checks if a report is a transaction thread associated with a report that has only one transaction
*/
function isOneTransactionThread(reportID: string, parentReportID: string): boolean {
const parentReportActions = reportActionsByReport?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`] ?? ([] as ReportAction[]);
const transactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(parentReportActions);
return reportID === transactionThreadReportID;
}

/**
* Should return true only for personal 1:1 report
*
Expand Down Expand Up @@ -1704,6 +1721,11 @@ function getIcons(
};
const isManager = currentUserAccountID === report?.managerID;

// For one transaction IOUs, display a simplified report icon
if (isOneTransactionReport(report?.reportID ?? '0')) {
return [ownerIcon];
}

return isManager ? [managerIcon, ownerIcon] : [ownerIcon, managerIcon];
}

Expand Down Expand Up @@ -4334,6 +4356,11 @@ function shouldReportBeInOptionList({
return false;
}

// If this is a transaction thread associated with a report that only has one transaction, omit it
if (isOneTransactionThread(report.reportID, report.parentReportID ?? '0')) {
return false;
}

// Include the currently viewed report. If we excluded the currently viewed report, then there
// would be no way to highlight it in the options list and it would be confusing to users because they lose
// a sense of context.
Expand Down Expand Up @@ -4798,6 +4825,10 @@ function shouldReportShowSubscript(report: OnyxEntry<Report>): boolean {
return true;
}

if (isExpenseReport(report) && isOneTransactionReport(report?.reportID ?? '')) {
return true;
}

if (isWorkspaceTaskReport(report)) {
return true;
}
Expand Down Expand Up @@ -5678,6 +5709,7 @@ export {
hasSingleParticipant,
getReportRecipientAccountIDs,
isOneOnOneChat,
isOneTransactionThread,
isPayer,
goBackToDetailsPage,
getTransactionReportName,
Expand Down
1 change: 1 addition & 0 deletions src/pages/home/ReportScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ function ReportScreen({
isLoadingNewerReportActions={reportMetadata?.isLoadingNewerReportActions}
isLoadingOlderReportActions={reportMetadata?.isLoadingOlderReportActions}
isReadyForCommentLinking={!shouldShowSkeleton}
transactionThreadReportID={ReportActionsUtils.getOneTransactionThreadReportID(reportActions ?? [])}
/>
)}

Expand Down
56 changes: 50 additions & 6 deletions src/pages/home/report/ReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import SelectionScraper from '@libs/SelectionScraper';
import * as TransactionUtils from '@libs/TransactionUtils';
import {ReactionListContext} from '@pages/home/ReportScreenContext';
import * as BankAccounts from '@userActions/BankAccounts';
import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
Expand Down Expand Up @@ -100,12 +101,22 @@ type ReportActionItemOnyxProps = {

/** The policy which the user has access to and which the report is tied to */
policy: OnyxEntry<OnyxTypes.Policy>;

/** Transaction associated with this report, if any */
transaction: OnyxEntry<OnyxTypes.Transaction>;
};

type ReportActionItemProps = {
/** Report for this action */
report: OnyxTypes.Report;

/** The transaction thread report associated with the report for this action, if any */
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;

/** Array of report actions for the report for this action */
// eslint-disable-next-line react/no-unused-prop-types
reportActions: OnyxTypes.ReportAction[];
NikkiWines marked this conversation as resolved.
Show resolved Hide resolved

/** Report action belonging to the report's parent */
parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;

Expand Down Expand Up @@ -142,6 +153,7 @@ const isIOUReport = (actionObj: OnyxEntry<OnyxTypes.ReportAction>): actionObj is
function ReportActionItem({
action,
report,
transactionThreadReport,
linkedReportActionID,
displayAsGroup,
emojiReactions,
Expand All @@ -155,6 +167,7 @@ function ReportActionItem({
shouldHideThreadDividerLine = false,
shouldShowSubscriptAvatar = false,
policy,
transaction,
onPress = undefined,
}: ReportActionItemProps) {
const {translate} = useLocalize();
Expand All @@ -180,7 +193,7 @@ function ReportActionItem({
const originalReportID = ReportUtils.getOriginalReportID(report.reportID, action);
const originalReport = report.reportID === originalReportID ? report : ReportUtils.getReport(originalReportID);
const isReportActionLinked = linkedReportActionID && action.reportActionID && linkedReportActionID === action.reportActionID;

const transactionCurrency = TransactionUtils.getCurrency(transaction);
const reportScrollManager = useReportScrollManager();

const highlightedBackgroundColorIfNeeded = useMemo(
Expand Down Expand Up @@ -700,6 +713,7 @@ function ReportActionItem({
<MoneyRequestView
report={report}
shouldShowHorizontalRule={!shouldHideThreadDividerLine}
shouldShowAnimatedBackground
/>
</ShowContextMenuContext.Provider>
);
Expand Down Expand Up @@ -739,11 +753,30 @@ function ReportActionItem({
if (ReportUtils.isExpenseReport(report) || ReportUtils.isIOUReport(report)) {
return (
<OfflineWithFeedback pendingAction={action.pendingAction}>
<MoneyReportView
report={report}
policy={policy}
shouldShowHorizontalRule={!shouldHideThreadDividerLine}
/>
{transactionThreadReport && !isEmptyObject(transactionThreadReport) ? (
<>
{transactionCurrency !== report.currency && (
<MoneyReportView
report={report}
policy={policy}
shouldShowHorizontalRule={!shouldHideThreadDividerLine}
/>
)}
Comment on lines +756 to +764
Copy link
Contributor

Choose a reason for hiding this comment

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

For BZ checklist in #44162:
MoneyReportView is briefly displayed even when there are no transactions (optimistic).
This caused flickering effect. More details in this PR description

<ShowContextMenuContext.Provider value={contextValue}>
<MoneyRequestView
report={transactionThreadReport}
shouldShowHorizontalRule={!shouldHideThreadDividerLine}
shouldShowAnimatedBackground={transactionCurrency === report.currency}
/>
</ShowContextMenuContext.Provider>
</>
) : (
<MoneyReportView
report={report}
policy={policy}
shouldShowHorizontalRule={!shouldHideThreadDividerLine}
/>
)}
</OfflineWithFeedback>
);
}
Expand Down Expand Up @@ -899,6 +932,14 @@ export default withOnyx<ReportActionItemProps, ReportActionItemOnyxProps>({
userWallet: {
key: ONYXKEYS.USER_WALLET,
},
transaction: {
key: ({transactionThreadReport, reportActions}) => {
const parentReportActionID = isEmptyObject(transactionThreadReport) ? '0' : transactionThreadReport.parentReportActionID;
const action = reportActions?.find((reportAction) => reportAction.reportActionID === parentReportActionID);
const transactionID = (action as OnyxTypes.OriginalMessageIOU)?.originalMessage.IOUTransactionID ? (action as OnyxTypes.OriginalMessageIOU).originalMessage.IOUTransactionID : 0;
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
},
},
})(
memo(ReportActionItem, (prevProps, nextProps) => {
const prevParentReportAction = prevProps.parentReportAction;
Expand Down Expand Up @@ -930,6 +971,9 @@ export default withOnyx<ReportActionItemProps, ReportActionItemOnyxProps>({
prevProps.linkedReportActionID === nextProps.linkedReportActionID &&
lodashIsEqual(prevProps.report.fieldList, nextProps.report.fieldList) &&
lodashIsEqual(prevProps.policy, nextProps.policy) &&
lodashIsEqual(prevProps.transactionThreadReport, nextProps.transactionThreadReport) &&
lodashIsEqual(prevProps.reportActions, nextProps.reportActions) &&
lodashIsEqual(prevProps.transaction, nextProps.transaction) &&
lodashIsEqual(prevParentReportAction, nextParentReportAction)
);
}),
Expand Down
17 changes: 16 additions & 1 deletion src/pages/home/report/ReportActionItemParentAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,24 @@ type ReportActionItemParentActionProps = {
/** The current report is displayed */
report: OnyxEntry<OnyxTypes.Report>;

/** The transaction thread report associated with the current report, if any */
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;

/** Array of report actions for this report */
reportActions: OnyxTypes.ReportAction[];

/** Report actions belonging to the report's parent */
parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;
};

function ReportActionItemParentAction({report, parentReportAction, index = 0, shouldHideThreadDividerLine = false}: ReportActionItemParentActionProps) {
function ReportActionItemParentAction({
report,
transactionThreadReport,
reportActions,
parentReportAction,
index = 0,
shouldHideThreadDividerLine = false,
}: ReportActionItemParentActionProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isSmallScreenWidth} = useWindowDimensions();
Expand Down Expand Up @@ -86,6 +99,8 @@ function ReportActionItemParentAction({report, parentReportAction, index = 0, sh
onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.reportID))}
parentReportAction={parentReportAction}
report={ancestor.report}
reportActions={reportActions}
transactionThreadReport={transactionThreadReport}
action={ancestor.reportAction}
displayAsGroup={false}
isMostRecentIOUReportAction={false}
Expand Down
22 changes: 21 additions & 1 deletion src/pages/home/report/ReportActionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ type ReportActionsListProps = WithCurrentUserPersonalDetailsProps & {
/** The report currently being looked at */
report: OnyxTypes.Report;

/** The transaction thread report associated with the current report, if any */
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;

/** Array of report actions for the current report */
reportActions: OnyxTypes.ReportAction[];

/** The report's parentReportAction */
parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;

Expand Down Expand Up @@ -125,6 +131,8 @@ const onScrollToIndexFailed = () => {};

function ReportActionsList({
report,
transactionThreadReport,
reportActions = [],
parentReportAction,
isLoadingInitialReportActions = false,
isLoadingOlderReportActions = false,
Expand Down Expand Up @@ -514,17 +522,29 @@ function ReportActionsList({
({item: reportAction, index}: ListRenderItemInfo<OnyxTypes.ReportAction>) => (
<ReportActionsListItemRenderer
reportAction={reportAction}
reportActions={reportActions}
parentReportAction={parentReportAction}
index={index}
report={report}
transactionThreadReport={transactionThreadReport}
linkedReportActionID={linkedReportActionID}
displayAsGroup={ReportActionsUtils.isConsecutiveActionMadeByPreviousActor(sortedVisibleReportActions, index)}
mostRecentIOUReportActionID={mostRecentIOUReportActionID}
shouldHideThreadDividerLine={shouldHideThreadDividerLine}
shouldDisplayNewMarker={shouldDisplayNewMarker(reportAction, index)}
/>
),
[report, linkedReportActionID, sortedVisibleReportActions, mostRecentIOUReportActionID, shouldHideThreadDividerLine, shouldDisplayNewMarker, parentReportAction],
[
report,
linkedReportActionID,
sortedVisibleReportActions,
mostRecentIOUReportActionID,
shouldHideThreadDividerLine,
shouldDisplayNewMarker,
parentReportAction,
reportActions,
transactionThreadReport,
],
);

// Native mobile does not render updates flatlist the changes even though component did update called.
Expand Down
Loading
Loading