Add reactions to /connect content (#585)
This commit is contained in:
parent
d407d9bc52
commit
5a2c549927
4 changed files with 194 additions and 21 deletions
|
|
@ -377,6 +377,59 @@
|
|||
top:-4px;
|
||||
}
|
||||
|
||||
.activechatchannel__activeArticle{
|
||||
position: absolute;
|
||||
top: 38px; left: 0; right: 0; bottom: 0;
|
||||
border-top: 1px solid $light-medium-gray !important;
|
||||
}
|
||||
|
||||
.chat .activechatchannel__activeArticle .container {
|
||||
position: absolute;
|
||||
top: 0px; left: 0; right: 0; bottom: 30px;
|
||||
overflow-y: scroll;
|
||||
border-radius: 0px;
|
||||
margin-top: 0px !important;
|
||||
pre{
|
||||
width:97%;
|
||||
margin-left:-3%;
|
||||
padding-left:4%;
|
||||
padding-right:7%;
|
||||
}
|
||||
}
|
||||
|
||||
.activechatchannel__activeArticleActions{
|
||||
position:absolute;
|
||||
bottom:0;
|
||||
left:0px;
|
||||
right:0px;
|
||||
padding: 19px;
|
||||
background: white;
|
||||
z-index: 20;
|
||||
border-top: 1px solid $light-medium-gray;
|
||||
button {
|
||||
border: 1px solid $light-medium-gray;
|
||||
padding: 3px 20px;
|
||||
border-radius: 3px;
|
||||
margin-right: 15px;
|
||||
&.active {
|
||||
border: 2px solid $black;
|
||||
padding: 2px 19px;
|
||||
background-color:$green;
|
||||
&.unicorn-reaction-button{
|
||||
background-color:$purple;
|
||||
}
|
||||
&.readinglist-reaction-button{
|
||||
background: lighten($bold-blue, 32%);
|
||||
}
|
||||
}
|
||||
img {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.activecontent__githubrepo{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class ReactionsController < ApplicationController
|
|||
)
|
||||
@result = "create"
|
||||
end
|
||||
render json: { result: @result }
|
||||
render json: { result: @result, category: params[:category] || "like" }
|
||||
end
|
||||
|
||||
def cached_user_positive_reactions(user)
|
||||
|
|
|
|||
138
app/javascript/chat/article.jsx
Normal file
138
app/javascript/chat/article.jsx
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
|
||||
|
||||
import { h, Component } from 'preact';
|
||||
import heartImage from 'images/emoji/emoji-one-heart.png';
|
||||
import unicornImage from 'images/emoji/emoji-one-unicorn.png';
|
||||
import bookmarkImage from 'images/emoji/emoji-one-bookmark.png';
|
||||
|
||||
export default class Article extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
reactionCounts: [],
|
||||
userReactions: [],
|
||||
optimisticUserReaction: null,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
fetch("/reactions?article_id="+this.props.resource.id, {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(this.displayReactions)
|
||||
.catch(this.displayReactionsFailure);
|
||||
}
|
||||
|
||||
displayReactions = response => {
|
||||
this.setState({userReactions:response.reactions})
|
||||
}
|
||||
|
||||
displayReactionsFailure = response => {
|
||||
console.log(response)
|
||||
}
|
||||
|
||||
handleNewReactionResponse = (response) => {
|
||||
let oldUserReactions = this.state.userReactions;
|
||||
let foundReactions = oldUserReactions.filter(obj => {
|
||||
return obj.category === response.category
|
||||
})
|
||||
if (foundReactions.length === 0 && response.result === 'create') {
|
||||
oldUserReactions.push({category: response.category})
|
||||
} else {
|
||||
oldUserReactions = oldUserReactions.filter(obj => {
|
||||
return obj.category != response.category
|
||||
})
|
||||
}
|
||||
this.setState({userReactions: oldUserReactions, optimisticUserReaction: null})
|
||||
}
|
||||
|
||||
handleNewReactionFailure = response => {
|
||||
console.log(response)
|
||||
}
|
||||
|
||||
handleReactionClick = e => {
|
||||
e.preventDefault();
|
||||
const target = e.target;
|
||||
console.log(target.dataset.category)
|
||||
this.setState({optimisticUserReaction: target.dataset.category })
|
||||
const article = this.props.resource
|
||||
fetch('/reactions', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-CSRF-Token': window.csrfToken,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
reactable_type: 'Article',
|
||||
reactable_id: article.id,
|
||||
category: target.dataset.category,
|
||||
}),
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(this.handleNewReactionResponse)
|
||||
.catch(this.handleNewReactionFailure);
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
const article = this.props.resource;
|
||||
let heartReactedClass = ''
|
||||
let unicornReactedClass = ''
|
||||
let bookmarkReactedClass = ''
|
||||
const state = this.state;
|
||||
state.userReactions.forEach((reaction) => {
|
||||
if (reaction.category === 'like' || state.optimisticUserReaction === 'like') {
|
||||
heartReactedClass = 'active'
|
||||
}
|
||||
if (reaction.category === 'unicorn' || state.optimisticUserReaction === 'unicorn') {
|
||||
unicornReactedClass = 'active'
|
||||
}
|
||||
if (reaction.category === 'readinglist' || state.optimisticUserReaction === 'readinglist') {
|
||||
bookmarkReactedClass = 'active'
|
||||
}
|
||||
});
|
||||
let coverImage = '';
|
||||
if (article.cover_image) {
|
||||
coverImage = <header><div class="image image-final" style={{backgroundImage:`url(${article.cover_image}`}}></div></header>
|
||||
}
|
||||
return (
|
||||
<div className='activechatchannel__activeArticle'>
|
||||
<div className="container">
|
||||
{coverImage}
|
||||
<div className="title">
|
||||
<h1>{article.title}</h1>
|
||||
<h3>
|
||||
<a href={'/'+article.user.username} className="author" data-content={'/users/'+article.user.id}>
|
||||
<img className="profile-pic" src={article.user.profile_image_90} alt={article.user.username}/>
|
||||
<span>{article.user.name}</span>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div className="body">
|
||||
<div dangerouslySetInnerHTML={{__html: article.body_html}} ></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="activechatchannel__activeArticleActions">
|
||||
<button className={'heart-reaction-button ' + heartReactedClass}
|
||||
onClick={this.handleReactionClick} data-category='like' >
|
||||
<img src={heartImage} />
|
||||
</button>
|
||||
<button className={'unicorn-reaction-button ' + unicornReactedClass}
|
||||
onClick={this.handleReactionClick} data-category='unicorn'>
|
||||
<img src={unicornImage} data-category='unicorn' />
|
||||
</button>
|
||||
<button className={'readinglist-reaction-button ' + bookmarkReactedClass}
|
||||
onClick={this.handleReactionClick} data-category='readinglist'>
|
||||
<img src={bookmarkImage} data-category='readinglist' />
|
||||
</button>
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4,6 +4,7 @@ import CodeEditor from './codeEditor';
|
|||
import GithubRepo from './githubRepo';
|
||||
import ChannelDetails from './channelDetails';
|
||||
import UserDetails from './userDetails';
|
||||
import Article from './article';
|
||||
|
||||
export default class Content extends Component {
|
||||
static propTypes = {
|
||||
|
|
@ -48,26 +49,7 @@ function display(props) {
|
|||
} else if (props.resource.type_of === "user") {
|
||||
return <UserDetails user={props.resource} />
|
||||
} else if (props.resource.type_of === "article") {
|
||||
let coverImage = '';
|
||||
if (props.resource.cover_image) {
|
||||
coverImage = <header><div class="image image-final" style={{marginTop: '20px', backgroundImage:`url(${props.resource.cover_image}`}}></div></header>
|
||||
}
|
||||
return (
|
||||
<div class="container">
|
||||
{coverImage}
|
||||
<div class="title">
|
||||
<h1>{props.resource.title}</h1>
|
||||
<h3>
|
||||
<a href={'/'+props.resource.user.username} class="author">
|
||||
<img class="profile-pic" src={props.resource.user.profile_image_90} alt={props.resource.user.username}/>
|
||||
<span>{props.resource.user.name}</span>
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div dangerouslySetInnerHTML={{__html: props.resource.body_html}} ></div>
|
||||
</div>
|
||||
</div>)
|
||||
return <Article resource={props.resource}/>
|
||||
} else if (props.resource.type_of === "github") {
|
||||
return <GithubRepo
|
||||
activeChannelId={props.activeChannelId}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue