feat: separate video id and url fields into two (#164)
This commit is contained in:
@@ -42,7 +42,7 @@ exports[`ThumbnailWidget snapshots snapshots: renders as expected where thumbnai
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
`;
|
||||
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoType equals edxVideo 1`] = `
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoId is valid 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
fontSize="x-small"
|
||||
isError={true}
|
||||
@@ -81,7 +81,7 @@ exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoTyp
|
||||
</injectIntl(ShimmedIntlComponent)>
|
||||
`;
|
||||
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoType equals edxVideo and no thumbnail 1`] = `
|
||||
exports[`ThumbnailWidget snapshots snapshots: renders as expected where videoId is valid and no thumbnail 1`] = `
|
||||
<injectIntl(ShimmedIntlComponent)
|
||||
fontSize="x-small"
|
||||
isError={true}
|
||||
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
import { Delete, FileUpload } from '@edx/paragon/icons';
|
||||
|
||||
import { selectors } from '../../../../../../data/redux';
|
||||
import { isEdxVideo } from '../../../../../../data/services/cms/api';
|
||||
|
||||
import { acceptedImgKeys } from './constants';
|
||||
import * as hooks from './hooks';
|
||||
import messages from './messages';
|
||||
@@ -36,7 +38,7 @@ export const ThumbnailWidget = ({
|
||||
isLibrary,
|
||||
allowThumbnailUpload,
|
||||
thumbnail,
|
||||
videoType,
|
||||
videoId,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [error] = React.useContext(ErrorContext).thumbnail;
|
||||
@@ -48,10 +50,10 @@ export const ThumbnailWidget = ({
|
||||
imgRef,
|
||||
fileSizeError,
|
||||
});
|
||||
const edxVideo = isEdxVideo(videoId);
|
||||
const deleteThumbnail = hooks.deleteThumbnail({ dispatch });
|
||||
const isEdxVideo = videoType === 'edxVideo';
|
||||
const getSubtitle = () => {
|
||||
if (isEdxVideo) {
|
||||
if (edxVideo) {
|
||||
if (thumbnail) {
|
||||
return intl.formatMessage(messages.yesSubtitle);
|
||||
}
|
||||
@@ -73,7 +75,7 @@ export const ThumbnailWidget = ({
|
||||
>
|
||||
<FormattedMessage {...messages.fileSizeError} />
|
||||
</ErrorAlert>
|
||||
{isEdxVideo ? null : (
|
||||
{edxVideo ? null : (
|
||||
<Alert variant="light">
|
||||
<FormattedMessage {...messages.unavailableMessage} />
|
||||
</Alert>
|
||||
@@ -88,7 +90,7 @@ export const ThumbnailWidget = ({
|
||||
src={thumbnailSrc || thumbnail}
|
||||
alt={intl.formatMessage(messages.thumbnailAltText)}
|
||||
/>
|
||||
{ (allowThumbnailUpload && isEdxVideo) ? (
|
||||
{ (allowThumbnailUpload && edxVideo) ? (
|
||||
<IconButtonWithTooltip
|
||||
tooltipPlacement="top"
|
||||
tooltipContent={intl.formatMessage(messages.deleteThumbnail)}
|
||||
@@ -113,7 +115,7 @@ export const ThumbnailWidget = ({
|
||||
iconBefore={FileUpload}
|
||||
onClick={fileInput.click}
|
||||
variant="link"
|
||||
disabled={!isEdxVideo}
|
||||
disabled={!edxVideo}
|
||||
>
|
||||
<FormattedMessage {...messages.uploadButtonLabel} />
|
||||
</Button>
|
||||
@@ -130,13 +132,13 @@ ThumbnailWidget.propTypes = {
|
||||
isLibrary: PropTypes.bool.isRequired,
|
||||
allowThumbnailUpload: PropTypes.bool.isRequired,
|
||||
thumbnail: PropTypes.string.isRequired,
|
||||
videoType: PropTypes.string.isRequired,
|
||||
videoId: PropTypes.string.isRequired,
|
||||
};
|
||||
export const mapStateToProps = (state) => ({
|
||||
isLibrary: selectors.app.isLibrary(state),
|
||||
allowThumbnailUpload: selectors.video.allowThumbnailUpload(state),
|
||||
thumbnail: selectors.video.thumbnail(state),
|
||||
videoType: selectors.video.videoType(state),
|
||||
videoId: selectors.video.videoId(state),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {};
|
||||
|
||||
@@ -19,7 +19,7 @@ jest.mock('../../../../../../data/redux', () => ({
|
||||
video: {
|
||||
allowThumbnailUpload: jest.fn(state => ({ allowThumbnailUpload: state })),
|
||||
thumbnail: jest.fn(state => ({ thumbnail: state })),
|
||||
videoType: jest.fn(state => ({ videoType: state })),
|
||||
videoId: jest.fn(state => ({ videoId: state })),
|
||||
},
|
||||
app: {
|
||||
isLibrary: jest.fn(state => ({ isLibrary: state })),
|
||||
@@ -27,6 +27,10 @@ jest.mock('../../../../../../data/redux', () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../../../../../../data/services/cms/api', () => ({
|
||||
isEdxVideo: (args) => (args),
|
||||
}));
|
||||
|
||||
describe('ThumbnailWidget', () => {
|
||||
const props = {
|
||||
error: {},
|
||||
@@ -35,10 +39,9 @@ describe('ThumbnailWidget', () => {
|
||||
isLibrary: false,
|
||||
allowThumbnailUpload: false,
|
||||
thumbnail: null,
|
||||
videoType: '',
|
||||
videoId: '',
|
||||
updateField: jest.fn().mockName('args.updateField'),
|
||||
};
|
||||
|
||||
describe('snapshots', () => {
|
||||
test('snapshots: renders as expected with default props', () => {
|
||||
expect(
|
||||
@@ -52,7 +55,7 @@ describe('ThumbnailWidget', () => {
|
||||
});
|
||||
test('snapshots: renders as expected with a thumbnail provided', () => {
|
||||
expect(
|
||||
shallow(<ThumbnailWidget {...props} thumbnail="sOMeUrl" videoType="edxVideo" />),
|
||||
shallow(<ThumbnailWidget {...props} thumbnail="sOMeUrl" videoId="sOMeViDEoID" />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected where thumbnail uploads are allowed', () => {
|
||||
@@ -60,14 +63,14 @@ describe('ThumbnailWidget', () => {
|
||||
shallow(<ThumbnailWidget {...props} thumbnail="sOMeUrl" allowThumbnailUpload />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected where videoType equals edxVideo', () => {
|
||||
test('snapshots: renders as expected where videoId is valid', () => {
|
||||
expect(
|
||||
shallow(<ThumbnailWidget {...props} thumbnail="sOMeUrl" allowThumbnailUpload videoType="edxVideo" />),
|
||||
shallow(<ThumbnailWidget {...props} thumbnail="sOMeUrl" allowThumbnailUpload videoId="sOMeViDEoID" />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
test('snapshots: renders as expected where videoType equals edxVideo and no thumbnail', () => {
|
||||
test('snapshots: renders as expected where videoId is valid and no thumbnail', () => {
|
||||
expect(
|
||||
shallow(<ThumbnailWidget {...props} allowThumbnailUpload videoType="edxVideo" />),
|
||||
shallow(<ThumbnailWidget {...props} allowThumbnailUpload videoId="sOMeViDEoID" />),
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -88,10 +91,10 @@ describe('ThumbnailWidget', () => {
|
||||
mapStateToProps(testState).thumbnail,
|
||||
).toEqual(selectors.video.thumbnail(testState));
|
||||
});
|
||||
test('videoType from video.videoType', () => {
|
||||
test('videoId from video.videoId', () => {
|
||||
expect(
|
||||
mapStateToProps(testState).videoType,
|
||||
).toEqual(selectors.video.videoType(testState));
|
||||
mapStateToProps(testState).videoId,
|
||||
).toEqual(selectors.video.videoId(testState));
|
||||
});
|
||||
});
|
||||
describe('mapDispatchToProps', () => {
|
||||
|
||||
@@ -10,14 +10,39 @@ exports[`VideoSourceWidget snapshots snapshots: renders as expected with default
|
||||
className="border-primary-100 border-bottom pb-4"
|
||||
>
|
||||
<Form.Control
|
||||
floatingLabel="Video ID or URL"
|
||||
floatingLabel="Video ID"
|
||||
onBlur={[Function]}
|
||||
onChange={[MockFunction]}
|
||||
value=""
|
||||
/>
|
||||
<Component
|
||||
className="text-primary-300 mb-4"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="If you were assigned a video ID by edX, enter the ID here."
|
||||
description="Feedback for video ID field"
|
||||
id="authoring.videoeditor.videoSource.videoId.feedback"
|
||||
/>
|
||||
</Component>
|
||||
<Form.Control
|
||||
floatingLabel="Video URL"
|
||||
onBlur={[Function]}
|
||||
onChange={[MockFunction]}
|
||||
value=""
|
||||
/>
|
||||
<Component
|
||||
className="text-primary-300"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="The URL for your video. This can be a YouTube URL, or a link
|
||||
to an .mp4, .ogg, or .webm video file hosted elsewhere on the internet."
|
||||
description="Feedback for video URL field"
|
||||
id="authoring.videoeditor.videoSource.videoUrl.feedback"
|
||||
/>
|
||||
</Component>
|
||||
</div>
|
||||
<div
|
||||
className="mt-3"
|
||||
className="mt-4"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Fallback videos"
|
||||
|
||||
@@ -2,43 +2,45 @@ import { actions } from '../../../../../../data/redux';
|
||||
import { isEdxVideo } from '../../../../../../data/services/cms/api';
|
||||
|
||||
/**
|
||||
* updateVideoType({ dispatch })({e, source})
|
||||
* updateVideoType takes the current onBlur event, the current object of the video
|
||||
* updateVideoId({ dispatch })({e, source})
|
||||
* updateVideoId takes the current onBlur event, the current object of the video
|
||||
* source, and dispatch method, and updates the redux value for all the fields to
|
||||
* their default values except videoId, fallbackVideos, videoType, and handouts.
|
||||
* their default values except videoId, fallbackVideos, and handouts.
|
||||
* @param {event} e - object for onBlur event
|
||||
* @param {func} dispatch - redux dispatch method
|
||||
* @param {object} source - object for the Video Source field functions and values
|
||||
*/
|
||||
export const updateVideoType = ({ dispatch }) => ({ e, source }) => {
|
||||
source.onBlur(e);
|
||||
let videoType;
|
||||
let videoId;
|
||||
if (isEdxVideo(source.local)) {
|
||||
videoType = 'edxVideo';
|
||||
videoId = source.local;
|
||||
} else if (source.local.includes('youtu.be')) {
|
||||
videoType = 'youtube';
|
||||
videoId = '';
|
||||
} else {
|
||||
videoType = 'html5source';
|
||||
videoId = '';
|
||||
export const updateVideoId = ({ dispatch }) => ({ e, source }) => {
|
||||
if (source.formValue !== e.target.value) {
|
||||
source.onBlur(e);
|
||||
let videoId;
|
||||
let videoSource;
|
||||
if (isEdxVideo(source.local)) {
|
||||
videoId = source.local;
|
||||
videoSource = '';
|
||||
} else if (source.local.includes('youtu.be') || source.local.includes('youtube')) {
|
||||
videoId = '';
|
||||
videoSource = source.local;
|
||||
} else {
|
||||
videoId = '';
|
||||
videoSource = source.local;
|
||||
}
|
||||
dispatch(actions.video.updateField({
|
||||
videoId,
|
||||
videoSource,
|
||||
allowVideoDownloads: false,
|
||||
thumbnail: null,
|
||||
transcripts: [],
|
||||
allowTranscriptDownloads: false,
|
||||
showTranscriptByDefault: false,
|
||||
duration: {
|
||||
startTime: '00:00:00',
|
||||
stopTime: '00:00:00',
|
||||
total: '00:00:00',
|
||||
},
|
||||
licenseType: null,
|
||||
}));
|
||||
}
|
||||
dispatch(actions.video.updateField({
|
||||
videoId,
|
||||
videoType,
|
||||
allowVideoDownloads: false,
|
||||
thumbnail: null,
|
||||
transcripts: [],
|
||||
allowTranscriptDownloads: false,
|
||||
showTranscriptByDefault: false,
|
||||
duration: {
|
||||
startTime: '00:00:00',
|
||||
stopTime: '00:00:00',
|
||||
total: '00:00:00',
|
||||
},
|
||||
licenseType: null,
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,10 +20,10 @@ jest.mock('../../../../../../data/redux', () => ({
|
||||
}));
|
||||
|
||||
describe('VideoEditorHandout hooks', () => {
|
||||
describe('updateVideoType', () => {
|
||||
describe('updateVideoId', () => {
|
||||
const sourceEdxVideo = {
|
||||
onBlur: jest.fn(),
|
||||
local: '06b1503a-7df4-4e72-b970-326e02dbcbe4',
|
||||
local: '06b15030-7df0-4e70-b979-326e02dbcbe0',
|
||||
};
|
||||
const sourceYouTube = {
|
||||
onBlur: jest.fn(),
|
||||
@@ -35,7 +35,7 @@ describe('VideoEditorHandout hooks', () => {
|
||||
};
|
||||
const mockState = {
|
||||
videoId: '',
|
||||
videoType: '',
|
||||
videoSource: '',
|
||||
allowVideoDownloads: false,
|
||||
thumbnail: null,
|
||||
transcripts: [],
|
||||
@@ -49,36 +49,33 @@ describe('VideoEditorHandout hooks', () => {
|
||||
licenseType: null,
|
||||
};
|
||||
it('returns dispatches updateField action with default state and edxVideo Id', () => {
|
||||
hooks.updateVideoType({ dispatch })({ e: { target: { value: sourceEdxVideo.local } }, source: sourceEdxVideo });
|
||||
hooks.updateVideoId({ dispatch })({ e: { target: { value: sourceEdxVideo.local } }, source: sourceEdxVideo });
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
...mockState,
|
||||
videoId: sourceEdxVideo.local,
|
||||
videoType: 'edxVideo',
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('returns dispatches updateField action with default state and YouTube video', () => {
|
||||
hooks.updateVideoType({ dispatch })({
|
||||
hooks.updateVideoId({ dispatch })({
|
||||
e: { target: { value: sourceYouTube.local } },
|
||||
source: sourceYouTube,
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
...mockState,
|
||||
videoId: sourceYouTube.local,
|
||||
}),
|
||||
);
|
||||
});
|
||||
it('returns dispatches updateField action with default state and html5source video', () => {
|
||||
hooks.updateVideoType({ dispatch })({
|
||||
hooks.updateVideoId({ dispatch })({
|
||||
e: { target: { value: sourceHtml5Source.local } },
|
||||
source: sourceHtml5Source,
|
||||
});
|
||||
expect(dispatch).toHaveBeenCalledWith(
|
||||
actions.video.updateField({
|
||||
...mockState,
|
||||
videoId: sourceHtml5Source.local,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Button,
|
||||
Tooltip,
|
||||
OverlayTrigger,
|
||||
FormControlFeedback,
|
||||
} from '@edx/paragon';
|
||||
import { Delete, Info, Add } from '@edx/paragon/icons';
|
||||
import {
|
||||
@@ -36,6 +37,7 @@ export const VideoSourceWidget = ({
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
videoId,
|
||||
videoSource: source,
|
||||
fallbackVideos,
|
||||
allowVideoDownloads: allowDownload,
|
||||
@@ -43,12 +45,13 @@ export const VideoSourceWidget = ({
|
||||
dispatch,
|
||||
fields: {
|
||||
[widgetHooks.selectorKeys.videoSource]: widgetHooks.genericWidget,
|
||||
[widgetHooks.selectorKeys.videoId]: widgetHooks.genericWidget,
|
||||
[widgetHooks.selectorKeys.fallbackVideos]: widgetHooks.arrayWidget,
|
||||
[widgetHooks.selectorKeys.allowVideoDownloads]: widgetHooks.genericWidget,
|
||||
},
|
||||
});
|
||||
const deleteFallbackVideo = module.deleteFallbackVideo({ fallbackVideos: fallbackVideos.formValue, dispatch });
|
||||
const updateVideoType = module.updateVideoType({ dispatch });
|
||||
const updateVideoId = module.updateVideoId({ dispatch });
|
||||
|
||||
return (
|
||||
<CollapsibleFormWidget
|
||||
@@ -58,19 +61,31 @@ export const VideoSourceWidget = ({
|
||||
<Form.Group>
|
||||
<div className="border-primary-100 border-bottom pb-4">
|
||||
<Form.Control
|
||||
floatingLabel={intl.formatMessage(messages.videoIdOrUrlLabel)}
|
||||
floatingLabel={intl.formatMessage(messages.videoIdLabel)}
|
||||
onChange={videoId.onChange}
|
||||
onBlur={(e) => updateVideoId({ e, source: videoId })}
|
||||
value={videoId.local}
|
||||
/>
|
||||
<FormControlFeedback className="text-primary-300 mb-4">
|
||||
<FormattedMessage {...messages.videoIdFeedback} />
|
||||
</FormControlFeedback>
|
||||
<Form.Control
|
||||
floatingLabel={intl.formatMessage(messages.videoUrlLabel)}
|
||||
onChange={source.onChange}
|
||||
onBlur={(e) => updateVideoType({ e, source })}
|
||||
onBlur={(e) => updateVideoId({ e, source })}
|
||||
value={source.local}
|
||||
/>
|
||||
<FormControlFeedback className="text-primary-300">
|
||||
<FormattedMessage {...messages.videoUrlFeedback} />
|
||||
</FormControlFeedback>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<div className="mt-4">
|
||||
<FormattedMessage {...messages.fallbackVideoTitle} />
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage {...messages.fallbackVideoMessage} />
|
||||
</div>
|
||||
{fallbackVideos.formValue.map((videoUrl, index) => (
|
||||
{fallbackVideos.formValue.length > 0 ? fallbackVideos.formValue.map((videoUrl, index) => (
|
||||
<Form.Row className="mt-4 flex-nowrap">
|
||||
<Form.Control
|
||||
floatingLabel={intl.formatMessage(messages.fallbackVideoLabel)}
|
||||
@@ -88,7 +103,7 @@ export const VideoSourceWidget = ({
|
||||
onClick={() => deleteFallbackVideo(videoUrl)}
|
||||
/>
|
||||
</Form.Row>
|
||||
))}
|
||||
)) : null}
|
||||
<ActionRow className="mt-4">
|
||||
<Form.Checkbox
|
||||
checked={allowDownload.local}
|
||||
|
||||
@@ -14,6 +14,7 @@ jest.mock('../../../../../../data/redux', () => ({
|
||||
selectors: {
|
||||
video: {
|
||||
videoSource: jest.fn(state => ({ videoSource: state })),
|
||||
videoId: jest.fn(state => ({ videoId: state })),
|
||||
fallbackVideos: jest.fn(state => ({ fallbackVideos: state })),
|
||||
allowVideoDownloads: jest.fn(state => ({ allowVideoDownloads: state })),
|
||||
},
|
||||
@@ -23,6 +24,7 @@ jest.mock('../../../../../../data/redux', () => ({
|
||||
jest.mock('../hooks', () => ({
|
||||
selectorKeys: ['soMEkEy'],
|
||||
widgetValues: jest.fn().mockReturnValue({
|
||||
videoId: { onChange: jest.fn(), onBlur: jest.fn(), local: '' },
|
||||
videoSource: { onChange: jest.fn(), onBlur: jest.fn(), local: '' },
|
||||
fallbackVideos: {
|
||||
formValue: ['somEUrL'],
|
||||
|
||||
@@ -4,16 +4,26 @@ export const messages = {
|
||||
defaultMessage: 'Video source',
|
||||
description: 'Title for the video source widget',
|
||||
},
|
||||
videoIdOrUrlLabel: {
|
||||
id: 'authoring.videoeditor.videoSource.videoIdOrUrl.label',
|
||||
defaultMessage: 'Video ID or URL',
|
||||
description: 'Label for video ID or URL field',
|
||||
videoIdLabel: {
|
||||
id: 'authoring.videoeditor.videoSource.videoId.label',
|
||||
defaultMessage: 'Video ID',
|
||||
description: 'Label for video ID field',
|
||||
},
|
||||
videoIdOrUrlFeedback: {
|
||||
id: 'authoring.videoeditor.videoSource.videoIdOrUrl.feedback',
|
||||
defaultMessage: `Your video ID, YouTube URL, or a link to an .mp4, .ogg, or
|
||||
.webm video file hosted elsewhere on the Internet`,
|
||||
description: 'Feedback for video ID or URL field',
|
||||
videoIdFeedback: {
|
||||
id: 'authoring.videoeditor.videoSource.videoId.feedback',
|
||||
defaultMessage: 'If you were assigned a video ID by edX, enter the ID here.',
|
||||
description: 'Feedback for video ID field',
|
||||
},
|
||||
videoUrlLabel: {
|
||||
id: 'authoring.videoeditor.videoSource.videoUrl.label',
|
||||
defaultMessage: 'Video URL',
|
||||
description: 'Label for video URL field',
|
||||
},
|
||||
videoUrlFeedback: {
|
||||
id: 'authoring.videoeditor.videoSource.videoUrl.feedback',
|
||||
defaultMessage: `The URL for your video. This can be a YouTube URL, or a link
|
||||
to an .mp4, .ogg, or .webm video file hosted elsewhere on the internet.`,
|
||||
description: 'Feedback for video URL field',
|
||||
},
|
||||
fallbackVideoTitle: {
|
||||
id: 'authoring.videoeditor.videoSource.fallbackVideo.title',
|
||||
|
||||
@@ -30,6 +30,7 @@ export const selectorKeys = keyStore(selectors.video);
|
||||
export const state = StrictDict(
|
||||
[
|
||||
selectorKeys.videoSource,
|
||||
selectorKeys.videoId,
|
||||
selectorKeys.fallbackVideos,
|
||||
selectorKeys.allowVideoDownloads,
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ export const loadVideoData = () => (dispatch, getState) => {
|
||||
const studioView = state.app.studioView?.data?.html;
|
||||
const {
|
||||
videoSource,
|
||||
videoType,
|
||||
videoId,
|
||||
fallbackVideos,
|
||||
} = module.determineVideoSource({
|
||||
@@ -28,7 +27,6 @@ export const loadVideoData = () => (dispatch, getState) => {
|
||||
|
||||
dispatch(actions.video.load({
|
||||
videoSource,
|
||||
videoType,
|
||||
videoId,
|
||||
fallbackVideos,
|
||||
allowVideoDownloads: rawVideoData.download_video,
|
||||
@@ -74,30 +72,21 @@ export const determineVideoSource = ({
|
||||
const youtubeUrl = `https://youtu.be/${youtubeId}`;
|
||||
const videoId = edxVideoId || '';
|
||||
let videoSource = '';
|
||||
let videoType = '';
|
||||
let fallbackVideos = [];
|
||||
if (youtubeId) {
|
||||
// videoSource = youtubeUrl;
|
||||
// fallbackVideos = html5Sources;
|
||||
[videoSource, fallbackVideos] = [youtubeUrl, html5Sources];
|
||||
videoType = 'youtube';
|
||||
} else if (edxVideoId) {
|
||||
// videoSource = edxVideoId;
|
||||
// fallbackVideos = html5Sources;
|
||||
[videoSource, fallbackVideos] = [edxVideoId, html5Sources];
|
||||
videoType = 'edxVideo';
|
||||
fallbackVideos = html5Sources;
|
||||
} else if (Array.isArray(html5Sources) && html5Sources[0]) {
|
||||
// videoSource = html5Sources[0];
|
||||
// fallbackVideos = html5Sources.slice(1);
|
||||
[videoSource, fallbackVideos] = [html5Sources[0], html5Sources.slice(1)];
|
||||
videoType = 'html5source';
|
||||
}
|
||||
if (!fallbackVideos || fallbackVideos.length === 0) {
|
||||
fallbackVideos = ['', ''];
|
||||
}
|
||||
return {
|
||||
videoSource,
|
||||
videoType,
|
||||
videoId,
|
||||
fallbackVideos,
|
||||
};
|
||||
|
||||
@@ -94,7 +94,6 @@ describe('video thunkActions', () => {
|
||||
videoSource: 'videOsOurce',
|
||||
videoId: 'videOiD',
|
||||
fallbackVideos: 'fALLbACKvIDeos',
|
||||
videoType: 'viDEOtyPE',
|
||||
});
|
||||
jest.spyOn(thunkActions, thunkActionsKeys.parseLicense).mockReturnValue([
|
||||
'liCENSEtyPe',
|
||||
@@ -123,7 +122,6 @@ describe('video thunkActions', () => {
|
||||
videoSource: 'videOsOurce',
|
||||
videoId: 'videOiD',
|
||||
fallbackVideos: 'fALLbACKvIDeos',
|
||||
videoType: 'viDEOtyPE',
|
||||
allowVideoDownloads: testMetadata.download_video,
|
||||
transcripts: testMetadata.transcripts,
|
||||
allowTranscriptDownloads: testMetadata.download_track,
|
||||
@@ -173,7 +171,6 @@ describe('video thunkActions', () => {
|
||||
})).toEqual({
|
||||
videoSource: youtubeUrl,
|
||||
videoId: edxVideoId,
|
||||
videoType: 'youtube',
|
||||
fallbackVideos: html5Sources,
|
||||
});
|
||||
});
|
||||
@@ -185,10 +182,9 @@ describe('video thunkActions', () => {
|
||||
youtubeId: '',
|
||||
html5Sources: '',
|
||||
})).toEqual({
|
||||
videoSource: edxVideoId,
|
||||
videoSource: '',
|
||||
videoId: edxVideoId,
|
||||
videoType: 'edxVideo',
|
||||
fallbackVideos: ['', ''],
|
||||
fallbackVideos: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -201,7 +197,6 @@ describe('video thunkActions', () => {
|
||||
})).toEqual({
|
||||
videoSource: youtubeUrl,
|
||||
videoId: '',
|
||||
videoType: 'youtube',
|
||||
fallbackVideos: html5Sources,
|
||||
});
|
||||
});
|
||||
@@ -215,7 +210,6 @@ describe('video thunkActions', () => {
|
||||
})).toEqual({
|
||||
videoSource: 'htmLOne',
|
||||
videoId: '',
|
||||
videoType: 'html5source',
|
||||
fallbackVideos: ['hTMlTwo', 'htMLthrEE'],
|
||||
});
|
||||
});
|
||||
@@ -227,8 +221,7 @@ describe('video thunkActions', () => {
|
||||
})).toEqual({
|
||||
videoSource: 'htmlOne',
|
||||
videoId: '',
|
||||
fallbackVideos: ['', ''],
|
||||
videoType: 'html5source',
|
||||
fallbackVideos: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -241,8 +234,7 @@ describe('video thunkActions', () => {
|
||||
})).toEqual({
|
||||
videoSource: '',
|
||||
videoId: '',
|
||||
fallbackVideos: ['', ''],
|
||||
videoType: '',
|
||||
fallbackVideos: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ import { StrictDict } from '../../../utils';
|
||||
|
||||
const initialState = {
|
||||
videoSource: '',
|
||||
videoType: '',
|
||||
videoId: '',
|
||||
fallbackVideos: [
|
||||
'',
|
||||
|
||||
@@ -28,7 +28,6 @@ export const simpleSelectors = [
|
||||
stateKeys.courseLicenseType,
|
||||
stateKeys.courseLicenseDetails,
|
||||
stateKeys.allowThumbnailUpload,
|
||||
stateKeys.videoType,
|
||||
].reduce((obj, key) => ({ ...obj, [key]: state => state.video[key] }), {});
|
||||
|
||||
export const openLanguages = createSelector(
|
||||
|
||||
@@ -117,6 +117,7 @@ export const apiMethods = {
|
||||
edxVideoId,
|
||||
youtubeId,
|
||||
} = module.processVideoIds({
|
||||
videoId: content.videoId,
|
||||
videoSource: content.videoSource,
|
||||
fallbackVideos: content.fallbackVideos,
|
||||
});
|
||||
@@ -173,14 +174,19 @@ export const loadImages = (rawImages) => camelizeKeys(rawImages).reduce(
|
||||
{},
|
||||
);
|
||||
|
||||
export const processVideoIds = ({ videoSource, fallbackVideos, edxVideoId }) => {
|
||||
export const processVideoIds = ({
|
||||
videoId,
|
||||
videoSource,
|
||||
fallbackVideos,
|
||||
edxVideoId,
|
||||
}) => {
|
||||
let newEdxVideoId = edxVideoId;
|
||||
let youtubeId = '';
|
||||
const html5Sources = [];
|
||||
|
||||
// overwrite videoId if source is changed.
|
||||
if (module.isEdxVideo(videoSource)) {
|
||||
newEdxVideoId = videoSource;
|
||||
if (module.isEdxVideo(videoId)) {
|
||||
newEdxVideoId = videoId;
|
||||
} else if (module.parseYoutubeId(videoSource)) {
|
||||
youtubeId = module.parseYoutubeId(videoSource);
|
||||
} else if (videoSource) {
|
||||
@@ -200,7 +206,7 @@ export const processVideoIds = ({ videoSource, fallbackVideos, edxVideoId }) =>
|
||||
|
||||
export const isEdxVideo = (src) => {
|
||||
const uuid4Regex = new RegExp(/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/);
|
||||
if (src.match(uuid4Regex)) {
|
||||
if (src && src.match(uuid4Regex)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -321,8 +321,9 @@ describe('cms api', () => {
|
||||
it('returns edxVideoId when there are no fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: edxVideoId,
|
||||
videoSource: '',
|
||||
fallbackVideos: [],
|
||||
videoId: edxVideoId,
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
html5Sources: [],
|
||||
@@ -332,8 +333,9 @@ describe('cms api', () => {
|
||||
it('returns edxVideoId and html5Sources when there are fallbackVideos', () => {
|
||||
expect(api.processVideoIds({
|
||||
edxVideoId,
|
||||
videoSource: edxVideoId,
|
||||
videoSource: 'edxVideoId',
|
||||
fallbackVideos: html5Sources,
|
||||
videoId: edxVideoId,
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
html5Sources,
|
||||
@@ -351,6 +353,7 @@ describe('cms api', () => {
|
||||
edxVideoId,
|
||||
videoSource: edxVideoId,
|
||||
fallbackVideos: [],
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
html5Sources: [],
|
||||
@@ -362,6 +365,7 @@ describe('cms api', () => {
|
||||
edxVideoId,
|
||||
videoSource: edxVideoId,
|
||||
fallbackVideos: html5Sources,
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
html5Sources,
|
||||
@@ -379,6 +383,7 @@ describe('cms api', () => {
|
||||
edxVideoId,
|
||||
videoSource: html5Sources[0],
|
||||
fallbackVideos: [],
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
html5Sources: [html5Sources[0]],
|
||||
@@ -390,6 +395,7 @@ describe('cms api', () => {
|
||||
edxVideoId,
|
||||
videoSource: html5Sources[0],
|
||||
fallbackVideos: [html5Sources[1]],
|
||||
videoId: '',
|
||||
})).toEqual({
|
||||
edxVideoId,
|
||||
html5Sources,
|
||||
|
||||
Reference in New Issue
Block a user