diff --git a/src/components/Reactions/EmojiReactionBubble.js b/src/components/Reactions/EmojiReactionBubble.js index 6066bf0a8199..0b1694dbe0cf 100644 --- a/src/components/Reactions/EmojiReactionBubble.js +++ b/src/components/Reactions/EmojiReactionBubble.js @@ -9,8 +9,12 @@ import withCurrentUserPersonalDetails, { withCurrentUserPersonalDetailsPropTypes, } from '../withCurrentUserPersonalDetails'; import * as Report from '../../libs/actions/Report'; +import Tooltip from '../Tooltip'; +import ReactionTooltipContent from './ReactionTooltipContent'; const propTypes = { + emojiName: PropTypes.string.isRequired, + /** * The emoji codes to display in the bubble. */ @@ -35,7 +39,7 @@ const propTypes = { /** * The account ids of the users who reacted. */ - reactionUsers: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])), + reactionUsers: PropTypes.arrayOf(PropTypes.string), /** * The default size of the reaction bubble is defined @@ -59,22 +63,31 @@ const defaultProps = { const EmojiReactionBubble = (props) => { const hasUserReacted = Report.hasAccountIDReacted(props.currentUserPersonalDetails.accountID, props.reactionUsers); return ( - [ - styles.emojiReactionBubble, - StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, hasUserReacted, props.sizeScale), - ]} - onPress={props.onPress} - onLongPress={props.onReactionListOpen} + ( + + )} > - [ + styles.emojiReactionBubble, + StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, hasUserReacted, props.sizeScale), + ]} + onPress={props.onPress} + onLongPress={props.onReactionListOpen} > - {props.emojiCodes.join('')} - - {props.count > 0 && ( + + {props.emojiCodes.join('')} + + {props.count > 0 && ( { > {props.count} - )} - + )} + + ); }; diff --git a/src/components/Reactions/ReactionTooltipContent.js b/src/components/Reactions/ReactionTooltipContent.js new file mode 100644 index 000000000000..5a190eee863b --- /dev/null +++ b/src/components/Reactions/ReactionTooltipContent.js @@ -0,0 +1,77 @@ +import React from 'react'; +import {View} from 'react-native'; +import PropTypes from 'prop-types'; +import _ from 'underscore'; +import styles from '../../styles/styles'; +import {withPersonalDetails} from '../OnyxProvider'; +import * as PersonalDetailsUtils from '../../libs/PersonalDetailsUtils'; +import Text from '../Text'; +import withCurrentUserPersonalDetails, { + withCurrentUserPersonalDetailsPropTypes, +} from '../withCurrentUserPersonalDetails'; +import compose from '../../libs/compose'; +import withLocalize from '../withLocalize'; + +const propTypes = { + /** + * A list of emoji codes to display in the tooltip. + */ + emojiCodes: PropTypes.arrayOf(PropTypes.string).isRequired, + + /** + * The name of the emoji to display in the tooltip. + */ + emojiName: PropTypes.string.isRequired, + + /** + * A list of account IDs to display in the tooltip. + */ + accountIDs: PropTypes.arrayOf(PropTypes.string).isRequired, + + ...withCurrentUserPersonalDetailsPropTypes, +}; + +const ReactionTooltipContent = (props) => { + const users = PersonalDetailsUtils.getPersonalDetailsByIDs(props.accountIDs, true); + const namesString = _.filter(_.map(users, user => user && user.displayName), n => n).join(', '); + + return ( + + + {_.map(props.emojiCodes, emojiCode => ( + + {emojiCode} + + ))} + + + + {namesString} + + + + {`reacted with :${props.emojiName}:`} + + + ); +}; + +ReactionTooltipContent.propTypes = propTypes; +ReactionTooltipContent.defaultProps = withCurrentUserPersonalDetails; +ReactionTooltipContent.displayName = 'ReactionTooltipContent'; +export default React.memo(compose( + withPersonalDetails(), + withLocalize, +)(ReactionTooltipContent)); diff --git a/src/components/Reactions/ReportActionItemReactions.js b/src/components/Reactions/ReportActionItemReactions.js index bfc67e95c1df..cbac72accf5f 100644 --- a/src/components/Reactions/ReportActionItemReactions.js +++ b/src/components/Reactions/ReportActionItemReactions.js @@ -59,11 +59,7 @@ const ReportActionItemReactions = (props) => { {_.map(reactionsWithCount, (reaction) => { const reactionCount = reaction.users.length; - if (reactionCount === 0) { - return null; - } - - const reactionUsers = _.map(reaction.users, sender => sender.accountID); + const reactionUsers = _.map(reaction.users, sender => sender.accountID.toString()); const emoji = _.find(emojis, e => e.name === reaction.emoji); const emojiCodes = getUniqueEmojiCodes(emoji, reaction.users); diff --git a/src/languages/en.js b/src/languages/en.js index 83de58b70b24..209f0f70fa1e 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -115,6 +115,7 @@ export default { enterManually: 'Enter it manually', message: 'Message ', leaveRoom: 'Leave room', + you: 'You', your: 'your', conciergeHelp: 'Please reach out to Concierge for help.', maxParticipantsReached: ({count}) => `You've selected the maximum number (${count}) of participants.`, diff --git a/src/languages/es.js b/src/languages/es.js index d2305eb4ca2a..89679622b719 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -114,6 +114,7 @@ export default { enterManually: 'Ingresar manualmente', message: 'Chatear con ', leaveRoom: 'Salir de la sala de chat', + you: 'Tú', your: 'tu', conciergeHelp: 'Por favor contacta con Concierge para obtener ayuda.', maxParticipantsReached: ({count}) => `Has seleccionado el número máximo (${count}) de participantes.`, diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js new file mode 100644 index 000000000000..8307e3587005 --- /dev/null +++ b/src/libs/PersonalDetailsUtils.js @@ -0,0 +1,43 @@ +import Onyx from 'react-native-onyx'; +import _ from 'underscore'; +import ONYXKEYS from '../ONYXKEYS'; +import * as Report from './actions/Report'; +import * as Localize from './Localize'; + +let personalDetails = []; +Onyx.connect({ + key: ONYXKEYS.PERSONAL_DETAILS, + callback: val => personalDetails = _.values(val), +}); + +/** + * Given a list of account IDs (as string) it will return an array of personal details objects. + * @param {Array} accountIDs - Array of accountIDs + * @param {boolean} shouldChangeUserDisplayName - It will replace the current user's personal detail object's displayName with 'You'. + * @returns {Array} - Array of personal detail objects + */ +function getPersonalDetailsByIDs(accountIDs, shouldChangeUserDisplayName = false) { + const result = []; + const currentAccountID = Report.getCurrentUserAccountID(); + _.each(personalDetails, (detail) => { + for (let i = 0; i < accountIDs.length; i++) { + if (detail.accountID === accountIDs[i]) { + if (shouldChangeUserDisplayName && currentAccountID.toString() === detail.accountID) { + result[i] = { + ...detail, + displayName: Localize.translateLocal('common.you'), + }; + } else { + result[i] = detail; + } + break; + } + } + }); + return result; +} + +export { + // eslint-disable-next-line import/prefer-default-export + getPersonalDetailsByIDs, +}; diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index c4549b6cc121..563816d396c1 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -1366,6 +1366,10 @@ function toggleEmojiReaction(reportID, reportAction, emoji, paramSkinTone = pref return addEmojiReaction(reportID, reportAction, emoji, skinTone); } +function getCurrentUserAccountID() { + return currentUserAccountID; +} + export { addComment, addAttachment, @@ -1401,4 +1405,5 @@ export { removeEmojiReaction, toggleEmojiReaction, hasAccountIDReacted, + getCurrentUserAccountID, }; diff --git a/src/styles/styles.js b/src/styles/styles.js index 64245fcde07a..841c02f5b11d 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2996,6 +2996,11 @@ const styles = { lineHeight: variables.iconSizeXLarge, }, + textReactionSenders: { + color: themeColors.dark, + ...wordBreak.breakWord, + }, + quickReactionsContainer: { gap: 12, flexDirection: 'row', diff --git a/src/styles/themes/default.js b/src/styles/themes/default.js index 97a3da5d500d..baa0e18e57d9 100644 --- a/src/styles/themes/default.js +++ b/src/styles/themes/default.js @@ -29,6 +29,7 @@ const darkTheme = { successPressed: colors.greenPressed, transparent: colors.transparent, midtone: colors.green700, + dark: colors.midnight, // Additional keys overlay: colors.greenHighlightBackground,