feat: setup game editor work (#363)
This commit is contained in:
102
src/editors/containers/GameEditor/index.jsx
Normal file
102
src/editors/containers/GameEditor/index.jsx
Normal file
@@ -0,0 +1,102 @@
|
||||
/* 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 <your>
|
||||
*/
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
import React 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';
|
||||
|
||||
export const hooks = {
|
||||
getContent: () => ({
|
||||
some: 'content',
|
||||
}),
|
||||
};
|
||||
|
||||
export const thumbEditor = ({
|
||||
onClose,
|
||||
// redux
|
||||
blockValue,
|
||||
lmsEndpointUrl,
|
||||
blockFailed,
|
||||
blockFinished,
|
||||
initializeEditor,
|
||||
exampleValue,
|
||||
// inject
|
||||
intl,
|
||||
}) => (
|
||||
<EditorContainer
|
||||
getContent={module.hooks.getContent}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div>
|
||||
{exampleValue}
|
||||
</div>
|
||||
<div className="editor-body h-75 overflow-auto">
|
||||
{!blockFinished
|
||||
? (
|
||||
<div className="text-center p-6">
|
||||
<Spinner
|
||||
animation="border"
|
||||
className="m-3"
|
||||
// Use a messages.js file for intl messages.
|
||||
screenreadertext={intl.formatMessage('Loading Spinner')}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<p>
|
||||
Your Editor Goes here.
|
||||
You can get at the xblock data with the blockValue field.
|
||||
here is what is in your xblock: {JSON.stringify(blockValue)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</EditorContainer>
|
||||
);
|
||||
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 }),
|
||||
// TODO fill with redux state here if needed
|
||||
exampleValue: selectors.game.exampleValue(state),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = {
|
||||
initializeEditor: actions.app.initializeEditor,
|
||||
// TODO fill with dispatches here if needed
|
||||
};
|
||||
|
||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(thumbEditor));
|
||||
@@ -7,4 +7,5 @@ export const blockTypes = StrictDict({
|
||||
problem: 'problem',
|
||||
// ADDED_EDITORS GO BELOW
|
||||
video_upload: 'video_upload',
|
||||
game: 'game',
|
||||
});
|
||||
|
||||
2
src/editors/data/redux/game/index.js
Normal file
2
src/editors/data/redux/game/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
export { actions, reducer } from './reducers';
|
||||
export { default as selectors } from './selectors';
|
||||
31
src/editors/data/redux/game/reducers.js
Normal file
31
src/editors/data/redux/game/reducers.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { StrictDict } from '../../../utils';
|
||||
|
||||
const initialState = {
|
||||
settings: {},
|
||||
// TODO fill in with mock state
|
||||
exampleValue: 'this is an example value from the redux state',
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const game = createSlice({
|
||||
name: 'game',
|
||||
initialState,
|
||||
reducers: {
|
||||
updateField: (state, { payload }) => ({
|
||||
...state,
|
||||
...payload,
|
||||
}),
|
||||
// TODO fill in reducers
|
||||
},
|
||||
});
|
||||
|
||||
const actions = StrictDict(game.actions);
|
||||
|
||||
const { reducer } = game;
|
||||
|
||||
export {
|
||||
actions,
|
||||
initialState,
|
||||
reducer,
|
||||
};
|
||||
15
src/editors/data/redux/game/selectors.js
Normal file
15
src/editors/data/redux/game/selectors.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import * as module from './selectors';
|
||||
|
||||
export const gameState = (state) => state.game;
|
||||
const mkSimpleSelector = (cb) => createSelector([module.gameState], cb);
|
||||
export const simpleSelectors = {
|
||||
exampleValue: mkSimpleSelector(gameData => gameData.exampleValue),
|
||||
settings: mkSimpleSelector(gameData => gameData.settings),
|
||||
completeState: mkSimpleSelector(gameData => gameData),
|
||||
// TODO fill in with selectors as needed
|
||||
};
|
||||
|
||||
export default {
|
||||
...simpleSelectors,
|
||||
};
|
||||
@@ -6,6 +6,7 @@ import * as app from './app';
|
||||
import * as requests from './requests';
|
||||
import * as video from './video';
|
||||
import * as problem from './problem';
|
||||
import * as game from './game';
|
||||
|
||||
/* eslint-disable import/no-cycle */
|
||||
export { default as thunkActions } from './thunkActions';
|
||||
@@ -15,6 +16,7 @@ const modules = {
|
||||
requests,
|
||||
video,
|
||||
problem,
|
||||
game,
|
||||
};
|
||||
|
||||
const moduleProps = (propName) => Object.keys(modules).reduce(
|
||||
|
||||
@@ -54,6 +54,11 @@ export const fetchBlockById = ({ blockId, studioEndpointUrl }) => {
|
||||
weight: 29,
|
||||
},
|
||||
};
|
||||
} else if (blockId === 'game-block-id') {
|
||||
data = {
|
||||
display_name: 'Game Block',
|
||||
// TODO: insert mock data from backend here
|
||||
};
|
||||
}
|
||||
return mockPromise({ data: { ...data } });
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import TextEditor from './containers/TextEditor';
|
||||
import VideoEditor from './containers/VideoEditor';
|
||||
import ProblemEditor from './containers/ProblemEditor';
|
||||
import VideoUploadEditor from './containers/VideoUploadEditor';
|
||||
import GameEditor from './containers/GameEditor';
|
||||
|
||||
// ADDED_EDITOR_IMPORTS GO HERE
|
||||
|
||||
@@ -13,6 +14,7 @@ const supportedEditors = {
|
||||
[blockTypes.problem]: ProblemEditor,
|
||||
[blockTypes.video_upload]: VideoUploadEditor,
|
||||
// ADDED_EDITORS GO BELOW
|
||||
[blockTypes.game]: GameEditor,
|
||||
};
|
||||
|
||||
export default supportedEditors;
|
||||
|
||||
Reference in New Issue
Block a user