diff --git a/src/discussions/common/AlertBanner.jsx b/src/discussions/common/AlertBanner.jsx index 3c2a96e7..1027faee 100644 --- a/src/discussions/common/AlertBanner.jsx +++ b/src/discussions/common/AlertBanner.jsx @@ -65,7 +65,7 @@ function AlertBanner({
{intl.formatMessage(messages.editedBy)} - + {intl.formatMessage(messages.reason)}: {content.lastEdit.reason}
@@ -76,7 +76,7 @@ function AlertBanner({
{intl.formatMessage(messages.closedBy)} - + {intl.formatMessage(messages.reason)}: {content.closeReason} diff --git a/src/discussions/common/AuthorLabel.jsx b/src/discussions/common/AuthorLabel.jsx index a58ed76f..001c9c88 100644 --- a/src/discussions/common/AuthorLabel.jsx +++ b/src/discussions/common/AuthorLabel.jsx @@ -1,14 +1,18 @@ -import React from 'react'; +import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import capitalize from 'lodash/capitalize'; +import { Link, useLocation } from 'react-router-dom'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { Icon } from '@edx/paragon'; import { Institution, School } from '@edx/paragon/icons'; +import { Routes } from '../../data/constants'; import messages from '../messages'; +import { discussionsPath } from '../utils'; +import { DiscussionContext } from './context'; function AuthorLabel({ intl, @@ -17,6 +21,8 @@ function AuthorLabel({ linkToProfile, labelColor, }) { + const location = useLocation(); + const { courseId } = useContext(DiscussionContext); let icon = null; let authorLabelMessage = null; @@ -33,8 +39,12 @@ function AuthorLabel({ const className = classNames('d-flex align-items-center', labelColor); const labelContents = ( - <> - +
+ {capitalize(author)} {icon && ( @@ -54,16 +64,25 @@ function AuthorLabel({ {authorLabelMessage} )} - +
); return linkToProfile - ? React.createElement('a', { href: '#nowhere', className }, labelContents) - : React.createElement('div', { className }, labelContents); + ? ( + + {labelContents} + + ) + : <>{labelContents}; } AuthorLabel.propTypes = { - intl: intlShape, + intl: intlShape.isRequired, author: PropTypes.string.isRequired, authorLabel: PropTypes.string, linkToProfile: PropTypes.bool, diff --git a/src/discussions/discussions-home/DiscussionSidebar.test.jsx b/src/discussions/discussions-home/DiscussionSidebar.test.jsx index 1dccc6de..2158c5a2 100644 --- a/src/discussions/discussions-home/DiscussionSidebar.test.jsx +++ b/src/discussions/discussions-home/DiscussionSidebar.test.jsx @@ -11,6 +11,7 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; import { AppProvider } from '@edx/frontend-platform/react'; import { initializeStore } from '../../store'; +import { DiscussionContext } from '../common/context'; import { fetchConfigSuccess } from '../data/slices'; import { threadsApiUrl } from '../posts/data/api'; import DiscussionSidebar from './DiscussionSidebar'; @@ -27,9 +28,11 @@ function renderComponent(displaySidebar = true, location = `/${courseId}/`) { - - - + + + + + , diff --git a/src/discussions/learners/LearnerPostsView.jsx b/src/discussions/learners/LearnerPostsView.jsx index 956c0fe7..828c01e3 100644 --- a/src/discussions/learners/LearnerPostsView.jsx +++ b/src/discussions/learners/LearnerPostsView.jsx @@ -20,7 +20,6 @@ import { import NoResults from '../posts/NoResults'; import { PostLink } from '../posts/post'; import { discussionsPath } from '../utils'; -import { selectLearnerProfile } from './data/selectors'; import { fetchUserPosts } from './data/thunks'; import messages from './messages'; @@ -33,14 +32,13 @@ function LearnerPostsView({ intl }) { const loadingStatus = useSelector(threadsLoadingStatus()); const { courseId, learnerUsername: username } = useContext(DiscussionContext); const nextPage = useSelector(selectThreadNextPage()); - const { id: userId } = useSelector(selectLearnerProfile(username)); useEffect(() => { - dispatch(fetchUserPosts(courseId, username, userId)); + dispatch(fetchUserPosts(courseId, username)); }, [courseId, username]); const loadMorePosts = () => ( - dispatch(fetchUserPosts(courseId, username, userId, { + dispatch(fetchUserPosts(courseId, username, { page: nextPage, })) ); @@ -57,11 +55,11 @@ function LearnerPostsView({ intl }) { return (
- + ); } - return (); + return (); }); return ( @@ -89,10 +87,10 @@ function LearnerPostsView({ intl }) {
) : ( - nextPage && ( - + nextPage && loadingStatus === RequestStatus.SUCCESSFUL && ( + ) )}
diff --git a/src/discussions/learners/LearnersView.jsx b/src/discussions/learners/LearnersView.jsx index 71e1f088..e51f40ab 100644 --- a/src/discussions/learners/LearnersView.jsx +++ b/src/discussions/learners/LearnersView.jsx @@ -66,7 +66,7 @@ function LearnersView({ intl }) { ) : ( - nextPage && ( + nextPage && loadingStatus === RequestStatus.SUCCESSFUL && ( diff --git a/src/discussions/learners/data/api.js b/src/discussions/learners/data/api.js index 3419acce..5aca91d3 100644 --- a/src/discussions/learners/data/api.js +++ b/src/discussions/learners/data/api.js @@ -45,10 +45,10 @@ export async function getUserProfiles(usernames) { * pagination: {count, num_pages, next, previous} * } */ -export async function getUserPosts(courseId, userId, { page }) { +export async function getUserPosts(courseId, username, { page }) { const learnerPostsApiUrl = `${coursesApiUrl}${courseId}/learner/`; const { data } = await getAuthenticatedHttpClient() - .get(learnerPostsApiUrl, { params: { user_id: userId, page } }); + .get(learnerPostsApiUrl, { params: { username, page } }); return data; } diff --git a/src/discussions/learners/data/selectors.js b/src/discussions/learners/data/selectors.js index 15926553..fae8940c 100644 --- a/src/discussions/learners/data/selectors.js +++ b/src/discussions/learners/data/selectors.js @@ -25,5 +25,3 @@ export const selectLearner = (username) => createSelector( [selectAllLearners], learners => learners.find(l => l.username === username) || {}, ); - -export const selectLearnerProfile = (username) => state => state.learners.learnerProfiles[username] || {}; diff --git a/src/discussions/learners/data/thunks.js b/src/discussions/learners/data/thunks.js index 33718eca..094a25a2 100644 --- a/src/discussions/learners/data/thunks.js +++ b/src/discussions/learners/data/thunks.js @@ -59,16 +59,16 @@ export function fetchLearners(courseId, { * redux state * * @param {string} courseId Course ID of the course eg., course-v1:X+Y+Z - * @param {string} userId userId of the learner + * @param {string} username name of the learner * @param page * @returns a promise that will update the state with the learner's posts */ -export function fetchUserPosts(courseId, username, userId, { page = 1 } = {}) { +export function fetchUserPosts(courseId, username, { page = 1 } = {}) { return async (dispatch) => { try { dispatch(fetchLearnerThreadsRequest({ courseId, author: username })); - const data = await getUserPosts(courseId, userId, { page }); + const data = await getUserPosts(courseId, username, { page }); const normalisedData = normaliseThreads(camelCaseObject(data)); dispatch(fetchThreadsSuccess({ ...normalisedData, page, author: username })); diff --git a/src/discussions/posts/PostsList.jsx b/src/discussions/posts/PostsList.jsx index d4e43223..a04d9556 100644 --- a/src/discussions/posts/PostsList.jsx +++ b/src/discussions/posts/PostsList.jsx @@ -79,7 +79,7 @@ function PostsList({ posts, topics, intl }) { ) : ( - nextPage && ( + nextPage && loadingStatus === RequestStatus.SUCCESSFUL && ( diff --git a/src/discussions/posts/data/slices.js b/src/discussions/posts/data/slices.js index 12a82ef4..5344fe5b 100644 --- a/src/discussions/posts/data/slices.js +++ b/src/discussions/posts/data/slices.js @@ -43,6 +43,7 @@ const threadsSlice = createSlice({ if (state.author !== payload.author) { state.pages = []; state.author = payload.author; + state.totalThreads = null; } state.status = RequestStatus.IN_PROGRESS; }, diff --git a/src/discussions/posts/post/PostLink.jsx b/src/discussions/posts/post/PostLink.jsx index 617a954c..e4818173 100644 --- a/src/discussions/posts/post/PostLink.jsx +++ b/src/discussions/posts/post/PostLink.jsx @@ -21,6 +21,7 @@ function PostLink({ post, isSelected, intl, + learnerTab, }) { const { page, @@ -72,7 +73,7 @@ function PostLink({ className={ classNames('text-truncate font-weight-500 font-size-14 text-primary-500 font-style-normal font-family-inter', { 'font-weight-bolder': !post.read }) -} + } > {post.title} @@ -100,6 +101,7 @@ function PostLink({ author={post.author || intl.formatMessage(messages.anonymous)} authorLabel={post.authorLabel} labelColor={authorLabelColor && `text-${authorLabelColor}`} + linkToProfile={!learnerTab && post.author} />
- true} /> + + true} learnerTab={learnerTab} /> + , ); @@ -65,3 +69,30 @@ describe('PostFooter', () => { expect(screen.getByTestId('reported-post')).toBeTruthy(); }); }); + +describe('Post username', () => { + beforeEach(async () => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + }); + + it.each([ + true, + false, + ])('is a clickable link %s', (leanerTab) => { + renderComponent(mockPost, leanerTab); + + if (leanerTab) { + expect(screen.queryByTestId('learner-posts-link')).not.toBeInTheDocument(); + } else { + expect(screen.queryByTestId('learner-posts-link')).toBeInTheDocument(); + } + }); +});