diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index bdb101362..c2f3a8056 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -9,7 +9,7 @@ const checkLoginFailure = error => ({type: actions.CHECK_LOGIN_FAILURE, error}); export const checkLogin = () => dispatch => { dispatch(checkLoginRequest()); - coralApi('/auth') + return coralApi('/auth') .then(result => { const isAdmin = !!result.user.roles.filter(i => i === 'ADMIN').length; dispatch(checkLoginSuccess(result.user, isAdmin)); diff --git a/client/coral-admin/src/components/EmptyCard.js b/client/coral-admin/src/components/EmptyCard.js new file mode 100644 index 000000000..42337a892 --- /dev/null +++ b/client/coral-admin/src/components/EmptyCard.js @@ -0,0 +1,14 @@ +import React, {PropTypes} from 'react'; +import {Card} from 'coral-ui'; + +const EmptyCard = props => ( + + {props.children} + +); + +EmptyCard.propTypes = { + children: PropTypes.node.isRequired +}; + +export default EmptyCard; diff --git a/client/coral-admin/src/containers/Community/Community.js b/client/coral-admin/src/containers/Community/Community.js index bad5654cf..08a962c34 100644 --- a/client/coral-admin/src/containers/Community/Community.js +++ b/client/coral-admin/src/containers/Community/Community.js @@ -1,12 +1,12 @@ import React from 'react'; import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../../translations.json'; +import translations from 'coral-admin/src/translations.json'; import styles from './Community.css'; import Table from './Table'; import Loading from './Loading'; -import NoResults from './NoResults'; import {Pager} from 'coral-ui'; +import EmptyCard from '../../components/EmptyCard'; const lang = new I18n(translations); @@ -54,13 +54,14 @@ const Community = ({isFetching, commenters, ...props}) => {
{ isFetching && } - { !hasResults && } - { hasResults && - + { + hasResults + ?
+ : {lang.t('community.no-results')} } ( -
- No users found with that user name or email address -
-); - -export default NoResults; diff --git a/client/coral-admin/src/containers/LayoutContainer.js b/client/coral-admin/src/containers/LayoutContainer.js index 225e92884..5ce208503 100644 --- a/client/coral-admin/src/containers/LayoutContainer.js +++ b/client/coral-admin/src/containers/LayoutContainer.js @@ -8,7 +8,11 @@ import {PermissionRequired} from '../components/PermissionRequired'; class LayoutContainer extends Component { componentWillMount () { const {checkLogin} = this.props; - checkLogin(); + checkLogin().then(() => { + if (!this.props.auth.isAdmin) { + location.href = '/admin/login'; + } + }); } render () { const {isAdmin, loggedIn, loadingUser} = this.props.auth; diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js index d30f24c1f..0d48acc92 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js @@ -1,14 +1,21 @@ import React, {PropTypes} from 'react'; import Comment from './components/Comment'; +import EmptyCard from '../../components/EmptyCard'; import {actionsMap} from './helpers/moderationQueueActionsMap'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from 'coral-admin/src/translations'; + +const lang = new I18n(translations); const ModerationQueue = ({activeTab = 'premod', ...props}) => { + const areComments = props.data[activeTab].length; return (
-
    +
      { - props.data[activeTab].map((comment, i) => { + areComments + ? props.data[activeTab].map((comment, i) => { const status = comment.action_summaries ? 'FLAGGED' : comment.status; return { currentAsset={props.currentAsset} />; }) + : {lang.t('modqueue.emptyqueue')} }
@@ -29,7 +37,12 @@ const ModerationQueue = ({activeTab = 'premod', ...props}) => { }; ModerationQueue.propTypes = { - data: PropTypes.object.isRequired + data: PropTypes.object.isRequired, + acceptComment: PropTypes.func.isRequired, + rejectComment: PropTypes.func.isRequired, + showBanUserDialog: PropTypes.func.isRequired, + currentAsset: PropTypes.object, + suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired }; export default ModerationQueue; diff --git a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js index f8f50c6df..b39eeb2f8 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js +++ b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {PropTypes} from 'react'; import timeago from 'timeago.js'; import Linkify from 'react-linkify'; import Highlighter from 'react-highlight-words'; @@ -17,7 +17,7 @@ const lang = new I18n(translations); const Comment = ({actions = [], ...props}) => { const links = linkify.getMatches(props.comment.body); - const actionSumaries = props.comment.action_summaries; + const actionSummaries = props.comment.action_summaries; return (
  • @@ -42,7 +42,7 @@ const Comment = ({actions = [], ...props}) => { /> )} - {props.comment.user.banned === 'banned' ? + {props.comment.user.status === 'banned' ? {lang.t('comment.banned_user')} @@ -62,11 +62,31 @@ const Comment = ({actions = [], ...props}) => {

    - {actionSumaries && } + {actionSummaries && }
  • ); }; +Comment.propTypes = { + acceptComment: PropTypes.func.isRequired, + rejectComment: PropTypes.func.isRequired, + suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired, + currentAsset: PropTypes.object, + isActive: PropTypes.bool.isRequired, + comment: PropTypes.shape({ + body: PropTypes.string.isRequired, + action_summaries: PropTypes.array, + created_at: PropTypes.string.isRequired, + user: PropTypes.shape({ + status: PropTypes.string + }), + asset: PropTypes.shape({ + title: PropTypes.string, + id: PropTypes.string + }) + }) +}; + const linkStyles = { backgroundColor: 'rgb(255, 219, 135)', padding: '1px 2px' diff --git a/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js b/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js index bf5a34f29..6140abd90 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js +++ b/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js @@ -5,7 +5,7 @@ const FlagBox = props => (

    Flags:

      - {props.actionSumaries.map((action, i) => + {props.actionSummaries.map((action, i) =>
    • {!action.reason ? No reason provided : action.reason} ({action.count})
    • )}
    @@ -13,7 +13,7 @@ const FlagBox = props => ( ); FlagBox.propTypes = { - actionSumaries: PropTypes.array.isRequired + actionSummaries: PropTypes.array.isRequired }; export default FlagBox; diff --git a/client/coral-admin/src/containers/Streams/Streams.js b/client/coral-admin/src/containers/Streams/Streams.js index 62f2f009e..96130fcba 100644 --- a/client/coral-admin/src/containers/Streams/Streams.js +++ b/client/coral-admin/src/containers/Streams/Streams.js @@ -8,6 +8,7 @@ import {Link} from 'react-router'; import {Pager, Icon} from 'coral-ui'; import {DataTable, TableHeader, RadioGroup, Radio} from 'react-mdl'; +import EmptyCard from 'coral-admin/src/components/EmptyCard'; const limit = 25; @@ -142,22 +143,25 @@ class Streams extends Component { {lang.t('streams.oldest')}
    -
    - - {lang.t('streams.article')} - - {lang.t('streams.pubdate')} - - - {lang.t('streams.status')} - - - -
    + { + assetsIds.length + ?
    + + {lang.t('streams.article')} + + {lang.t('streams.pubdate')} + + + {lang.t('streams.status')} + + + +
    + : {lang.t('streams.empty_result')} + } ); } diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index 5b15564d7..7219a22ca 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -7,7 +7,7 @@ "admin": "Administrator", "moderator": "Moderator", "role": "Select role...", - "no-results": "No users found with that user name or email address.", + "no-results": "No users found with that user name or email address. They're hiding!", "status": "Status", "select-status": "Select status...", "active": "Active", @@ -32,6 +32,7 @@ "prevcomment": "Go to the previous comment", "singleview": "Toggle single comment edit view", "thismenu": "Open this menu", + "emptyqueue": "No more comments to moderate! You're all caught up. Go have some ☕️", "showshortcuts": "Show Shortcuts" }, "comment": { @@ -113,6 +114,7 @@ "comment_count": "Comments" }, "streams": { + "empty_result": "No assets match this search. Maybe try widening your search?", "search": "Search", "filter-streams": "Filter Streams", "stream-status": "Stream Status", @@ -152,6 +154,7 @@ "flagged": "marcado", "shortcuts": "Atajos de teclado", "close": "Cerrar", + "emptyqueue": "No se encontro ningún usuario. Están escondidos.", "showshortcuts": "Mostrar atajos" }, "comment": { @@ -220,6 +223,7 @@ "comment_count": "Comentarios" }, "streams": { + "empty_result": "No se encuentro articulo con esta busqueda. Tal vez extender la busqueda?", "search": "", "filter-streams": "", "stream-status": "", diff --git a/client/coral-embed-stream/src/Comment.js b/client/coral-embed-stream/src/Comment.js index 9d679473e..8371cec45 100644 --- a/client/coral-embed-stream/src/Comment.js +++ b/client/coral-embed-stream/src/Comment.js @@ -177,7 +177,7 @@ class Comment extends React.Component { comment.replies &&
    comment.replies.length} diff --git a/client/coral-embed-stream/src/Embed.js b/client/coral-embed-stream/src/Embed.js index a7c4dcb38..5e979d243 100644 --- a/client/coral-embed-stream/src/Embed.js +++ b/client/coral-embed-stream/src/Embed.js @@ -12,6 +12,7 @@ const {fetchAssetSuccess} = assetActions; import {queryStream} from 'coral-framework/graphql/queries'; import {postComment, postFlag, postLike, deleteAction} from 'coral-framework/graphql/mutations'; import {editName} from 'coral-framework/actions/user'; +import {updateCountCache} from 'coral-framework/actions/asset'; import {Notification, notificationActions, authActions, assetActions, pym} from 'coral-framework'; import Stream from './Stream'; @@ -28,6 +29,7 @@ import SettingsContainer from 'coral-settings/containers/SettingsContainer'; import RestrictedContent from 'coral-framework/components/RestrictedContent'; import ConfigureStreamContainer from 'coral-configure/containers/ConfigureStreamContainer'; import LoadMore from './LoadMore'; +import NewCount from './NewCount'; class Embed extends Component { @@ -82,7 +84,7 @@ class Embed extends Component { render () { const {activeTab} = this.state; - const {closedAt} = this.props.asset; + const {closedAt, countCache = {}} = this.props.asset; const {loading, asset, refetch} = this.props.data; const {loggedIn, isAdmin, user, showSignInDialog, signInOffset} = this.props.auth; @@ -98,6 +100,11 @@ class Embed extends Component { return ; } + // 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(); + return (
    @@ -132,6 +139,8 @@ class Embed extends Component { postItem={this.props.postItem} appendItemArray={this.props.appendItemArray} updateItem={this.props.updateItem} + updateCountCache={this.props.updateCountCache} + countCache={countCache[asset.id]} assetId={asset.id} premod={asset.settings.moderation} isReply={false} @@ -147,6 +156,14 @@ class Embed extends Component { } {!loggedIn && } {loggedIn && user && } + ({ clearNotification: () => dispatch(clearNotification()), editName: (username) => dispatch(editName(username)), showSignInDialog: (offset) => dispatch(showSignInDialog(offset)), + updateCountCache: (id, count) => dispatch(updateCountCache(id, count)), logout: () => dispatch(logout()), dispatch: d => dispatch(d) }); diff --git a/client/coral-embed-stream/src/LoadMore.js b/client/coral-embed-stream/src/LoadMore.js index 89708272a..e33828bc1 100644 --- a/client/coral-embed-stream/src/LoadMore.js +++ b/client/coral-embed-stream/src/LoadMore.js @@ -12,7 +12,7 @@ const loadMoreComments = (assetId, comments, loadMore, parentId) => { } const cursor = parentId - ? comments[1].created_at + ? comments[0].created_at : comments[comments.length - 1].created_at; loadMore({ diff --git a/client/coral-embed-stream/src/NewCount.js b/client/coral-embed-stream/src/NewCount.js new file mode 100644 index 000000000..429ecc113 --- /dev/null +++ b/client/coral-embed-stream/src/NewCount.js @@ -0,0 +1,40 @@ +import React, {PropTypes} from 'react'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from 'coral-framework/translations.json'; +const lang = new I18n(translations); + +const onLoadMoreClick = ({loadMore, commentCount, firstCommentDate, assetId, updateCountCache}) => (e) => { + e.preventDefault(); + updateCountCache(assetId, commentCount); + loadMore({ + limit: 500, + cursor: firstCommentDate, + assetId, + sort: 'CHRONOLOGICAL' + }, true); +}; + +const NewCount = (props) => { + const newComments = props.commentCount - props.countCache; + + return
    + { + props.countCache && newComments > 0 && + + } +
    ; +}; + +NewCount.propTypes = { + commentCount: PropTypes.number.isRequired, + countCache: PropTypes.number, + loadMore: PropTypes.func.isRequired, + assetId: PropTypes.string.isRequired, + firstCommentDate: PropTypes.string.isRequired +}; + +export default NewCount; diff --git a/client/coral-embed-stream/src/Stream.js b/client/coral-embed-stream/src/Stream.js index 2f0f4b01b..89a637ceb 100644 --- a/client/coral-embed-stream/src/Stream.js +++ b/client/coral-embed-stream/src/Stream.js @@ -1,5 +1,6 @@ import React, {PropTypes} from 'react'; import Comment from './Comment'; +import {NEW_COMMENT_COUNT_POLL_INTERVAL} from 'coral-framework/constants/comments'; class Stream extends React.Component { @@ -17,10 +18,30 @@ class Stream extends React.Component { constructor(props) { super(props); - this.state = {activeReplyBox: ''}; + this.state = {activeReplyBox: '', countPoll: null}; this.setActiveReplyBox = this.setActiveReplyBox.bind(this); } + componentDidMount() { + const {asset, getCounts, updateCountCache} = this.props; + + updateCountCache(asset.id, asset.commentCount); + + // Note: Apollo's built-in polling doesn't work with fetchMore queries, so a + // setInterval is being used instead. + this.setState({ + countPoll: setInterval(() => getCounts({ + asset_id: asset.id, + limit: asset.comments.length, + sort: 'REVERSE_CHRONOLOGICAL' + }), NEW_COMMENT_COUNT_POLL_INTERVAL), + }); + } + + componentWillUnmount() { + clearInterval(this.state.countPoll); + } + setActiveReplyBox (reactKey) { if (!this.props.currentUser) { const offset = document.getElementById(`c_${reactKey}`).getBoundingClientRect().top - 75; diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 61965519b..52876ff79 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -359,18 +359,26 @@ button.coral-load-more { text-align: center; color: #FFF; background-color: #2376D8; + cursor: pointer; } button.coral-load-more:hover { background-color: #4399FF; } -.coral-load-more-replies { +.coral-load-more-replies, .coral-new-comments { width: 100%; display: flex; justify-content: center; + cursor: pointer; } -.coral-load-more-replies button.coral-load-more { +.coral-new-comments { + position: relative; + top: 1.8em; + z-index: 100; +} + +.coral-load-more-replies button.coral-load-more, .coral-new-comments button.coral-load-more{ width: initial; } diff --git a/client/coral-framework/actions/asset.js b/client/coral-framework/actions/asset.js index d5db289c3..02e72ea98 100644 --- a/client/coral-framework/actions/asset.js +++ b/client/coral-framework/actions/asset.js @@ -38,6 +38,7 @@ export const updateOpenStream = closedBody => (dispatch, getState) => { const openStream = () => ({type: actions.OPEN_COMMENTS}); const closeStream = () => ({type: actions.CLOSE_COMMENTS}); +export const updateCountCache = (id, count) => ({type: actions.UPDATE_COUNT_CACHE, id, count}); export const updateOpenStatus = status => dispatch => { if (status === 'open') { diff --git a/client/coral-framework/constants/asset.js b/client/coral-framework/constants/asset.js index 40f746706..234095d9d 100644 --- a/client/coral-framework/constants/asset.js +++ b/client/coral-framework/constants/asset.js @@ -8,3 +8,4 @@ export const UPDATE_ASSET_SETTINGS_FAILURE = 'UPDATE_ASSET_SETTINGS_FAILURE'; export const OPEN_COMMENTS = 'OPEN_COMMENTS'; export const CLOSE_COMMENTS = 'CLOSE_COMMENTS'; +export const UPDATE_COUNT_CACHE = 'UPDATE_COUNT_CACHE'; diff --git a/client/coral-framework/constants/comments.js b/client/coral-framework/constants/comments.js index 17ea2223e..28db9cdf9 100644 --- a/client/coral-framework/constants/comments.js +++ b/client/coral-framework/constants/comments.js @@ -1 +1,2 @@ export const ADDTL_COMMENTS_ON_LOAD_MORE = 10; +export const NEW_COMMENT_COUNT_POLL_INTERVAL = 20000; diff --git a/client/coral-framework/graphql/queries/index.js b/client/coral-framework/graphql/queries/index.js index 09b3159d0..c993dfb6a 100644 --- a/client/coral-framework/graphql/queries/index.js +++ b/client/coral-framework/graphql/queries/index.js @@ -1,6 +1,7 @@ import {graphql} from 'react-apollo'; import STREAM_QUERY from './streamQuery.graphql'; import LOAD_MORE from './loadMore.graphql'; +import GET_COUNTS from './getCounts.graphql'; import MY_COMMENT_HISTORY from './myCommentHistory.graphql'; function getQueryVariable(variable) { @@ -17,6 +18,72 @@ function getQueryVariable(variable) { return 'http://localhost/default/stream'; } +export const getCounts = (data) => ({asset_id, limit, sort}) => { + return data.fetchMore({ + query: GET_COUNTS, + variables: { + asset_id, + limit, + sort + }, + updateQuery: (oldData, {fetchMoreResult:{data}}) => { + + return { + ...oldData, + asset: { + ...oldData.asset, + commentCount: data.asset.commentCount + } + }; + } + }); +}; + +export const loadMore = (data) => ({limit, cursor, parent_id, asset_id, sort}, newComments) => { + return data.fetchMore({ + query: LOAD_MORE, + variables: { + limit, + cursor, + parent_id, + asset_id, + sort + }, + updateQuery: (oldData, {fetchMoreResult:{data:{new_top_level_comments}}}) => { + + let updatedAsset; + + if (parent_id) { + + // If loading more replies + updatedAsset = { + ...oldData, + asset: { + ...oldData.asset, + comments: oldData.asset.comments.map((comment) => + comment.id === parent_id + ? {...comment, replies: [...comment.replies, ...new_top_level_comments]} + : comment) + } + }; + } else { + + // If loading more top-level comments + updatedAsset = { + ...oldData, + asset: { + ...oldData.asset, + comments: newComments ? [...new_top_level_comments.reverse(), ...oldData.asset.comments] + : [...oldData.asset.comments, ...new_top_level_comments] + } + }; + } + + return updatedAsset; + } + }); +}; + export const queryStream = graphql(STREAM_QUERY, { options: () => ({ variables: { @@ -25,40 +92,8 @@ export const queryStream = graphql(STREAM_QUERY, { }), props: ({data}) => ({ data, - loadMore: ({limit, cursor, parent_id, asset_id, sort}) => { - return data.fetchMore({ - query: LOAD_MORE, - variables: { - limit, - cursor, - parent_id, - asset_id, - sort - }, - updateQuery: (oldData, {fetchMoreResult:{data:{new_top_level_comments}}}) => - - // If loading more replies - parent_id ? { - ...oldData, - asset: { - ...oldData.asset, - comments: oldData.asset.comments.map((comment) => - comment.id === parent_id - ? {...comment, replies: [...comment.replies, ...new_top_level_comments]} - : comment) - } - } - - // If loading more top-level comments - : { - ...oldData, - asset: { - ...oldData.asset, - comments: [...oldData.asset.comments, ...new_top_level_comments] - } - } - }); - } + loadMore: loadMore(data), + getCounts: getCounts(data), }) }); diff --git a/client/coral-framework/reducers/asset.js b/client/coral-framework/reducers/asset.js index f9d0a55e3..067edfc5b 100644 --- a/client/coral-framework/reducers/asset.js +++ b/client/coral-framework/reducers/asset.js @@ -19,6 +19,9 @@ export default function asset (state = initialState, action) { case actions.UPDATE_ASSET_SETTINGS_SUCCESS: return state .setIn(['settings'], action.settings); + case actions.UPDATE_COUNT_CACHE: + return state + .setIn(['countCache', action.id], action.count); default: return state; } diff --git a/client/coral-framework/translations.json b/client/coral-framework/translations.json index 2884178b6..c817925eb 100644 --- a/client/coral-framework/translations.json +++ b/client/coral-framework/translations.json @@ -11,6 +11,9 @@ "button": "Submit", "error": "Usernames can contain letters, numbers and _ only" }, + "newCount": "View {0} more {1}", + "comment": "comment", + "comments": "comments", "error": { "emailNotVerified": "Email address {0} not verified.", "email": "Not a valid E-Mail", @@ -39,6 +42,9 @@ "bannedAccountMsg": "Tu cuenta se encuentra suspendida. Esto significa que no puedes dar Like, Marcar o escribir commentarios. Por favor, contacta moderator@fakeurl for more information", "editNameMsg": "", "loadMore": "Ver más", + "newCount": "Ver {0} {1} más", + "comment": "commentario", + "comments": "commentarios", "error": { "emailNotVerified": "Dirección de correo electrónico {0} no verificada.", "email": "No es un email válido", diff --git a/client/coral-plugin-commentbox/CommentBox.js b/client/coral-plugin-commentbox/CommentBox.js index 344ade150..3d895df07 100644 --- a/client/coral-plugin-commentbox/CommentBox.js +++ b/client/coral-plugin-commentbox/CommentBox.js @@ -29,6 +29,8 @@ class CommentBox extends Component { commentPostedHandler, postItem, assetId, + updateCountCache, + countCache, parentId, addNotification, authorId @@ -44,14 +46,17 @@ class CommentBox extends Component { if (this.props.charCount && this.state.body.length > this.props.charCount) { return; } + updateCountCache(assetId, countCache + 1); postItem(comment, 'comments') .then(({data}) => { const postedComment = data.createComment.comment; if (postedComment.status === 'REJECTED') { addNotification('error', lang.t('comment-post-banned-word')); + updateCountCache(assetId, countCache); } else if (postedComment.status === 'PREMOD') { addNotification('success', lang.t('comment-post-notif-premod')); + updateCountCache(assetId, countCache); } else { addNotification('success', 'Your comment has been posted.'); } diff --git a/client/coral-settings/translations.json b/client/coral-settings/translations.json index 953708e61..c8398bd7b 100644 --- a/client/coral-settings/translations.json +++ b/client/coral-settings/translations.json @@ -1,6 +1,6 @@ { "en":{ - "userNoComment": "This user has not yet left a comment.", + "userNoComment": "You've never left a comment. Join the conversation!", "allComments": "All Comments", "profileSettings": "Profile Settings", "myCommentHistory": "My comment History", @@ -9,7 +9,7 @@ "fromSettingsPage": "From the Settings Page you can see your comment history." }, "es":{ - "userNoComment": "Aún no ha escrito ningún comentario.", + "userNoComment": "No has dejado áun ningún comentario. ¡Unete a la conversación!", "allComments": "Todos los comentarios", "profileSettings": "Configuración del perfil", "myCommentHistory": "Mi historial de comentarios", diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js index 33d2c4f85..5112ba829 100644 --- a/graph/mutators/comment.js +++ b/graph/mutators/comment.js @@ -150,10 +150,8 @@ const createPublicComment = (context, commentInput) => { item_id: comment.id, item_type: 'COMMENTS', action_type: 'FLAG', - metadata: { - field: 'body', - details: 'Matched suspect word filters.' - } + group_id: 'Matched suspect word filter', + metadata: {} }) .then(() => comment); } diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index 72a54a0cd..7db4dbad8 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -448,7 +448,7 @@ type RootQuery { # Comments returned based on a query. comments(query: CommentsQuery!): [Comment] - # Returne the count of comments satisfied by the query. Note that this edge is + # Return the count of comments satisfied by the query. Note that this edge is # expensive as it is not batched. Requires the `ADMIN` role. commentCount(query: CommentCountQuery!): Int diff --git a/test/client/coral-framework/reducers/assetReducer.spec.js b/test/client/coral-framework/reducers/assetReducer.spec.js new file mode 100644 index 000000000..c54f51737 --- /dev/null +++ b/test/client/coral-framework/reducers/assetReducer.spec.js @@ -0,0 +1,19 @@ +import {Map} from 'immutable'; +import {expect} from 'chai'; +import assetReducer from '../../../../client/coral-framework/reducers/asset'; +import * as actions from '../../../../client/coral-framework/constants/asset'; + +describe ('coral-embed-stream assetReducer', () => { + describe('UPDATE_COUNT_CACHE', () => { + it('should update the count cache', () => { + const action = { + type: actions.UPDATE_COUNT_CACHE, + id: '123', + count: 456 + }; + const store = new Map({}); + const result = assetReducer(store, action); + expect(result.getIn(['countCache', '123'])).to.equal(456); + }); + }); +}); diff --git a/test/client/coral-framework/reducers/notificationReducer.spec.js b/test/client/coral-framework/reducers/notificationReducer.spec.js new file mode 100644 index 000000000..40c50d11a --- /dev/null +++ b/test/client/coral-framework/reducers/notificationReducer.spec.js @@ -0,0 +1,35 @@ +import {Map} from 'immutable'; +import {expect} from 'chai'; +import notificationReducer from '../../../../client/coral-framework/reducers/notification'; +import * as actions from '../../../../client/coral-framework/actions/notification'; + +describe ('notificationsReducer', () => { + describe('ADD_NOTIFICATION', () => { + it('should add a notification', () => { + const action = { + type: actions.ADD_NOTIFICATION, + text: 'Test notification', + notifType: 'test' + }; + const store = new Map({}); + const result = notificationReducer(store, action); + expect(result.get('text')).to.equal(action.text); + expect(result.get('type')).to.equal(action.notifType); + }); + }); + + describe('CLEAR_NOTIFICATION', () => { + it('should clear a notification', () => { + const action = { + type: actions.CLEAR_NOTIFICATION + }; + const store = new Map({ + text: 'Test notification', + type: 'test' + }); + const result = notificationReducer(store, action); + expect(result.get('text')).to.equal(''); + expect(result.get('type')).to.equal(''); + }); + }); +});