From 2973614e3b130fdb38d44ea04c2564b030d948df Mon Sep 17 00:00:00 2001
From: Muhammad Anas <88967643+Anas12091101@users.noreply.github.com>
Date: Wed, 9 Jul 2025 21:35:58 +0500
Subject: [PATCH] fix: loading unit page directly from link after logging in in
Teak (#2246)
This is a simple version of the fix for Teak; on master it was fixed with https://github.com/openedx/frontend-app-authoring/pull/1867
---
src/course-unit/CourseUnit.jsx | 2 ++
src/course-unit/course-sequence/hooks.js | 13 ++++++----
.../SequenceNavigation.jsx | 4 +--
src/course-unit/data/selectors.js | 2 +-
src/course-unit/hooks.jsx | 3 +++
src/course-unit/sidebar/utils.js | 2 +-
.../xblock-container-iframe/index.tsx | 26 ++++++++++++++++++-
.../xblock-container-iframe/types.ts | 5 ++++
8 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx
index 10a9ad25b..0054a77e2 100644
--- a/src/course-unit/CourseUnit.jsx
+++ b/src/course-unit/CourseUnit.jsx
@@ -41,6 +41,7 @@ const CourseUnit = ({ courseId }) => {
courseUnit,
isLoading,
sequenceId,
+ courseUnitLoadingStatus,
unitTitle,
unitCategory,
errorMessage,
@@ -210,6 +211,7 @@ const CourseUnit = ({ courseId }) => {
courseId={courseId}
blockId={blockId}
isUnitVerticalType={isUnitVerticalType}
+ courseUnitLoadingStatus={courseUnitLoadingStatus}
unitXBlockActions={unitXBlockActions}
courseVerticalChildren={courseVerticalChildren.children}
handleConfigureSubmit={handleConfigureSubmit}
diff --git a/src/course-unit/course-sequence/hooks.js b/src/course-unit/course-sequence/hooks.js
index 28035e1af..cb541f1ab 100644
--- a/src/course-unit/course-sequence/hooks.js
+++ b/src/course-unit/course-sequence/hooks.js
@@ -12,16 +12,19 @@ export function useSequenceNavigationMetadata(courseId, currentSequenceId, curre
const isLastUnit = !nextUrl;
const sequenceIds = useSelector(getSequenceIds);
const sequenceIndex = sequenceIds.indexOf(currentSequenceId);
- const unitIndex = sequence.unitIds.indexOf(currentUnitId);
+ let unitIndex = sequence?.unitIds.indexOf(currentUnitId);
const nextSequenceId = sequenceIndex < sequenceIds.length - 1 ? sequenceIds[sequenceIndex + 1] : null;
const previousSequenceId = sequenceIndex > 0 ? sequenceIds[sequenceIndex - 1] : null;
-
+ if (!unitIndex) {
+ // Handle case where unitIndex is not found
+ unitIndex = 0;
+ }
let nextLink;
const nextIndex = unitIndex + 1;
- if (nextIndex < sequence.unitIds.length) {
- const nextUnitId = sequence.unitIds[nextIndex];
+ if (nextIndex < sequence?.unitIds.length) {
+ const nextUnitId = sequence?.unitIds[nextIndex];
nextLink = `/course/${courseId}/container/${nextUnitId}/${currentSequenceId}`;
} else if (nextSequenceId) {
const pathToNextUnit = decodeURIComponent(nextUrl);
@@ -32,7 +35,7 @@ export function useSequenceNavigationMetadata(courseId, currentSequenceId, curre
const previousIndex = unitIndex - 1;
if (previousIndex >= 0) {
- const previousUnitId = sequence.unitIds[previousIndex];
+ const previousUnitId = sequence?.unitIds[previousIndex];
previousLink = `/course/${courseId}/container/${previousUnitId}/${currentSequenceId}`;
} else if (previousSequenceId) {
const pathToPreviousUnit = decodeURIComponent(prevUrl);
diff --git a/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx b/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx
index 0fa15fa29..0af7ef63b 100644
--- a/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx
+++ b/src/course-unit/course-sequence/sequence-navigation/SequenceNavigation.jsx
@@ -35,7 +35,7 @@ const SequenceNavigation = ({
const shouldDisplayNotificationTriggerInSequence = useWindowSize().width < breakpoints.small.minWidth;
const renderUnitButtons = () => {
- if (sequence.unitIds?.length === 0 || unitId === null) {
+ if (sequence?.unitIds?.length === 0 || unitId === null) {
return (
);
@@ -43,7 +43,7 @@ const SequenceNavigation = ({
return (
state.courseUnit.courseVerti
export const getCourseOutlineInfo = (state) => state.courseUnit.courseOutlineInfo;
export const getCourseOutlineInfoLoadingStatus = (state) => state.courseUnit.courseOutlineInfoLoadingStatus;
export const getMovedXBlockParams = (state) => state.courseUnit.movedXBlockParams;
-const getLoadingStatuses = (state) => state.courseUnit.loadingStatus;
+export const getLoadingStatuses = (state) => state.courseUnit.loadingStatus;
export const getIsLoading = createSelector(
[getLoadingStatuses],
loadingStatus => Object.values(loadingStatus)
diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx
index fc8fe092e..7ab5eb591 100644
--- a/src/course-unit/hooks.jsx
+++ b/src/course-unit/hooks.jsx
@@ -35,6 +35,7 @@ import {
getSavingStatus,
getSequenceStatus,
getStaticFileNotices,
+ getLoadingStatuses,
} from './data/selectors';
import {
changeEditTitleFormOpen,
@@ -51,6 +52,7 @@ export const useCourseUnit = ({ courseId, blockId }) => {
const [isMoveModalOpen, openMoveModal, closeMoveModal] = useToggle(false);
const courseUnit = useSelector(getCourseUnitData);
+ const courseUnitLoadingStatus = useSelector(getLoadingStatuses);
const savingStatus = useSelector(getSavingStatus);
const isLoading = useSelector(getIsLoading);
const errorMessage = useSelector(getErrorMessage);
@@ -218,6 +220,7 @@ export const useCourseUnit = ({ courseId, blockId }) => {
return {
sequenceId,
courseUnit,
+ courseUnitLoadingStatus,
unitTitle,
unitCategory,
errorMessage,
diff --git a/src/course-unit/sidebar/utils.js b/src/course-unit/sidebar/utils.js
index af3263861..390d9a316 100644
--- a/src/course-unit/sidebar/utils.js
+++ b/src/course-unit/sidebar/utils.js
@@ -99,4 +99,4 @@ export const getIconVariant = (visibilityState, published, hasChanges) => {
* @param {string} id - The course unit ID.
* @returns {string} The clear course unit ID extracted from the provided data.
*/
-export const extractCourseUnitId = (id) => id.match(/block@(.+)$/)[1];
+export const extractCourseUnitId = (id) => id?.match(/block@(.+)$/)[1];
diff --git a/src/course-unit/xblock-container-iframe/index.tsx b/src/course-unit/xblock-container-iframe/index.tsx
index 48be568b2..ac6fc9293 100644
--- a/src/course-unit/xblock-container-iframe/index.tsx
+++ b/src/course-unit/xblock-container-iframe/index.tsx
@@ -37,9 +37,16 @@ import { useIframeContent } from '../../generic/hooks/useIframeContent';
import { useIframeMessages } from '../../generic/hooks/useIframeMessages';
import VideoSelectorPage from '../../editors/VideoSelectorPage';
import EditorPage from '../../editors/EditorPage';
+import { RequestStatus } from '../../data/constants';
const XBlockContainerIframe: FC = ({
- courseId, blockId, unitXBlockActions, courseVerticalChildren, handleConfigureSubmit, isUnitVerticalType,
+ courseId,
+ blockId,
+ unitXBlockActions,
+ courseVerticalChildren,
+ handleConfigureSubmit,
+ isUnitVerticalType,
+ courseUnitLoadingStatus,
}) => {
const intl = useIntl();
const dispatch = useDispatch();
@@ -70,6 +77,23 @@ const XBlockContainerIframe: FC = ({
setIframeRef(iframeRef);
}, [setIframeRef]);
+ useEffect(() => {
+ const iframe = iframeRef?.current;
+ if (!iframe) { return undefined; }
+
+ const handleIframeLoad = () => {
+ if (courseUnitLoadingStatus.fetchUnitLoadingStatus === RequestStatus.FAILED) {
+ window.location.reload();
+ }
+ };
+
+ iframe.addEventListener('load', handleIframeLoad);
+
+ return () => {
+ iframe.removeEventListener('load', handleIframeLoad);
+ };
+ }, [iframeRef]);
+
const onXBlockSave = useCallback(/* istanbul ignore next */ () => {
closeXBlockEditorModal();
closeVideoSelectorModal();
diff --git a/src/course-unit/xblock-container-iframe/types.ts b/src/course-unit/xblock-container-iframe/types.ts
index 084577d16..e83d5f759 100644
--- a/src/course-unit/xblock-container-iframe/types.ts
+++ b/src/course-unit/xblock-container-iframe/types.ts
@@ -42,6 +42,11 @@ export interface XBlockContainerIframeProps {
courseId: string;
blockId: string;
isUnitVerticalType: boolean,
+ courseUnitLoadingStatus: {
+ fetchUnitLoadingStatus: string;
+ fetchVerticalChildrenLoadingStatus: string;
+ fetchXBlockDataLoadingStatus: string;
+ };
unitXBlockActions: {
handleDelete: (XBlockId: string | null) => void;
handleDuplicate: (XBlockId: string | null) => void;