Skip to content

Commit

Permalink
Merge pull request #4603 from parasharrajat/newmarker
Browse files Browse the repository at this point in the history
Added new marker Badge for Report unread messages
  • Loading branch information
Beamanator committed Aug 13, 2021
2 parents 496086a + fae11b0 commit 9368288
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ export default {
reportActionsView: {
beFirstPersonToComment: 'Be the first person to comment',
},
reportActionsViewMarkerBadge: {
newMsg: ({count}) => `${count} new message${count > 1 ? 's' : ''}`,
},
reportTypingIndicator: {
isTyping: 'is typing...',
areTyping: 'are typing...',
Expand Down
3 changes: 3 additions & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ export default {
reportActionsView: {
beFirstPersonToComment: 'Sé el primero en comentar',
},
reportActionsViewMarkerBadge: {
newMsg: ({count}) => `${count} mensaje${count > 1 ? 's' : ''} nuevo${count > 1 ? 's' : ''}`,
},
reportTypingIndicator: {
isTyping: 'está escribiendo...',
areTyping: 'están escribiendo...',
Expand Down
5 changes: 4 additions & 1 deletion src/pages/home/ReportScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ class ReportScreen extends React.Component {
onNavigationMenuButtonClicked={() => Navigation.navigate(ROUTES.HOME)}
/>

<View nativeID={CONST.REPORT.DROP_NATIVE_ID} style={[styles.flex1, styles.justifyContentEnd]}>
<View
nativeID={CONST.REPORT.DROP_NATIVE_ID}
style={[styles.flex1, styles.justifyContentEnd, styles.overflowHidden]}
>
<FullScreenLoadingIndicator visible={this.shouldShowLoader()} />
{!this.shouldShowLoader() && <ReportActionsView reportID={reportID} />}
{this.props.session.shouldShowComposeInput && (
Expand Down
125 changes: 125 additions & 0 deletions src/pages/home/report/MarkerBadge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, {PureComponent} from 'react';
import {Animated, Text, View} from 'react-native';
import PropTypes from 'prop-types';
import styles from '../../../styles/styles';
import Button from '../../../components/Button';
import Icon from '../../../components/Icon';
import {Close, DownArrow} from '../../../components/Icon/Expensicons';
import themeColors from '../../../styles/themes/default';
import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';

const MARKER_NOT_ACTIVE_TRANSLATE_Y = -30;
const MARKER_ACTIVE_TRANSLATE_Y = 10;
const propTypes = {
/** Count of new messages to show in the badge */
count: PropTypes.number,

/** Whether the marker is active */
active: PropTypes.bool,

/** Callback to be called when user closes the badge */
onClose: PropTypes.func,

/** Callback to be called when user clicks the marker */
onClick: PropTypes.func,

...withLocalizePropTypes,
};
const defaultProps = {
count: 0,
active: false,
onClose: () => {},
onClick: () => {},
};
class MarkerBadge extends PureComponent {
constructor(props) {
super(props);
this.translateY = new Animated.Value(MARKER_NOT_ACTIVE_TRANSLATE_Y);
this.show = this.show.bind(this);
this.hide = this.hide.bind(this);
}

componentDidUpdate() {
if (this.props.active && this.props.count > 0) {
this.show();
} else {
this.hide();
}
}

show() {
Animated.spring(this.translateY, {
toValue: MARKER_ACTIVE_TRANSLATE_Y,
duration: 80,
useNativeDriver: true,
}).start();
}

hide() {
Animated.spring(this.translateY, {
toValue: MARKER_NOT_ACTIVE_TRANSLATE_Y,
duration: 80,
useNativeDriver: true,
}).start();
}

render() {
return (
<View style={styles.reportMarkerBadgeWrapper}>
<Animated.View style={[
styles.reportMarkerBadge,
styles.reportMarkerBadgeTransformation(this.translateY),
]}
>
<View style={[
styles.flexRow,
styles.justifyContentBetween,
styles.alignItemsCenter,
]}
>
<Button
success
small
onPress={this.props.onClick}
ContentComponent={() => (
<View style={[styles.flexRow]}>
<Icon small src={DownArrow} fill={themeColors.textReversed} />
<Text
selectable={false}
style={[
styles.ml2,
styles.buttonSmallText,
styles.textWhite,
]}
>
{this.props.translate(
'reportActionsViewMarkerBadge.newMsg',
{count: this.props.count},
)}
</Text>
</View>
)}
shouldRemoveRightBorderRadius
/>
<Button
success
small
style={[styles.buttonDropdown]}
onPress={this.props.onClose}
shouldRemoveLeftBorderRadius
ContentComponent={() => (
<Icon small src={Close} fill={themeColors.textReversed} />
)}
/>
</View>
</Animated.View>
</View>
);
}
}

MarkerBadge.propTypes = propTypes;
MarkerBadge.defaultProps = defaultProps;
MarkerBadge.displayName = 'MarkerBadge';

export default withLocalize(MarkerBadge);
58 changes: 58 additions & 0 deletions src/pages/home/report/ReportActionsView.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFo
import {contextMenuRef} from './ContextMenu/ReportActionContextMenu';
import PopoverReportActionContextMenu from './ContextMenu/PopoverReportActionContextMenu';
import variables from '../../../styles/variables';
import MarkerBadge from './MarkerBadge';

const propTypes = {
/** The ID of the report actions will be created for */
Expand Down Expand Up @@ -99,11 +100,17 @@ class ReportActionsView extends React.Component {

this.state = {
isLoadingMoreChats: false,
isMarkerActive: false,
};

this.currentScrollOffset = 0;
this.updateSortedReportActions(props.reportActions);
this.updateMostRecentIOUReportActionNumber(props.reportActions);
this.keyExtractor = this.keyExtractor.bind(this);
this.trackScroll = this.trackScroll.bind(this);
this.showMarker = this.showMarker.bind(this);
this.hideMarker = this.hideMarker.bind(this);
this.toggleMarker = this.toggleMarker.bind(this);
}

componentDidMount() {
Expand Down Expand Up @@ -152,6 +159,10 @@ class ReportActionsView extends React.Component {
return true;
}

if (nextState.isMarkerActive !== this.state.isMarkerActive) {
return true;
}

if (this.props.isSmallScreenWidth !== nextProps.isSmallScreenWidth) {
return true;
}
Expand Down Expand Up @@ -189,6 +200,9 @@ class ReportActionsView extends React.Component {
if (shouldRecordMaxAction) {
updateLastReadActionID(this.props.reportID);
}

// show new MarkerBadge when there is a new Message
this.toggleMarker();
}

// We want to mark the unread comments when user resize the screen to desktop
Expand Down Expand Up @@ -346,6 +360,43 @@ class ReportActionsView extends React.Component {
updateLastReadActionID(this.props.reportID);
}

/**
* Show/hide the new MarkerBadge when user is scrolling back/forth in the history of messages.
*/
toggleMarker() {
if (this.currentScrollOffset < -200 && !this.state.isMarkerActive) {
this.showMarker();
}

if (this.currentScrollOffset > -200 && this.state.isMarkerActive) {
this.hideMarker();
}
}

/**
* Show the new MarkerBadge
*/
showMarker() {
this.setState({isMarkerActive: true});
}

/**
* Hide the new MarkerBadge
*/
hideMarker() {
this.setState({isMarkerActive: false});
}

/**
* keeps track of the Scroll offset of the main messages list
*
* @param {Object} {nativeEvent}
*/
trackScroll({nativeEvent}) {
this.currentScrollOffset = -nativeEvent.contentOffset.y;
this.toggleMarker();
}

/**
* Runs when the FlatList finishes laying out
*/
Expand Down Expand Up @@ -427,6 +478,12 @@ class ReportActionsView extends React.Component {

return (
<>
<MarkerBadge
active={this.state.isMarkerActive}
count={this.props.report.unreadActionCount}
onClick={scrollToBottom}
onClose={this.hideMarker}
/>
<InvertedFlatList
ref={flatListRef}
data={this.sortedReportActions}
Expand All @@ -443,6 +500,7 @@ class ReportActionsView extends React.Component {
: null}
keyboardShouldPersistTaps="handled"
onLayout={this.recordTimeToMeasureItemLayout}
onScroll={this.trackScroll}
/>
<PopoverReportActionContextMenu ref={contextMenuRef} />
</>
Expand Down
23 changes: 22 additions & 1 deletion src/styles/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import textInputAlignSelf from './utilities/textInputAlignSelf';
import CONST from '../CONST';
import positioning from './utilities/positioning';
import codeStyles from './codeStyles';
import visibility from './utilities/visibility';

const expensiPicker = {
backgroundColor: 'transparent',
Expand Down Expand Up @@ -250,7 +251,8 @@ const styles = {
},

buttonDropdown: {
marginLeft: 1,
borderLeftWidth: 1,
borderColor: themeColors.textReversed,
},

noRightBorderRadius: {
Expand Down Expand Up @@ -1985,6 +1987,25 @@ const styles = {
communicationsLinkHeight: {
height: 20,
},

reportMarkerBadgeWrapper: {
position: 'absolute',
left: '50%',
top: 0,
zIndex: 100,
...visibility('hidden'),
},

reportMarkerBadge: {
left: '-50%',
...visibility('visible'),
},

reportMarkerBadgeTransformation: translateY => ({
transform: [
{translateY},
],
}),
};

const baseCodeTagStyles = {
Expand Down
1 change: 1 addition & 0 deletions src/styles/utilities/visibility/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default visibility => ({visibility});
1 change: 1 addition & 0 deletions src/styles/utilities/visibility/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => ({});

0 comments on commit 9368288

Please sign in to comment.