diff --git a/client/coral-embed-stream/src/components/Comment.js b/client/coral-embed-stream/src/components/Comment.js
index 2e854633b..649adb941 100644
--- a/client/coral-embed-stream/src/components/Comment.js
+++ b/client/coral-embed-stream/src/components/Comment.js
@@ -496,6 +496,7 @@ export default class Comment extends React.Component {
fill="commentReactions"
data={this.props.data}
root={this.props.root}
+ asset={asset}
comment={comment}
commentId={comment.id}
inline
diff --git a/plugins/talk-plugin-featured-comments/client/components/FeaturedButton.js b/plugins/talk-plugin-featured-comments/client/components/FeaturedButton.js
new file mode 100644
index 000000000..31f7ee32c
--- /dev/null
+++ b/plugins/talk-plugin-featured-comments/client/components/FeaturedButton.js
@@ -0,0 +1,16 @@
+import React from 'react';
+import withTags from './withTags';
+
+class FeaturedButton extends React.Component {
+ render() {
+ const {alreadyTagged, deleteTag, postTag} = this.props;
+ return (
+
+ );
+ }
+}
+
+export default withTags('featured')(FeaturedButton);
+
\ No newline at end of file
diff --git a/plugins/talk-plugin-featured-comments/client/components/FeaturedTag.js b/plugins/talk-plugin-featured-comments/client/components/FeaturedTag.js
new file mode 100644
index 000000000..23f62a6d8
--- /dev/null
+++ b/plugins/talk-plugin-featured-comments/client/components/FeaturedTag.js
@@ -0,0 +1,17 @@
+import React from 'react';
+import styles from './styles.css';
+import {t} from 'plugin-api/beta/client/services';
+
+const isFeatured = (tags) => !!tags.filter((t) => t.tag.name === 'FEATURED').length;
+
+export default (props) => (
+
+ {
+ isFeatured(props.comment.tags) && props.depth === 0 ? (
+
+ Featured
+
+ ) : null
+ }
+
+);
diff --git a/plugins/talk-plugin-featured-comments/client/components/styles.css b/plugins/talk-plugin-featured-comments/client/components/styles.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/plugins/talk-plugin-featured-comments/client/components/withTags.js b/plugins/talk-plugin-featured-comments/client/components/withTags.js
new file mode 100644
index 000000000..4e7401577
--- /dev/null
+++ b/plugins/talk-plugin-featured-comments/client/components/withTags.js
@@ -0,0 +1,186 @@
+import React from 'react';
+import {connect} from 'react-redux';
+import {bindActionCreators} from 'redux';
+import {compose, gql} from 'react-apollo';
+import {getDisplayName} from 'coral-framework/helpers/hoc';
+import {capitalize} from 'coral-framework/helpers/strings';
+import withMutation from 'coral-framework/hocs/withMutation';
+import withFragments from 'coral-framework/hocs/withFragments';
+import {showSignInDialog} from 'coral-framework/actions/auth';
+import {addNotification} from 'coral-framework/actions/notification';
+
+export default (tag) => (WrappedComponent) => {
+ if (typeof tag !== 'string') {
+ console.error('Tag must be a valid string');
+ return null;
+ }
+
+ tag = tag.toLowerCase();
+ const Tag = capitalize(tag);
+
+ const COMMENT_FRAGMENT = gql`
+ fragment Coral_UpdateFragment on Comment {
+ tags {
+ tag {
+ name
+ }
+ }
+ }
+ `;
+
+ const withAddTag = withMutation(
+ gql`
+ mutation AddTag($id: ID!, $asset_id: ID!, $name: String!) {
+ addTag(tag: {name: $name, id: $id, item_type: COMMENTS, asset_id: $asset_id}) {
+ ...ModifyTagResponse
+ }
+ }
+ `, {
+ props: ({mutate}) => ({
+ addTag: ({id, name, assetId}) => {
+ return mutate({
+ variables: {
+ id,
+ name,
+ asset_id: assetId
+ },
+ optimisticResponse: {
+ addTag: {
+ __typename: 'ModifyTagResponse',
+ errors: null,
+ }
+ },
+ update: (proxy) => {
+ const fragmentId = `Comment_${id}`;
+
+ // Read the data from our cache for this query.
+ const data = proxy.readFragment({fragment: COMMENT_FRAGMENT, id: fragmentId});
+
+ data.tags.push({
+ tag: {
+ __typename: 'Tag',
+ name: Tag.toUpperCase()
+ },
+ __typename: 'TagLink'
+ });
+
+ // Write our data back to the cache.
+ proxy.writeFragment({fragment: COMMENT_FRAGMENT, id: fragmentId, data});
+ },
+ });
+ }}),
+ });
+
+ const withRemoveTag = withMutation(
+ gql`
+ mutation RemoveTag($id: ID!, $asset_id: ID!, $name: String!) {
+ removeTag(tag: {name: $name, id: $id, item_type: COMMENTS, asset_id: $asset_id}) {
+ ...ModifyTagResponse
+ }
+ }
+ `, {
+ props: ({mutate}) => ({
+ removeTag: ({id, name, assetId}) => {
+ return mutate({
+ variables: {
+ id,
+ name,
+ asset_id: assetId
+ },
+ optimisticResponse: {
+ removeTag: {
+ __typename: 'ModifyTagResponse',
+ errors: null,
+ }
+ },
+ update: (proxy) => {
+ const fragmentId = `Comment_${id}`;
+
+ // Read the data from our cache for this query.
+ const data = proxy.readFragment({fragment: COMMENT_FRAGMENT, id: fragmentId});
+
+ const idx = data.tags.findIndex((i) => i.tag.name === Tag.toUpperCase());
+
+ data.tags = [...data.tags.slice(0, idx), ...data.tags.slice(idx + 1)];
+
+ // Write our data back to the cache.
+ proxy.writeFragment({fragment: COMMENT_FRAGMENT, id: fragmentId, data});
+ }
+ });
+ }}),
+ });
+
+ class WithTags extends React.Component {
+
+ postTag = () => {
+ console.log(this.props);
+
+ const {comment, asset} = this.props;
+
+ this.props.addTag({
+ id: comment.id,
+ name: Tag.toUpperCase(),
+ assetId: asset.id
+ });
+
+ console.log('Post Tag');
+ }
+
+ deleteTag = () => {
+ const {comment, asset} = this.props;
+
+ this.props.removeTag({
+ id: comment.id,
+ name: Tag.toUpperCase(),
+ assetId: asset.id
+ });
+
+ console.log('delete Tag');
+ }
+
+
+
+ render() {
+ const {comment} = this.props;
+
+ const isTagged = (tags) => !!tags.filter((t) => t.tag.name === Tag.toUpperCase()).length;
+
+ const alreadyTagged = isTagged(comment.tags);
+
+ return ;
+ }
+ }
+
+ const mapStateToProps = (state) => ({
+ user: state.auth.toJS().user,
+ });
+
+ const mapDispatchToProps = (dispatch) =>
+ bindActionCreators({showSignInDialog, addNotification}, dispatch);
+
+ const enhance = compose(
+ withFragments({
+ comment: gql`
+ fragment ${Tag}Button_comment on Comment {
+ tags {
+ tag {
+ name
+ }
+ }
+ }`
+ }),
+ connect(mapStateToProps, mapDispatchToProps),
+ withAddTag,
+ withRemoveTag
+ );
+
+ WithTags.displayName = `WithTags(${getDisplayName(WrappedComponent)})`;
+
+ return enhance(WithTags);
+};
diff --git a/plugins/talk-plugin-featured-comments/client/index.js b/plugins/talk-plugin-featured-comments/client/index.js
new file mode 100644
index 000000000..613d70d13
--- /dev/null
+++ b/plugins/talk-plugin-featured-comments/client/index.js
@@ -0,0 +1,11 @@
+import translations from './translations.json';
+import FeaturedTag from './components/FeaturedTag';
+import FeaturedButton from './components/FeaturedButton';
+
+export default {
+ translations,
+ slots: {
+ commentInfoBar: [FeaturedTag],
+ commentReactions: [FeaturedButton]
+ }
+};
diff --git a/plugins/talk-plugin-featured-comments/client/translations.json b/plugins/talk-plugin-featured-comments/client/translations.json
new file mode 100644
index 000000000..077404aaa
--- /dev/null
+++ b/plugins/talk-plugin-featured-comments/client/translations.json
@@ -0,0 +1,3 @@
+{
+
+}
\ No newline at end of file