From b4fb88c73c4d1489fda0871b4c14ac9e9657bd69 Mon Sep 17 00:00:00 2001 From: Keith Grootboom Date: Tue, 14 Mar 2023 14:19:41 +0200 Subject: [PATCH] feat: add video preview widget to settings modal --- .../components/ThumbnailWidget/hooks.js | 2 + .../TranscriptWidget/LanguageSelector.jsx | 1 - .../LanguageNamesWidget.jsx | 34 ++++++++ .../components/VideoPreviewWidget/hooks.js | 18 ++++ .../components/VideoPreviewWidget/index.jsx | 84 +++++++++++++++++++ .../VideoSettingsModal/components/messages.js | 14 ++++ .../components/VideoSettingsModal/index.jsx | 2 + 7 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/LanguageNamesWidget.jsx create mode 100644 src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/hooks.js create mode 100644 src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/index.jsx diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/ThumbnailWidget/hooks.js b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/ThumbnailWidget/hooks.js index 02c2d320a..9e307e96d 100644 --- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/ThumbnailWidget/hooks.js +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/ThumbnailWidget/hooks.js @@ -105,9 +105,11 @@ export const fileInput = ({ setThumbnailSrc, imgRef, fileSizeError }) => { const [resampledUrl, resampledFile] = module.resampleImage({ image, filename: file.name }); setThumbnailSrc(resampledUrl); dispatch(thunkActions.video.uploadThumbnail({ thumbnail: resampledFile })); + dispatch(actions.video.updateField({ thumbnail: resampledUrl })); return; } dispatch(thunkActions.video.uploadThumbnail({ thumbnail: file })); + dispatch(actions.video.updateField({ thumbnail: reader.result })); }; }; dispatch(actions.video.updateField({ thumbnail: ' ' })); diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/LanguageSelector.jsx b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/LanguageSelector.jsx index 511c59bed..751659953 100644 --- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/LanguageSelector.jsx +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/TranscriptWidget/LanguageSelector.jsx @@ -59,7 +59,6 @@ export const LanguageSelector = ({ const onLanguageChange = module.hooks.onSelectLanguage({ dispatch: useDispatch(), languageBeforeChange: localLang, setLocalLang, triggerupload: input.click, }); - console.log({ localLang, language, openLanguages }); const getTitle = () => { if (Object.prototype.hasOwnProperty.call(videoTranscriptLanguages, language)) { diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/LanguageNamesWidget.jsx b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/LanguageNamesWidget.jsx new file mode 100644 index 000000000..2fabd32cb --- /dev/null +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/LanguageNamesWidget.jsx @@ -0,0 +1,34 @@ +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { Icon } from '@edx/paragon'; +import { ClosedCaptionOff, ClosedCaption } from '@edx/paragon/icons'; +import PropTypes from 'prop-types'; +import React from 'react'; +import messages from '../messages'; +import { hooks as transcriptHooks } from '../TranscriptWidget'; + +export const LanguageNamesWidget = ({ transcripts, intl }) => { + let icon = ClosedCaptionOff; + const hasTranscripts = transcriptHooks.hasTranscripts(transcripts); + let message = intl.formatMessage(messages.noTranscriptsAdded); + let fontClass = 'text-gray'; + + if (hasTranscripts) { + message = transcriptHooks.transcriptLanguages(transcripts, intl); + fontClass = 'text-primary'; + icon = ClosedCaption; + } + + return ( +
+ + {message} +
+ ); +}; + +LanguageNamesWidget.propTypes = { + intl: intlShape.isRequired, + transcripts: PropTypes.arrayOf(PropTypes.string).isRequired, +}; + +export default injectIntl(LanguageNamesWidget); diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/hooks.js b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/hooks.js new file mode 100644 index 000000000..ac2a03fc3 --- /dev/null +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/hooks.js @@ -0,0 +1,18 @@ +import messages from '../messages'; + +// https://stackoverflow.com/a/28735961/479084 +const youtubeRegex = /^(?:https?:\/\/)?(?:m\.|www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/; +function isYoutubeUrl(url) { + return url.match(youtubeRegex) !== null; +} + +function getVideoType(videoSource) { + if (isYoutubeUrl(videoSource)) { + return messages.videoTypeYoutube; + } + return messages.videoTypeOther; +} + +export default { + getVideoType, +}; diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/index.jsx b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/index.jsx new file mode 100644 index 000000000..4a17b2372 --- /dev/null +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/index.jsx @@ -0,0 +1,84 @@ +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { + Collapsible, Icon, Image, Stack, +} from '@edx/paragon'; +import { Launch } from '@edx/paragon/icons'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { connect } from 'react-redux'; +import { selectors } from '../../../../../../data/redux'; +import thumbnailMessages from '../ThumbnailWidget/messages'; +import hooks from './hooks'; +import LanguageNamesWidget from './LanguageNamesWidget'; + +export const VideoPreviewWidget = ({ + thumbnail, + videoSource, + transcripts, + blockTitle, + intl, +}) => { + const imgRef = React.useRef(); + const videoType = intl.formatMessage(hooks.getVideoType(videoSource)); + + return ( + + +
+ {intl.formatMessage(thumbnailMessages.thumbnailAltText)} + +

{blockTitle}

+ + {videoType && ( + + {videoType} + + + )} +
+
+
+
+ ); +}; + +VideoPreviewWidget.propTypes = { + intl: intlShape.isRequired, + videoSource: PropTypes.string.isRequired, + thumbnail: PropTypes.string.isRequired, + transcripts: PropTypes.arrayOf(PropTypes.string).isRequired, + blockTitle: PropTypes.string.isRequired, +}; + +export const mapStateToProps = (state) => ({ + transcripts: selectors.video.transcripts(state), + videoSource: selectors.video.videoSource(state), + thumbnail: selectors.video.thumbnail(state), + blockTitle: selectors.app.blockTitle(state), +}); + +export default injectIntl(connect(mapStateToProps)(VideoPreviewWidget)); diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/messages.js b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/messages.js index 2daece6bf..63b6636ba 100644 --- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/messages.js +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/components/messages.js @@ -61,6 +61,20 @@ export const messages = { id: 'authoring.videoeditor.duration.custom', defaultMessage: 'Custom: {total}', description: 'Text describing a video with custom start time and custom stop time, or just a custom stop time for a collapsed widget', + noTranscriptsAdded: { + id: 'authoring.videoeditor.transcripts.empty', + defaultMessage: 'No transcripts added', + description: 'Message shown when the user has not selected any transcripts for the video.', + }, + videoTypeYoutube: { + id: 'authoring.videoeditor.videotype.youtube', + defaultMessage: 'Youtube video', + description: 'Shown on the preview card if the video is from youtube.com.', + }, + videoTypeOther: { + id: 'authoring.videoeditor.videotype.other', + defaultMessage: 'Other video', + description: 'Shown on the preview card if the video source could not be identified.', }, }; diff --git a/src/editors/containers/VideoEditor/components/VideoSettingsModal/index.jsx b/src/editors/containers/VideoEditor/components/VideoSettingsModal/index.jsx index 24d194ae3..b896c11e1 100644 --- a/src/editors/containers/VideoEditor/components/VideoSettingsModal/index.jsx +++ b/src/editors/containers/VideoEditor/components/VideoSettingsModal/index.jsx @@ -8,11 +8,13 @@ import LicenseWidget from './components/LicenseWidget'; import ThumbnailWidget from './components/ThumbnailWidget'; import TranscriptWidget from './components/TranscriptWidget'; import VideoSourceWidget from './components/VideoSourceWidget'; +import VideoPreviewWidget from './components/VideoPreviewWidget'; import './index.scss'; export const VideoSettingsModal = () => ( <> +