diff --git a/src/CONST.js b/src/CONST.js index 1644d40ad249..781a3930a162 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -181,6 +181,10 @@ const CONST = { // If the length is longer than 13 digits, we show the first 6 and last 4 digits, hiding the rest with X MASKED_US_ACCOUNT_NUMBER: /^[X]{0,9}[0-9]{4}$|^[0-9]{6}[X]{4,7}[0-9]{4}$/, SWIFT_BIC: /^[A-Za-z0-9]{8,11}$/, + + TIME_STARTS_01: /^01:\d{2} [AP]M$/, + TIME_FORMAT: /^\d{2}:\d{2} [AP]M$/, + DATE_TIME_FORMAT: /^\d{2}-\d{2} \d{2}:\d{2} [AP]M$/, }, VERIFICATION_MAX_ATTEMPTS: 7, STATE: { diff --git a/src/languages/en.js b/src/languages/en.js index 229166a3f858..4ce07f7e00ca 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -875,6 +875,8 @@ export default { clearStatus: 'Clear status', save: 'Save', message: 'Message', + untilTomorrow: 'Until tomorrow', + untilTime: ({time}) => `Until ${time}`, }, stepCounter: ({step, total, text}) => { let result = `Step ${step}`; diff --git a/src/languages/es.js b/src/languages/es.js index 0e24a386cd14..7cee163470f3 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -879,6 +879,23 @@ export default { clearStatus: 'Borrar estado', save: 'Guardar', message: 'Mensaje', + untilTomorrow: 'Hasta mañana', + untilTime: ({time}) => { + // Check for HH:MM AM/PM format and starts with '01:' + if (CONST.REGEX.TIME_STARTS_01.test(time)) { + return `Hasta la ${time}`; + } + // Check for any HH:MM AM/PM format not starting with '01:' + if (CONST.REGEX.TIME_FORMAT.test(time)) { + return `Hasta las ${time}`; + } + // Check for date-time format like "06-29 11:30 AM" + if (CONST.REGEX.DATE_TIME_FORMAT.test(time)) { + return `Hasta el día ${time}`; + } + // Default case + return `Hasta ${time}`; + }, }, stepCounter: ({step, total, text}) => { let result = `Paso ${step}`; diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js index 6be627dc643d..4115e8f1b9e3 100644 --- a/src/libs/DateUtils.js +++ b/src/libs/DateUtils.js @@ -205,6 +205,39 @@ function getDateStringFromISOTimestamp(isoTimestamp) { return dateString; } +/** + * receive date like 2020-05-16 05:34:14 and format it to show in string like "Until 05:34 PM" + * + * @param {String} inputDate + * @returns {String} + */ +function getStatusUntilDate(inputDate) { + if (!inputDate) return ''; + const {translateLocal} = Localize; + + const input = moment(inputDate, 'YYYY-MM-DD HH:mm:ss'); + const now = moment(); + const endOfToday = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'); + + // If the date is equal to the end of today + if (input.isSame(endOfToday)) { + return translateLocal('statusPage.untilTomorrow'); + } + + // If it's a time on the same date + if (input.isSame(now, 'day')) { + return translateLocal('statusPage.untilTime', {time: input.format('hh:mm A')}); + } + + // If it's further in the future than tomorrow but within the same year + if (input.isAfter(now) && input.isSame(now, 'year')) { + return translateLocal('statusPage.untilTime', {time: input.format('MM-DD hh:mm A')}); + } + + // If it's in another year + return translateLocal('statusPage.untilTime', {time: input.format('YYYY-MM-DD hh:mm A')}); +} + /** * @namespace DateUtils */ @@ -220,6 +253,7 @@ const DateUtils = { getDBTime, subtractMillisecondsFromDateTime, getDateStringFromISOTimestamp, + getStatusUntilDate, }; export default DateUtils; diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js index 8633f8f8a224..c00f98c613e4 100644 --- a/src/pages/home/report/ReportActionItemSingle.js +++ b/src/pages/home/report/ReportActionItemSingle.js @@ -3,6 +3,7 @@ import React, {useCallback, useMemo} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; +import {withOnyx} from 'react-native-onyx'; import reportActionPropTypes from './reportActionPropTypes'; import ReportActionItemFragment from './ReportActionItemFragment'; import styles from '../../../styles/styles'; @@ -26,6 +27,11 @@ import UserDetailsTooltip from '../../../components/UserDetailsTooltip'; import MultipleAvatars from '../../../components/MultipleAvatars'; import * as StyleUtils from '../../../styles/StyleUtils'; import themeColors from '../../../styles/themes/default'; +import Permissions from '../../../libs/Permissions'; +import ONYXKEYS from '../../../ONYXKEYS'; +import Text from '../../../components/Text'; +import Tooltip from '../../../components/Tooltip'; +import DateUtils from '../../../libs/DateUtils'; const propTypes = { /** All the data of the action */ @@ -84,7 +90,7 @@ const showWorkspaceDetails = (reportID) => { function ReportActionItemSingle(props) { const actorAccountID = props.action.actorAccountID; let {displayName} = props.personalDetailsList[actorAccountID] || {}; - const {avatar, login, pendingFields} = props.personalDetailsList[actorAccountID] || {}; + const {avatar, login, pendingFields, status} = props.personalDetailsList[actorAccountID] || {}; let actorHint = (login || displayName || '').replace(CONST.REGEX.MERGED_ACCOUNT_PREFIX, ''); const isWorkspaceActor = ReportUtils.isPolicyExpenseChat(props.report) && !actorAccountID; let avatarSource = UserUtils.getAvatar(avatar, actorAccountID); @@ -189,6 +195,10 @@ function ReportActionItemSingle(props) { ); }; + const hasEmojiStatus = !displayAllActors && status && status.emojiCode && Permissions.canUseCustomStatus(props.betas); + const formattedDate = DateUtils.getStatusUntilDate(lodashGet(status, 'clearAfter')); + const statusText = lodashGet(status, 'text', ''); + const statusTooltipText = formattedDate ? `${statusText} (${formattedDate})` : statusText; return ( @@ -228,6 +238,14 @@ function ReportActionItemSingle(props) { /> ))} + {Boolean(hasEmojiStatus) && ( + + {`${status.emojiCode}`} + + )} ) : null} @@ -241,4 +259,12 @@ ReportActionItemSingle.propTypes = propTypes; ReportActionItemSingle.defaultProps = defaultProps; ReportActionItemSingle.displayName = 'ReportActionItemSingle'; -export default compose(withLocalize, withPersonalDetails())(ReportActionItemSingle); +export default compose( + withLocalize, + withPersonalDetails(), + withOnyx({ + betas: { + key: ONYXKEYS.BETAS, + }, + }), +)(ReportActionItemSingle); diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js index c239f9e45f2d..d896fc2fed63 100644 --- a/src/pages/settings/Profile/CustomStatus/StatusPage.js +++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js @@ -38,8 +38,8 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) { const hasDraftStatus = !!draftEmojiCode || !!draftText; const updateStatus = useCallback(() => { - const endOfDay = moment().endOf('day').toDate(); - User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: endOfDay.toISOString()}); + const endOfDay = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss'); + User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: endOfDay}); User.clearDraftCustomStatus(); Navigation.goBack(ROUTES.SETTINGS_PROFILE); diff --git a/src/styles/styles.js b/src/styles/styles.js index 174662ed1d29..0bef42f3edc2 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -3676,6 +3676,11 @@ const styles = { rotate90: { transform: [{rotate: '90deg'}], }, + + userReportStatusEmoji: { + fontSize: variables.fontSizeNormal, + marginRight: 4, + }, }; export default styles;