From b47e6b51b59fbbdc2177cc59b8ce0e4d3bfb1ae4 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Mon, 5 Jul 2021 22:21:26 +0530 Subject: [PATCH 1/5] feature: local time over the comoser for 1:1 chat --- src/pages/home/report/ReportActionCompose.js | 35 ++++++++++++++++++-- src/styles/styles.js | 2 +- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 0d8dbea95889..e0770f4e4d7b 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -12,6 +12,7 @@ import {withNavigationFocus} from '@react-navigation/compat'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; +import moment from 'moment'; import styles, {getButtonBackgroundColorStyle, getIconFillColor} from '../../../styles/styles'; import themeColors from '../../../styles/themes/default'; import TextInputFocusable from '../../../components/TextInputFocusable'; @@ -53,6 +54,8 @@ import * as User from '../../../libs/actions/User'; import ReportActionPropTypes from './ReportActionPropTypes'; import {canEditReportAction} from '../../../libs/reportUtils'; import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager'; +import {participantPropTypes} from '../sidebar/optionPropTypes'; +import ExpensiText from '../../../components/Text'; const propTypes = { /** Beta features list */ @@ -73,6 +76,10 @@ const propTypes = { isVisible: PropTypes.bool, }), + /** Personal details of all the users */ + personalDetails: PropTypes.objectOf(participantPropTypes).isRequired, + + /** The report currently being looked at */ report: PropTypes.shape({ @@ -392,8 +399,13 @@ class ReportActionCompose extends React.Component { render() { // eslint-disable-next-line no-unused-vars - const hasMultipleParticipants = lodashGet(this.props.report, 'participants.length') > 1; - const hasConciergeParticipant = _.contains(this.props.report.participants, CONST.EMAIL.CONCIERGE); + const reportParticipants = lodashGet(this.props.report, 'participants', []); + const hasMultipleParticipants = reportParticipants.length > 1; + const hasConciergeParticipant = _.contains(reportParticipants, CONST.EMAIL.CONCIERGE); + const reportRecipient = this.props.personalDetails[reportParticipants[0]]; + const reportRecipientLocalTime = moment().tz(reportRecipient.timezone.selected).format('LT'); + const isReportRecipientLocalTimeReady = reportRecipient.timezone + && reportRecipientLocalTime.toString().match(/(A|P)M/ig); // Prevents focusing and showing the keyboard while the drawer is covering the chat. const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; @@ -410,6 +422,22 @@ class ReportActionCompose extends React.Component { return ( + {!hasMultipleParticipants + && (isReportRecipientLocalTimeReady ? ( + + + {reportRecipientLocalTime} + {' '} + {this.props.translate('detailsPage.localTime')} + + + ) + : + )} `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, canEvict: false, diff --git a/src/styles/styles.js b/src/styles/styles.js index f517f1d0be9d..00b74396e469 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -919,7 +919,7 @@ const styles = { }, chatItemCompose: { - minHeight: 65, + minHeight: 85, marginBottom: 5, paddingLeft: 20, paddingRight: 20, From 148bf3bfd6364c486b617594459a6c3300350ada Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Mon, 5 Jul 2021 22:58:19 +0530 Subject: [PATCH 2/5] show the time only when timezone is different --- src/pages/home/report/ReportActionCompose.js | 21 ++++++++++--- src/pages/settings/Profile/ProfilePage.js | 28 ++--------------- .../currentUserPersonalDetailsPropsTypes.js | 31 +++++++++++++++++++ 3 files changed, 49 insertions(+), 31 deletions(-) create mode 100644 src/pages/settings/Profile/currentUserPersonalDetailsPropsTypes.js diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index e0770f4e4d7b..83d55d5f90ca 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -56,6 +56,7 @@ import {canEditReportAction} from '../../../libs/reportUtils'; import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager'; import {participantPropTypes} from '../sidebar/optionPropTypes'; import ExpensiText from '../../../components/Text'; +import currentUserPersonalDetailsPropsTypes from '../../settings/Profile/currentUserPersonalDetailsPropsTypes'; const propTypes = { /** Beta features list */ @@ -76,10 +77,12 @@ const propTypes = { isVisible: PropTypes.bool, }), + /** The personal details of the person who is logged in */ + myPersonalDetails: PropTypes.shape(currentUserPersonalDetailsPropsTypes).isRequired, + /** Personal details of all the users */ personalDetails: PropTypes.objectOf(participantPropTypes).isRequired, - /** The report currently being looked at */ report: PropTypes.shape({ @@ -403,9 +406,14 @@ class ReportActionCompose extends React.Component { const hasMultipleParticipants = reportParticipants.length > 1; const hasConciergeParticipant = _.contains(reportParticipants, CONST.EMAIL.CONCIERGE); const reportRecipient = this.props.personalDetails[reportParticipants[0]]; - const reportRecipientLocalTime = moment().tz(reportRecipient.timezone.selected).format('LT'); - const isReportRecipientLocalTimeReady = reportRecipient.timezone - && reportRecipientLocalTime.toString().match(/(A|P)M/ig); + const currentUserTimezone = lodashGet(this.props.myPersonalDetails, 'timezone', {}); + const reportRecipientTimezone = lodashGet(reportRecipient, 'timezone', {}); + console.debug(reportRecipientTimezone); + const reportRecipientLocalTime = moment().tz(reportRecipientTimezone.selected).format('LT'); + const shouldShowReportRecipientLocalTime = !hasMultipleParticipants + && reportRecipientTimezone + && currentUserTimezone.selected !== reportRecipientTimezone.selected; + const isReportRecipientLocalTimeReady = reportRecipientLocalTime.toString().match(/(A|P)M/ig); // Prevents focusing and showing the keyboard while the drawer is covering the chat. const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; @@ -422,7 +430,7 @@ class ReportActionCompose extends React.Component { return ( - {!hasMultipleParticipants + {shouldShowReportRecipientLocalTime && (isReportRecipientLocalTimeReady ? ( Date: Wed, 7 Jul 2021 02:48:42 +0530 Subject: [PATCH 3/5] local time update for 1:1 chat --- src/languages/en.js | 1 + src/languages/es.js | 1 + src/pages/home/report/ParticipantLocalTime.js | 82 +++++++++++++++++++ src/pages/home/report/ReportActionCompose.js | 25 +----- src/pages/home/sidebar/optionPropTypes.js | 3 + 5 files changed, 91 insertions(+), 21 deletions(-) create mode 100644 src/pages/home/report/ParticipantLocalTime.js diff --git a/src/languages/en.js b/src/languages/en.js index 989b8091bcf7..8510d44ba83a 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -105,6 +105,7 @@ export default { blockedFromConcierge: 'Communication is barred', youAppearToBeOffline: 'You appear to be offline.', fileUploadFailed: 'Upload Failed. File is not supported.', + localTime: ({user, time}) => `It's ${time} for ${user}`, }, reportActionContextMenu: { copyToClipboard: 'Copy to Clipboard', diff --git a/src/languages/es.js b/src/languages/es.js index 8779ff802b2f..d9dbe0e530f7 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -100,6 +100,7 @@ export default { writeSomething: 'Escribe algo...', blockedFromConcierge: 'Comunicación no permitida', youAppearToBeOffline: 'Parece que estás desconectado.', + localTime: ({user, time}) => `Son las ${time} para ${user}`, }, reportActionContextMenu: { copyToClipboard: 'Copiar al Portapapeles', diff --git a/src/pages/home/report/ParticipantLocalTime.js b/src/pages/home/report/ParticipantLocalTime.js new file mode 100644 index 000000000000..908bb9d94c3d --- /dev/null +++ b/src/pages/home/report/ParticipantLocalTime.js @@ -0,0 +1,82 @@ +import React from 'react'; +import { + View, +} from 'react-native'; +import lodashGet from 'lodash/get'; +import moment from 'moment'; +import Str from 'expensify-common/lib/str'; +import styles from '../../../styles/styles'; +import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; +import {participantPropTypes} from '../sidebar/optionPropTypes'; +import ExpensiText from '../../../components/Text'; +import Timers from '../../../libs/Timers'; + +const propTypes = { + /** Personal details of the participant */ + participant: participantPropTypes.isRequired, + + ...withLocalizePropTypes, +}; + +class ParticipantLocalTime extends React.Component { + constructor(props) { + super(props); + this.getParticipantLocalTime = this.getParticipantLocalTime.bind(this); + this.state = { + localTime: this.getParticipantLocalTime(), + }; + } + + componentDidMount() { + this.timer = Timers.register(setInterval(() => { + this.setState({ + localTime: this.getParticipantLocalTime(), + }); + }, 1000)); + } + + componentWillUnmount() { + clearInterval(this.timer); + clearInterval(this.readyTimer); + } + + getParticipantLocalTime() { + const reportRecipientTimezone = lodashGet(this.props.participant, 'timezone', {}); + return moment().tz(reportRecipientTimezone.selected).format('LT'); + } + + + render() { + // Moment.format does not return AM or PM values immediately. + // So we have to wait until we are ready before showing the time to the user + const isReportRecipientLocalTimeReady = this.state.localTime.toString().match(/(A|P)M/ig); + + return ( + isReportRecipientLocalTimeReady ? ( + + + {this.props.translate( + 'reportActionCompose.localTime', + { + user: this.props.participant.firstName + || (Str.isSMSLogin(this.props.participant.login) + ? this.props.toLocalPhone(this.props.participant.displayName) + : this.props.participant.displayName), + time: this.state.localTime, + }, + )} + + + ) + : + ); + } +} + +ParticipantLocalTime.propTypes = propTypes; + +export default withLocalize(ParticipantLocalTime); diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 83d55d5f90ca..dd0fd19b7365 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -12,7 +12,6 @@ import {withNavigationFocus} from '@react-navigation/compat'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import moment from 'moment'; import styles, {getButtonBackgroundColorStyle, getIconFillColor} from '../../../styles/styles'; import themeColors from '../../../styles/themes/default'; import TextInputFocusable from '../../../components/TextInputFocusable'; @@ -55,8 +54,8 @@ import ReportActionPropTypes from './ReportActionPropTypes'; import {canEditReportAction} from '../../../libs/reportUtils'; import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager'; import {participantPropTypes} from '../sidebar/optionPropTypes'; -import ExpensiText from '../../../components/Text'; import currentUserPersonalDetailsPropsTypes from '../../settings/Profile/currentUserPersonalDetailsPropsTypes'; +import ParticipantLocalTime from './ParticipantLocalTime'; const propTypes = { /** Beta features list */ @@ -408,12 +407,10 @@ class ReportActionCompose extends React.Component { const reportRecipient = this.props.personalDetails[reportParticipants[0]]; const currentUserTimezone = lodashGet(this.props.myPersonalDetails, 'timezone', {}); const reportRecipientTimezone = lodashGet(reportRecipient, 'timezone', {}); - console.debug(reportRecipientTimezone); - const reportRecipientLocalTime = moment().tz(reportRecipientTimezone.selected).format('LT'); - const shouldShowReportRecipientLocalTime = !hasMultipleParticipants + const shouldShowReportRecipientLocalTime = !hasConciergeParticipant + && !hasMultipleParticipants && reportRecipientTimezone && currentUserTimezone.selected !== reportRecipientTimezone.selected; - const isReportRecipientLocalTimeReady = reportRecipientLocalTime.toString().match(/(A|P)M/ig); // Prevents focusing and showing the keyboard while the drawer is covering the chat. const isComposeDisabled = this.props.isDrawerOpen && this.props.isSmallScreenWidth; @@ -431,21 +428,7 @@ class ReportActionCompose extends React.Component { return ( {shouldShowReportRecipientLocalTime - && (isReportRecipientLocalTimeReady ? ( - - - {reportRecipientLocalTime} - {' '} - {this.props.translate('detailsPage.localTime')} - - - ) - : - )} + && } Date: Wed, 7 Jul 2021 19:03:26 +0530 Subject: [PATCH 4/5] fix crash on login --- src/pages/home/report/ReportActionCompose.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index dd0fd19b7365..ca9e185613be 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -409,6 +409,7 @@ class ReportActionCompose extends React.Component { const reportRecipientTimezone = lodashGet(reportRecipient, 'timezone', {}); const shouldShowReportRecipientLocalTime = !hasConciergeParticipant && !hasMultipleParticipants + && reportRecipient && reportRecipientTimezone && currentUserTimezone.selected !== reportRecipientTimezone.selected; From fe0587b93d471753212382e42a342c051017e569 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Thu, 8 Jul 2021 02:52:12 +0530 Subject: [PATCH 5/5] fix composer jumping --- src/pages/home/report/ParticipantLocalTime.js | 9 +++++---- src/pages/home/report/ReportActionCompose.js | 6 +++++- src/styles/styles.js | 6 +++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/pages/home/report/ParticipantLocalTime.js b/src/pages/home/report/ParticipantLocalTime.js index 908bb9d94c3d..977bb3a8b39d 100644 --- a/src/pages/home/report/ParticipantLocalTime.js +++ b/src/pages/home/report/ParticipantLocalTime.js @@ -50,6 +50,10 @@ class ParticipantLocalTime extends React.Component { // Moment.format does not return AM or PM values immediately. // So we have to wait until we are ready before showing the time to the user const isReportRecipientLocalTimeReady = this.state.localTime.toString().match(/(A|P)M/ig); + const reportRecipientDisplayName = this.props.participant.firstName + || (Str.isSMSLogin(this.props.participant.login) + ? this.props.toLocalPhone(this.props.participant.displayName) + : this.props.participant.displayName); return ( isReportRecipientLocalTimeReady ? ( @@ -62,10 +66,7 @@ class ParticipantLocalTime extends React.Component { {this.props.translate( 'reportActionCompose.localTime', { - user: this.props.participant.firstName - || (Str.isSMSLogin(this.props.participant.login) - ? this.props.toLocalPhone(this.props.participant.displayName) - : this.props.participant.displayName), + user: reportRecipientDisplayName, time: this.state.localTime, }, )} diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index ca9e185613be..b454f0b0746e 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -427,7 +427,11 @@ class ReportActionCompose extends React.Component { : this.props.translate('reportActionCompose.writeSomething'); return ( - + {shouldShowReportRecipientLocalTime && }