@@ -9,26 +9,14 @@ import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultPro
9
9
import withLocalize from '../withLocalize' ;
10
10
import compose from '../../libs/compose' ;
11
11
import * as Report from '../../libs/actions/Report' ;
12
+ import EmojiReactionsPropTypes from './EmojiReactionsPropTypes' ;
12
13
import Tooltip from '../Tooltip' ;
13
14
import ReactionTooltipContent from './ReactionTooltipContent' ;
14
15
import * as EmojiUtils from '../../libs/EmojiUtils' ;
15
16
import ReportScreenContext from '../../pages/home/ReportScreenContext' ;
16
17
17
18
const propTypes = {
18
- /**
19
- * An array of objects containing the reaction data.
20
- * The shape of a reaction looks like this:
21
- *
22
- * "reactionName": {
23
- * emoji: string,
24
- * users: {
25
- * accountID: string,
26
- * skinTone: number,
27
- * }[]
28
- * }
29
- */
30
- // eslint-disable-next-line react/forbid-prop-types
31
- reactions : PropTypes . arrayOf ( PropTypes . object ) . isRequired ,
19
+ emojiReactions : EmojiReactionsPropTypes ,
32
20
33
21
/** The ID of the reportAction. It is the string representation of the a 64-bit integer. */
34
22
reportActionID : PropTypes . string . isRequired ,
@@ -45,27 +33,66 @@ const propTypes = {
45
33
46
34
const defaultProps = {
47
35
...withCurrentUserPersonalDetailsDefaultProps ,
36
+ emojiReactions : { } ,
48
37
} ;
49
38
50
- function ReportActionItemReactions ( props ) {
39
+ function ReportActionItemEmojiReactions ( props ) {
51
40
const { reactionListRef} = useContext ( ReportScreenContext ) ;
52
41
const popoverReactionListAnchor = useRef ( null ) ;
53
- const reactionsWithCount = _ . filter ( props . reactions , ( reaction ) => reaction . users . length > 0 ) ;
42
+ let totalReactionCount = 0 ;
43
+
44
+ // Each emoji is sorted by the oldest timestamp of user reactions so that they will always appear in the same order for everyone
45
+ const sortedReactions = _ . sortBy ( props . emojiReactions , ( emojiReaction , emojiName ) => {
46
+ // Since the emojiName is only stored as the object key, when _.sortBy() runs, the object is converted to an array and the
47
+ // keys are lost. To keep from losing the emojiName, it's copied to the emojiReaction object.
48
+ // eslint-disable-next-line no-param-reassign
49
+ emojiReaction . emojiName = emojiName ;
50
+ const oldestUserReactionTimestamp = _ . chain ( emojiReaction . users )
51
+ . reduce ( ( allTimestampsArray , userData ) => {
52
+ if ( ! userData ) {
53
+ return allTimestampsArray ;
54
+ }
55
+ _ . each ( userData . skinTones , ( createdAt ) => {
56
+ allTimestampsArray . push ( createdAt ) ;
57
+ } ) ;
58
+ return allTimestampsArray ;
59
+ } , [ ] )
60
+ . sort ( )
61
+ . first ( )
62
+ . value ( ) ;
63
+
64
+ // Just in case two emojis have the same timestamp, also combine the timestamp with the
65
+ // emojiName so that the order will always be the same. Without this, the order can be pretty random
66
+ // and shift around a little bit.
67
+ return ( oldestUserReactionTimestamp || emojiReaction . createdAt ) + emojiName ;
68
+ } ) ;
54
69
55
70
return (
56
71
< View
57
72
ref = { popoverReactionListAnchor }
58
73
style = { [ styles . flexRow , styles . flexWrap , styles . gap1 , styles . mt2 ] }
59
74
>
60
- { _ . map ( reactionsWithCount , ( reaction ) => {
61
- const reactionCount = reaction . users . length ;
62
- const reactionUsers = _ . map ( reaction . users , ( sender ) => sender . accountID ) ;
63
- const emoji = EmojiUtils . findEmojiByName ( reaction . emoji ) ;
64
- const emojiCodes = EmojiUtils . getUniqueEmojiCodes ( emoji , reaction . users ) ;
65
- const hasUserReacted = Report . hasAccountIDReacted ( props . currentUserPersonalDetails . accountID , reactionUsers ) ;
75
+ { _ . map ( sortedReactions , ( reaction ) => {
76
+ const reactionEmojiName = reaction . emojiName ;
77
+ const usersWithReactions = _ . pick ( reaction . users , _ . identity ) ;
78
+ let reactionCount = 0 ;
79
+
80
+ // Loop through the users who have reacted and see how many skintones they reacted with so that we get the total count
81
+ _ . forEach ( usersWithReactions , ( user ) => {
82
+ reactionCount += _ . size ( user . skinTones ) ;
83
+ } ) ;
84
+ if ( ! reactionCount ) {
85
+ return null ;
86
+ }
87
+ totalReactionCount += reactionCount ;
88
+ const emojiAsset = EmojiUtils . findEmojiByName ( reactionEmojiName ) ;
89
+ const emojiCodes = EmojiUtils . getUniqueEmojiCodes ( emojiAsset , reaction . users ) ;
90
+ const hasUserReacted = Report . hasAccountIDEmojiReacted ( props . currentUserPersonalDetails . accountID , reaction . users ) ;
91
+ const reactionUsers = _ . keys ( usersWithReactions ) ;
92
+ const reactionUserAccountIDs = _ . map ( reactionUsers , Number ) ;
66
93
67
94
const onPress = ( ) => {
68
- props . toggleReaction ( emoji ) ;
95
+ props . toggleReaction ( emojiAsset ) ;
69
96
} ;
70
97
71
98
const onReactionListOpen = ( event ) => {
@@ -76,14 +103,14 @@ function ReportActionItemReactions(props) {
76
103
< Tooltip
77
104
renderTooltipContent = { ( ) => (
78
105
< ReactionTooltipContent
79
- emojiName = { EmojiUtils . getLocalizedEmojiName ( reaction . emoji , props . preferredLocale ) }
106
+ emojiName = { EmojiUtils . getLocalizedEmojiName ( reactionEmojiName , props . preferredLocale ) }
80
107
emojiCodes = { emojiCodes }
81
- accountIDs = { reactionUsers }
108
+ accountIDs = { reactionUserAccountIDs }
82
109
currentUserPersonalDetails = { props . currentUserPersonalDetails }
83
110
/>
84
111
) }
85
112
renderTooltipContentKey = { [ ..._ . map ( reactionUsers , ( user ) => user . toString ( ) ) , ...emojiCodes ] }
86
- key = { reaction . emoji }
113
+ key = { reactionEmojiName }
87
114
>
88
115
< View >
89
116
< EmojiReactionBubble
@@ -99,7 +126,7 @@ function ReportActionItemReactions(props) {
99
126
</ Tooltip >
100
127
) ;
101
128
} ) }
102
- { reactionsWithCount . length > 0 && (
129
+ { totalReactionCount > 0 && (
103
130
< AddReactionBubble
104
131
onSelectEmoji = { props . toggleReaction }
105
132
reportAction = { { reportActionID : props . reportActionID } }
@@ -109,7 +136,7 @@ function ReportActionItemReactions(props) {
109
136
) ;
110
137
}
111
138
112
- ReportActionItemReactions . displayName = 'ReportActionItemReactions' ;
113
- ReportActionItemReactions . propTypes = propTypes ;
114
- ReportActionItemReactions . defaultProps = defaultProps ;
115
- export default compose ( withLocalize , withCurrentUserPersonalDetails ) ( ReportActionItemReactions ) ;
139
+ ReportActionItemEmojiReactions . displayName = 'ReportActionItemReactions' ;
140
+ ReportActionItemEmojiReactions . propTypes = propTypes ;
141
+ ReportActionItemEmojiReactions . defaultProps = defaultProps ;
142
+ export default compose ( withLocalize , withCurrentUserPersonalDetails ) ( ReportActionItemEmojiReactions ) ;
0 commit comments