diff --git a/src/editors/containers/library_contentEditor/BlockSettingsEditor.jsx b/src/editors/containers/library_contentEditor/BlockSettingsEditor.jsx new file mode 100644 index 000000000..987ad9d6c --- /dev/null +++ b/src/editors/containers/library_contentEditor/BlockSettingsEditor.jsx @@ -0,0 +1,88 @@ +import React from 'react'; +import { modes } from './constants'; +import { selectors, thunkActions } from '../../data/redux'; + +const BlockSettingsEditor = ({ + selectionMode, + onSelectionModeChange, + selectionSettings, + blocksInSelectedLibrary, + onSelectionSettingsChange, + }) => { + + const getSelectionSettings = () =>{ + if (selectionMode === modes.all){ + return (<>) + } + if (selectionMode === modes.random){ + return ( + <> + + onSelectionSettingsChange({ + count: e.target.value, + ...selectionSettings + })} + floatingLabel="How many blocks do you want to show the author?" + /> + + + onSelectionSettingsChange({ + showReset: e.target.checked, + ...selectionSettings + })} + > + Show Reset Button + +
+ Determines whether a 'Reset Problems' button is shown, so users may reset their answers and reshuffle selected items. +
+
+ {/* TODO: ADD CAPA FILTERING FOR V1 ONLY */} + + ) + } + if (selectionMode === modes.selected){ + return ( + <> + {/*TODO: ADD BLOCK PICKER*/} +

Block Selection Can be Made by Saving the editor and clicking the "view" button or going here.

+ {/* Opens library page in new window.*/} + https://studio.edx.org/container/block-v1:edX+LA101+2022_Summer+type@library_content+block@6a0e7d3c67614ae78e28d575408624cf + + ) + } + } + return ( +
+ + + { + modes.values().map(mode => ()) + } + + {getSelectionSettings()} + +
+ ); +}; + +export const mapStateToProps = (state) => ({ + selectionMode: selectors.library.selectionMode(state), + selectionSettings: selectors.library.selectionSettings(state), + blocksInSelectedLibrary: selectors.library.blocksInSelectedLibrary(state), +}) + +export const mapDispatchToProps = { + onSelectionModeChange: thunkActions.library.onSelectionModeChange, + onSelectionSettingsChange: thunkActions.library.onSelectionSettingsChange, +}; + +export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(LibraryBlockPicker)); \ No newline at end of file diff --git a/src/editors/containers/library_contentEditor/LibrarySelector.jsx b/src/editors/containers/library_contentEditor/LibrarySelector.jsx new file mode 100644 index 000000000..e22f91510 --- /dev/null +++ b/src/editors/containers/library_contentEditor/LibrarySelector.jsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { Dropdown } from '@edx/paragon'; + + +const LibrarySelector = ({ libraries, selectedLibrary, onSelectLibrary }) => { + return ( +
+ + ({ + label: library.name, + value: library.id, + }))} + value={selectedLibrary} + onChange={onSelectLibrary} + /> +
+ ); +}; + +export const mapStateToProps = (state) => ({ + selectionMode: selectors.library.libraries(state), + selectionSettings: selectors.library.selectedLibrary(state), +}) + +export const mapDispatchToProps = { + onSelectLibrary: reducers.library.onSelectLibrary, +}; + +export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(LibrarySelector)); + + diff --git a/src/editors/containers/library_contentEditor/constants.js b/src/editors/containers/library_contentEditor/constants.js new file mode 100644 index 000000000..ee23162e8 --- /dev/null +++ b/src/editors/containers/library_contentEditor/constants.js @@ -0,0 +1,16 @@ +import messages from "./messages" + +export const modes = { + all: { + description: messages.modeAll, + value: 'all' + }, + random: { + description: messages.modeRandom, + value: 'random' + }, + selected: { + description: messages.modeSelected, + value: 'selected' + } +} diff --git a/src/editors/containers/library_contentEditor/data/api.js b/src/editors/containers/library_contentEditor/data/api.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/editors/containers/library_contentEditor/data/reducers.js b/src/editors/containers/library_contentEditor/data/reducers.js new file mode 100644 index 000000000..3e4155f19 --- /dev/null +++ b/src/editors/containers/library_contentEditor/data/reducers.js @@ -0,0 +1,51 @@ +import { createSlice } from '@reduxjs/toolkit'; +import { modes } from '../constants'; + +const initialState = { + libraries: [], + selectedLibrary: null, + selectionMode: modes.all, + selectionSettings: { + count: false, + showReset: false, + }, + blocksInSelectedLibrary: [], +}; + +const library = createSlice({ + name: 'library', + initialState, + reducers: { + initialize: (state, { payload }) => ({ + ...state, + studioEndpointUrl: payload.studioEndpointUrl, + lmsEndpointUrl: payload.lmsEndpointUrl, + blockId: payload.blockId, + learningContextId: payload.learningContextId, + blockType: payload.blockType, + blockValue: null, + }), + onSelectLibrary: (state, {payload}) => ({ + ...state, + selectedLibrary: payload.selectedLibrary, + }), + onSelectionModeChange: (state, {payload}) => ({ + ...state, + selectionMode: payload.selectionMode, + }), + onSelectionSettingsChange: (state,{payload})=>({ + ...state, + selectionSettings:payload.selectionSettings, + }), + }, + }); + +const actions = StrictDict(app.actions); + +const { reducer } = library; + +export { + actions, + initialState, + reducer, +}; \ No newline at end of file diff --git a/src/editors/containers/library_contentEditor/data/selectors.js b/src/editors/containers/library_contentEditor/data/selectors.js new file mode 100644 index 000000000..fb5fbfb0c --- /dev/null +++ b/src/editors/containers/library_contentEditor/data/selectors.js @@ -0,0 +1,20 @@ +import { createSelector } from 'reselect'; +import { blockTypes } from '../../constants/app'; +import * as urls from '../../services/cms/urls'; +import * as module from './selectors'; + +export const appSelector = (state) => state.app; + +const mkSimpleSelector = (cb) => createSelector([module.appSelector], cb); + +export const simpleSelectors = { + libraries: mkSimpleSelector(app => app.libraries), + selectedLibrary: mkSimpleSelector(app => app.selectedLibrary), + selectionMode: mkSimpleSelector(app => app.selectionMode), + selectionSettings: mkSimpleSelector(app => app.selectionSettings), + blocksInSelectedLibrary: mkSimpleSelector(app => app.blocksInSelectedLibrary), +} + +export default { + ...simpleSelectors, +} \ No newline at end of file diff --git a/src/editors/containers/library_contentEditor/data/urls.js b/src/editors/containers/library_contentEditor/data/urls.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/editors/containers/library_contentEditor/index.jsx b/src/editors/containers/library_contentEditor/index.jsx new file mode 100644 index 000000000..4a4167b16 --- /dev/null +++ b/src/editors/containers/library_contentEditor/index.jsx @@ -0,0 +1,111 @@ +/* eslint-disable import/extensions */ +/* eslint-disable import/no-unresolved */ +/** + * This is an example component for an xblock Editor + * It uses pre-existing components to handle the saving of a the result of a function into the xblock's data. + * To use run npm run-script addXblock + */ + +/* eslint-disable no-unused-vars */ + +import React, { useState } from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; + +import { Spinner } from '@edx/paragon'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; + +import EditorContainer from '../EditorContainer'; +import * as module from '.'; +import { actions, selectors } from '../../data/redux'; +import { RequestKeys } from '../../data/constants/requests'; +import LibrarySelector from './LibrarySelector'; +import LibraryBlockPicker from './LibraryBlockPicker'; + +export const hooks = { + getContent: () => ({ + some: 'content', + }), +}; + +export const thumbEditor = ({ + onClose, + // redux app layer + blockValue, + lmsEndpointUrl, + blockFailed, + blockFinished, + initializeEditor, + // inject + intl, +}) => +{ + const libraries, setLibraries = useState([]); + + useEffect(() => { + setLibraries(api.getLibraries(cmsEndpointUrl)); + }, []); + + return ( + +
+ {!blockFinished + ? ( +
+ +
+ ) + : ( +
+ + { + selected_library ? + (): + (<>) + } +
+ )} +
+
+)}; +thumbEditor.defaultProps = { + blockValue: null, + lmsEndpointUrl: null, +}; +thumbEditor.propTypes = { + onClose: PropTypes.func.isRequired, + // redux + blockValue: PropTypes.shape({ + data: PropTypes.shape({ data: PropTypes.string }), + }), + lmsEndpointUrl: PropTypes.string, + blockFailed: PropTypes.bool.isRequired, + blockFinished: PropTypes.bool.isRequired, + initializeEditor: PropTypes.func.isRequired, + // inject + intl: intlShape.isRequired, +}; + +export const mapStateToProps = (state) => ({ + blockValue: selectors.app.blockValue(state), + lmsEndpointUrl: selectors.app.lmsEndpointUrl(state), + blockFailed: selectors.requests.isFailed(state, { requestKey: RequestKeys.fetchBlock }), + blockFinished: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchBlock }), +}); + +export const mapDispatchToProps = { + initializeEditor: actions.app.initializeEditor, +}; + +export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(thumbEditor)); diff --git a/src/editors/containers/library_contentEditor/messages.js b/src/editors/containers/library_contentEditor/messages.js new file mode 100644 index 000000000..46a50345e --- /dev/null +++ b/src/editors/containers/library_contentEditor/messages.js @@ -0,0 +1,22 @@ +import { defineMessages } from '@edx/frontend-platform/i18n'; + +const messages = defineMessages({ + modeAll: { + id: 'authoring.library_content.mode.all', + defaultMessage: 'Show all content from the library to every learner', + description: 'mode of selecting content from a library to put in a course', + }, + modeRandom: { + id: 'authoring.library_content.mode.random', + defaultMessage: 'Show X problems at random from the Library', + description: 'mode of selecting content from a library to put in a course', + }, + modeSelected: { + id: 'authoring.library_content.mode.selected', + defaultMessage: 'Show a specfic portion of the library to all users', + description: 'mode of selecting content from a library to put in a course', + }, + +}); + +export default messages; \ No newline at end of file diff --git a/src/editors/data/constants/app.js b/src/editors/data/constants/app.js index 3b0fc7b9c..bdebaf4fe 100644 --- a/src/editors/data/constants/app.js +++ b/src/editors/data/constants/app.js @@ -5,6 +5,8 @@ export const blockTypes = StrictDict({ html: 'html', video: 'video', problem: 'problem', + library_content: 'library_content', + // ADDED_EDITORS GO BELOW video_upload: 'video_upload', game: 'game', diff --git a/src/editors/supportedEditors.js b/src/editors/supportedEditors.js index 82d9c568a..f1d6401c2 100644 --- a/src/editors/supportedEditors.js +++ b/src/editors/supportedEditors.js @@ -4,6 +4,8 @@ import ProblemEditor from './containers/ProblemEditor'; import VideoUploadEditor from './containers/VideoUploadEditor'; import GameEditor from './containers/GameEditor'; +import library_contentEditor from './containers/library_contentEditor' + // ADDED_EDITOR_IMPORTS GO HERE import { blockTypes } from './data/constants/app'; @@ -13,6 +15,8 @@ const supportedEditors = { [blockTypes.video]: VideoEditor, [blockTypes.problem]: ProblemEditor, [blockTypes.video_upload]: VideoUploadEditor, + [blockTypes.library_content]: library_contentEditor, + // ADDED_EDITORS GO BELOW [blockTypes.game]: GameEditor, };