diff --git a/src/discussions/common/ActionsDropdown.jsx b/src/discussions/common/ActionsDropdown.jsx
index 0df904c8..f699473c 100644
--- a/src/discussions/common/ActionsDropdown.jsx
+++ b/src/discussions/common/ActionsDropdown.jsx
@@ -13,9 +13,9 @@ import {
import { MoreHoriz } from '@edx/paragon/icons';
import { ContentActions } from '../../data/constants';
-import { selectBlackoutDate } from '../data/selectors';
+import { selectIsPostingEnabled } from '../data/selectors';
import messages from '../messages';
-import { inBlackoutDateRange, useActions } from '../utils';
+import { useActions } from '../utils';
const ActionsDropdown = ({
actionHandlers,
@@ -29,7 +29,7 @@ const ActionsDropdown = ({
const intl = useIntl();
const [isOpen, open, close] = useToggle(false);
const [target, setTarget] = useState(null);
- const blackoutDateRange = useSelector(selectBlackoutDate);
+ const isPostingEnabled = useSelector(selectIsPostingEnabled);
const actions = useActions(contentType, id);
const handleActions = useCallback((action) => {
@@ -41,12 +41,12 @@ const ActionsDropdown = ({
}
}, [actionHandlers]);
- // Find and remove edit action if in blackout date range.
+ // Find and remove edit action if in Posting is disabled.
useMemo(() => {
- if (inBlackoutDateRange(blackoutDateRange)) {
+ if (!isPostingEnabled) {
actions.splice(actions.findIndex(action => action.id === 'edit'), 1);
}
- }, [actions, blackoutDateRange]);
+ }, [actions, isPostingEnabled]);
const onClickButton = useCallback(() => {
setTarget(buttonRef.current);
diff --git a/src/discussions/common/ActionsDropdown.test.jsx b/src/discussions/common/ActionsDropdown.test.jsx
index dd4711d7..570705b2 100644
--- a/src/discussions/common/ActionsDropdown.test.jsx
+++ b/src/discussions/common/ActionsDropdown.test.jsx
@@ -13,6 +13,8 @@ import { AppProvider } from '@edx/frontend-platform/react';
import { ContentActions } from '../../data/constants';
import { initializeStore } from '../../store';
import { executeThunk } from '../../test-utils';
+import { getCourseConfigApiUrl } from '../data/api';
+import { fetchCourseConfig } from '../data/thunks';
import messages from '../messages';
import { getCommentsApiUrl } from '../post-comments/data/api';
import { addComment, fetchThreadComments } from '../post-comments/data/thunks';
@@ -29,6 +31,7 @@ let store;
let axiosMock;
const commentsApiUrl = getCommentsApiUrl();
const threadsApiUrl = getThreadsApiUrl();
+const courseId = 'course-v1:edX+TestX+Test_Course';
const discussionThreadId = 'thread-1';
const questionThreadId = 'thread-2';
const commentContent = 'This is a comment for thread-1';
@@ -170,7 +173,7 @@ const findOpenActionsDropdownButton = async () => (
);
describe('ActionsDropdown', () => {
- beforeEach(() => {
+ beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
userId: 3,
@@ -182,6 +185,11 @@ describe('ActionsDropdown', () => {
store = initializeStore();
Factory.resetAll();
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
+
+ axiosMock.onGet(`${getCourseConfigApiUrl()}${courseId}/`)
+ .reply(200, { isPostingEnabled: true });
+
+ await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState);
});
it.each(Object.values(buildTestContent()))('can open drop down if enabled', async (commentOrPost) => {
diff --git a/src/discussions/common/HoverCard.jsx b/src/discussions/common/HoverCard.jsx
index 0cd24746..05c51cbe 100644
--- a/src/discussions/common/HoverCard.jsx
+++ b/src/discussions/common/HoverCard.jsx
@@ -11,7 +11,7 @@ import {
import {
StarFilled, StarOutline, ThumbUpFilled, ThumbUpOutline,
} from '../../components/icons';
-import { useUserCanAddThreadInBlackoutDate } from '../data/hooks';
+import { useUserPostingEnabled } from '../data/hooks';
import { PostCommentsContext } from '../post-comments/postCommentsContext';
import ActionsDropdown from './ActionsDropdown';
import { DiscussionContext } from './context';
@@ -31,7 +31,7 @@ const HoverCard = ({
const intl = useIntl();
const { enableInContextSidebar } = useContext(DiscussionContext);
const { isClosed } = useContext(PostCommentsContext);
- const userCanAddThreadInBlackoutDate = useUserCanAddThreadInBlackoutDate();
+ const isUserPrivilagedInPostingRestriction = useUserPostingEnabled();
return (
- {userCanAddThreadInBlackoutDate && (
+ {isUserPrivilagedInPostingRestriction && (
{isFeedbackBannerVisible &&
}
-
+
{provider === DiscussionProvider.LEGACY && (
)}>
diff --git a/src/discussions/discussions-home/BlackoutInformationBanner.jsx b/src/discussions/discussions-home/DiscussionsRestrictionBanner.jsx
similarity index 53%
rename from src/discussions/discussions-home/BlackoutInformationBanner.jsx
rename to src/discussions/discussions-home/DiscussionsRestrictionBanner.jsx
index 301a460b..e948036b 100644
--- a/src/discussions/discussions-home/BlackoutInformationBanner.jsx
+++ b/src/discussions/discussions-home/DiscussionsRestrictionBanner.jsx
@@ -1,23 +1,20 @@
-import React, { useCallback, useMemo, useState } from 'react';
+import React, { useCallback, useState } from 'react';
import { useSelector } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
import { PageBanner } from '@edx/paragon';
-import { selectBlackoutDate } from '../data/selectors';
+import { RequestStatus } from '../../data/constants';
+import { selectconfigLoadingStatus, selectIsPostingEnabled } from '../data/selectors';
import messages from '../messages';
-import { inBlackoutDateRange } from '../utils';
-const BlackoutInformationBanner = () => {
+const DiscussionsRestrictionBanner = () => {
const intl = useIntl();
- const blackoutDate = useSelector(selectBlackoutDate);
+ const isPostingEnabled = useSelector(selectIsPostingEnabled);
+ const configLoadingStatus = useSelector(selectconfigLoadingStatus);
const [showBanner, setShowBanner] = useState(true);
- const isDiscussionsBlackout = useMemo(() => (
- inBlackoutDateRange(blackoutDate)
- ), [blackoutDate]);
-
const handleDismiss = useCallback(() => {
setShowBanner(false);
}, []);
@@ -25,7 +22,7 @@ const BlackoutInformationBanner = () => {
return (
@@ -36,4 +33,4 @@ const BlackoutInformationBanner = () => {
);
};
-export default BlackoutInformationBanner;
+export default DiscussionsRestrictionBanner;
diff --git a/src/discussions/discussions-home/BlackoutInformationBanner.test.jsx b/src/discussions/discussions-home/DiscussionsRestrictionBanner.test.jsx
similarity index 72%
rename from src/discussions/discussions-home/BlackoutInformationBanner.test.jsx
rename to src/discussions/discussions-home/DiscussionsRestrictionBanner.test.jsx
index 58a220be..f308e521 100644
--- a/src/discussions/discussions-home/BlackoutInformationBanner.test.jsx
+++ b/src/discussions/discussions-home/DiscussionsRestrictionBanner.test.jsx
@@ -8,7 +8,7 @@ import { initializeStore } from '../../store';
import { DiscussionContext } from '../common/context';
import { fetchConfigSuccess } from '../data/slices';
import messages from '../messages';
-import BlackoutInformationBanner from './BlackoutInformationBanner';
+import DiscussionsRestrictionBanner from './DiscussionsRestrictionBanner';
let store;
let container;
@@ -20,13 +20,13 @@ activeEndDate.setDate(activeEndDate.getDate() + 2);
activeStartDate = activeStartDate.toISOString();
activeEndDate = activeEndDate.toISOString();
-const getConfigData = (blackouts = []) => ({
+const getConfigData = (isPostingEnabled) => ({
id: 'course-v1:edX+DemoX+Demo_Course',
userRoles: ['Admin', 'Student'],
hasModerationPrivileges: false,
isGroupTa: false,
isUserAdmin: false,
- blackouts,
+ isPostingEnabled,
});
function renderComponent() {
@@ -34,7 +34,7 @@ function renderComponent() {
-
+
,
@@ -43,7 +43,7 @@ function renderComponent() {
return container;
}
-describe('Blackout Information Banner', () => {
+describe('Discussions Restriction Banner', () => {
beforeEach(async () => {
initializeMockApp({
authenticatedUser: {
@@ -56,13 +56,11 @@ describe('Blackout Information Banner', () => {
});
test.each([
- { blackouts: [], visibility: false },
- { blackouts: ['2021-12-31T10:15', '2021-12-31T10:20'], visibility: false },
- { blackouts: [{ start: activeStartDate, end: activeEndDate }], visibility: true },
- { blackouts: [{ start: activeEndDate, end: activeEndDate }], visibility: false },
- ])('Test Blackout Banner is visible on app load if blackout date is active', async ({ blackouts, visibility }) => {
+ { isPostingEnabled: false, visibility: true },
+ { isPostingEnabled: true, visibility: false },
+ ])('Test Discussions Restriction is visible on app load if posting is disabled', async ({ isPostingEnabled, visibility }) => {
store = initializeStore();
- await store.dispatch(fetchConfigSuccess(getConfigData(blackouts)));
+ await store.dispatch(fetchConfigSuccess(getConfigData(isPostingEnabled)));
renderComponent();
if (visibility) {
const element = await screen.findByRole('alert');
diff --git a/src/discussions/in-context-topics/TopicPostsView.test.jsx b/src/discussions/in-context-topics/TopicPostsView.test.jsx
index bb76a2f7..f8abeb2d 100644
--- a/src/discussions/in-context-topics/TopicPostsView.test.jsx
+++ b/src/discussions/in-context-topics/TopicPostsView.test.jsx
@@ -92,7 +92,6 @@ describe('InContext Topic Posts View', () => {
enableInContext: true,
provider: 'openedx',
hasModerationPrivileges: true,
- blackouts: [],
},
});
Factory.resetAll();
diff --git a/src/discussions/messages.js b/src/discussions/messages.js
index c1cc14ed..a23276f2 100644
--- a/src/discussions/messages.js
+++ b/src/discussions/messages.js
@@ -185,7 +185,7 @@ const messages = defineMessages({
},
blackoutDiscussionInformation: {
id: 'discussion.blackoutBanner.information',
- defaultMessage: 'Posting in discussions is temporarily disabled by the course team',
+ defaultMessage: 'Posting in discussions is disabled by the course team',
description: 'Informative text when discussion posting is disabled',
},
imageWarningMessage: {
diff --git a/src/discussions/post-comments/PostCommentsView.test.jsx b/src/discussions/post-comments/PostCommentsView.test.jsx
index ea97dc02..50b6e86c 100644
--- a/src/discussions/post-comments/PostCommentsView.test.jsx
+++ b/src/discussions/post-comments/PostCommentsView.test.jsx
@@ -109,6 +109,24 @@ async function getThreadAPIResponse(attr = null) {
await executeThunk(fetchThread(discussionPostId), store.dispatch, store.getState);
}
+async function setupCourseConfig(reasonCodesEnabled = true) {
+ axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, {
+ has_moderation_privileges: true,
+ isPostingEnabled: true,
+ reason_codes_enabled: reasonCodesEnabled,
+ editReasons: [
+ { code: 'reason-1', label: 'reason 1' },
+ { code: 'reason-2', label: 'reason 2' },
+ ],
+ postCloseReasons: [
+ { code: 'reason-1', label: 'reason 1' },
+ { code: 'reason-2', label: 'reason 2' },
+ ],
+ });
+ axiosMock.onGet(`${courseConfigApiUrl}${courseId}/settings`).reply(200, {});
+ await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState);
+}
+
function renderComponent(postId) {
const wrapper = render(
@@ -218,6 +236,7 @@ describe('ThreadView', () => {
});
it('should show and hide the editor', async () => {
+ await setupCourseConfig();
await waitFor(() => renderComponent(discussionPostId));
const post = screen.getByTestId('post-thread-1');
@@ -232,6 +251,7 @@ describe('ThreadView', () => {
});
it('should allow posting a response', async () => {
+ await setupCourseConfig();
await waitFor(() => renderComponent(discussionPostId));
const post = await screen.findByTestId('post-thread-1');
@@ -246,6 +266,7 @@ describe('ThreadView', () => {
});
it('should not allow posting a response on a closed post', async () => {
+ await setupCourseConfig();
renderComponent(closedPostId);
const post = screen.getByTestId('post-thread-2');
const hoverCard = within(post).getByTestId('hover-card-thread-2');
@@ -254,6 +275,7 @@ describe('ThreadView', () => {
});
it('should allow posting a comment', async () => {
+ await setupCourseConfig();
await waitFor(() => renderComponent(discussionPostId));
const comment = await waitFor(() => screen.findByTestId('comment-comment-1'));
@@ -267,6 +289,7 @@ describe('ThreadView', () => {
});
it('should allow editing an existing comment', async () => {
+ await setupCourseConfig();
await waitFor(() => renderComponent(discussionPostId));
const comment = await waitFor(() => screen.findByTestId('comment-comment-1'));
@@ -281,23 +304,6 @@ describe('ThreadView', () => {
});
});
- async function setupCourseConfig(reasonCodesEnabled = true) {
- axiosMock.onGet(`${courseConfigApiUrl}${courseId}/`).reply(200, {
- has_moderation_privileges: true,
- reason_codes_enabled: reasonCodesEnabled,
- editReasons: [
- { code: 'reason-1', label: 'reason 1' },
- { code: 'reason-2', label: 'reason 2' },
- ],
- postCloseReasons: [
- { code: 'reason-1', label: 'reason 1' },
- { code: 'reason-2', label: 'reason 2' },
- ],
- });
- axiosMock.onGet(`${courseConfigApiUrl}${courseId}/settings`).reply(200, {});
- await executeThunk(fetchCourseConfig(courseId), store.dispatch, store.getState);
- }
-
it('should show reason codes when closing a post', async () => {
await setupCourseConfig();
await waitFor(() => renderComponent(discussionPostId));
diff --git a/src/discussions/post-comments/comments/CommentsView.jsx b/src/discussions/post-comments/comments/CommentsView.jsx
index 6011826d..f3e6e27e 100644
--- a/src/discussions/post-comments/comments/CommentsView.jsx
+++ b/src/discussions/post-comments/comments/CommentsView.jsx
@@ -5,7 +5,7 @@ import { useIntl } from '@edx/frontend-platform/i18n';
import { Button, Spinner } from '@edx/paragon';
import { EndorsementStatus } from '../../../data/constants';
-import { useUserCanAddThreadInBlackoutDate } from '../../data/hooks';
+import { useUserPostingEnabled } from '../../data/hooks';
import { isLastElementOfList } from '../../utils';
import { usePostComments } from '../data/hooks';
import messages from '../messages';
@@ -16,7 +16,8 @@ const CommentsView = ({ endorsed }) => {
const intl = useIntl();
const [addingResponse, setAddingResponse] = useState(false);
const { isClosed } = useContext(PostCommentsContext);
- const userCanAddThreadInBlackoutDate = useUserCanAddThreadInBlackoutDate();
+ const isUserPrivilagedInPostingRestriction = useUserPostingEnabled();
+
const {
endorsedCommentsIds,
unEndorsedCommentsIds,
@@ -89,7 +90,7 @@ const CommentsView = ({ endorsed }) => {
{handleDefinition(messages.responseCount, unEndorsedCommentsIds.length)}
{unEndorsedCommentsIds.length === 0 &&
}
{handleComments(unEndorsedCommentsIds, false)}
- {(userCanAddThreadInBlackoutDate && !!unEndorsedCommentsIds.length && !isClosed) && (
+ {(isUserPrivilagedInPostingRestriction && !!unEndorsedCommentsIds.length && !isClosed) && (
{!addingResponse && (
) : (
- !isClosed && userCanAddThreadInBlackoutDate && (inlineReplies.length >= 5) && (
+ !isClosed && isUserPrivilagedInPostingRestriction && (inlineReplies.length >= 5) && (