diff --git a/client/coral-embed-stream/src/components/Stream.js b/client/coral-embed-stream/src/components/Stream.js
index 6959ff662..8ba34e3b4 100644
--- a/client/coral-embed-stream/src/components/Stream.js
+++ b/client/coral-embed-stream/src/components/Stream.js
@@ -13,7 +13,7 @@ import t, {timeago} from 'coral-framework/services/i18n';
import CommentBox from 'talk-plugin-commentbox/CommentBox';
import QuestionBox from 'talk-plugin-questionbox/QuestionBox';
import {isCommentActive} from 'coral-framework/utils';
-import {Spinner, Button, Tab, TabCount, TabPane} from 'coral-ui';
+import {Button, Tab, TabCount, TabPane} from 'coral-ui';
import cn from 'classnames';
import {getTopLevelParent, attachCommentToParent} from '../graphql/utils';
@@ -23,8 +23,6 @@ import StreamTabPanel from '../containers/StreamTabPanel';
import styles from './Stream.css';
-const SpinnerWhenLoading = ({loading, children}) => loading ? :
{children}
;
-
class Stream extends React.Component {
constructor(props) {
@@ -144,6 +142,7 @@ class Stream extends React.Component {
emit,
sortOrder,
sortBy,
+ loading,
} = this.props;
const slotProps = {data};
@@ -171,6 +170,7 @@ class Stream extends React.Component {
tabPaneSlot={'streamTabPanes'}
slotProps={slotProps}
queryData={slotQueryData}
+ loading={loading}
appendTabs={
All Comments {totalCommentCount}
@@ -223,7 +223,6 @@ class Stream extends React.Component {
viewAllComments,
auth: {loggedIn, user},
editName,
- loading,
} = this.props;
const {keepCommentBox} = this.state;
const open = !asset.isClosed;
@@ -310,12 +309,10 @@ class Stream extends React.Component {
/>
)}
-
- {highlightedComment
- ? this.renderHighlightedComment()
- : this.renderTabPanel()
- }
-
+ {highlightedComment
+ ? this.renderHighlightedComment()
+ : this.renderTabPanel()
+ }
);
}
diff --git a/client/coral-embed-stream/src/components/StreamTabPanel.css b/client/coral-embed-stream/src/components/StreamTabPanel.css
new file mode 100644
index 000000000..9398d373c
--- /dev/null
+++ b/client/coral-embed-stream/src/components/StreamTabPanel.css
@@ -0,0 +1,3 @@
+.spinnerContainer {
+ margin-top: 16px;
+}
diff --git a/client/coral-embed-stream/src/components/StreamTabPanel.js b/client/coral-embed-stream/src/components/StreamTabPanel.js
index 0f2092092..a511ac555 100644
--- a/client/coral-embed-stream/src/components/StreamTabPanel.js
+++ b/client/coral-embed-stream/src/components/StreamTabPanel.js
@@ -1,19 +1,23 @@
import React from 'react';
-import {TabBar, TabContent} from 'coral-ui';
+import {Spinner, TabBar, TabContent} from 'coral-ui';
import PropTypes from 'prop-types';
+import styles from './StreamTabPanel.css';
class StreamTabPanel extends React.Component {
render() {
- const {activeTab, setActiveTab, tabs, tabPanes, sub} = this.props;
+ const {activeTab, setActiveTab, tabs, tabPanes, sub, loading} = this.props;
return (
{tabs}
-
- {tabPanes}
-
+ {loading
+ ?
+ :
+ {tabPanes}
+
+ }
);
}
diff --git a/client/coral-embed-stream/src/containers/Stream.js b/client/coral-embed-stream/src/containers/Stream.js
index 271421dea..194bfc5d9 100644
--- a/client/coral-embed-stream/src/containers/Stream.js
+++ b/client/coral-embed-stream/src/containers/Stream.js
@@ -84,6 +84,10 @@ class StreamContainer extends React.Component {
return prev;
}
+ // Newest top-level comments are only added when sorting by 'newest first'.
+ if (!commentAdded.parent && !this.isSortedByNewestFirst()) {
+ return prev;
+ }
return insertCommentIntoEmbedQuery(prev, commentAdded);
},
});
@@ -163,32 +167,9 @@ class StreamContainer extends React.Component {
}
componentWillReceiveProps(nextProps) {
- const prevSortedNewest = this.isSortedByNewestFirst(this.props);
- const nextSortedNewest = this.isSortedByNewestFirst(nextProps);
-
- // When switching to 'Newest first' we refetch and subscribe so that
- // we always have the newest comments.
- if (!prevSortedNewest && nextSortedNewest) {
+ if (this.props.sortOrder !== nextProps.sortOrder || this.props.sortBy !== nextProps.sortBy) {
nextProps.data.refetch();
- this.subscribeToCommentsAdded();
}
-
- // When switching away from 'Newest first' unsubscribe from newest comments.
- if (prevSortedNewest && !nextSortedNewest) {
- this.unsubscribeCommentsAdded();
- }
- }
-
- shouldComponentUpdate(nextProps) {
- const prevSortedNewest = this.isSortedByNewestFirst(this.props);
- const nextSortedNewest = this.isSortedByNewestFirst(nextProps);
- if (!prevSortedNewest && nextSortedNewest) {
-
- // When switching to 'Newest first' we refetch => skip
- // rendering this frame and wait for refetch to kick in.
- return false;
- }
- return true;
}
userIsDegraged({auth: {user}} = this.props) {
diff --git a/client/coral-embed-stream/src/containers/StreamTabPanel.js b/client/coral-embed-stream/src/containers/StreamTabPanel.js
index 152f34e39..fde6e3be4 100644
--- a/client/coral-embed-stream/src/containers/StreamTabPanel.js
+++ b/client/coral-embed-stream/src/containers/StreamTabPanel.js
@@ -86,6 +86,7 @@ class StreamTabPanelContainer extends React.Component {
setActiveTab={this.props.setActiveTab}
tabs={this.getPluginTabElements().concat(this.props.appendTabs)}
tabPanes={this.getPluginTabPaneElements().concat(this.props.appendTabPanes)}
+ loading={this.props.loading}
sub={this.props.sub}
/>
);
@@ -110,6 +111,7 @@ StreamTabPanelContainer.propTypes = {
queryData: PropTypes.object,
className: PropTypes.string,
sub: PropTypes.bool,
+ loading: PropTypes.bool,
};
const mapStateToProps = (state) => ({
diff --git a/client/coral-framework/components/Popup.js b/client/coral-framework/components/Popup.js
index 1fe3408ea..33041442f 100644
--- a/client/coral-framework/components/Popup.js
+++ b/client/coral-framework/components/Popup.js
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
export default class Popup extends Component {
ref = null;
detectCloseInterval = null;
+ resetCallbackInterval = null;
constructor(props) {
super(props);
@@ -41,16 +42,26 @@ export default class Popup extends Component {
this.ref.onunload = () => {
this.onUnload();
- const interval = setInterval(() => {
+ if (this.resetCallbackInterval) {
+ clearInterval(this.resetCallbackInterval);
+ }
+
+ this.resetCallbackInterval = setInterval(() => {
if (this.ref && this.ref.onload === null) {
+ clearInterval(this.resetCallbackInterval);
+ this.resetCallbackInterval = null;
this.setCallbacks();
- clearInterval(interval);
}
}, 50);
+ if (this.detectCloseInterval) {
+ clearInterval(this.detectCloseInterval);
+ }
+
this.detectCloseInterval = setInterval(() => {
if (!this.ref || this.ref.closed) {
clearInterval(this.detectCloseInterval);
+ this.detectCloseInterval = null;
this.onClose();
}
}, 50);
diff --git a/client/coral-framework/helpers/validate.js b/client/coral-framework/helpers/validate.js
index dd36ae07f..ef64a2c84 100644
--- a/client/coral-framework/helpers/validate.js
+++ b/client/coral-framework/helpers/validate.js
@@ -1,5 +1,5 @@
export default {
- email: (email) => (/^([A-Za-z0-9_\-\.\+])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/.test(email)),
+ email: (email) => (/^.+@.+\..+$/.test(email)),
password: (pass) => (/^(?=.{8,}).*$/.test(pass)),
confirmPassword: () => true,
username: (username) => (/^[a-zA-Z0-9_]+$/.test(username)),
diff --git a/client/coral-framework/utils/index.js b/client/coral-framework/utils/index.js
index 533ed85db..26f6b627e 100644
--- a/client/coral-framework/utils/index.js
+++ b/client/coral-framework/utils/index.js
@@ -184,3 +184,16 @@ export function getShallowChanges(a, b) {
return union(Object.keys(a), Object.keys(b))
.filter((key) => a[key] !== b[key]);
}
+
+// TODO: replace with something less fragile.
+// NOT_REACTION_TYPES are the action summaries that are not reactions.
+const NOT_REACTION_TYPES = [
+ 'FlagActionSummary',
+ 'DontAgreeActionSummary',
+];
+
+export function getTotalReactionsCount(actionSummaries) {
+ return actionSummaries
+ .filter(({__typename}) => !NOT_REACTION_TYPES.includes(__typename))
+ .reduce((total, {count}) => total + count, 0);
+}
diff --git a/client/coral-settings/containers/ProfileContainer.js b/client/coral-settings/containers/ProfileContainer.js
index f5ea64005..571952639 100644
--- a/client/coral-settings/containers/ProfileContainer.js
+++ b/client/coral-settings/containers/ProfileContainer.js
@@ -108,6 +108,11 @@ const CommentFragment = gql`
nodes {
id
body
+ replyCount
+ action_summaries {
+ count
+ __typename
+ }
asset {
id
title
diff --git a/client/talk-plugin-history/Comment.css b/client/talk-plugin-history/Comment.css
index 646e1f054..1200709a3 100644
--- a/client/talk-plugin-history/Comment.css
+++ b/client/talk-plugin-history/Comment.css
@@ -6,6 +6,7 @@
display: flex;
align-items: baseline;
justify-content: space-between;
+ padding-bottom: 20px;
}
.myComment:last-child {
@@ -16,13 +17,28 @@
text-decoration: none;
font-weight: bold;
font-size: 12px;
- color: #2c3e50;
+ color: #757575;
}
-.commentBody {
-
+.commentSummary {
+ font-size: 14px;
+ margin: 30px 0 10px;
+ color: #424242;
}
+.commentSummaryReactions {
+ margin-right: 10px;
+}
+
+.reactionCount, .replyCount {
+ margin: 0 4px;
+}
+
+.countZero {
+ color: #9E9E9E;
+}
+
+
.sidebar {
ul {
margin-top: 0;
diff --git a/client/talk-plugin-history/Comment.js b/client/talk-plugin-history/Comment.js
index 4cf9d875c..b813e514b 100644
--- a/client/talk-plugin-history/Comment.js
+++ b/client/talk-plugin-history/Comment.js
@@ -4,6 +4,8 @@ import styles from './Comment.css';
import Slot from 'coral-framework/components/Slot';
import PubDate from '../talk-plugin-pubdate/PubDate';
import CommentContent from '../coral-embed-stream/src/components/CommentContent';
+import cn from 'classnames';
+import {getTotalReactionsCount} from 'coral-framework/utils';
import t from 'coral-framework/services/i18n';
@@ -11,24 +13,41 @@ class Comment extends React.Component {
render() {
const {comment, link, data, root} = this.props;
+ const reactionCount = getTotalReactionsCount(comment.action_summaries);
+
return (
@@ -38,7 +57,7 @@ class Comment extends React.Component {
-
-
+
{
username: 'usernameC'
}
]);
- comments = await CommentsService.publicCreate([0, 1, 0, 1].map((idx) => ({
+ comments = await CommentsService.publicCreate([0, 0, 1, 1].map((idx) => ({
author_id: users[idx].id,
asset_id: assets[idx].id,
body: `hello there! ${String(Math.random()).slice(2)}`,
@@ -74,12 +74,12 @@ describe('graph.queries.asset', () => {
expect(asset.nodes).to.have.length(2);
expect(asset.hasNextPage).to.be.false;
- expect(asset.nodes[0]).to.have.property('id', comments[2].id);
+ expect(asset.nodes[0]).to.have.property('id', comments[1].id);
expect(asset.nodes[1]).to.have.property('id', comments[0].id);
expect(otherAsset.nodes).to.have.length(2);
expect(otherAsset.hasNextPage).to.be.false;
expect(otherAsset.nodes[0]).to.have.property('id', comments[3].id);
- expect(otherAsset.nodes[1]).to.have.property('id', comments[1].id);
+ expect(otherAsset.nodes[1]).to.have.property('id', comments[2].id);
for (let node of asset.nodes) {
for (let otherNode of otherAsset.nodes) {