Skip to content

Commit 3f5a3dd

Browse files
committed
feat: refactor course details management by removing deprecated actions and integrating new API hooks
1 parent 0828e3b commit 3f5a3dd

8 files changed

Lines changed: 52 additions & 68 deletions

File tree

src/editors/sharedComponents/TinyMceWidget/hooks.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
99
import { getLocale, isRtl } from '@edx/frontend-platform/i18n';
1010
import { a11ycheckerCss } from 'frontend-components-tinymce-advanced-plugins';
1111
import { isEmpty } from 'lodash';
12-
import { updateCourseDetailsOverview } from '../../../schedule-and-details/data/slice';
1312
import tinyMCEStyles from '../../data/constants/tinyMCEStyles';
1413
import { StrictDict } from '../../utils';
1514
import pluginConfig from './pluginConfig';
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { useQuery, useQueryClient } from '@tanstack/react-query';
2+
3+
import { getCourseDetails } from './api';
4+
5+
/**
6+
* Get the details of a course.
7+
*/
8+
export const useGetCourseDetails = (courseId?: string) => {
9+
const queryClient = useQueryClient();
10+
11+
const {
12+
data, isLoading, isError, refetch,
13+
} = useQuery({
14+
queryKey: ['courseDetails', courseId],
15+
queryFn: () => getCourseDetails(courseId),
16+
refetchOnWindowFocus: false,
17+
});
18+
let globalDefaults: { [key: string]: any } | undefined;
19+
if (data === undefined && courseId) {
20+
// If course-specific waffle flags were requested, first default to the
21+
// global (studio-wide) flags until we've loaded the course-specific ones.
22+
globalDefaults = queryClient.getQueryData(['courseDetails', undefined]);
23+
}
24+
return {
25+
...globalDefaults,
26+
...data,
27+
id: courseId,
28+
isLoading,
29+
isError,
30+
refetch,
31+
};
32+
};
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
export const getLoadingDetailsStatus = (state) => state.scheduleAndDetails.loadingDetailsStatus;
21
export const getLoadingSettingsStatus = (state) => state.scheduleAndDetails.loadingSettingsStatus;
32
export const getSavingStatus = (state) => state.scheduleAndDetails.savingStatus;
4-
export const getCourseDetails = state => state.scheduleAndDetails.courseDetails;
53
export const getCourseSettings = (state) => state.scheduleAndDetails.courseSettings;

src/schedule-and-details/data/slice.js

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,27 @@ import { RequestStatus } from '../../data/constants';
66
const slice = createSlice({
77
name: 'scheduleAndDetails',
88
initialState: {
9-
loadingDetailsStatus: RequestStatus.IN_PROGRESS,
109
loadingSettingsStatus: RequestStatus.IN_PROGRESS,
1110
savingStatus: '',
12-
courseDetails: {},
1311
courseSettings: {},
1412
},
1513
reducers: {
16-
updateLoadingDetailsStatus: (state, { payload }) => {
17-
state.loadingDetailsStatus = payload.status;
18-
},
1914
updateLoadingSettingsStatus: (state, { payload }) => {
2015
state.loadingSettingsStatus = payload.status;
2116
},
2217
updateSavingStatus: (state, { payload }) => {
2318
state.savingStatus = payload.status;
2419
},
25-
updateCourseDetailsSuccess: (state, { payload }) => {
26-
Object.assign(state.courseDetails, payload);
27-
},
28-
fetchCourseDetailsSuccess: (state, { payload }) => {
29-
Object.assign(state.courseDetails, payload);
30-
},
3120
fetchCourseSettingsSuccess: (state, { payload }) => {
3221
Object.assign(state.courseSettings, payload);
3322
},
34-
updateCourseDetailsOverview: (state, { payload }) => {
35-
state.courseDetails.overview = payload;
36-
},
3723
},
3824
});
3925

4026
export const {
4127
updateSavingStatus,
42-
updateLoadingDetailsStatus,
4328
updateLoadingSettingsStatus,
44-
updateCourseDetailsSuccess,
45-
fetchCourseDetailsSuccess,
4629
fetchCourseSettingsSuccess,
47-
updateCourseDetailsOverview,
4830
} = slice.actions;
4931

5032
export const {

src/schedule-and-details/data/thunks.js

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,21 @@
11
import { RequestStatus } from '../../data/constants';
22
import {
3-
getCourseDetails,
43
updateCourseDetails,
54
getCourseSettings,
65
} from './api';
76
import {
87
updateSavingStatus,
9-
updateLoadingDetailsStatus,
108
updateLoadingSettingsStatus,
11-
fetchCourseDetailsSuccess,
12-
updateCourseDetailsSuccess,
139
fetchCourseSettingsSuccess,
1410
} from './slice';
1511

16-
export function fetchCourseDetailsQuery(courseId) {
17-
return async (dispatch) => {
18-
dispatch(updateLoadingDetailsStatus({ status: RequestStatus.IN_PROGRESS }));
19-
20-
try {
21-
const detailsValues = await getCourseDetails(courseId);
22-
dispatch(fetchCourseDetailsSuccess(detailsValues));
23-
dispatch(updateLoadingDetailsStatus({ status: RequestStatus.SUCCESSFUL }));
24-
} catch (error) {
25-
if (error.response && error.response.status === 403) {
26-
dispatch(updateLoadingDetailsStatus({ courseId, status: RequestStatus.DENIED }));
27-
} else {
28-
dispatch(updateLoadingDetailsStatus({ status: RequestStatus.FAILED }));
29-
}
30-
}
31-
};
32-
}
33-
3412
export function updateCourseDetailsQuery(courseId, details) {
3513
return async (dispatch) => {
3614
dispatch(updateSavingStatus({ status: RequestStatus.IN_PROGRESS }));
3715

3816
try {
39-
const detailsValues = await updateCourseDetails(courseId, details);
17+
await updateCourseDetails(courseId, details);
4018
dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL }));
41-
dispatch(updateCourseDetailsSuccess(detailsValues));
4219
return true;
4320
} catch {
4421
dispatch(updateSavingStatus({ status: RequestStatus.FAILED }));

src/schedule-and-details/hooks.jsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,28 @@ import { useDispatch, useSelector } from 'react-redux';
33
import { useIntl } from '@edx/frontend-platform/i18n';
44

55
import { RequestStatus } from '../data/constants';
6-
import { getLoadingDetailsStatus, getLoadingSettingsStatus, getSavingStatus } from './data/selectors';
6+
import { getLoadingSettingsStatus, getSavingStatus } from './data/selectors';
77
import { validateScheduleAndDetails, updateWithDefaultValues } from './utils';
88

99
const useLoadValuesPrompt = (
1010
courseId,
11-
fetchCourseDetailsQuery,
1211
fetchCourseSettingsQuery,
12+
courseDetailsError,
1313
) => {
1414
const dispatch = useDispatch();
15-
const loadingDetailsStatus = useSelector(getLoadingDetailsStatus);
1615
const loadingSettingsStatus = useSelector(getLoadingSettingsStatus);
1716
const [showLoadFailedAlert, setShowLoadFailedAlert] = useState(false);
1817

1918
useEffect(() => {
20-
dispatch(fetchCourseDetailsQuery(courseId));
2119
dispatch(fetchCourseSettingsQuery(courseId));
2220
}, [courseId]);
2321

2422
useEffect(() => {
25-
if (loadingDetailsStatus === RequestStatus.FAILED || loadingSettingsStatus === RequestStatus.FAILED) {
23+
if (courseDetailsError || loadingSettingsStatus === RequestStatus.FAILED) {
2624
setShowLoadFailedAlert(true);
2725
window.scrollTo({ top: 0, behavior: 'smooth' });
2826
}
29-
}, [loadingDetailsStatus, loadingSettingsStatus]);
27+
}, [courseDetailsError, loadingSettingsStatus]);
3028

3129
return {
3230
showLoadFailedAlert,
@@ -54,7 +52,7 @@ const useSaveValuesPrompt = (
5452
if (!isQueryPending && !isEditableState) {
5553
setEditedValues(initialEditedData);
5654
}
57-
}, [initialEditedData]);
55+
}, [initialEditedData.isLoading]);
5856

5957
useEffect(() => {
6058
const errors = validateScheduleAndDetails(editedValues, canShowCertificateAvailableDateField, intl);
@@ -115,6 +113,8 @@ const useSaveValuesPrompt = (
115113
if (!isEditableState) {
116114
setShowModifiedAlert(false);
117115
}
116+
// Refresh course data after successful save
117+
initialEditedData.refetch();
118118
} else if (savingStatus === RequestStatus.FAILED) {
119119
setIsQueryPending(false);
120120
setShowSuccessfulAlert(false);

src/schedule-and-details/index.jsx

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,21 @@ import {
99
} from '@openedx/paragon/icons';
1010
import { useIntl } from '@edx/frontend-platform/i18n';
1111

12-
import Placeholder from '@src/editors/Placeholder';
13-
import { RequestStatus } from '@src/data/constants';
14-
import AlertMessage from '@src/generic/alert-message';
15-
import InternetConnectionAlert from '@src/generic/internet-connection-alert';
16-
import { STATEFUL_BUTTON_STATES } from '@src/constants';
17-
import getPageHeadTitle from '@src/generic/utils';
18-
import { useScrollToHashElement } from '@src/hooks';
12+
import Placeholder from '../editors/Placeholder';
13+
import { RequestStatus } from '../data/constants';
14+
import { useGetCourseDetails } from './data/apiHooks';
15+
import AlertMessage from '../generic/alert-message';
16+
import InternetConnectionAlert from '../generic/internet-connection-alert';
17+
import { STATEFUL_BUTTON_STATES } from '../constants';
18+
import getPageHeadTitle from '../generic/utils';
19+
import { useScrollToHashElement } from '../hooks';
1920
import { useCourseAuthoringContext } from '@src/CourseAuthoringContext';
20-
2121
import {
2222
fetchCourseSettingsQuery,
23-
fetchCourseDetailsQuery,
2423
updateCourseDetailsQuery,
2524
} from './data/thunks';
2625
import {
2726
getCourseSettings,
28-
getCourseDetails,
29-
getLoadingDetailsStatus,
3027
getLoadingSettingsStatus,
3128
} from './data/selectors';
3229
import BasicSection from './basic-section';
@@ -45,11 +42,10 @@ import { useLoadValuesPrompt, useSaveValuesPrompt } from './hooks';
4542

4643
const ScheduleAndDetails = () => {
4744
const intl = useIntl();
45+
const courseDetails = useGetCourseDetails(courseId);
4846
const courseSettings = useSelector(getCourseSettings);
49-
const courseDetails = useSelector(getCourseDetails);
50-
const loadingDetailsStatus = useSelector(getLoadingDetailsStatus);
5147
const loadingSettingsStatus = useSelector(getLoadingSettingsStatus);
52-
const isLoading = loadingDetailsStatus === RequestStatus.IN_PROGRESS
48+
const isLoading = courseDetails.isLoading
5349
|| loadingSettingsStatus === RequestStatus.IN_PROGRESS;
5450

5551
const { courseId, courseDetails: course } = useCourseAuthoringContext();
@@ -81,8 +77,8 @@ const ScheduleAndDetails = () => {
8177
showLoadFailedAlert,
8278
} = useLoadValuesPrompt(
8379
courseId,
84-
fetchCourseDetailsQuery,
8580
fetchCourseSettingsQuery,
81+
courseDetails.isError,
8682
);
8783

8884
const {
@@ -149,7 +145,7 @@ const ScheduleAndDetails = () => {
149145
return <></>;
150146
}
151147

152-
if (loadingDetailsStatus === RequestStatus.DENIED || loadingSettingsStatus === RequestStatus.DENIED) {
148+
if (courseDetails.isError || loadingSettingsStatus === RequestStatus.DENIED) {
153149
return (
154150
<div className="row justify-content-center m-6">
155151
<Placeholder />

0 commit comments

Comments
 (0)