Skip to content

Commit d738b6f

Browse files
Merge branch 'master' into keblysh/feat/user-avatar-master
2 parents 9367409 + b5d036a commit d738b6f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1402
-1101
lines changed

package-lock.json

+670-475
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+12-12
Original file line numberDiff line numberDiff line change
@@ -34,34 +34,34 @@
3434
},
3535
"dependencies": {
3636
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
37-
"@edx/frontend-component-footer": "12.5.1",
38-
"@edx/frontend-component-header": "4.9.1",
39-
"@edx/frontend-platform": "4.6.3",
40-
"@edx/paragon": "20.44.0",
41-
"@reduxjs/toolkit": "1.8.0",
37+
"@edx/frontend-component-footer": "12.6.1",
38+
"@edx/frontend-component-header": "4.10.1",
39+
"@edx/frontend-platform": "5.6.1",
40+
"@edx/paragon": "20.46.3",
41+
"@reduxjs/toolkit": "1.9.7",
4242
"@tinymce/tinymce-react": "3.13.1",
4343
"babel-polyfill": "6.26.0",
4444
"classnames": "2.3.2",
4545
"core-js": "3.21.1",
4646
"dompurify": "^2.4.3",
47-
"formik": "2.2.9",
47+
"formik": "2.4.5",
4848
"lodash.snakecase": "4.1.1",
4949
"prop-types": "15.8.1",
5050
"raw-loader": "4.0.2",
5151
"react": "17.0.2",
5252
"react-dom": "17.0.2",
5353
"react-redux": "7.2.9",
54-
"react-router": "5.2.1",
55-
"react-router-dom": "5.3.0",
56-
"redux": "4.1.2",
57-
"regenerator-runtime": "0.13.9",
54+
"react-router": "6.18.0",
55+
"react-router-dom": "6.18.0",
56+
"redux": "4.2.1",
57+
"regenerator-runtime": "0.14.1",
5858
"timeago.js": "4.0.2",
5959
"tinymce": "5.10.7",
6060
"yup": "0.31.1"
6161
},
6262
"devDependencies": {
6363
"@edx/browserslist-config": "1.2.0",
64-
"@edx/frontend-build": "13.0.5",
64+
"@edx/frontend-build": "13.0.14",
6565
"@edx/reactifex": "1.1.0",
6666
"@testing-library/jest-dom": "5.17.0",
6767
"@testing-library/react": "12.1.5",
@@ -72,6 +72,6 @@
7272
"glob": "7.2.0",
7373
"husky": "7.0.4",
7474
"jest": "27.5.1",
75-
"rosie": "2.1.0"
75+
"rosie": "2.1.1"
7676
}
7777
}

src/components/TinyMCEEditor.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useCallback, useEffect, useState } from 'react';
22

33
import { Editor } from '@tinymce/tinymce-react';
4-
import { useLocation, useParams } from 'react-router';
4+
import { useLocation, useParams } from 'react-router-dom';
55
// TinyMCE so the global var exists
66
// eslint-disable-next-line no-unused-vars,import/no-extraneous-dependencies
77
import tinymce from 'tinymce/tinymce';

src/data/constants.js

+25-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { getConfig } from '@edx/frontend-platform';
22

33
export const getApiBaseUrl = () => getConfig().LMS_BASE_URL;
4+
export const getFullUrl = (path) => (
5+
new URL(`${getConfig().PUBLIC_PATH.replace(/\/$/, '')}/${path}`, window.location.origin).href
6+
);
47

58
/**
69
* Enum for thread types.
@@ -137,25 +140,24 @@ export const DiscussionProvider = {
137140
OPEN_EDX: 'openedx',
138141
};
139142

140-
const BASE_PATH = `${getConfig().PUBLIC_PATH}:courseId`;
143+
const BASE_PATH = '/:courseId';
141144

142145
export const Routes = {
143146
DISCUSSIONS: {
144147
PATH: BASE_PATH,
145148
},
146149
LEARNERS: {
147-
PATH: `${BASE_PATH}/learners`,
148-
POSTS: `${BASE_PATH}/learners/:learnerUsername/posts(/:postId)?`,
150+
PATH: `${BASE_PATH}/learners/:learnerUsername?`,
151+
POSTS: `${BASE_PATH}/learners/:learnerUsername/posts/:postId?`,
152+
POSTS_EDIT: `${BASE_PATH}/learners/:learnerUsername/posts/:postId/edit`,
149153
},
150154
POSTS: {
151155
PATH: `${BASE_PATH}/topics/:topicId`,
152-
MY_POSTS: `${BASE_PATH}/my-posts(/:postId)?`,
153-
ALL_POSTS: `${BASE_PATH}/posts(/:postId)?`,
154-
NEW_POST: [
155-
`${BASE_PATH}/topics/:topicId/posts/:postId`,
156-
`${BASE_PATH}/topics/:topicId`,
157-
`${BASE_PATH}`,
158-
],
156+
MY_POSTS: `${BASE_PATH}/my-posts/:postId?`,
157+
ALL_POSTS: `${BASE_PATH}/posts/:postId?`,
158+
EDIT_MY_POSTS: `${BASE_PATH}/my-posts/:postId/edit`,
159+
EDIT_ALL_POSTS: `${BASE_PATH}/posts/:postId/edit`,
160+
NEW_POST: `${BASE_PATH}/*`,
159161
EDIT_POST: [
160162
`${BASE_PATH}/category/:category/posts/:postId/edit`,
161163
`${BASE_PATH}/topics/:topicId/posts/:postId/edit`,
@@ -166,19 +168,19 @@ export const Routes = {
166168
},
167169
COMMENTS: {
168170
PATH: [
169-
`${BASE_PATH}/category/:category/posts/:postId`,
170-
`${BASE_PATH}/topics/:topicId/posts/:postId`,
171+
`${BASE_PATH}/category/:category/posts/:postId?`,
172+
`${BASE_PATH}/topics/:topicId/posts/:postId?`,
171173
`${BASE_PATH}/posts/:postId`,
172174
`${BASE_PATH}/my-posts/:postId`,
173-
`${BASE_PATH}/learners/:learnerUsername/posts/:postId`,
175+
`${BASE_PATH}/learners/:learnerUsername/posts/:postId?`,
174176
],
175-
PAGE: `${BASE_PATH}/:page`,
177+
PAGE: `${BASE_PATH}/:page/*`,
176178
PAGES: {
177-
category: `${BASE_PATH}/category/:category/posts/:postId`,
178-
topics: `${BASE_PATH}/topics/:topicId/posts/:postId`,
179+
category: `${BASE_PATH}/category/:category/posts/:postId?`,
180+
topics: `${BASE_PATH}/topics/:topicId/posts/:postId?`,
179181
posts: `${BASE_PATH}/posts/:postId`,
180182
'my-posts': `${BASE_PATH}/my-posts/:postId`,
181-
learners: `${BASE_PATH}/learners/:learnerUsername/posts/:postId`,
183+
learners: `${BASE_PATH}/learners/:learnerUsername/posts/:postId?`,
182184
},
183185
},
184186
TOPICS: {
@@ -189,9 +191,10 @@ export const Routes = {
189191
],
190192
ALL: `${BASE_PATH}/topics`,
191193
CATEGORY: `${BASE_PATH}/category/:category`,
192-
CATEGORY_POST: `${BASE_PATH}/category/:category/posts/:postId`,
194+
CATEGORY_POST: `${BASE_PATH}/category/:category/posts/:postId?`,
195+
CATEGORY_POST_EDIT: `${BASE_PATH}/category/:category/posts/:postId/edit`,
193196
TOPIC: `${BASE_PATH}/topics/:topicId`,
194-
TOPIC_POST: `${BASE_PATH}/topics/:topicId/posts/:postId`,
197+
TOPIC_POST: `${BASE_PATH}/topics/:topicId/posts/:postId?`,
195198
TOPIC_POST_EDIT: `${BASE_PATH}/topics/:topicId/posts/:postId/edit`,
196199
},
197200
};
@@ -205,11 +208,12 @@ export const PostsPages = {
205208
};
206209

207210
export const ALL_ROUTES = []
208-
.concat([Routes.TOPICS.CATEGORY_POST, Routes.TOPICS.CATEGORY])
211+
.concat([Routes.TOPICS.CATEGORY_POST, `${Routes.TOPICS.CATEGORY}?`])
209212
.concat(Routes.COMMENTS.PATH)
210213
.concat(Routes.TOPICS.PATH)
214+
.concat(Routes.POSTS.EDIT_POST)
211215
.concat([Routes.POSTS.ALL_POSTS, Routes.POSTS.MY_POSTS])
212216
.concat([Routes.LEARNERS.POSTS, Routes.LEARNERS.PATH])
213-
.concat([Routes.DISCUSSIONS.PATH]);
217+
.concat([`${Routes.DISCUSSIONS.PATH}/*`]);
214218

215219
export const MAX_UPLOAD_FILE_SIZE = 1024;

src/discussions/common/AlertBanner.jsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { Report } from '@edx/paragon/icons';
1010

1111
import { AvatarOutlineAndLabelColors } from '../../data/constants';
1212
import {
13-
selectModerationSettings, selectUserHasModerationPrivileges, selectUserIsGroupTa, selectUserIsStaff,
13+
selectUserHasModerationPrivileges, selectUserIsGroupTa, selectUserIsStaff,
1414
} from '../data/selectors';
1515
import messages from '../post-comments/messages';
1616
import AlertBar from './AlertBar';
@@ -29,7 +29,6 @@ const AlertBanner = ({
2929
const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges);
3030
const userIsGroupTa = useSelector(selectUserIsGroupTa);
3131
const userIsGlobalStaff = useSelector(selectUserIsStaff);
32-
const { reasonCodesEnabled } = useSelector(selectModerationSettings);
3332
const userIsContentAuthor = getAuthenticatedUser().username === author;
3433
const canSeeReportedBanner = abuseFlagged;
3534
const canSeeLastEditOrClosedAlert = (userHasModerationPrivileges || userIsGroupTa
@@ -45,7 +44,7 @@ const AlertBanner = ({
4544
{intl.formatMessage(messages.abuseFlaggedMessage)}
4645
</Alert>
4746
)}
48-
{reasonCodesEnabled && canSeeLastEditOrClosedAlert && (
47+
{ canSeeLastEditOrClosedAlert && (
4948
<>
5049
{lastEdit?.reason && (
5150
<AlertBar

src/discussions/common/AlertBanner.test.jsx

-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ describe.each([
9090
store = initializeStore({
9191
config: {
9292
hasModerationPrivileges: true,
93-
reasonCodesEnabled: true,
9493
},
9594
});
9695
const content = buildTestContent(type, props);

src/discussions/common/AuthorLabel.jsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import React, { useContext, useMemo } from 'react';
22
import PropTypes from 'prop-types';
33

44
import classNames from 'classnames';
5-
import { generatePath } from 'react-router';
6-
import { Link } from 'react-router-dom';
5+
import { generatePath, Link } from 'react-router-dom';
76
import * as timeago from 'timeago.js';
87

98
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -51,7 +50,7 @@ const AuthorLabel = ({
5150

5251
const authorName = useMemo(() => (
5352
<span
54-
className={classNames('mr-1.5 font-size-14 font-style font-weight-500', {
53+
className={classNames('mr-1.5 font-size-14 font-style font-weight-500 author-name', {
5554
'text-gray-700': isRetiredUser,
5655
'text-primary-500': !authorLabelMessage && !isRetiredUser,
5756
})}

src/discussions/common/EndorsedAlertBanner.test.jsx

-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ describe.each([
8484
store = initializeStore({
8585
config: {
8686
hasModerationPrivileges: true,
87-
reasonCodesEnabled: true,
8887
},
8988
});
9089
const content = buildTestContent(type, props);

src/discussions/common/HoverCard.test.jsx

+3-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
} from '@testing-library/react';
44
import MockAdapter from 'axios-mock-adapter';
55
import { IntlProvider } from 'react-intl';
6-
import { MemoryRouter, Route } from 'react-router';
6+
import { MemoryRouter } from 'react-router-dom';
77
import { Factory } from 'rosie';
88

99
import { initializeMockApp } from '@edx/frontend-platform';
@@ -60,15 +60,12 @@ async function mockAxiosReturnPagedCommentsResponses() {
6060
function renderComponent(postId) {
6161
const wrapper = render(
6262
<IntlProvider locale="en">
63-
<AppProvider store={store}>
63+
<AppProvider store={store} wrapWithRouter={false}>
6464
<DiscussionContext.Provider
65-
value={{ courseId, postId }}
65+
value={{ courseId, postId, page: 'posts' }}
6666
>
6767
<MemoryRouter initialEntries={[`/${courseId}/posts/${postId}`]}>
6868
<DiscussionContent />
69-
<Route
70-
path="*"
71-
/>
7269
</MemoryRouter>
7370
</DiscussionContext.Provider>
7471
</AppProvider>

src/discussions/data/hooks.js

+13-11
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import {
44
} from 'react';
55

66
import { useDispatch, useSelector } from 'react-redux';
7-
import { useHistory, useLocation, useRouteMatch } from 'react-router';
7+
import {
8+
matchPath, useLocation, useMatch, useNavigate,
9+
} from 'react-router-dom';
810

911
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
1012
import { useIntl } from '@edx/frontend-platform/i18n';
@@ -30,7 +32,6 @@ import {
3032
selectIsCourseStaff,
3133
selectIsPostingEnabled,
3234
selectLearnersTabEnabled,
33-
selectModerationSettings,
3435
selectPostThreadCount,
3536
selectUserHasModerationPrivileges,
3637
selectUserIsGroupTa,
@@ -53,16 +54,18 @@ export function useTotalTopicThreadCount() {
5354
}
5455

5556
export const useSidebarVisible = () => {
57+
const location = useLocation();
5658
const enableInContext = useSelector(selectEnableInContext);
57-
const isViewingTopics = useRouteMatch(Routes.TOPICS.ALL);
58-
const isViewingLearners = useRouteMatch(Routes.LEARNERS.PATH);
59+
const isViewingTopics = useMatch(Routes.TOPICS.ALL);
60+
const isViewingLearners = useMatch(`${Routes.LEARNERS.PATH}/*`);
5961
const isFiltered = useSelector(selectAreThreadsFiltered);
6062
const totalThreads = useSelector(selectPostThreadCount);
6163
const isThreadsEmpty = Boolean(useSelector(threadsLoadingStatus()) === RequestStatus.SUCCESSFUL && !totalThreads);
62-
const isIncontextTopicsView = Boolean(useRouteMatch(Routes.TOPICS.PATH) && enableInContext);
63-
const hideSidebar = Boolean(isThreadsEmpty && !isFiltered && !(isViewingTopics?.isExact || isViewingLearners));
64+
const matchInContextTopicView = Routes.TOPICS.PATH.find((route) => matchPath({ path: `${route}/*` }, location.pathname));
65+
const isInContextTopicsView = Boolean(matchInContextTopicView && enableInContext);
66+
const hideSidebar = Boolean(isThreadsEmpty && !isFiltered && !(isViewingTopics || isViewingLearners));
6467

65-
if (isIncontextTopicsView) {
68+
if (isInContextTopicsView) {
6669
return true;
6770
}
6871

@@ -85,7 +88,7 @@ export function useCourseDiscussionData(courseId) {
8588

8689
export function useRedirectToThread(courseId, enableInContextSidebar) {
8790
const dispatch = useDispatch();
88-
const history = useHistory();
91+
const navigate = useNavigate();
8992
const location = useLocation();
9093

9194
const redirectToThread = useSelector(
@@ -102,7 +105,7 @@ export function useRedirectToThread(courseId, enableInContextSidebar) {
102105
postId: redirectToThread.threadId,
103106
topicId: redirectToThread.topicId,
104107
})(location);
105-
history.push(newLocation);
108+
navigate({ ...newLocation });
106109
}
107110
}, [redirectToThread]);
108111
}
@@ -159,13 +162,12 @@ export const useAlertBannerVisible = (
159162
) => {
160163
const userHasModerationPrivileges = useSelector(selectUserHasModerationPrivileges);
161164
const userIsGroupTa = useSelector(selectUserIsGroupTa);
162-
const { reasonCodesEnabled } = useSelector(selectModerationSettings);
163165
const userIsContentAuthor = getAuthenticatedUser().username === author;
164166
const canSeeLastEditOrClosedAlert = (userHasModerationPrivileges || userIsContentAuthor || userIsGroupTa);
165167
const canSeeReportedBanner = abuseFlagged;
166168

167169
return (
168-
(reasonCodesEnabled && canSeeLastEditOrClosedAlert && (lastEdit?.reason || closed)) || (canSeeReportedBanner)
170+
(canSeeLastEditOrClosedAlert && (lastEdit?.reason || closed)) || (canSeeReportedBanner)
169171
);
170172
};
171173

src/discussions/data/selectors.js

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ export const selectIsPostingEnabled = state => state.config.isPostingEnabled;
3333
export const selectModerationSettings = state => ({
3434
postCloseReasons: state.config.postCloseReasons,
3535
editReasons: state.config.editReasons,
36-
reasonCodesEnabled: state.config.reasonCodesEnabled,
3736
});
3837

3938
export const selectDiscussionProvider = state => state.config.provider;

src/discussions/data/slices.js

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ const configSlice = createSlice({
2424
dividedInlineDiscussions: [],
2525
dividedCourseWideDiscussions: [],
2626
},
27-
reasonCodesEnabled: false,
2827
editReasons: [],
2928
postCloseReasons: [],
3029
enableInContext: false,

src/discussions/discussions-home/DiscussionContent.jsx

+16-16
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React, { lazy, Suspense } from 'react';
22

33
import { useSelector } from 'react-redux';
4-
import { Route, Switch } from 'react-router';
4+
import { Route, Routes } from 'react-router-dom';
55

66
import Spinner from '../../components/Spinner';
7-
import { Routes } from '../../data/constants';
7+
import { Routes as ROUTES } from '../../data/constants';
88

99
const PostEditor = lazy(() => import('../posts/post-editor/PostEditor'));
1010
const PostCommentsView = lazy(() => import('../post-comments/PostCommentsView'));
@@ -16,20 +16,20 @@ const DiscussionContent = () => {
1616
<div className="d-flex bg-light-400 flex-column w-75 w-xs-100 w-xl-75 align-items-center">
1717
<div className="d-flex flex-column w-100">
1818
<Suspense fallback={(<Spinner />)}>
19-
{postEditorVisible ? (
20-
<Route path={Routes.POSTS.NEW_POST}>
21-
<PostEditor />
22-
</Route>
23-
) : (
24-
<Switch>
25-
<Route path={Routes.POSTS.EDIT_POST}>
26-
<PostEditor editExisting />
27-
</Route>
28-
<Route path={Routes.COMMENTS.PATH}>
29-
<PostCommentsView />
30-
</Route>
31-
</Switch>
32-
)}
19+
<Routes>
20+
{postEditorVisible ? (
21+
<Route path={ROUTES.POSTS.NEW_POST} element={<PostEditor />} />
22+
) : (
23+
<>
24+
{ROUTES.POSTS.EDIT_POST.map(route => (
25+
<Route key={route} path={route} element={<PostEditor editExisting />} />
26+
))}
27+
{ROUTES.COMMENTS.PATH.map(route => (
28+
<Route key={route} path={route} element={<PostCommentsView />} />
29+
))}
30+
</>
31+
)}
32+
</Routes>
3333
</Suspense>
3434
</div>
3535
</div>

0 commit comments

Comments
 (0)