diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx
index cbe42ee20c..2f734991c6 100644
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx
@@ -7,7 +7,7 @@ import { getConfig } from '@edx/frontend-platform';
import { selectors } from '../../../../../data/redux';
import messages from './messages';
import TinyMceWidget from '../../../../../sharedComponents/TinyMceWidget';
-import { prepareEditorRef, replaceStaticWithAsset } from '../../../../../sharedComponents/TinyMceWidget/hooks';
+import { prepareEditorRef, useProcessedEditorContent } from '../../../../../sharedComponents/TinyMceWidget/hooks';
const ExplanationWidget = ({
// redux
@@ -19,12 +19,11 @@ const ExplanationWidget = ({
}) => {
const intl = useIntl();
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
- const initialContent = settings?.solutionExplanation || '';
- const newContent = replaceStaticWithAsset({
- initialContent,
+
+ const solutionContent = useProcessedEditorContent({
+ initialContent: settings?.solutionExplanation || '',
learningContextId,
});
- const solutionContent = newContent || initialContent;
let staticRootUrl;
if (isLibrary) {
staticRootUrl = `${getConfig().STUDIO_BASE_URL }/library_assets/blocks/${ blockId }/`;
diff --git a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx
index f8020721a1..44b8d877b5 100644
--- a/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx
+++ b/src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx
@@ -7,7 +7,7 @@ import { getConfig } from '@edx/frontend-platform';
import { selectors } from '../../../../../data/redux';
import messages from './messages';
import TinyMceWidget from '../../../../../sharedComponents/TinyMceWidget';
-import { prepareEditorRef, replaceStaticWithAsset } from '../../../../../sharedComponents/TinyMceWidget/hooks';
+import { prepareEditorRef, useProcessedEditorContent } from '../../../../../sharedComponents/TinyMceWidget/hooks';
const QuestionWidget = ({
// redux
@@ -19,12 +19,11 @@ const QuestionWidget = ({
}) => {
const intl = useIntl();
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
- const initialContent = question;
- const newContent = replaceStaticWithAsset({
- initialContent,
+
+ const questionContent = useProcessedEditorContent({
+ initialContent: question,
learningContextId,
});
- const questionContent = newContent || initialContent;
let staticRootUrl;
if (isLibrary) {
staticRootUrl = `${getConfig().STUDIO_BASE_URL }/library_assets/blocks/${ blockId }/`;
diff --git a/src/editors/containers/TextEditor/index.jsx b/src/editors/containers/TextEditor/index.jsx
index 03fb498e9f..4f1b5f9083 100644
--- a/src/editors/containers/TextEditor/index.jsx
+++ b/src/editors/containers/TextEditor/index.jsx
@@ -17,7 +17,7 @@ import RawEditor from '../../sharedComponents/RawEditor';
import * as hooks from './hooks';
import messages from './messages';
import TinyMceWidget from '../../sharedComponents/TinyMceWidget';
-import { prepareEditorRef, replaceStaticWithAsset } from '../../sharedComponents/TinyMceWidget/hooks';
+import { prepareEditorRef, useProcessedEditorContent } from '../../sharedComponents/TinyMceWidget/hooks';
const TextEditor = ({
onClose,
@@ -32,15 +32,16 @@ const TextEditor = ({
learningContextId,
images,
isLibrary,
+ validateAssetUrl,
}) => {
const intl = useIntl();
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
- const initialContent = blockValue ? blockValue.data.data : '';
- const newContent = replaceStaticWithAsset({
- initialContent,
+
+ const editorContent = useProcessedEditorContent({
+ initialContent: blockValue ? blockValue.data.data : '',
learningContextId,
+ validateAssetUrl,
});
- const editorContent = newContent || initialContent;
let staticRootUrl;
if (isLibrary) {
staticRootUrl = `${getConfig().STUDIO_BASE_URL }/library_assets/blocks/${ blockId }/`;
@@ -106,6 +107,7 @@ TextEditor.defaultProps = {
blockValue: null,
blockFinished: null,
returnFunction: null,
+ validateAssetUrl: null,
};
TextEditor.propTypes = {
onClose: PropTypes.func.isRequired,
@@ -122,6 +124,7 @@ TextEditor.propTypes = {
learningContextId: PropTypes.string, // This should be required but is NULL when the store is in initial state :/
images: PropTypes.shape({}).isRequired,
isLibrary: PropTypes.bool.isRequired,
+ validateAssetUrl: PropTypes.bool,
};
export const mapStateToProps = (state) => ({
diff --git a/src/editors/containers/TextEditor/index.test.tsx b/src/editors/containers/TextEditor/index.test.tsx
index 0844ffb932..bbf11b0739 100644
--- a/src/editors/containers/TextEditor/index.test.tsx
+++ b/src/editors/containers/TextEditor/index.test.tsx
@@ -1,5 +1,7 @@
import React from 'react';
-import { render, screen, initializeMocks } from '@src/testUtils';
+import {
+ render, screen, initializeMocks, waitFor,
+} from '@src/testUtils';
import { actions, selectors } from '../../data/redux';
import { RequestKeys } from '../../data/constants/requests';
import { TextEditorInternal as TextEditor, mapStateToProps, mapDispatchToProps } from '.';
@@ -67,15 +69,20 @@ describe('TextEditor', () => {
expect(element?.getAttribute('editorcontenthtml')).toBe('eDiTablE Text');
});
- test('renders static images with relative paths', () => {
+ test('renders static images with relative paths', async () => {
const updatedProps = {
...props,
+ validateAssetUrl: false,
blockValue: { data: { data: 'eDiTablE Text with
' } },
};
const { container } = render(
');
+ await waitFor(() => {
+ expect(element?.getAttribute('editorcontenthtml')).toBe(
+ 'eDiTablE Text with
',
+ );
+ });
});
test('not yet loaded, Spinner appears', () => {
const { container } = render(
test
`;
const learningContextId = 'course-v1:org+test+run';
const lmsEndpointUrl = getConfig().LMS_BASE_URL;
- it('returns updated src for text editor to update content', () => {
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('returns updated src for text editor to update content', async () => {
const expected = `
test
`;
- const actual = module.replaceStaticWithAsset({ initialContent, learningContextId });
+ const actual = await module.replaceStaticWithAsset({
+ initialContent,
+ learningContextId,
+ validateAssetUrl: false,
+ });
expect(actual).toEqual(expected);
});
- it('returns updated src with absolute url for expandable editor to update content', () => {
- const editorType = 'expandable';
+ it('returns updated src with absolute url for expandable editor to update content', async () => {
const expected = `
test
`;
- const actual = module.replaceStaticWithAsset({
+ const actual = await module.replaceStaticWithAsset({
initialContent,
- editorType,
+ editorType: 'expandable',
lmsEndpointUrl,
learningContextId,
+ validateAssetUrl: false,
});
expect(actual).toEqual(expected);
});
- it('returns false when there are no srcs to update', () => {
+ it('returns false when there are no srcs to update', async () => {
const content = '

';
const expected = `
`;
- const actual = module.replaceStaticWithAsset({
+ const actual = await module.replaceStaticWithAsset({
initialContent: contentWithSubdirectory,
learningContextId,
+ validateAssetUrl: false,
});
expect(actual).toEqual(expected);
});
+
+ it('replaces multiple static assets in one content string', async () => {
+ const content = `
+
+
+ `;
+
+ const result = await module.replaceStaticWithAsset({
+ initialContent: content,
+ learningContextId,
+ validateAssetUrl: false,
+ });
+
+ expect(result).toBeTruthy();
+ });
+
+ it('validateAssetUrl success path replaces url', async () => {
+ getAuthenticatedHttpClient.mockReturnValue({
+ get: jest.fn(() => Promise.resolve({})),
+ });
+
+ const content = '
';
+
+ const result = await module.replaceStaticWithAsset({
+ initialContent: content,
+ learningContextId,
+ validateAssetUrl: true,
+ });
+
+ expect(result).toBeTruthy();
+ });
+
+ it('validateAssetUrl failure path keeps original content', async () => {
+ getAuthenticatedHttpClient.mockReturnValue({
+ get: jest.fn(() => Promise.reject(new Error('404'))),
+ });
+
+ const content = '
';
+
+ const result = await module.replaceStaticWithAsset({
+ initialContent: content,
+ learningContextId,
+ validateAssetUrl: true,
+ });
+
+ expect(result).toBeFalsy();
+ });
+
+ it('handles library keys correctly', async () => {
+ jest.spyOn(keyUtils, 'isLibraryKey').mockReturnValue(true);
+
+ const content = '
';
+
+ const result = await module.replaceStaticWithAsset({
+ initialContent: content,
+ learningContextId: 'lib:test',
+ validateAssetUrl: false,
+ });
+
+ expect(result).toContain('static/test.png');
+ });
+
+ it('returns false when asset already valid and no replacement needed', async () => {
+ const content = '
';
+
+ const result = await module.replaceStaticWithAsset({
+ initialContent: content,
+ learningContextId,
+ validateAssetUrl: false,
+ });
+
+ expect(result).toBe(false);
+ });
});
describe('setAssetToStaticUrl', () => {
it('returns content with updated img links', () => {
diff --git a/src/editors/sharedComponents/TinyMceWidget/hooks.ts b/src/editors/sharedComponents/TinyMceWidget/hooks.ts
index 7b906de2d1..83afbe81cf 100644
--- a/src/editors/sharedComponents/TinyMceWidget/hooks.ts
+++ b/src/editors/sharedComponents/TinyMceWidget/hooks.ts
@@ -5,6 +5,7 @@ import {
useEffect,
} from 'react';
import { getConfig } from '@edx/frontend-platform';
+import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getLocale, isRtl } from '@edx/frontend-platform/i18n';
import { a11ycheckerCss } from 'frontend-components-tinymce-advanced-plugins';
import { isEmpty } from 'lodash';
@@ -104,11 +105,12 @@ export const parseContentForLabels = ({ editor, updateContent }) => {
}
};
-export const replaceStaticWithAsset = ({
+export const replaceStaticWithAsset = async ({
initialContent,
learningContextId,
editorType,
lmsEndpointUrl,
+ validateAssetUrl = true,
}) => {
let content = initialContent;
let hasChanges = false;
@@ -116,7 +118,7 @@ export const replaceStaticWithAsset = ({
src => src.startsWith('/static') || src.startsWith('/asset'),
);
if (!isEmpty(srcs)) {
- srcs.forEach(src => {
+ for (const src of srcs) {
const currentContent = content;
let staticFullUrl;
const isStatic = src.startsWith('/static/');
@@ -154,10 +156,25 @@ export const replaceStaticWithAsset = ({
}
if (staticFullUrl) {
const currentSrc = src.substring(0, src.indexOf('"'));
- content = currentContent.replace(currentSrc, staticFullUrl);
- hasChanges = true;
+
+ // check if the asset exists on the server before replacing
+ try {
+ if (validateAssetUrl) {
+ // We intentionally await inside this loop because each replacement
+ // depends on the progressively updated `content` value.
+ // Executing the requests in parallel could introduce race conditions
+ // and produce inconsistent string replacements.
+ // eslint-disable-next-line no-await-in-loop
+ await getAuthenticatedHttpClient()
+ .get(staticFullUrl);
+ }
+ content = currentContent.replace(currentSrc, staticFullUrl);
+ hasChanges = true;
+ } catch (e) {
+ content = currentContent;
+ }
}
- });
+ }
if (hasChanges) { return content; }
}
return false;
@@ -341,9 +358,9 @@ export const setupCustomBehavior = ({
onAction: toggleLabelFormatting,
});
if (editorType === 'expandable') {
- editor.on('init', () => {
+ editor.on('init', async () => {
const initialContent = editor.getContent();
- const newContent = replaceStaticWithAsset({
+ const newContent = await replaceStaticWithAsset({
initialContent,
editorType,
lmsEndpointUrl,
@@ -369,10 +386,10 @@ export const setupCustomBehavior = ({
}
});
- editor.on('ExecCommand', /* istanbul ignore next */ (e) => {
+ editor.on('ExecCommand', /* istanbul ignore next */ async (e) => {
if (editorType === 'text' && e.command === 'mceFocus') {
const initialContent = editor.getContent();
- const newContent = replaceStaticWithAsset({
+ const newContent = await replaceStaticWithAsset({
initialContent,
editorType,
lmsEndpointUrl,
@@ -560,3 +577,39 @@ export const selectedImage = (val) => {
setSelection,
};
};
+
+export const useProcessedEditorContent = ({
+ initialContent,
+ learningContextId,
+ editorType,
+ validateAssetUrl = false,
+}) => {
+ const [content, setContent] = useState(initialContent);
+
+ useEffect(() => {
+ let mounted = true;
+
+ const process = async () => {
+ const newContent = await replaceStaticWithAsset({
+ initialContent,
+ learningContextId,
+ editorType,
+ lmsEndpointUrl: getConfig().LMS_BASE_URL,
+ validateAssetUrl,
+ });
+
+ if (mounted) {
+ setContent(newContent || initialContent);
+ }
+ };
+
+ // eslint-disable-next-line no-void
+ void process();
+
+ return () => {
+ mounted = false;
+ };
+ }, [initialContent, learningContextId, editorType, validateAssetUrl]);
+
+ return content;
+};
diff --git a/src/schedule-and-details/data/api.js b/src/schedule-and-details/data/api.ts
similarity index 100%
rename from src/schedule-and-details/data/api.js
rename to src/schedule-and-details/data/api.ts
diff --git a/src/schedule-and-details/data/apiHooks.ts b/src/schedule-and-details/data/apiHooks.ts
new file mode 100644
index 0000000000..9b65a2f5c0
--- /dev/null
+++ b/src/schedule-and-details/data/apiHooks.ts
@@ -0,0 +1,24 @@
+import { useQuery } from '@tanstack/react-query';
+import { getCourseDetails } from './api';
+
+/**
+ * Get the details of a course.
+ */
+export const useGetCourseDetails = (courseId?: string) => {
+ const {
+ data, isLoading, isError, refetch, dataUpdatedAt
+ } = useQuery({
+ queryKey: ['courseDetails', courseId],
+ queryFn: () => getCourseDetails(courseId),
+ enabled: !!courseId,
+ refetchOnWindowFocus: false,
+ });
+ return {
+ ...data,
+ id: courseId,
+ isLoading,
+ isError,
+ refetch,
+ dataUpdatedAt,
+ };
+};
diff --git a/src/schedule-and-details/data/selectors.js b/src/schedule-and-details/data/selectors.js
index cff5c69ba3..e388de4eee 100644
--- a/src/schedule-and-details/data/selectors.js
+++ b/src/schedule-and-details/data/selectors.js
@@ -1,5 +1,3 @@
-export const getLoadingDetailsStatus = (state) => state.scheduleAndDetails.loadingDetailsStatus;
export const getLoadingSettingsStatus = (state) => state.scheduleAndDetails.loadingSettingsStatus;
export const getSavingStatus = (state) => state.scheduleAndDetails.savingStatus;
-export const getCourseDetails = state => state.scheduleAndDetails.courseDetails;
export const getCourseSettings = (state) => state.scheduleAndDetails.courseSettings;
diff --git a/src/schedule-and-details/data/slice.js b/src/schedule-and-details/data/slice.js
index ba65e02a18..a73b3a1d19 100644
--- a/src/schedule-and-details/data/slice.js
+++ b/src/schedule-and-details/data/slice.js
@@ -6,28 +6,17 @@ import { RequestStatus } from '../../data/constants';
const slice = createSlice({
name: 'scheduleAndDetails',
initialState: {
- loadingDetailsStatus: RequestStatus.IN_PROGRESS,
loadingSettingsStatus: RequestStatus.IN_PROGRESS,
savingStatus: '',
- courseDetails: {},
courseSettings: {},
},
reducers: {
- updateLoadingDetailsStatus: (state, { payload }) => {
- state.loadingDetailsStatus = payload.status;
- },
updateLoadingSettingsStatus: (state, { payload }) => {
state.loadingSettingsStatus = payload.status;
},
updateSavingStatus: (state, { payload }) => {
state.savingStatus = payload.status;
},
- updateCourseDetailsSuccess: (state, { payload }) => {
- Object.assign(state.courseDetails, payload);
- },
- fetchCourseDetailsSuccess: (state, { payload }) => {
- Object.assign(state.courseDetails, payload);
- },
fetchCourseSettingsSuccess: (state, { payload }) => {
Object.assign(state.courseSettings, payload);
},
@@ -36,10 +25,7 @@ const slice = createSlice({
export const {
updateSavingStatus,
- updateLoadingDetailsStatus,
updateLoadingSettingsStatus,
- updateCourseDetailsSuccess,
- fetchCourseDetailsSuccess,
fetchCourseSettingsSuccess,
} = slice.actions;
diff --git a/src/schedule-and-details/data/thunks.js b/src/schedule-and-details/data/thunks.js
index bc2be6dc41..45773b91df 100644
--- a/src/schedule-and-details/data/thunks.js
+++ b/src/schedule-and-details/data/thunks.js
@@ -1,44 +1,21 @@
import { RequestStatus } from '../../data/constants';
import {
- getCourseDetails,
updateCourseDetails,
getCourseSettings,
} from './api';
import {
updateSavingStatus,
- updateLoadingDetailsStatus,
updateLoadingSettingsStatus,
- fetchCourseDetailsSuccess,
- updateCourseDetailsSuccess,
fetchCourseSettingsSuccess,
} from './slice';
-export function fetchCourseDetailsQuery(courseId) {
- return async (dispatch) => {
- dispatch(updateLoadingDetailsStatus({ status: RequestStatus.IN_PROGRESS }));
-
- try {
- const detailsValues = await getCourseDetails(courseId);
- dispatch(fetchCourseDetailsSuccess(detailsValues));
- dispatch(updateLoadingDetailsStatus({ status: RequestStatus.SUCCESSFUL }));
- } catch (error) {
- if (error.response && error.response.status === 403) {
- dispatch(updateLoadingDetailsStatus({ courseId, status: RequestStatus.DENIED }));
- } else {
- dispatch(updateLoadingDetailsStatus({ status: RequestStatus.FAILED }));
- }
- }
- };
-}
-
export function updateCourseDetailsQuery(courseId, details) {
return async (dispatch) => {
dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS }));
try {
- const detailsValues = await updateCourseDetails(courseId, details);
+ await updateCourseDetails(courseId, details);
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
- dispatch(updateCourseDetailsSuccess(detailsValues));
return true;
} catch {
dispatch(updateSavingStatus({ status: RequestStatus.FAILED }));
diff --git a/src/schedule-and-details/hooks.jsx b/src/schedule-and-details/hooks.jsx
index 218b92dc1c..25e208a9ef 100644
--- a/src/schedule-and-details/hooks.jsx
+++ b/src/schedule-and-details/hooks.jsx
@@ -3,30 +3,28 @@ import { useDispatch, useSelector } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
import { RequestStatus } from '../data/constants';
-import { getLoadingDetailsStatus, getLoadingSettingsStatus, getSavingStatus } from './data/selectors';
+import { getLoadingSettingsStatus, getSavingStatus } from './data/selectors';
import { validateScheduleAndDetails, updateWithDefaultValues } from './utils';
const useLoadValuesPrompt = (
courseId,
- fetchCourseDetailsQuery,
fetchCourseSettingsQuery,
+ courseDetailsError,
) => {
const dispatch = useDispatch();
- const loadingDetailsStatus = useSelector(getLoadingDetailsStatus);
const loadingSettingsStatus = useSelector(getLoadingSettingsStatus);
const [showLoadFailedAlert, setShowLoadFailedAlert] = useState(false);
useEffect(() => {
- dispatch(fetchCourseDetailsQuery(courseId));
dispatch(fetchCourseSettingsQuery(courseId));
}, [courseId]);
useEffect(() => {
- if (loadingDetailsStatus === RequestStatus.FAILED || loadingSettingsStatus === RequestStatus.FAILED) {
+ if (courseDetailsError || loadingSettingsStatus === RequestStatus.FAILED) {
setShowLoadFailedAlert(true);
window.scrollTo({ top: 0, behavior: 'smooth' });
}
- }, [loadingDetailsStatus, loadingSettingsStatus]);
+ }, [courseDetailsError, loadingSettingsStatus]);
return {
showLoadFailedAlert,
@@ -54,7 +52,7 @@ const useSaveValuesPrompt = (
if (!isQueryPending && !isEditableState) {
setEditedValues(initialEditedData);
}
- }, [initialEditedData]);
+ }, [initialEditedData.dataUpdatedAt]);
useEffect(() => {
const errors = validateScheduleAndDetails(editedValues, canShowCertificateAvailableDateField, intl);
@@ -115,6 +113,8 @@ const useSaveValuesPrompt = (
if (!isEditableState) {
setShowModifiedAlert(false);
}
+ // Refresh course data after successful save
+ initialEditedData.refetch();
} else if (savingStatus === RequestStatus.FAILED) {
setIsQueryPending(false);
setShowSuccessfulAlert(false);
diff --git a/src/schedule-and-details/index.jsx b/src/schedule-and-details/index.jsx
index 9b6aad15e3..5ded3520c6 100644
--- a/src/schedule-and-details/index.jsx
+++ b/src/schedule-and-details/index.jsx
@@ -9,24 +9,21 @@ import {
} from '@openedx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
-import Placeholder from '@src/editors/Placeholder';
-import { RequestStatus } from '@src/data/constants';
-import AlertMessage from '@src/generic/alert-message';
-import InternetConnectionAlert from '@src/generic/internet-connection-alert';
-import { STATEFUL_BUTTON_STATES } from '@src/constants';
-import getPageHeadTitle from '@src/generic/utils';
-import { useScrollToHashElement } from '@src/hooks';
import { useCourseAuthoringContext } from '@src/CourseAuthoringContext';
-
+import Placeholder from '../editors/Placeholder';
+import { RequestStatus } from '../data/constants';
+import { useGetCourseDetails } from './data/apiHooks';
+import AlertMessage from '../generic/alert-message';
+import InternetConnectionAlert from '../generic/internet-connection-alert';
+import { STATEFUL_BUTTON_STATES } from '../constants';
+import getPageHeadTitle from '../generic/utils';
+import { useScrollToHashElement } from '../hooks';
import {
fetchCourseSettingsQuery,
- fetchCourseDetailsQuery,
updateCourseDetailsQuery,
} from './data/thunks';
import {
getCourseSettings,
- getCourseDetails,
- getLoadingDetailsStatus,
getLoadingSettingsStatus,
} from './data/selectors';
import BasicSection from './basic-section';
@@ -46,15 +43,14 @@ import { useLoadValuesPrompt, useSaveValuesPrompt } from './hooks';
const ScheduleAndDetails = () => {
const intl = useIntl();
const courseSettings = useSelector(getCourseSettings);
- const courseDetails = useSelector(getCourseDetails);
- const loadingDetailsStatus = useSelector(getLoadingDetailsStatus);
const loadingSettingsStatus = useSelector(getLoadingSettingsStatus);
- const isLoading = loadingDetailsStatus === RequestStatus.IN_PROGRESS
- || loadingSettingsStatus === RequestStatus.IN_PROGRESS;
-
const { courseId, courseDetails: course } = useCourseAuthoringContext();
document.title = getPageHeadTitle(course?.name || '', intl.formatMessage(messages.headingTitle));
+ const courseDetails = useGetCourseDetails(courseId);
+ const isLoading = courseDetails.isLoading
+ || loadingSettingsStatus === RequestStatus.IN_PROGRESS;
+
const {
platformName,
isCreditCourse,
@@ -81,8 +77,8 @@ const ScheduleAndDetails = () => {
showLoadFailedAlert,
} = useLoadValuesPrompt(
courseId,
- fetchCourseDetailsQuery,
fetchCourseSettingsQuery,
+ courseDetails.isError,
);
const {
@@ -149,7 +145,7 @@ const ScheduleAndDetails = () => {
return <>>;
}
- if (loadingDetailsStatus === RequestStatus.DENIED || loadingSettingsStatus === RequestStatus.DENIED) {
+ if (loadingSettingsStatus === RequestStatus.DENIED) {
return (