diff --git a/src/course-outline/CourseOutline.test.jsx b/src/course-outline/CourseOutline.test.jsx
index cfd019191..29ab59b91 100644
--- a/src/course-outline/CourseOutline.test.jsx
+++ b/src/course-outline/CourseOutline.test.jsx
@@ -27,7 +27,7 @@ import { RequestStatus } from '../data/constants';
import {
fetchCourseBestPracticesQuery,
fetchCourseLaunchQuery,
- fetchCourseOutlineIndexQuery,
+ fetchCourseOutlineIndexQuery, syncDiscussionsTopics,
updateCourseSectionHighlightsQuery,
} from './data/thunk';
import initializeStore from '../store';
@@ -126,6 +126,10 @@ jest.mock('@dnd-kit/core', () => ({
closestCorners: jest.fn(),
}));
+jest.mock('./data/api', () => ({
+ ...jest.requireActual('./data/api'),
+ createDiscussionsTopics: jest.fn().mockResolvedValue(undefined),
+}));
// eslint-disable-next-line no-promise-executor-return
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -173,6 +177,7 @@ describe('', () => {
}))
.reply(200, courseLaunchMock);
await executeThunk(fetchCourseOutlineIndexQuery(courseId), store.dispatch);
+ await executeThunk(syncDiscussionsTopics(courseId), store.dispatch);
});
afterEach(() => {
diff --git a/src/course-outline/data/api.js b/src/course-outline/data/api.js
index 2b2865c29..69bf8f018 100644
--- a/src/course-outline/data/api.js
+++ b/src/course-outline/data/api.js
@@ -59,6 +59,17 @@ export async function getCourseOutlineIndex(courseId) {
return camelCaseObject(data);
}
+/**
+ *
+ * @param courseId
+ * @returns {Promise}
+ */
+export async function createDiscussionsTopics(courseId) {
+ const { data } = await getAuthenticatedHttpClient()
+ .post(`${getApiBaseUrl()}/api/discussions/v0/course/${courseId}/sync_discussion_topics`);
+ return camelCaseObject(data);
+}
+
/**
* Get course best practices.
* @param {{courseId: string, excludeGraded: boolean, all: boolean}} options
diff --git a/src/course-outline/data/selectors.js b/src/course-outline/data/selectors.js
index 6ad81c7a4..4768d9959 100644
--- a/src/course-outline/data/selectors.js
+++ b/src/course-outline/data/selectors.js
@@ -11,3 +11,4 @@ export const getCustomRelativeDatesActiveFlag = (state) => state.courseOutline.i
export const getProctoredExamsFlag = (state) => state.courseOutline.enableProctoredExams;
export const getPasteFileNotices = (state) => state.courseOutline.pasteFileNotices;
export const getErrors = (state) => state.courseOutline.errors;
+export const getCreatedOn = (state) => state.courseOutline.createdOn;
diff --git a/src/course-outline/data/slice.js b/src/course-outline/data/slice.js
index 027555526..95d3c4235 100644
--- a/src/course-outline/data/slice.js
+++ b/src/course-outline/data/slice.js
@@ -47,6 +47,7 @@ const slice = createSlice({
},
enableProctoredExams: false,
pasteFileNotices: {},
+ createdOn: null,
},
reducers: {
fetchOutlineIndexSuccess: (state, { payload }) => {
@@ -54,6 +55,7 @@ const slice = createSlice({
state.sectionsList = payload.courseStructure?.childInfo?.children || [];
state.isCustomRelativeDatesActive = payload.isCustomRelativeDatesActive;
state.enableProctoredExams = payload.courseStructure?.enableProctoredExams;
+ state.createdOn = payload.createdOn;
},
updateOutlineIndexLoadingStatus: (state, { payload }) => {
state.loadingStatus = {
diff --git a/src/course-outline/data/thunk.js b/src/course-outline/data/thunk.js
index 3091f3ec9..46f3ce4ba 100644
--- a/src/course-outline/data/thunk.js
+++ b/src/course-outline/data/thunk.js
@@ -30,7 +30,7 @@ import {
setVideoSharingOption,
setCourseItemOrderList,
pasteBlock,
- dismissNotification,
+ dismissNotification, createDiscussionsTopics,
} from './api';
import {
addSection,
@@ -95,6 +95,17 @@ export function fetchCourseOutlineIndexQuery(courseId) {
};
}
+export function syncDiscussionsTopics(courseId) {
+ return async () => {
+ try {
+ await createDiscussionsTopics(courseId);
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.log('There was an issue in discussion topic sync', error);
+ }
+ };
+}
+
export function fetchCourseLaunchQuery({
courseId,
gradedOnly = true,
diff --git a/src/course-outline/hooks.jsx b/src/course-outline/hooks.jsx
index 55cdc69ad..25a9bb5be 100644
--- a/src/course-outline/hooks.jsx
+++ b/src/course-outline/hooks.jsx
@@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom';
import { useToggle } from '@openedx/paragon';
import { getConfig } from '@edx/frontend-platform';
+import moment from 'moment';
import { getSavingStatus as getGenericSavingStatus } from '../generic/data/selectors';
import { getWaffleFlags } from '../data/selectors';
import { RequestStatus } from '../data/constants';
@@ -25,6 +26,7 @@ import {
getCurrentSubsection,
getCustomRelativeDatesActiveFlag,
getErrors,
+ getCreatedOn,
} from './data/selectors';
import {
addNewSectionQuery,
@@ -53,7 +55,7 @@ import {
setUnitOrderListQuery,
pasteClipboardContent,
dismissNotificationQuery,
- addUnitFromLibrary,
+ addUnitFromLibrary, syncDiscussionsTopics,
} from './data/thunk';
const useCourseOutline = ({ courseId }) => {
@@ -73,7 +75,7 @@ const useCourseOutline = ({ courseId }) => {
mfeProctoredExamSettingsUrl,
advanceSettingsUrl,
} = useSelector(getOutlineIndexData);
-
+ const createdOn = useSelector(getCreatedOn);
const { outlineIndexLoadingStatus, reIndexLoadingStatus } = useSelector(getLoadingStatus);
const statusBarData = useSelector(getStatusBarData);
const savingStatus = useSelector(getSavingStatus);
@@ -292,6 +294,12 @@ const useCourseOutline = ({ courseId }) => {
dispatch(fetchCourseLaunchQuery({ courseId }));
}, [courseId]);
+ useEffect(() => {
+ if (createdOn && moment(new Date(createdOn)).isAfter(moment().subtract(31, 'days'))) {
+ dispatch(syncDiscussionsTopics);
+ }
+ }, [createdOn]);
+
useEffect(() => {
setShowSuccessAlert(reIndexLoadingStatus === RequestStatus.SUCCESSFUL);
}, [reIndexLoadingStatus]);