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

Revert "Revert "Add One Transaction Report View"" #11

Merged
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
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 @@ -213,6 +213,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,
);

// 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 @@ -1034,6 +1063,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 @@ -1265,6 +1265,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 @@ -1795,6 +1812,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 @@ -4398,6 +4420,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 @@ -4868,6 +4895,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 @@ -5798,6 +5829,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 @@ -635,6 +635,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[];

/** 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 @@ -743,6 +756,7 @@ function ReportActionItem({
<MoneyRequestView
report={report}
shouldShowHorizontalRule={!shouldHideThreadDividerLine}
shouldShowAnimatedBackground
/>
</ShowContextMenuContext.Provider>
);
Expand Down Expand Up @@ -782,11 +796,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}
/>
)}
<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 @@ -947,6 +980,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 @@ -978,6 +1019,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
18 changes: 17 additions & 1 deletion src/pages/home/report/ReportActionItemParentAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,28 @@ 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>;

/** Whether we should display "Replies" divider */
shouldDisplayReplyDivider: boolean;
};

function ReportActionItemParentAction({report, parentReportAction, index = 0, shouldHideThreadDividerLine = false, shouldDisplayReplyDivider}: ReportActionItemParentActionProps) {
function ReportActionItemParentAction({
report,
transactionThreadReport,
reportActions,
parentReportAction,
index = 0,
shouldHideThreadDividerLine = false,
shouldDisplayReplyDivider,
}: ReportActionItemParentActionProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isSmallScreenWidth} = useWindowDimensions();
Expand Down Expand Up @@ -92,6 +106,8 @@ function ReportActionItemParentAction({report, parentReportAction, index = 0, sh
onPress={() => Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(ancestor.report.parentReportID ?? ''))}
parentReportAction={parentReportAction}
report={ancestor.report}
reportActions={reportActions}
transactionThreadReport={transactionThreadReport}
action={ancestor.reportAction}
displayAsGroup={false}
isMostRecentIOUReportAction={false}
Expand Down
12 changes: 12 additions & 0 deletions 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,9 +522,11 @@ 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}
Expand All @@ -534,6 +544,8 @@ function ReportActionsList({
shouldHideThreadDividerLine,
shouldDisplayNewMarker,
parentReportAction,
reportActions,
transactionThreadReport,
],
);

Expand Down
Loading
Loading