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

Web - The horizontal line separating the header and the messages #27307

Merged
merged 10 commits into from
Sep 20, 2023
6 changes: 6 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
@@ -2667,6 +2667,12 @@ const CONST = {
HTTPS: 'https',
PUSHER: 'pusher',
},
HORIZONTAL_SPACER: {
DEFAULT_BORDER_BOTTOM_WIDTH: 1,
DEFAULT_MARGIN_VERTICAL: 8,
HIDDEN_MARGIN_VERTICAL: 0,
HIDDEN_BORDER_BOTTOM_WIDTH: 0,
},
} as const;

export default CONST;
6 changes: 5 additions & 1 deletion src/components/ReportActionItem/MoneyReportView.js
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ import variables from '../../styles/variables';
import * as CurrencyUtils from '../../libs/CurrencyUtils';
import EmptyStateBackgroundImage from '../../../assets/images/empty-state_background-fade.png';
import useLocalize from '../../hooks/useLocalize';
import SpacerView from '../SpacerView';

const propTypes = {
/** The report currently being looked at */
@@ -65,7 +66,10 @@ function MoneyReportView(props) {
</Text>
</View>
</View>
{props.shouldShowHorizontalRule && <View style={styles.reportHorizontalRule} />}
<SpacerView
shouldShow={props.shouldShowHorizontalRule}
style={[props.shouldShowHorizontalRule ? styles.reportHorizontalRule : {}]}
/>
</View>
);
}
6 changes: 5 additions & 1 deletion src/components/ReportActionItem/MoneyRequestView.js
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ import Image from '../Image';
import ReportActionItemImage from './ReportActionItemImage';
import * as TransactionUtils from '../../libs/TransactionUtils';
import OfflineWithFeedback from '../OfflineWithFeedback';
import SpacerView from '../SpacerView';

const propTypes = {
/** The report currently being looked at */
@@ -165,7 +166,10 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans
subtitleTextStyle={styles.textLabelError}
/>
</OfflineWithFeedback>
{shouldShowHorizontalRule && <View style={styles.reportHorizontalRule} />}
<SpacerView
shouldShow={shouldShowHorizontalRule}
style={[shouldShowHorizontalRule ? styles.reportHorizontalRule : {}]}
/>
</View>
);
}
6 changes: 5 additions & 1 deletion src/components/ReportActionItem/TaskView.js
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ import getButtonState from '../../libs/getButtonState';
import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction';
import * as Session from '../../libs/actions/Session';
import * as Expensicons from '../Icon/Expensicons';
import SpacerView from '../SpacerView';

const propTypes = {
/** The report currently being looked at */
@@ -157,7 +158,10 @@ function TaskView(props) {
/>
)}
</OfflineWithFeedback>
{props.shouldShowHorizontalRule && <View style={styles.reportHorizontalRule} />}
<SpacerView
shouldShow={props.shouldShowHorizontalRule}
style={[props.shouldShowHorizontalRule ? styles.reportHorizontalRule : {}]}
/>
</View>
);
}
49 changes: 49 additions & 0 deletions src/components/SpacerView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import PropTypes from 'prop-types';
import * as StyleUtils from '../styles/StyleUtils';
import CONST from '../CONST';

const propTypes = {
/**
* Should we show the spacer
*/
shouldShow: PropTypes.bool.isRequired,

/**
* Array of style objects
* @default []
*/
// eslint-disable-next-line react/forbid-prop-types
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

const defaultProps = {
style: [],
};

function SpacerView({shouldShow = true, style = []}) {
const marginVertical = useSharedValue(CONST.HORIZONTAL_SPACER.DEFAULT_MARGIN_VERTICAL);
const borderBottomWidth = useSharedValue(CONST.HORIZONTAL_SPACER.DEFAULT_BORDER_BOTTOM_WIDTH);
const animatedStyles = useAnimatedStyle(() => ({
marginVertical: marginVertical.value,
borderBottomWidth: borderBottomWidth.value,
}));

React.useEffect(() => {
const duration = CONST.ANIMATED_TRANSITION;
const values = {
marginVertical: shouldShow ? CONST.HORIZONTAL_SPACER.DEFAULT_MARGIN_VERTICAL : CONST.HORIZONTAL_SPACER.HIDDEN_MARGIN_VERTICAL,
borderBottomWidth: shouldShow ? CONST.HORIZONTAL_SPACER.DEFAULT_BORDER_BOTTOM_WIDTH : CONST.HORIZONTAL_SPACER.HIDDEN_BORDER_BOTTOM_WIDTH,
};
marginVertical.value = withTiming(values.marginVertical, {duration});
borderBottomWidth.value = withTiming(values.borderBottomWidth, {duration});
}, [shouldShow, borderBottomWidth, marginVertical]);

return <Animated.View style={[animatedStyles, ...StyleUtils.parseStyleAsArray(style)]} />;
}

SpacerView.displayName = 'SpacerView';
SpacerView.propTypes = propTypes;
SpacerView.defaultProps = defaultProps;
export default SpacerView;
34 changes: 21 additions & 13 deletions src/pages/home/report/ReportActionsList.js
Original file line number Diff line number Diff line change
@@ -109,7 +109,7 @@ function ReportActionsList({
const {isOffline} = useNetwork();
const opacity = useSharedValue(0);
const userActiveSince = useRef(null);
const currentUnreadMarker = useRef(null);
const [currentUnreadMarker, setCurrentUnreadMarker] = useState(null);
const scrollingVerticalOffset = useRef(0);
const readActionSkipped = useRef(false);
const reportActionSize = useRef(sortedReportActions.length);
@@ -152,12 +152,12 @@ function ReportActionsList({
}
}

if (currentUnreadMarker.current || reportActionSize.current === sortedReportActions.length) {
if (currentUnreadMarker || reportActionSize.current === sortedReportActions.length) {
return;
}

reportActionSize.current = sortedReportActions.length;
currentUnreadMarker.current = null;
setCurrentUnreadMarker(null);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sortedReportActions.length, report.reportID]);

@@ -169,7 +169,7 @@ function ReportActionsList({
}

// Clearing the current unread marker so that it can be recalculated
currentUnreadMarker.current = null;
setCurrentUnreadMarker(null);
setMessageManuallyMarked({read: true});

// We only care when a new lastReadTime is set in the report
@@ -180,7 +180,7 @@ function ReportActionsList({
* Show/hide the new floating message counter when user is scrolling back/forth in the history of messages.
*/
const handleUnreadFloatingButton = () => {
if (scrollingVerticalOffset.current > VERTICAL_OFFSET_THRESHOLD && !isFloatingMessageCounterVisible && !!currentUnreadMarker.current) {
if (scrollingVerticalOffset.current > VERTICAL_OFFSET_THRESHOLD && !isFloatingMessageCounterVisible && !!currentUnreadMarker) {
setIsFloatingMessageCounterVisible(true);
}

@@ -216,6 +216,15 @@ function ReportActionsList({
return Math.ceil(availableHeight / minimumReportActionHeight);
}, [windowHeight]);

/**
* Thread's divider line should hide when the first chat in the thread is marked as unread.
* This is so that it will not be conflicting with header's separator line.
*/
const shouldHideThreadDividerLine = useMemo(
() => sortedReportActions.length > 1 && sortedReportActions[sortedReportActions.length - 2].reportActionID === currentUnreadMarker,
[sortedReportActions, currentUnreadMarker],
);

/**
* @param {Object} args
* @param {Number} args.index
@@ -225,7 +234,7 @@ function ReportActionsList({
({item: reportAction, index}) => {
let shouldDisplayNewMarker = false;

if (!currentUnreadMarker.current) {
if (!currentUnreadMarker) {
const nextMessage = sortedReportActions[index + 1];
const isCurrentMessageUnread = isMessageUnread(reportAction, report.lastReadTime);
shouldDisplayNewMarker = isCurrentMessageUnread && !isMessageUnread(nextMessage, report.lastReadTime);
@@ -235,18 +244,17 @@ function ReportActionsList({
}
const canDisplayMarker = scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD ? reportAction.created < userActiveSince.current : true;

if (!currentUnreadMarker.current && shouldDisplayNewMarker && canDisplayMarker) {
currentUnreadMarker.current = reportAction.reportActionID;
if (!currentUnreadMarker && shouldDisplayNewMarker && canDisplayMarker) {
setCurrentUnreadMarker(reportAction.reportActionID);
}
} else {
shouldDisplayNewMarker = reportAction.reportActionID === currentUnreadMarker.current;
shouldDisplayNewMarker = reportAction.reportActionID === currentUnreadMarker;
}

const shouldDisplayParentAction =
reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED &&
ReportUtils.isChatThread(report) &&
!ReportActionsUtils.isTransactionThread(ReportActionsUtils.getParentReportAction(report));
const shouldHideThreadDividerLine = sortedReportActions.length > 1 && sortedReportActions[sortedReportActions.length - 2].reportActionID === currentUnreadMarker.current;

return shouldDisplayParentAction ? (
<ReportActionItemParentAction
@@ -272,19 +280,19 @@ function ReportActionsList({
/>
);
},
[report, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, messageManuallyMarked],
[report, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, messageManuallyMarked, shouldHideThreadDividerLine, currentUnreadMarker],
);

// Native mobile does not render updates flatlist the changes even though component did update called.
// To notify there something changes we can use extraData prop to flatlist
const extraData = [isSmallScreenWidth ? currentUnreadMarker.current : undefined, ReportUtils.isArchivedRoom(report)];
const extraData = [isSmallScreenWidth ? currentUnreadMarker : undefined, ReportUtils.isArchivedRoom(report)];
const hideComposer = ReportUtils.shouldDisableWriteActions(report);
const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(personalDetailsList, report, currentUserPersonalDetails.accountID) && !isComposerFullSize;

return (
<>
<FloatingMessageCounter
isActive={isFloatingMessageCounterVisible && !!currentUnreadMarker.current}
isActive={isFloatingMessageCounterVisible && !!currentUnreadMarker}
onClick={scrollToBottomAndMarkReportAsRead}
/>
<Animated.View style={[animatedStyles, styles.flex1, !shouldShowReportRecipientLocalTime && !hideComposer ? styles.pb4 : {}]}>
2 changes: 0 additions & 2 deletions src/styles/styles.js
Original file line number Diff line number Diff line change
@@ -3606,10 +3606,8 @@ const styles = (theme) => ({
},

reportHorizontalRule: {
borderBottomWidth: 1,
borderColor: theme.border,
...spacing.mh5,
...spacing.mv2,
},

assigneeTextStyle: {