chore: All selection and save flow added

This commit is contained in:
XnpioChV
2023-04-06 14:20:48 -05:00
parent 23593b44fe
commit da00ad7539
4 changed files with 100 additions and 14 deletions

View File

@@ -12,9 +12,9 @@ export const {
} = appHooks;
export const hooks = {
initialize: (dispatch) => {
initialize: (dispatch, selectedVideoId) => {
React.useEffect(() => {
dispatch(thunkActions.video.loadVideoData());
dispatch(thunkActions.video.loadVideoData(selectedVideoId));
}, []);
},
returnToGallery: () => {
@@ -29,10 +29,11 @@ const VideoEditorModal = ({
isOpen,
}) => {
const dispatch = useDispatch();
module.hooks.initialize(dispatch);
const searchParams = new URLSearchParams(document.location.search);
const showReturn = searchParams.get('return') !== null;
const selectedVideoId = searchParams.get('selectedVideoId');
const showReturn = selectedVideoId != null;
const onReturn = module.hooks.returnToGallery();
module.hooks.initialize(dispatch, selectedVideoId);
return (
<VideoSettingsModal {...{
close,

View File

@@ -129,8 +129,7 @@ export const videoListProps = ({ searchSortProps, videos }) => {
selectBtnProps: {
onClick: () => {
if (highlighted) {
// TODO save the metadata of the video on the block to fill it into the cideo editor
navigateTo(`/course/${learningContextId}/editor/video/${blockId}?return=true`);
navigateTo(`/course/${learningContextId}/editor/video/${blockId}?selectedVideoId=${highlighted}`);
} else {
setShowSelectVideoError(true);
}

View File

@@ -1,16 +1,27 @@
/* eslint-disable import/no-cycle */
import { actions, selectors } from '..';
import { removeItemOnce } from '../../../utils';
import { formatDuration, removeItemOnce } from '../../../utils';
import * as requests from './requests';
import * as module from './video';
import { valueFromDuration } from '../../../containers/VideoEditor/components/VideoSettingsModal/components/DurationWidget/hooks';
import { parseYoutubeId } from '../../services/cms/api';
export const loadVideoData = () => (dispatch, getState) => {
export const loadVideoData = (selectedVideoId) => (dispatch, getState) => {
const state = getState();
const blockValueData = state.app.blockValue.data;
const rawVideoData = blockValueData.metadata ? blockValueData.metadata : {};
const courseData = state.app.courseDetails.data ? state.app.courseDetails.data : {};
if (Object.keys(rawVideoData).length === 0 && selectedVideoId !== null) {
const rawVideos = Object.values(selectors.app.videos(state));
const selectedVideo = rawVideos.find(video => video.edx_video_id === selectedVideoId);
// TODO it's missing laod the transcripts
rawVideoData = {
edx_video_id: selectedVideo.edx_video_id,
thumbnail: selectedVideo.course_video_image_url,
end_time: formatDuration(selectedVideo.duration),
duration: selectedVideo.duration,
};
}
const studioView = state.app.studioView?.data?.html;
const {
videoId,
@@ -45,7 +56,7 @@ export const loadVideoData = () => (dispatch, getState) => {
duration: { // TODO duration is not always sent so they should be calculated.
startTime: valueFromDuration(rawVideoData.start_time || '00:00:00'),
stopTime: valueFromDuration(rawVideoData.end_time || '00:00:00'),
total: 0, // TODO can we get total duration? if not, probably dropping from widget
total: rawVideoData.duration || 0, // TODO can we get total duration? if not, probably dropping from widget
},
handout: rawVideoData.handout,
licenseType,

View File

@@ -12,6 +12,7 @@ jest.mock('..', () => ({
selectors: {
app: {
courseDetails: (state) => ({ courseDetails: state }),
videos: (state) => ({ videos: state.app.videos }),
},
video: {
videoId: (state) => ({ videoId: state }),
@@ -34,6 +35,7 @@ jest.mock('./requests', () => ({
}));
jest.mock('../../../utils', () => ({
...jest.requireActual('../../../utils'),
removeItemOnce: (args) => (args),
}));
@@ -56,6 +58,7 @@ const mockVideoFeatures = {
videoSharingEnabled: 'soMEbOolEAn',
},
};
const mockSelectedVideoId = 'ThisIsAVideoId';
const testMetadata = {
download_track: 'dOWNlOAdTraCK',
@@ -80,6 +83,11 @@ const testState = {
originalThumbnail: null,
videoId: 'soMEvIDEo',
};
const testVideosState = {
edx_video_id: mockSelectedVideoId,
thumbnail: 'thumbnail',
duration: 60,
};
const testUpload = { transcripts: ['la', 'en'] };
const testReplaceUpload = {
file: mockFile,
@@ -130,25 +138,37 @@ describe('video thunkActions', () => {
jest.spyOn(thunkActions, thunkActionsKeys.parseTranscripts).mockReturnValue(
testMetadata.transcripts,
);
});
afterEach(() => {
jest.restoreAllMocks();
});
it('dispatches fetchVideoFeatures action', () => {
thunkActions.loadVideoData()(dispatch, getState);
[
[dispatchedLoad],
[dispatchedAction1],
[dispatchedAction2],
] = dispatch.mock.calls;
});
afterEach(() => {
jest.restoreAllMocks();
});
it('dispatches fetchVideoFeatures action', () => {
expect(dispatchedLoad).not.toEqual(undefined);
expect(dispatchedAction1.fetchVideoFeatures).not.toEqual(undefined);
});
it('dispatches checkTranscriptsForImport action', () => {
thunkActions.loadVideoData()(dispatch, getState);
[
[dispatchedLoad],
[dispatchedAction1],
[dispatchedAction2],
] = dispatch.mock.calls;
expect(dispatchedLoad).not.toEqual(undefined);
expect(dispatchedAction2.checkTranscriptsForImport).not.toEqual(undefined);
});
it('dispatches actions.video.load', () => {
thunkActions.loadVideoData()(dispatch, getState);
[
[dispatchedLoad],
[dispatchedAction1],
[dispatchedAction2],
] = dispatch.mock.calls;
expect(dispatchedLoad.load).toEqual({
videoSource: 'videOsOurce',
videoId: 'videOiD',
@@ -186,7 +206,62 @@ describe('video thunkActions', () => {
thumbnail: testMetadata.thumbnail,
});
});
it('dispatches actions.video.load with selectedVideoId', () => {
getState = jest.fn(() => ({
app: {
blockId: 'soMEBloCk',
studioEndpointUrl: 'soMEeNDPoiNT',
blockValue: { data: { metadata: {} } },
courseDetails: { data: { license: null } },
studioView: { data: { html: 'sOMeHTml' } },
videos: testVideosState,
},
}));
thunkActions.loadVideoData(mockSelectedVideoId)(dispatch, getState);
[
[dispatchedLoad],
[dispatchedAction1],
[dispatchedAction2],
] = dispatch.mock.calls;
expect(dispatchedLoad.load).toEqual({
videoSource: 'videOsOurce',
videoId: 'videOiD',
fallbackVideos: 'fALLbACKvIDeos',
allowVideoDownloads: undefined,
transcripts: testMetadata.transcripts,
allowTranscriptDownloads: undefined,
allowVideoSharing: undefined,
showTranscriptByDefault: undefined,
duration: {
startTime: testMetadata.start_time,
stopTime: testVideosState.duration * 1000,
total: testVideosState.duration,
},
handout: undefined,
licenseType: 'liCENSEtyPe',
licenseDetails: {
attribution: true,
noncommercial: true,
noDerivatives: true,
shareAlike: false,
},
courseLicenseType: 'liCENSEtyPe',
courseLicenseDetails: {
attribution: true,
noncommercial: true,
noDerivatives: true,
shareAlike: false,
},
thumbnail: undefined,
});
});
it('dispatches actions.video.updateField on success', () => {
thunkActions.loadVideoData()(dispatch, getState);
[
[dispatchedLoad],
[dispatchedAction1],
[dispatchedAction2],
] = dispatch.mock.calls;
dispatch.mockClear();
dispatchedAction1.fetchVideoFeatures.onSuccess(mockVideoFeatures);
expect(dispatch).toHaveBeenCalledWith(actions.video.updateField({