diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index bd2d9f73ae2a..139b5fde58b2 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -7,7 +7,6 @@ import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; -import SpacerView from '@components/SpacerView'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; @@ -29,12 +28,9 @@ type MoneyReportViewProps = { /** Policy that the report belongs to */ policy: OnyxEntry; - - /** Whether we should display the horizontal rule below the component */ - shouldShowHorizontalRule: boolean; }; -function MoneyReportView({report, policy, shouldShowHorizontalRule}: MoneyReportViewProps) { +function MoneyReportView({report, policy}: MoneyReportViewProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -168,10 +164,6 @@ function MoneyReportView({report, policy, shouldShowHorizontalRule}: MoneyReport )} - )} diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index 1c821fc8965a..73bc7898c6df 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -9,7 +9,6 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {useSession} from '@components/OnyxProvider'; import {ReceiptAuditHeader, ReceiptAuditMessages} from '@components/ReceiptAudit'; import ReceiptEmptyState from '@components/ReceiptEmptyState'; -import SpacerView from '@components/SpacerView'; import Switch from '@components/Switch'; import Text from '@components/Text'; import ViolationMessages from '@components/ViolationMessages'; @@ -77,9 +76,6 @@ type MoneyRequestViewPropsWithoutTransaction = MoneyRequestViewOnyxPropsWithoutT /** The report currently being looked at */ report: OnyxTypes.Report; - /** Whether we should display the horizontal rule below the component */ - shouldShowHorizontalRule: boolean; - /** Whether we should display the animated banner above the component */ shouldShowAnimatedBackground: boolean; }; @@ -91,7 +87,6 @@ function MoneyRequestView({ parentReport, parentReportActions, policyCategories, - shouldShowHorizontalRule, transaction, policyTagList, policy, @@ -566,10 +561,6 @@ function MoneyRequestView({ )} - ); } diff --git a/src/components/ReportActionItem/TaskView.tsx b/src/components/ReportActionItem/TaskView.tsx index ae361ce9dc47..e7b32ebc6fed 100644 --- a/src/components/ReportActionItem/TaskView.tsx +++ b/src/components/ReportActionItem/TaskView.tsx @@ -11,7 +11,6 @@ import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import {usePersonalDetails} from '@components/OnyxProvider'; import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction'; -import SpacerView from '@components/SpacerView'; import Text from '@components/Text'; import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails'; import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails'; @@ -40,12 +39,9 @@ type TaskViewProps = TaskViewOnyxProps & WithCurrentUserPersonalDetailsProps & { /** The report currently being looked at */ report: Report; - - /** Whether we should display the horizontal rule below the component */ - shouldShowHorizontalRule: boolean; }; -function TaskView({report, shouldShowHorizontalRule, ...props}: TaskViewProps) { +function TaskView({report, ...props}: TaskViewProps) { const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); useEffect(() => { @@ -185,10 +181,6 @@ function TaskView({report, shouldShowHorizontalRule, ...props}: TaskViewProps) { )} - ); } diff --git a/src/components/UnreadActionIndicator.tsx b/src/components/UnreadActionIndicator.tsx index f422ae24bd4f..c63079e69853 100755 --- a/src/components/UnreadActionIndicator.tsx +++ b/src/components/UnreadActionIndicator.tsx @@ -6,18 +6,24 @@ import CONST from '@src/CONST'; import Text from './Text'; type UnreadActionIndicatorProps = { + /** The ID of the report action */ reportActionID: string; + + /** Whether we should hide thread divider line */ + shouldHideThreadDividerLine?: boolean; }; -function UnreadActionIndicator({reportActionID}: UnreadActionIndicatorProps) { +function UnreadActionIndicator({reportActionID, shouldHideThreadDividerLine}: UnreadActionIndicatorProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const containerStyle = shouldHideThreadDividerLine ? styles.topUnreadIndicatorContainer : styles.unreadIndicatorContainer; + return ( diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx index 84a689c6f03c..64cc31fca993 100644 --- a/src/pages/home/report/ReportActionItem.tsx +++ b/src/pages/home/report/ReportActionItem.tsx @@ -29,6 +29,7 @@ import TaskAction from '@components/ReportActionItem/TaskAction'; import TaskPreview from '@components/ReportActionItem/TaskPreview'; import TaskView from '@components/ReportActionItem/TaskView'; import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; +import SpacerView from '@components/SpacerView'; import Text from '@components/Text'; import UnreadActionIndicator from '@components/UnreadActionIndicator'; import useLocalize from '@hooks/useLocalize'; @@ -151,6 +152,12 @@ type ReportActionItemProps = { /** Callback to be called on onPress */ onPress?: () => void; + + /** If this is the first visible report action */ + isFirstVisibleReportAction: boolean; + + /** IF the thread divider line will be used */ + shouldUseThreadDividerLine?: boolean; } & ReportActionItemOnyxProps; const isIOUReport = (actionObj: OnyxEntry): actionObj is OnyxTypes.ReportActionBase & OnyxTypes.OriginalMessageIOU => @@ -175,6 +182,8 @@ function ReportActionItem({ policy, transaction, onPress = undefined, + isFirstVisibleReportAction = false, + shouldUseThreadDividerLine = false, }: ReportActionItemProps) { const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); @@ -460,6 +469,22 @@ function ReportActionItem({ ]; }, [action, report.reportID]); + const renderThreadDivider = useMemo( + () => + shouldHideThreadDividerLine ? ( + + ) : ( + + ), + [shouldHideThreadDividerLine, styles.reportHorizontalRule, report.reportID], + ); + /** * Get the content of ReportActionItem * @param hovered whether the ReportActionItem is hovered @@ -765,11 +790,13 @@ function ReportActionItem({ } return ( - + + + {renderThreadDivider} + ); } @@ -797,10 +824,8 @@ function ReportActionItem({ - + + {renderThreadDivider} ); @@ -811,26 +836,32 @@ function ReportActionItem({ {transactionThreadReport && !isEmptyObject(transactionThreadReport) ? ( <> {transactionCurrency !== report.currency && ( - + <> + + {renderThreadDivider} + )} - + + + {renderThreadDivider} + ) : ( - + <> + + {renderThreadDivider} + )} ); @@ -907,7 +938,7 @@ function ReportActionItem({ > {(hovered) => ( - {shouldDisplayNewMarker && } + {shouldDisplayNewMarker && (!shouldUseThreadDividerLine || !isFirstVisibleReportAction) && } ))} diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx index c280a093cb13..5d4ba47877d1 100644 --- a/src/pages/home/report/ReportActionsList.tsx +++ b/src/pages/home/report/ReportActionsList.tsx @@ -422,6 +422,8 @@ function ReportActionsList({ [sortedReportActions, isOffline, currentUnreadMarker], ); + const firstVisibleReportActionID = useMemo(() => ReportActionsUtils.getFirstVisibleReportActionID(sortedReportActions, isOffline), [sortedReportActions, isOffline]); + /** * Evaluate new unread marker visibility for each of the report actions. */ @@ -451,6 +453,24 @@ function ReportActionsList({ [currentUnreadMarker, sortedVisibleReportActions, report.reportID, messageManuallyMarkedUnread], ); + const shouldUseThreadDividerLine = useMemo(() => { + const topReport = sortedVisibleReportActions[sortedVisibleReportActions.length - 1]; + + if (topReport.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED) { + return false; + } + + if (ReportActionsUtils.isTransactionThread(parentReportAction)) { + return !ReportActionsUtils.isDeletedParentAction(parentReportAction) && !ReportActionsUtils.isReversedTransaction(parentReportAction); + } + + if (ReportUtils.isTaskReport(report)) { + return !ReportUtils.isCanceledTaskReport(report, parentReportAction); + } + + return ReportUtils.isExpenseReport(report) || ReportUtils.isIOUReport(report); + }, [parentReportAction, report, sortedVisibleReportActions]); + const calculateUnreadMarker = useCallback(() => { // Iterate through the report actions and set appropriate unread marker. // This is to avoid a warning of: @@ -536,6 +556,8 @@ function ReportActionsList({ shouldHideThreadDividerLine={shouldHideThreadDividerLine} shouldDisplayNewMarker={shouldDisplayNewMarker(reportAction, index)} shouldDisplayReplyDivider={sortedReportActions.length > 1} + isFirstVisibleReportAction={firstVisibleReportActionID === reportAction.reportActionID} + shouldUseThreadDividerLine={shouldUseThreadDividerLine} /> ), [ @@ -550,6 +572,8 @@ function ReportActionsList({ reportActions, transactionThreadReport, parentReportActionForTransactionThread, + shouldUseThreadDividerLine, + firstVisibleReportActionID, ], ); diff --git a/src/pages/home/report/ReportActionsListItemRenderer.tsx b/src/pages/home/report/ReportActionsListItemRenderer.tsx index e35b58dd9dae..8782d6dbce55 100644 --- a/src/pages/home/report/ReportActionsListItemRenderer.tsx +++ b/src/pages/home/report/ReportActionsListItemRenderer.tsx @@ -46,6 +46,12 @@ type ReportActionsListItemRendererProps = { /** Whether we should display "Replies" divider */ shouldDisplayReplyDivider: boolean; + + /** If this is the first visible report action */ + isFirstVisibleReportAction: boolean; + + /** If the thread divider line will be used */ + shouldUseThreadDividerLine?: boolean; }; function ReportActionsListItemRenderer({ @@ -61,6 +67,8 @@ function ReportActionsListItemRenderer({ shouldDisplayNewMarker, linkedReportActionID = '', shouldDisplayReplyDivider, + isFirstVisibleReportAction = false, + shouldUseThreadDividerLine = false, parentReportActionForTransactionThread, }: ReportActionsListItemRendererProps) { const shouldDisplayParentAction = @@ -144,6 +152,8 @@ function ReportActionsListItemRenderer({ reportActions={reportActions} transactionThreadReport={transactionThreadReport} index={index} + isFirstVisibleReportAction={isFirstVisibleReportAction} + shouldUseThreadDividerLine={shouldUseThreadDividerLine} /> ) : ( ); } diff --git a/src/styles/index.ts b/src/styles/index.ts index be79c3af4819..365c89ac4a18 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -2822,6 +2822,18 @@ const styles = (theme: ThemeColors) => ...cursor.cursorDefault, }, + topUnreadIndicatorContainer: { + position: 'relative', + width: '100%', + /** 17 = height of the indicator 1px + 8px top and bottom */ + height: 17, + paddingHorizontal: 20, + flexDirection: 'row', + alignItems: 'center', + zIndex: 1, + ...cursor.cursorDefault, + }, + unreadIndicatorLine: { height: 1, backgroundColor: theme.unreadIndicator,