diff --git a/src/components/icons/Help.js b/src/components/icons/Help.js new file mode 100644 index 00000000..72fcd68b --- /dev/null +++ b/src/components/icons/Help.js @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import { _extends } from './common'; + +export default function Help(props) { + return /* #__PURE__ */React.createElement('svg', _extends({ + width: 24, + height: 24, + viewBox: '0 0 24 24', + fill: 'none', + xmlns: 'http://www.w3.org/2000/svg', + }, props), /* #__PURE__ */React.createElement('path', { + d: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z', + fill: '#2D494E', + })); +} diff --git a/src/components/icons/People.jsx b/src/components/icons/People.jsx deleted file mode 100644 index 02808f14..00000000 --- a/src/components/icons/People.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -export default function People() { - return ( - - - - ); -} diff --git a/src/components/icons/Question.jsx b/src/components/icons/Question.jsx deleted file mode 100644 index ff050534..00000000 --- a/src/components/icons/Question.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; - -export default function Question() { - return ( - - - - - - - - - - - - ); -} diff --git a/src/components/icons/QuestionAnswer.js b/src/components/icons/QuestionAnswer.js new file mode 100644 index 00000000..62ea0911 --- /dev/null +++ b/src/components/icons/QuestionAnswer.js @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import { _extends } from './common'; + +export default function QuestionAnswer(props) { + return /* #__PURE__ */React.createElement('svg', _extends({ + width: 20, + height: 20, + viewBox: '0 0 20 20', + fill: 'none', + xmlns: 'http://www.w3.org/2000/svg', + }, props), /* #__PURE__ */React.createElement('path', { + d: 'M16.7371 4.00002H14.2371V11.5H3.4038V14H13.4038L16.7371 17.3334V4.00002ZM12.5705 9.83335V0.666687H0.0704651V13.1667L3.4038 9.83335H12.5705Z', + fill: 'currentColor', + })); +} diff --git a/src/components/icons/QuestionAnswer.jsx b/src/components/icons/QuestionAnswer.jsx deleted file mode 100644 index 3146afe0..00000000 --- a/src/components/icons/QuestionAnswer.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -export default function QuestionAnswer() { - return ( - - - - ); -} diff --git a/src/components/icons/QuestionAnswerOutline.js b/src/components/icons/QuestionAnswerOutline.js new file mode 100644 index 00000000..cdc944dc --- /dev/null +++ b/src/components/icons/QuestionAnswerOutline.js @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import { _extends } from './common'; + +export default function QuestionAnswerOutline(props) { + return /* #__PURE__ */React.createElement('svg', _extends({ + width: 20, + height: 20, + viewBox: '0 0 20 20', + fill: 'none', + xmlns: 'http://www.w3.org/2000/svg', + }, props), /* #__PURE__ */React.createElement('path', { + d: 'M 16.7371 4 H 14.2371 V 11.5 H 3.4038 V 14 H 13.4038 L 16.7371 17.3334 V 4 Z M 12.5705 9.8333 V 0.6667 H 0.0705 V 13.1667 L 3.4038 9.8333 H 12.5705 Z M 11.465 8.618 H 1.038 V 1.683 H 11.465Z', + fill: 'currentColor', + })); +} diff --git a/src/components/icons/QuestionAnswerOutline.jsx b/src/components/icons/QuestionAnswerOutline.jsx deleted file mode 100644 index f115c031..00000000 --- a/src/components/icons/QuestionAnswerOutline.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -export default function QuestionAnswerOutline() { - return ( - - - - ); -} diff --git a/src/components/icons/StarFilled.js b/src/components/icons/StarFilled.js new file mode 100644 index 00000000..2afce196 --- /dev/null +++ b/src/components/icons/StarFilled.js @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import { _extends } from './common'; + +export default function StarFilled(props) { + return /* #__PURE__ */React.createElement('svg', _extends({ + width: 20, + height: 20, + viewBox: '0 0 20 20', + fill: 'none', + xmlns: 'http://www.w3.org/2000/svg', + }, props), /* #__PURE__ */React.createElement('path', { + d: 'M8.4038 13.3917L13.5538 16.5L12.1871 10.6417L16.7371 6.70002L10.7455 6.19169L8.4038 0.666687L6.06213 6.19169L0.0704651 6.70002L4.62047 10.6417L3.2538 16.5L8.4038 13.3917Z', + fill: 'currentColor', + })); +} diff --git a/src/components/icons/StarFilled.jsx b/src/components/icons/StarFilled.jsx deleted file mode 100644 index 1eff3ed0..00000000 --- a/src/components/icons/StarFilled.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -export default function StarFilled() { - return ( - - - - ); -} diff --git a/src/components/icons/StarOutline.js b/src/components/icons/StarOutline.js new file mode 100644 index 00000000..f340015a --- /dev/null +++ b/src/components/icons/StarOutline.js @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import { _extends } from './common'; + +export default function StarOutline(props) { + return /* #__PURE__ */React.createElement('svg', _extends({ + width: 20, + height: 20, + viewBox: '0 0 20 20', + fill: 'none', + xmlns: 'http://www.w3.org/2000/svg', + }, props), /* #__PURE__ */React.createElement('path', { + d: 'M16.7371 6.69999L10.7455 6.18332L8.4038 0.666656L6.06213 6.19166L0.0704651 6.69999L4.62047 10.6417L3.2538 16.5L8.4038 13.3917L13.5538 16.5L12.1955 10.6417L16.7371 6.69999ZM8.4038 11.8333L5.27047 13.725L6.1038 10.1583L3.33713 7.75832L6.98713 7.44166L8.4038 4.08332L9.8288 7.44999L13.4788 7.76666L10.7121 10.1667L11.5455 13.7333L8.4038 11.8333Z', + fill: 'currentColor', + })); +} diff --git a/src/components/icons/StarOutline.jsx b/src/components/icons/StarOutline.jsx deleted file mode 100644 index 3e4fa397..00000000 --- a/src/components/icons/StarOutline.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -export default function StarOutline() { - return ( - - - - ); -} diff --git a/src/components/icons/ThumbUpFilled.js b/src/components/icons/ThumbUpFilled.js new file mode 100644 index 00000000..18d0da17 --- /dev/null +++ b/src/components/icons/ThumbUpFilled.js @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import { _extends } from './common'; + +export default function ThumbUpFilled(props) { + return /* #__PURE__ */React.createElement('svg', _extends({ + width: 20, + height: 20, + viewBox: '0 0 20 20', + fill: 'none', + xmlns: 'http://www.w3.org/2000/svg', + }, props), /* #__PURE__ */React.createElement('path', { + d: 'M11.2122 0.833344L5.23715 6.81668V17.5H15.4955L18.5705 10.3333V6.66668H11.6455L12.5788 2.18334L11.2122 0.833344ZM0.237152 7.50001H3.57049V17.5H0.237152V7.50001Z', + fill: 'currentColor', + })); +} diff --git a/src/components/icons/ThumbUpFilled.jsx b/src/components/icons/ThumbUpFilled.jsx deleted file mode 100644 index 51f9c555..00000000 --- a/src/components/icons/ThumbUpFilled.jsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from 'react'; - -export default function ThumbUpFilled() { - return ( - - - - ); -} diff --git a/src/components/icons/ThumbUpOutline.js b/src/components/icons/ThumbUpOutline.js new file mode 100644 index 00000000..9870c900 --- /dev/null +++ b/src/components/icons/ThumbUpOutline.js @@ -0,0 +1,16 @@ +import * as React from 'react'; + +import { _extends } from './common'; + +export default function ThumbUpOutline(props) { + return /* #__PURE__ */React.createElement('svg', _extends({ + width: 20, + height: 20, + viewBox: '0 0 20 20', + fill: 'none', + xmlns: 'http://www.w3.org/2000/svg', + }, props), /* #__PURE__ */React.createElement('path', { + d: 'M18.5705 6.66668V10.3333L15.4955 17.5L5.23715 17.5L5.23715 6.81668L11.2122 0.833344L12.5788 2.18334L11.6455 6.66668L18.5705 6.66668ZM6.90382 7.50834L6.90382 15.8333L14.3955 15.8333L16.9038 9.99168V8.33334L9.59548 8.33334L10.5205 3.88334L6.90382 7.50834Z M3.57049 17.5H0.237152L0.237152 7.50001H3.57049L3.57049 17.5Z', + fill: 'currentColor', + })); +} diff --git a/src/components/icons/ThumbUpOutline.jsx b/src/components/icons/ThumbUpOutline.jsx deleted file mode 100644 index b4c17c9c..00000000 --- a/src/components/icons/ThumbUpOutline.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -export default function ThumbUpOutline() { - return ( - - - - - ); -} diff --git a/src/components/icons/common.js b/src/components/icons/common.js new file mode 100644 index 00000000..7e30aae0 --- /dev/null +++ b/src/components/icons/common.js @@ -0,0 +1,21 @@ +/* eslint-disable no-underscore-dangle */ +/* eslint-disable no-func-assign */ +/* eslint-disable prefer-object-spread */ +/* eslint-disable prefer-rest-params */ +/* eslint-disable no-param-reassign */ +/* eslint-disable no-restricted-syntax */ +// eslint-disable-next-line import/prefer-default-export +export function _extends() { + _extends = Object.assign || function (target) { + for (let i = 1; i < arguments.length; i++) { + const source = arguments[i]; + for (const key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target; + }; + return _extends.apply(this, arguments); +} diff --git a/src/components/icons/index.js b/src/components/icons/index.js index 27d2ff35..6948c86c 100644 --- a/src/components/icons/index.js +++ b/src/components/icons/index.js @@ -1,5 +1,4 @@ -export { default as People } from './People'; -export { default as Question } from './Question'; +export { default as Help } from './Help'; export { default as QuestionAnswer } from './QuestionAnswer'; export { default as QuestionAnswerOutline } from './QuestionAnswerOutline'; export { default as StarFilled } from './StarFilled'; diff --git a/src/discussions/common/AuthorLabel.jsx b/src/discussions/common/AuthorLabel.jsx index ba07a354..c0dcded1 100644 --- a/src/discussions/common/AuthorLabel.jsx +++ b/src/discussions/common/AuthorLabel.jsx @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import capitalize from 'lodash/capitalize'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { Icon } from '@edx/paragon'; @@ -19,7 +18,6 @@ function AuthorLabel({ }) { let icon = null; let authorLabelMessage = null; - if (authorLabel === 'Staff') { icon = Institution; authorLabelMessage = intl.formatMessage(messages.authorLabelStaff); @@ -28,15 +26,9 @@ function AuthorLabel({ icon = School; authorLabelMessage = intl.formatMessage(messages.authorLabelTA); } - - const fontWeight = authorLabelMessage ? 'font-weight-500' : 'font-weight-normal text-primary-500'; - const className = classNames('d-flex align-items-center', labelColor); - const labelContents = ( <> - - {capitalize(author)} - + {author} {icon && ( )} {authorLabelMessage && ( - + {authorLabelMessage} )} ); - + const className = classNames('d-flex align-items-center', labelColor); return linkToProfile ? React.createElement('a', { href: '#nowhere', className }, labelContents) : React.createElement('div', { className }, labelContents); diff --git a/src/discussions/common/time-locale.js b/src/discussions/common/time-locale.js index cea761c8..4e955aaa 100644 --- a/src/discussions/common/time-locale.js +++ b/src/discussions/common/time-locale.js @@ -11,8 +11,8 @@ export default function timeLocale(number, index, totalSec) { ['%sd', 'in %s days'], ['1w', 'in 1 week'], ['%sw', 'in %s weeks'], - ['1m', 'in 1 month'], - ['%sm', 'in %s months'], + ['1M', 'in 1 month'], + ['%sM', 'in %s months'], ['1y', 'in 1 year'], ['%sy', 'in %s years'], ][index]; diff --git a/src/discussions/posts/PostsView.test.jsx b/src/discussions/posts/PostsView.test.jsx index c6ef28e2..d213dbc8 100644 --- a/src/discussions/posts/PostsView.test.jsx +++ b/src/discussions/posts/PostsView.test.jsx @@ -114,21 +114,18 @@ describe('PostsView', () => { }); expect(screen.getAllByText(/this is thread-\d+/i)).toHaveLength(threadCount); }); - test('displays a list of user posts', async () => { await act(async () => { await renderComponent({ myPosts: true }); }); - expect(screen.getAllByText('Abc123')).toHaveLength(threadCount); + expect(screen.getAllByText('abc123')).toHaveLength(threadCount); }); - test('displays a list of posts in a topic', async () => { await act(async () => { await renderComponent({ topicId: 'some-topic-1' }); }); expect(screen.getAllByText(/this is thread-\d+ in topic some-topic-1/i)).toHaveLength(Math.ceil(threadCount / 3)); }); - test('displays a list of posts in a category', async () => { await act(async () => { await renderComponent({ category: 'test-usage-key' }); diff --git a/src/discussions/posts/post/LikeButton.jsx b/src/discussions/posts/post/LikeButton.jsx index 1baac194..14d54582 100644 --- a/src/discussions/posts/post/LikeButton.jsx +++ b/src/discussions/posts/post/LikeButton.jsx @@ -2,7 +2,9 @@ import React from 'react'; import PropTypes from 'prop-types'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { Icon, IconButtonWithTooltip } from '@edx/paragon'; +import { + Icon, IconButton, OverlayTrigger, Tooltip, +} from '@edx/paragon'; import { ThumbUpFilled, ThumbUpOutline } from '../../../components/icons'; import messages from './messages'; @@ -22,19 +24,23 @@ function LikeButton({ }; return ( -
- +
+ + {intl.formatMessage(voted ? messages.removeLike : messages.like)} + + )} + > + + {(count && count > 0) ? count : null}
); diff --git a/src/discussions/posts/post/PostFooter.jsx b/src/discussions/posts/post/PostFooter.jsx index ead2436c..237c8b68 100644 --- a/src/discussions/posts/post/PostFooter.jsx +++ b/src/discussions/posts/post/PostFooter.jsx @@ -6,14 +6,13 @@ import * as timeago from 'timeago.js'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { - Badge, Icon, IconButtonWithTooltip, OverlayTrigger, Tooltip, + Badge, Icon, IconButton, OverlayTrigger, Tooltip, } from '@edx/paragon'; import { - Locked, + Locked, People, } from '@edx/paragon/icons'; import { - People, QuestionAnswer, QuestionAnswerOutline, StarFilled, @@ -32,7 +31,6 @@ function PostFooter({ }) { const dispatch = useDispatch(); timeago.register('time-locale', timeLocale); - return (
dispatch(updateExistingThread(post.id, { voted: !post.voted }))} voted={post.voted} /> - { - dispatch(updateExistingThread(post.id, { following: !post.following })); - return true; - }} - size="inline" - className="p-3" - iconClassNames="icon-size" - /> - {preview && post.commentCount > 1 && ( -
- - {post.commentCount} -
- )} - {preview && post?.unreadCommentCount > 0 && post.commentCount > 1 && ( - - {intl.formatMessage(messages.newLabel, { count: post.unreadCommentCount })} - - )} -
- {post.groupId && ( + + {intl.formatMessage(post.following ? messages.unfollow : messages.follow)} + + )} + > + { + dispatch(updateExistingThread(post.id, { following: !post.following })); + return true; + }} + alt="Follow" + iconAs={Icon} + size="inline" + src={post.following ? StarFilled : StarOutline} + /> + + {preview && post.commentCount > 1 + && ( <> - {post.groupName} - )} - > - - - - - - · + + + {post.commentCount} )} + {post.unreadCommentCount && post.unreadCommentCount > 0 && post.commentCount > 1 ? ( + {intl.formatMessage(messages.newLabel, { count: post.unreadCommentCount })} + ) : null} +
+ { + post.groupId + ? ( + <> + + {post.groupName || intl.formatMessage(messages.visibleToAll)} + + )} + > + + + + · + + + ) : null + } {timeago.format(post.createdAt, 'time-locale')} diff --git a/src/discussions/posts/post/PostFooter.test.jsx b/src/discussions/posts/post/PostFooter.test.jsx index 1655d73b..27af98bd 100644 --- a/src/discussions/posts/post/PostFooter.test.jsx +++ b/src/discussions/posts/post/PostFooter.test.jsx @@ -61,7 +61,7 @@ describe('PostFooter', () => { }); it("shows 'x new' badge for new comments", () => { - renderComponent(mockPost, true); + renderComponent(mockPost); expect(screen.getByText('2 New')).toBeTruthy(); }); @@ -84,7 +84,6 @@ describe('PostFooter', () => { renderComponent({ ...mockPost, groupId: 5, groupName: 'Test Cohort' }); expect(screen.getByTestId('cohort-icon')).toBeTruthy(); }); - it.each([[true, /unfollow/i], [false, /follow/i]])('test follow button when following=%s', async (following, message) => { renderComponent({ ...mockPost, following }); const followButton = screen.getByRole('button', { name: /follow/i }); diff --git a/src/discussions/posts/post/PostHeader.jsx b/src/discussions/posts/post/PostHeader.jsx index b1127327..0d7f98e5 100644 --- a/src/discussions/posts/post/PostHeader.jsx +++ b/src/discussions/posts/post/PostHeader.jsx @@ -6,7 +6,7 @@ import { useSelector } from 'react-redux'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { Avatar, Badge, Icon } from '@edx/paragon'; -import { Question } from '../../../components/icons'; +import { Help } from '../../../components/icons'; import { AvatarBorderAndLabelColors, ThreadType } from '../../../data/constants'; import { ActionsDropdown, AuthorLabel } from '../../common'; import { selectAuthorAvatars } from '../data/selectors'; @@ -16,37 +16,31 @@ import { postShape } from './proptypes'; export function PostAvatar({ post, authorLabel, fromPostLink }) { const authorAvatars = useSelector(selectAuthorAvatars(post.author)); const borderColor = AvatarBorderAndLabelColors[authorLabel]; - return ( -
- {post.type === ThreadType.QUESTION && ( +
+
+ {post.type === ThreadType.QUESTION && ( - )} - + )} + +
); } diff --git a/src/discussions/posts/post/PostLink.jsx b/src/discussions/posts/post/PostLink.jsx index 8eaf3ea4..35441f0b 100644 --- a/src/discussions/posts/post/PostLink.jsx +++ b/src/discussions/posts/post/PostLink.jsx @@ -39,11 +39,11 @@ function PostLink({ const authorLabelColor = AvatarBorderAndLabelColors[post.authorLabel]; return ( isSelected(post.id)} - style={{ lineHeight: '21px' }} > {post.pinned && (
@@ -52,53 +52,44 @@ function PostLink({
)}
-
-
-
-
- {post.title} +
+
+
+
+
+ {post.title} +
+ {showAnsweredBadge + && ( +
+ {intl.formatMessage(messages.answered)} + {' '}answered +
+ )} + + {(post.abuseFlagged || post.abuseFlaggedCount) + && ( +
+ {intl.formatMessage(messages.contentReported)} + {' '}reported +
+ )}
- - {showAnsweredBadge && ( - - {intl.formatMessage(messages.answered)} - {' '}answered - - )} - - {(post.abuseFlagged || post.abuseFlaggedCount) && ( - - {intl.formatMessage(messages.contentReported)} - {' '}reported - - )} +
- -
+
{isPostPreviewAvailable(post.previewBody) ? post.previewBody : intl.formatMessage(messages.postWithoutPreview)} diff --git a/src/discussions/posts/post/messages.js b/src/discussions/posts/post/messages.js index ad376b73..8d8764e5 100644 --- a/src/discussions/posts/post/messages.js +++ b/src/discussions/posts/post/messages.js @@ -33,8 +33,8 @@ const messages = defineMessages({ defaultMessage: 'Answered', description: 'Tooltip/alttext for button to unfollow a discussion post', }, - unFollow: { - id: 'discussions.post.unFollow', + unfollow: { + id: 'discussions.post.unfollow', defaultMessage: 'Unfollow', description: 'Tooltip/alttext for button to unfollow a discussion post', }, @@ -45,14 +45,9 @@ const messages = defineMessages({ }, removeLike: { id: 'discussions.post.removeLike', - defaultMessage: 'Unlike', + defaultMessage: 'Remove like', description: 'Tooltip/alttext for button to remove the like applied to a discussion post', }, - viewActivity: { - id: 'discussions.post.viewActivity', - defaultMessage: 'View Activity', - description: 'Tooltip/alttext for button to view the activity of a discussion post', - }, postClosed: { id: 'discussions.post.closed', defaultMessage: 'Post closed for responses and comments', @@ -63,6 +58,11 @@ const messages = defineMessages({ defaultMessage: 'Related to', description: 'Message followed the category and topic of post linking to in-course context', }, + visibleToAll: { + id: 'discussions.post.cohort.everyone', + defaultMessage: 'Everyone', + description: 'Cohort visibility indicator for all people', + }, deletePostTitle: { id: 'discussions.editor.delete.post.title', defaultMessage: 'Delete post', diff --git a/src/index.scss b/src/index.scss index ad40eb5e..4f289cf1 100755 --- a/src/index.scss +++ b/src/index.scss @@ -6,9 +6,8 @@ $fa-font-path: "~font-awesome/fonts"; @import "~font-awesome/scss/font-awesome"; -#post, -#comment, -#reply { + +#post, #comment, #reply { img { height: auto; max-width: 100%; @@ -23,10 +22,6 @@ $fa-font-path: "~font-awesome/fonts"; border-color: #998200; } -.border-anonymous { - border-color: #F2F0EF; -} - .font-size-14 { font-size: 14px; } @@ -40,23 +35,5 @@ $fa-font-path: "~font-awesome/fonts"; } .font-family-inter { - font-family: "Inter"; -} - -.icon-size { - height: 20px !important; - width: 20px !important; -} - -.mr-0\.5 { - margin-right: 2px; -} - -.badge-padding { - padding-top: 1px; - padding-bottom: 1px -} - -.discussion-post:hover { - background-color: unset !important; -} + font-family: 'Inter'; +} \ No newline at end of file