-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
reactions: support removing reaction
constants: add REMOVE_REACTION actions: add removeReaction reaction: add decrement prop (via dispatch / connect) in onClick, decrement if user has reacted, otherwise increment if userHasReacted, keep background blue create ReactionsList component reactions: refactor, add userHasReacted prop to reaction replace this.reactionsUsers and this.emojiNames with this.emojis keep track of all users across all reactions for this message (for displaying) pass this.emojis[emoji_code] to Reaction use connect/redux and config.username to check if userHasReacted use reactionsList change forEach to for of loop package.json: use zulip/zulip-js.git (reactions code has been merged) update yarn.lock
- Loading branch information
Showing
7 changed files
with
94 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,47 @@ | ||
import React, { Component } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import { replaceColons } from '../emoji'; | ||
import { addReaction } from '../actions'; | ||
import { addReaction, removeReaction } from '../actions'; | ||
import { style, hover } from '../styles/reaction'; | ||
|
||
class Reaction extends Component { | ||
state = { style }; | ||
constructor(props) { | ||
super(props); | ||
if (props.userHasReacted) { | ||
this.state = { style: hover }; | ||
} else { | ||
this.state = { style }; | ||
} | ||
this.onHover = this.onHover.bind(this); | ||
} | ||
|
||
onHover = (shouldHighlight) => { | ||
onHover(shouldHighlight) { | ||
if (shouldHighlight) { | ||
this.setState({ style: hover }); | ||
} else { | ||
this.setState({ style }); | ||
} | ||
this.props.onHover(); | ||
}; | ||
} | ||
|
||
render() { | ||
const reactionEmoji = replaceColons(`:${this.props.emojiName}:`); | ||
return <button style={this.state.style} | ||
onClick={this.props.increment} | ||
onClick={() => { | ||
if (this.props.userHasReacted) { | ||
this.props.decrement(); | ||
} else { | ||
this.props.increment(); | ||
} | ||
}} | ||
onMouseEnter={() => this.onHover(true)} | ||
onMouseLeave={() => this.onHover(false)}> | ||
onMouseLeave={() => this.onHover(this.props.userHasReacted)}> | ||
{reactionEmoji} | ||
</button>; | ||
} | ||
} | ||
|
||
export default connect(null, (dispatch, { emojiName, messageID, emojiCode }) => ({ | ||
increment: () => dispatch(addReaction(messageID, emojiName, emojiCode)), | ||
decrement: () => dispatch(removeReaction(messageID, emojiName, emojiCode)), | ||
}))(Reaction); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,58 @@ | ||
import React, { Component } from 'react'; | ||
import Reaction from './Reaction'; | ||
import { connect } from 'react-redux'; | ||
import ReactionsList from './ReactionsList'; | ||
import ReactionUsers from './ReactionUsers'; | ||
import style from '../styles/reactions'; | ||
|
||
export default class Reactions extends Component { | ||
class Reactions extends Component { | ||
constructor(props) { | ||
super(props); | ||
this.reactionsUsers = {}; | ||
this.emojiNames = {}; | ||
this.props.reactions.forEach(({ emoji_name, user, emoji_code }) => { | ||
this.emojiNames[emoji_code] = emoji_name; | ||
if (!this.reactionsUsers[emoji_code]) { | ||
this.reactionsUsers[emoji_code] = [user]; | ||
} else { | ||
this.reactionsUsers[emoji_code].push(user); | ||
this.emojis = {}; | ||
this.users = {}; | ||
for (({ emoji_name, emoji_code, user }) of props.reactions) { | ||
if (!this.emojis[emoji_code]) { | ||
this.emojis[emoji_code] = { | ||
emojiName: emoji_name, | ||
emojiCode: emoji_code, | ||
userHasReacted: false, | ||
users: [], | ||
}; | ||
} | ||
}); | ||
if (user.email === this.props.username) { | ||
this.emojis[emoji_code].userHasReacted = true; | ||
} | ||
this.users[user.email] = user; | ||
this.emojis[emoji_code].users.push(user); | ||
} | ||
this.state = { | ||
displayUsers: false, | ||
users: [] | ||
}; | ||
this.toggleDisplayUsers = () => { | ||
if (!this.state.displayUsers) { | ||
const allUsers = [].concat(...Object.values(this.reactionsUsers)); | ||
const uniqueUsers = {}; | ||
for (const user of allUsers) { | ||
uniqueUsers[user.email] = user; | ||
} | ||
this.setState({ users: Object.values(uniqueUsers) }); | ||
} | ||
this.setState({ displayUsers: !this.state.displayUsers }); | ||
}; | ||
this.displayUsers = (emojiCode) => this.setState({ users: this.reactionsUsers[emojiCode] }); | ||
this.toggleDisplayUsers = this.toggleDisplayUsers.bind(this); | ||
this.displayUsers = this.displayUsers.bind(this); | ||
} | ||
|
||
toggleDisplayUsers() { | ||
if (!this.state.displayUsers) { | ||
this.setState({ users: Object.values(this.users) }); | ||
} | ||
this.setState({ displayUsers: !this.state.displayUsers }); | ||
} | ||
|
||
displayUsers(emojiCode) { | ||
this.setState({ users: this.emojis[emojiCode].users }); | ||
} | ||
|
||
render() { | ||
const reactions = Object.keys(this.reactionsUsers).map((emojiCode) => { | ||
return <Reaction key={emojiCode} | ||
emojiCode={emojiCode} | ||
emojiName={this.emojiNames[emojiCode]} | ||
messageID={this.props.messageID} | ||
onHover={() => this.displayUsers(emojiCode)} | ||
/>; | ||
}); | ||
return <div style={style} onMouseEnter={this.toggleDisplayUsers} onMouseLeave={this.toggleDisplayUsers} > | ||
{reactions} | ||
<ReactionsList emojis={Object.values(this.emojis)} | ||
onHover={this.displayUsers} | ||
messageID={this.props.messageID} | ||
/> | ||
<ReactionUsers users={this.state.users} shouldDisplay={this.state.displayUsers} /> | ||
</div>; | ||
} | ||
} | ||
export default connect( | ||
({config}) => ({username: config.username}), | ||
)(Reactions); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import React from 'react'; | ||
import Reaction from './Reaction'; | ||
|
||
function reaction(emoji, onHover, messageID) { | ||
return <Reaction key={emoji.emojiCode} | ||
messageID={messageID} | ||
onHover={() => onHover(emoji.emojiCode)} | ||
{...emoji} | ||
/>; | ||
} | ||
|
||
export default ({ emojis, onHover, messageID }) => { | ||
return emojis.map(emoji => reaction(emoji, onHover, messageID)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters