mirror of
https://github.com/wassname/talk.git
synced 2026-07-07 07:28:35 +08:00
@@ -197,7 +197,9 @@ class Comment extends React.Component {
|
||||
}
|
||||
|
||||
<Content body={comment.body} />
|
||||
<Slot fill="commentContent" />
|
||||
<div className="commentActionsLeft comment__action-container">
|
||||
<Slot fill="commentReactions" inline />
|
||||
<ActionButton>
|
||||
{/* TODO implmement iPerformedThisAction for the like */}
|
||||
<LikeButton
|
||||
@@ -228,7 +230,7 @@ class Comment extends React.Component {
|
||||
</IfUserCanModifyBest>
|
||||
</ActionButton>
|
||||
<Slot
|
||||
fill="commentDetail"
|
||||
fill="commentActions"
|
||||
data={this.props.data}
|
||||
root={this.props.root}
|
||||
comment={comment}
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import React, {PropTypes} from 'react';
|
||||
|
||||
import {Button} from 'coral-ui';
|
||||
import Comment from '../containers/Comment';
|
||||
import CommentBox from 'coral-plugin-commentbox/CommentBox';
|
||||
import SuspendedAccount from 'coral-framework/components/SuspendedAccount';
|
||||
import RestrictedContent from 'coral-framework/components/RestrictedContent';
|
||||
import ChangeUsernameContainer from 'coral-sign-in/containers/ChangeUsernameContainer';
|
||||
import IgnoredCommentTombstone from './IgnoredCommentTombstone';
|
||||
import InfoBox from 'coral-plugin-infobox/InfoBox';
|
||||
import QuestionBox from 'coral-plugin-questionbox/QuestionBox';
|
||||
import LoadMore from './LoadMore';
|
||||
import NewCount from './NewCount';
|
||||
import Comment from '../containers/Comment';
|
||||
import InfoBox from 'coral-plugin-infobox/InfoBox';
|
||||
import {ModerationLink} from 'coral-plugin-moderation';
|
||||
import CommentBox from 'coral-plugin-commentbox/CommentBox';
|
||||
import QuestionBox from 'coral-plugin-questionbox/QuestionBox';
|
||||
import IgnoredCommentTombstone from './IgnoredCommentTombstone';
|
||||
import SuspendedAccount from 'coral-framework/components/SuspendedAccount';
|
||||
import RestrictedContent from 'coral-framework/components/RestrictedContent';
|
||||
import ChangeUsernameContainer
|
||||
from 'coral-sign-in/containers/ChangeUsernameContainer';
|
||||
|
||||
class Stream extends React.Component {
|
||||
|
||||
setActiveReplyBox = (reactKey) => {
|
||||
setActiveReplyBox = reactKey => {
|
||||
if (!this.props.auth.user) {
|
||||
this.props.showSignInDialog();
|
||||
} else {
|
||||
this.props.setActiveReplyBox(reactKey);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render () {
|
||||
render() {
|
||||
const {
|
||||
root: {asset, asset: {comments}, comment, myIgnoredUsers},
|
||||
postItem,
|
||||
@@ -39,152 +40,158 @@ class Stream extends React.Component {
|
||||
ignoreUser,
|
||||
auth: {loggedIn, isAdmin, user},
|
||||
commentCountCache,
|
||||
editName,
|
||||
editName
|
||||
} = this.props;
|
||||
const open = asset.closedAt === null;
|
||||
|
||||
// even though the permalinked comment is the highlighted one, we're displaying its parent + replies
|
||||
const highlightedComment = comment && comment.parent ? comment.parent : comment;
|
||||
const highlightedComment = comment && comment.parent
|
||||
? comment.parent
|
||||
: comment;
|
||||
|
||||
const banned = user && user.status === 'BANNED';
|
||||
|
||||
const hasOlderComments = !!(
|
||||
asset &&
|
||||
const hasOlderComments = !!(asset &&
|
||||
asset.lastComment &&
|
||||
asset.lastComment.id !== asset.comments[asset.comments.length - 1].id
|
||||
);
|
||||
asset.lastComment.id !== asset.comments[asset.comments.length - 1].id);
|
||||
|
||||
// Find the created_at date of the first comment. If no comments exist, set the date to a week ago.
|
||||
const firstCommentDate = asset.comments[0]
|
||||
? asset.comments[0].created_at
|
||||
: new Date(Date.now() - 1000 * 60 * 60 * 24 * 7).toISOString();
|
||||
const commentIsIgnored = (comment) => myIgnoredUsers && myIgnoredUsers.includes(comment.user.id);
|
||||
const commentIsIgnored = comment =>
|
||||
myIgnoredUsers && myIgnoredUsers.includes(comment.user.id);
|
||||
return (
|
||||
<div id='stream'>
|
||||
{
|
||||
open
|
||||
? <div id="commentBox">
|
||||
<InfoBox
|
||||
content={asset.settings.infoBoxContent}
|
||||
enable={asset.settings.infoBoxEnable}
|
||||
/>
|
||||
<QuestionBox
|
||||
content={asset.settings.questionBoxContent}
|
||||
enable={asset.settings.questionBoxEnable}
|
||||
/>
|
||||
<RestrictedContent restricted={banned} restrictedComp={
|
||||
<SuspendedAccount
|
||||
canEditName={user && user.canEditName}
|
||||
editName={editName}
|
||||
/>
|
||||
}>
|
||||
{
|
||||
user
|
||||
? <CommentBox
|
||||
addNotification={this.props.addNotification}
|
||||
postItem={this.props.postItem}
|
||||
appendItemArray={this.props.appendItemArray}
|
||||
updateItem={this.props.updateItem}
|
||||
setCommentCountCache={this.props.setCommentCountCache}
|
||||
commentCountCache={commentCountCache}
|
||||
assetId={asset.id}
|
||||
premod={asset.settings.moderation}
|
||||
isReply={false}
|
||||
authorId={user.id}
|
||||
charCountEnable={asset.settings.charCountEnable}
|
||||
maxCharCount={asset.settings.charCount} />
|
||||
: null
|
||||
}
|
||||
</RestrictedContent>
|
||||
</div>
|
||||
: <p>{asset.settings.closedMessage}</p>
|
||||
}
|
||||
{!loggedIn && <Button id='coralSignInButton' onClick={this.props.showSignInDialog} full>Sign in to comment</Button>}
|
||||
{loggedIn && user && <ChangeUsernameContainer loggedIn={loggedIn} user={user} />}
|
||||
<div id="stream">
|
||||
{open
|
||||
? <div id="commentBox">
|
||||
<InfoBox
|
||||
content={asset.settings.infoBoxContent}
|
||||
enable={asset.settings.infoBoxEnable}
|
||||
/>
|
||||
<QuestionBox
|
||||
content={asset.settings.questionBoxContent}
|
||||
enable={asset.settings.questionBoxEnable}
|
||||
/>
|
||||
<RestrictedContent
|
||||
restricted={banned}
|
||||
restrictedComp={
|
||||
<SuspendedAccount
|
||||
canEditName={user && user.canEditName}
|
||||
editName={editName}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{user
|
||||
? <CommentBox
|
||||
addNotification={this.props.addNotification}
|
||||
postItem={this.props.postItem}
|
||||
appendItemArray={this.props.appendItemArray}
|
||||
updateItem={this.props.updateItem}
|
||||
setCommentCountCache={this.props.setCommentCountCache}
|
||||
commentCountCache={commentCountCache}
|
||||
assetId={asset.id}
|
||||
premod={asset.settings.moderation}
|
||||
isReply={false}
|
||||
authorId={user.id}
|
||||
charCountEnable={asset.settings.charCountEnable}
|
||||
maxCharCount={asset.settings.charCount}
|
||||
/>
|
||||
: null}
|
||||
</RestrictedContent>
|
||||
</div>
|
||||
: <p>{asset.settings.closedMessage}</p>}
|
||||
{!loggedIn &&
|
||||
<Button
|
||||
id="coralSignInButton"
|
||||
onClick={this.props.showSignInDialog}
|
||||
full
|
||||
>
|
||||
Sign in to comment
|
||||
</Button>}
|
||||
{loggedIn &&
|
||||
user &&
|
||||
<ChangeUsernameContainer loggedIn={loggedIn} user={user} />}
|
||||
{loggedIn && <ModerationLink assetId={asset.id} isAdmin={isAdmin} />}
|
||||
|
||||
{/* the highlightedComment is isolated after the user followed a permalink */}
|
||||
{
|
||||
highlightedComment
|
||||
{highlightedComment
|
||||
? <Comment
|
||||
data={this.props.data}
|
||||
root={this.props.root}
|
||||
setActiveReplyBox={this.setActiveReplyBox}
|
||||
activeReplyBox={this.props.activeReplyBox}
|
||||
addNotification={addNotification}
|
||||
depth={0}
|
||||
postItem={this.props.postItem}
|
||||
asset={asset}
|
||||
currentUser={user}
|
||||
highlighted={comment.id}
|
||||
postLike={this.props.postLike}
|
||||
postFlag={this.props.postFlag}
|
||||
postDontAgree={this.props.postDontAgree}
|
||||
loadMore={this.props.loadMore}
|
||||
deleteAction={this.props.deleteAction}
|
||||
showSignInDialog={this.props.showSignInDialog}
|
||||
key={highlightedComment.id}
|
||||
commentIsIgnored={commentIsIgnored}
|
||||
reactKey={highlightedComment.id}
|
||||
comment={highlightedComment}
|
||||
charCountEnable={asset.settings.charCountEnable}
|
||||
maxCharCount={asset.settings.charCount}
|
||||
/>
|
||||
: <div>
|
||||
<NewCount
|
||||
commentCount={asset.commentCount}
|
||||
commentCountCache={commentCountCache}
|
||||
data={this.props.data}
|
||||
root={this.props.root}
|
||||
setActiveReplyBox={this.setActiveReplyBox}
|
||||
activeReplyBox={this.props.activeReplyBox}
|
||||
addNotification={addNotification}
|
||||
depth={0}
|
||||
postItem={this.props.postItem}
|
||||
asset={asset}
|
||||
currentUser={user}
|
||||
highlighted={comment.id}
|
||||
postLike={this.props.postLike}
|
||||
postFlag={this.props.postFlag}
|
||||
postDontAgree={this.props.postDontAgree}
|
||||
loadMore={this.props.loadMore}
|
||||
firstCommentDate={firstCommentDate}
|
||||
assetId={asset.id}
|
||||
setCommentCountCache={this.props.setCommentCountCache}
|
||||
deleteAction={this.props.deleteAction}
|
||||
showSignInDialog={this.props.showSignInDialog}
|
||||
key={highlightedComment.id}
|
||||
commentIsIgnored={commentIsIgnored}
|
||||
reactKey={highlightedComment.id}
|
||||
comment={highlightedComment}
|
||||
charCountEnable={asset.settings.charCountEnable}
|
||||
maxCharCount={asset.settings.charCount}
|
||||
/>
|
||||
: <div>
|
||||
<NewCount
|
||||
commentCount={asset.commentCount}
|
||||
commentCountCache={commentCountCache}
|
||||
loadMore={this.props.loadMore}
|
||||
firstCommentDate={firstCommentDate}
|
||||
assetId={asset.id}
|
||||
setCommentCountCache={this.props.setCommentCountCache}
|
||||
/>
|
||||
<div className="embed__stream">
|
||||
{
|
||||
comments.map(comment =>
|
||||
commentIsIgnored(comment)
|
||||
? <IgnoredCommentTombstone
|
||||
key={comment.id}
|
||||
/>
|
||||
: <Comment
|
||||
data={this.props.data}
|
||||
root={this.props.root}
|
||||
disableReply={!open}
|
||||
setActiveReplyBox={this.setActiveReplyBox}
|
||||
activeReplyBox={this.props.activeReplyBox}
|
||||
addNotification={addNotification}
|
||||
depth={0}
|
||||
postItem={postItem}
|
||||
asset={asset}
|
||||
currentUser={user}
|
||||
postLike={postLike}
|
||||
postFlag={postFlag}
|
||||
postDontAgree={postDontAgree}
|
||||
addCommentTag={addCommentTag}
|
||||
removeCommentTag={removeCommentTag}
|
||||
ignoreUser={ignoreUser}
|
||||
commentIsIgnored={commentIsIgnored}
|
||||
loadMore={loadMore}
|
||||
deleteAction={deleteAction}
|
||||
showSignInDialog={showSignInDialog}
|
||||
key={comment.id}
|
||||
reactKey={comment.id}
|
||||
comment={comment}
|
||||
pluginProps={pluginProps}
|
||||
charCountEnable={asset.settings.charCountEnable}
|
||||
maxCharCount={asset.settings.charCount}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<LoadMore
|
||||
topLevel={true}
|
||||
assetId={asset.id}
|
||||
comments={asset.comments}
|
||||
moreComments={hasOlderComments}
|
||||
loadMore={this.props.loadMore} />
|
||||
</div>
|
||||
}
|
||||
<div className="embed__stream">
|
||||
{comments.map(
|
||||
comment =>
|
||||
(commentIsIgnored(comment)
|
||||
? <IgnoredCommentTombstone key={comment.id} />
|
||||
: <Comment
|
||||
data={this.props.data}
|
||||
root={this.props.root}
|
||||
disableReply={!open}
|
||||
setActiveReplyBox={this.setActiveReplyBox}
|
||||
activeReplyBox={this.props.activeReplyBox}
|
||||
addNotification={addNotification}
|
||||
depth={0}
|
||||
postItem={postItem}
|
||||
asset={asset}
|
||||
currentUser={user}
|
||||
postLike={postLike}
|
||||
postFlag={postFlag}
|
||||
postDontAgree={postDontAgree}
|
||||
addCommentTag={addCommentTag}
|
||||
removeCommentTag={removeCommentTag}
|
||||
ignoreUser={ignoreUser}
|
||||
commentIsIgnored={commentIsIgnored}
|
||||
loadMore={loadMore}
|
||||
deleteAction={deleteAction}
|
||||
showSignInDialog={showSignInDialog}
|
||||
key={comment.id}
|
||||
reactKey={comment.id}
|
||||
comment={comment}
|
||||
pluginProps={pluginProps}
|
||||
charCountEnable={asset.settings.charCountEnable}
|
||||
maxCharCount={asset.settings.charCount}
|
||||
/>)
|
||||
)}
|
||||
</div>
|
||||
<LoadMore
|
||||
topLevel={true}
|
||||
assetId={asset.id}
|
||||
comments={asset.comments}
|
||||
moreComments={hasOlderComments}
|
||||
loadMore={this.props.loadMore}
|
||||
/>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -201,7 +208,7 @@ Stream.propTypes = {
|
||||
removeCommentTag: PropTypes.func,
|
||||
|
||||
// dispatch action to ignore another user
|
||||
ignoreUser: React.PropTypes.func,
|
||||
ignoreUser: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default Stream;
|
||||
|
||||
@@ -3,7 +3,15 @@ import Comment from '../components/Comment';
|
||||
import withFragments from 'coral-framework/hocs/withFragments';
|
||||
import {getSlotsFragments} from 'coral-framework/helpers/plugins';
|
||||
|
||||
const pluginFragments = getSlotsFragments(['commentInfoBar', 'commentDetail']);
|
||||
const pluginFragments = getSlotsFragments([
|
||||
'streamQuestionArea',
|
||||
'commentInputArea',
|
||||
'commentInputDetailArea',
|
||||
'commentInfoBar',
|
||||
'commentActions',
|
||||
'commentContent',
|
||||
'commentReactions'
|
||||
]);
|
||||
|
||||
export default withFragments({
|
||||
root: gql`
|
||||
@@ -36,5 +44,5 @@ export default withFragments({
|
||||
${pluginFragments.spreads('comment')}
|
||||
}
|
||||
${pluginFragments.definitions('comment')}
|
||||
`,
|
||||
`
|
||||
})(Comment);
|
||||
|
||||
@@ -1,20 +1,16 @@
|
||||
import React, {Component} from 'react';
|
||||
import {getSlotElements} from 'coral-framework/helpers/plugins';
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import styles from './Slot.css';
|
||||
import {getSlotElements} from 'coral-framework/helpers/plugins';
|
||||
|
||||
class Slot extends Component {
|
||||
render() {
|
||||
const {fill, inline = false, ...rest} = this.props;
|
||||
return (
|
||||
<div className={inline ? styles.inline : ''}>
|
||||
{getSlotElements(fill, rest)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default function Slot ({fill, inline = false, ...rest}) {
|
||||
return (
|
||||
<div className={cn({[styles.inline]: inline})}>
|
||||
{getSlotElements(fill, rest)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Slot.propTypes = {
|
||||
fill: React.PropTypes.string
|
||||
};
|
||||
|
||||
export default Slot;
|
||||
|
||||
@@ -44,7 +44,7 @@ function getComponentFragments(components) {
|
||||
* Returns an object that can be used to compose fragments or queries.
|
||||
*
|
||||
* Example:
|
||||
* const pluginFragments = getSlotsFragments(['commentInfoBar', 'commentDetail']);
|
||||
* const pluginFragments = getSlotsFragments(['commentInfoBar', 'commentActions']);
|
||||
* const rootFragment = gql`
|
||||
* fragment Comment_root on RootQuery {
|
||||
+ ${pluginFragments.spreads('root')}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import React, {PropTypes} from 'react';
|
||||
import {Button} from 'coral-ui';
|
||||
import {connect} from 'react-redux';
|
||||
import {I18n} from '../coral-framework';
|
||||
import translations from './translations.json';
|
||||
import {Button} from 'coral-ui';
|
||||
import Slot from 'coral-framework/components/Slot';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
const name = 'coral-plugin-commentbox';
|
||||
|
||||
class CommentBox extends Component {
|
||||
class CommentBox extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -151,13 +151,14 @@ class CommentBox extends Component {
|
||||
id={isReply ? 'replyText' : 'commentText'}
|
||||
onChange={this.handleChange}
|
||||
rows={3}/>
|
||||
<Slot fill='commentInputArea' />
|
||||
</div>
|
||||
<div className={`${name}-char-count ${length > maxCharCount ? `${name}-char-max` : ''}`}>
|
||||
{maxCharCount && `${maxCharCount - length} ${lang.t('characters-remaining')}`}
|
||||
</div>
|
||||
<div className={`${name}-button-container`}>
|
||||
<Slot
|
||||
fill="commentBoxDetail"
|
||||
fill="commentInputDetailArea"
|
||||
registerHook={this.registerHook}
|
||||
unregisterHook={this.unregisterHook}
|
||||
inline
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
const packagename = 'coral-plugin-questionbox';
|
||||
import Slot from 'coral-framework/components/Slot';
|
||||
|
||||
const QuestionBox = ({enable, content}) =>
|
||||
<div className={`${packagename}-info ${enable ? null : 'hidden'}` }>
|
||||
@@ -10,6 +11,7 @@ const QuestionBox = ({enable, content}) =>
|
||||
<div className={`${packagename}-content`}>
|
||||
{content}
|
||||
</div>
|
||||
<Slot fill="streamQuestionArea" />
|
||||
</div>;
|
||||
|
||||
export default QuestionBox;
|
||||
|
||||
@@ -3,7 +3,7 @@ import OffTopicTag from './components/OffTopicTag';
|
||||
|
||||
export default {
|
||||
slots: {
|
||||
commentBoxDetail: [OffTopicCheckbox],
|
||||
commentInputDetailArea: [OffTopicCheckbox],
|
||||
commentInfoBar: [OffTopicTag]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,6 +2,6 @@ import RespectButton from './containers/RespectButton';
|
||||
|
||||
export default {
|
||||
slots: {
|
||||
commentDetail: [RespectButton],
|
||||
commentActions: [RespectButton],
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user