Skip to content

Commit d747151

Browse files
authored
Merge pull request #2624 from tekdi/release-prod-fix
Release prod fix to admin prod
2 parents 4418d03 + 316ba15 commit d747151

File tree

3 files changed

+241
-16
lines changed

3 files changed

+241
-16
lines changed

apps/admin-app-repo/src/pages/importCsv.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ const ImportCsv = () => {
164164
const userProjectDetailsResponse = await getUserProjectDetails({
165165
id: courseId,
166166
});
167-
setUserProjectDetails(userProjectDetailsResponse?.result?.tasks);
167+
setUserProjectDetails(userProjectDetailsResponse?.result?.tasks?.filter((task: any) => task !== null && task !== undefined) || []);
168168
if (userProjectDetails?.length) {
169169
}
170170
setLoading(false);

apps/learner-web-app/src/components/Content/Player.tsx

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const App = ({
5757
const [breadCrumbs, setBreadCrumbs] = useState<any>();
5858
const [isShowMoreContent, setIsShowMoreContent] = useState(false);
5959
const [mimeType, setMemetype] = useState('');
60+
const [isVideo, setIsVideo] = useState(false);
6061
const [isDownloading, setIsDownloading] = useState(false);
6162
const [showSuccessMessage, setShowSuccessMessage] = useState(false);
6263
const [showJotFormModal, setShowJotFormModal] = useState(false);
@@ -66,6 +67,31 @@ const App = ({
6667
mimeType: string;
6768
} | null>(null);
6869

70+
const [isPortrait, setIsPortrait] = useState(false);
71+
72+
useEffect(() => {
73+
setIsVideo(mimeType=='video/mp4' || mimeType=='video/webm');
74+
}, [mimeType]);
75+
76+
// Check if device is in portrait mode (width < height)
77+
useEffect(() => {
78+
const checkOrientation = () => {
79+
setIsPortrait(window.innerWidth < window.innerHeight);
80+
};
81+
82+
// Check on mount
83+
checkOrientation();
84+
85+
// Listen for resize and orientation changes
86+
window.addEventListener('resize', checkOrientation);
87+
window.addEventListener('orientationchange', checkOrientation);
88+
89+
return () => {
90+
window.removeEventListener('resize', checkOrientation);
91+
window.removeEventListener('orientationchange', checkOrientation);
92+
};
93+
}, []);
94+
6995
let activeLink = null;
7096
if (typeof window !== 'undefined') {
7197
const searchParams = new URLSearchParams(window.location.search);
@@ -403,9 +429,13 @@ const App = ({
403429
unitId={unitId}
404430
mimeType={mimeType}
405431
{..._config?.player}
432+
isPortrait={isPortrait}
433+
isVideo={isVideo}
406434
/>
407435
{item?.content?.artifactUrl &&
436+
408437
isDownloadableMimeType(item?.content?.mimeType || mimeType) &&
438+
(!isPortrait || (isVideo && !isPortrait)) &&
409439
isDownloadContentEnabled() && (
410440
<Box
411441
sx={{
@@ -457,7 +487,8 @@ const App = ({
457487

458488
<Grid
459489
sx={{
460-
display: isShowMoreContent ? 'flex' : 'none',
490+
display: isShowMoreContent && (!isPortrait || (isVideo && !isPortrait)) ? 'flex' : 'none',
491+
461492
flexDirection: 'column',
462493
flex: { xs: 1, sm: 1, md: 9 },
463494
}}
@@ -615,6 +646,8 @@ const PlayerBox = ({
615646
trackable,
616647
isShowMoreContent,
617648
mimeType,
649+
isPortrait,
650+
isVideo
618651
}: any) => {
619652
const router = useRouter();
620653
const { t } = useTranslation();
@@ -696,6 +729,7 @@ const PlayerBox = ({
696729
width: isShowMoreContent
697730
? '100%'
698731
: { xs: '100%', sm: '100%', md: '90%', lg: '80%', xl: '70%' },
732+
...(isPortrait && isVideo ? { p:0, ml:-10, mr:-5 } : {}),
699733
}}
700734
>
701735
<iframe
@@ -718,8 +752,8 @@ const PlayerBox = ({
718752
aspectRatio: getAspectRatio(),
719753
}}
720754
allowFullScreen
721-
width="100%"
722-
height="100%"
755+
width={isPortrait && isVideo ? "110%" : "100%"}
756+
height={isPortrait && isVideo ? '300%' : '100%'}
723757
title="Embedded Localhost"
724758
allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture"
725759
frameBorder="0"

mfes/players/src/components/players/SunbirdVideoPlayer.tsx

Lines changed: 203 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useRef, useEffect } from 'react';
1+
import React, { useRef, useEffect, useState } from 'react';
22
import { getTelemetryEvents } from '../../services/TelemetryService';
33
import { handleExitEvent } from '../utils/Helper';
44

@@ -16,16 +16,21 @@ const SunbirdVideoPlayer = ({
1616
configFunctionality,
1717
}: PlayerConfigProps) => {
1818
const sunbirdVideoPlayerRef = useRef<HTMLIFrameElement | null>(null);
19+
const [iframeHeight, setIframeHeight] = useState<string>('0vw'); // Default 16:9 aspect ratio
20+
const [iframeWidth, setIframeWidth] = useState<string>('100%'); // Dynamic width
1921

2022
useEffect(() => {
2123
const playerElement: any = sunbirdVideoPlayerRef.current;
24+
let timeoutIds: NodeJS.Timeout[] = [];
25+
let observer: MutationObserver | null = null;
26+
2227
if (playerElement) {
2328
const originalSrc = playerElement.src;
2429
playerElement.src = '';
2530
playerElement.src = originalSrc;
2631

2732
const handleLoad = () => {
28-
setTimeout(() => {
33+
const timeoutId = setTimeout(() => {
2934
if (
3035
playerElement.contentWindow &&
3136
playerElement.contentWindow.setData
@@ -64,28 +69,214 @@ const SunbirdVideoPlayer = ({
6469
if (myPlayer) {
6570
myPlayer.appendChild(videoElement);
6671
}
72+
73+
// Function to detect video and adjust iframe height
74+
const adjustIframeHeight = () => {
75+
try {
76+
const iframeDoc = playerElement.contentDocument;
77+
if (!iframeDoc) {
78+
const retryTimeout = setTimeout(adjustIframeHeight, 500);
79+
timeoutIds.push(retryTimeout);
80+
return;
81+
}
82+
83+
// Find the video element
84+
let video: HTMLVideoElement | null = null;
85+
86+
// Try shadow DOM first
87+
const sunbirdPlayer = iframeDoc.querySelector('sunbird-video-player');
88+
if (sunbirdPlayer?.shadowRoot) {
89+
video = sunbirdPlayer.shadowRoot.querySelector('video');
90+
}
91+
92+
// Try direct query
93+
if (!video) {
94+
video = iframeDoc.querySelector('video') ||
95+
iframeDoc.querySelector('.video-js video') as HTMLVideoElement;
96+
}
97+
98+
if (video) {
99+
const updateHeight = () => {
100+
const videoWidth = video!.videoWidth;
101+
const videoHeight = video!.videoHeight;
102+
const containerElement = playerElement.parentElement;
103+
const availableWidth = containerElement?.offsetWidth || window.innerWidth;
104+
const availableHeight = window.innerHeight;
105+
106+
// Reserve space for padding/margins (approximately 40px top/bottom)
107+
const reservedSpace = 0;
108+
const maxAvailableHeight = availableHeight - reservedSpace;
109+
110+
if (videoWidth && videoHeight && videoWidth > 0 && videoHeight > 0 && availableWidth > 0) {
111+
// Calculate aspect ratio
112+
const aspectRatio = videoWidth / videoHeight;
113+
114+
// Start with full available width
115+
let calculatedWidth = availableWidth;
116+
let calculatedHeight = calculatedWidth / aspectRatio;
117+
118+
// If calculated height exceeds viewport, adjust width to fit viewport
119+
if (calculatedHeight > maxAvailableHeight) {
120+
// Recalculate width based on available height to fit within viewport
121+
calculatedWidth = maxAvailableHeight * aspectRatio;
122+
calculatedHeight = maxAvailableHeight;
123+
}
124+
125+
// Ensure width doesn't exceed available width
126+
calculatedWidth = Math.min(calculatedWidth, availableWidth);
127+
128+
// Set both width and height in pixels
129+
setIframeWidth(`${calculatedWidth}px`);
130+
setIframeHeight(`${calculatedHeight}px`);
131+
132+
console.log('Iframe dimensions adjusted:', {
133+
videoWidth,
134+
videoHeight,
135+
aspectRatio,
136+
availableWidth,
137+
availableHeight,
138+
maxAvailableHeight,
139+
calculatedWidth,
140+
calculatedHeight,
141+
});
142+
}
143+
};
144+
145+
// If metadata already loaded
146+
if (video.readyState >= 1 && video.videoWidth > 0) {
147+
updateHeight();
148+
} else {
149+
// Wait for metadata
150+
const handleMetadata = () => {
151+
if (video!.videoWidth > 0 && video!.videoHeight > 0) {
152+
updateHeight();
153+
}
154+
};
155+
156+
video.addEventListener('loadedmetadata', handleMetadata, { once: true });
157+
video.addEventListener('loadeddata', handleMetadata, { once: true });
158+
video.addEventListener('canplay', handleMetadata, { once: true });
159+
}
160+
} else {
161+
// Video not found, retry
162+
const retryTimeout = setTimeout(adjustIframeHeight, 500);
163+
timeoutIds.push(retryTimeout);
164+
}
165+
} catch (error) {
166+
console.error('Error adjusting iframe height:', error);
167+
const retryTimeout = setTimeout(adjustIframeHeight, 1000);
168+
timeoutIds.push(retryTimeout);
169+
}
170+
};
171+
172+
// Use MutationObserver to watch for video element
173+
const startObserving = () => {
174+
try {
175+
const iframeDoc = playerElement.contentDocument;
176+
if (!iframeDoc) {
177+
setTimeout(startObserving, 500);
178+
return;
179+
}
180+
181+
observer = new MutationObserver(() => {
182+
adjustIframeHeight();
183+
});
184+
185+
observer.observe(iframeDoc.body || iframeDoc.documentElement, {
186+
childList: true,
187+
subtree: true,
188+
});
189+
190+
// Try immediately
191+
adjustIframeHeight();
192+
193+
// Cleanup observer after 15 seconds
194+
const cleanupTimeout = setTimeout(() => {
195+
if (observer) {
196+
observer.disconnect();
197+
observer = null;
198+
}
199+
}, 15000);
200+
timeoutIds.push(cleanupTimeout);
201+
} catch (error) {
202+
console.error('Error starting observer:', error);
203+
}
204+
};
205+
206+
// Start observing after a delay to allow video element to be created
207+
const observeTimeout = setTimeout(startObserving, 1000);
208+
timeoutIds.push(observeTimeout);
67209
}
68210
}, 200);
211+
timeoutIds.push(timeoutId);
69212
};
70213

71214
playerElement.addEventListener('load', handleLoad);
72215

216+
// Also listen for window resize to recalculate dimensions
217+
const handleResize = () => {
218+
const iframeDoc = playerElement.contentDocument;
219+
if (iframeDoc) {
220+
const video = iframeDoc.querySelector('video') as HTMLVideoElement;
221+
if (video && video.videoWidth > 0 && video.videoHeight > 0) {
222+
const aspectRatio = video.videoWidth / video.videoHeight;
223+
const containerElement = playerElement.parentElement;
224+
const availableWidth = containerElement?.offsetWidth || window.innerWidth;
225+
const availableHeight = window.innerHeight;
226+
const reservedSpace = 80;
227+
const maxAvailableHeight = availableHeight - reservedSpace;
228+
229+
if (availableWidth > 0) {
230+
// Start with full available width
231+
let calculatedWidth = availableWidth;
232+
let calculatedHeight = calculatedWidth / aspectRatio;
233+
234+
// If calculated height exceeds viewport, adjust width to fit viewport
235+
if (calculatedHeight > maxAvailableHeight) {
236+
calculatedWidth = maxAvailableHeight * aspectRatio;
237+
calculatedHeight = maxAvailableHeight;
238+
}
239+
240+
// Ensure width doesn't exceed available width
241+
calculatedWidth = Math.min(calculatedWidth, availableWidth);
242+
243+
// Set both width and height
244+
setIframeWidth(`${calculatedWidth}px`);
245+
setIframeHeight(`${calculatedHeight}px`);
246+
}
247+
}
248+
}
249+
};
250+
251+
window.addEventListener('resize', handleResize);
252+
73253
return () => {
74254
playerElement.removeEventListener('load', handleLoad);
255+
window.removeEventListener('resize', handleResize);
256+
timeoutIds.forEach((id) => clearTimeout(id));
257+
if (observer) {
258+
observer.disconnect();
259+
}
75260
};
76261
}
77-
}, [playerConfig]);
262+
}, [playerConfig, courseId, unitId, userId, configFunctionality]);
78263

79264
return (
80-
<iframe
81-
ref={sunbirdVideoPlayerRef}
82-
id="contentPlayer"
83-
title="Content Player"
84-
src={`${basePath}/libs/sunbird-video-player/index.html`}
85-
aria-label="Content Player"
86-
style={{ border: 'none', aspectRatio: `16 / 9` }}
87-
width="100%"
88-
></iframe>
265+
<iframe
266+
ref={sunbirdVideoPlayerRef}
267+
id="contentPlayer"
268+
title="Content Player"
269+
src={`${basePath}/libs/sunbird-video-player/index.html`}
270+
aria-label="Content Player"
271+
style={{
272+
border: 'none',
273+
width: iframeWidth || '100%',
274+
maxWidth: '100%',
275+
height: iframeHeight || '56.25vw',
276+
display: 'block',
277+
margin: '0 auto',
278+
}}
279+
></iframe>
89280
);
90281
};
91282

0 commit comments

Comments
 (0)