feat: setup game editor work (#363)

This commit is contained in:
Raymond Zhou
2023-07-20 04:59:54 -04:00
committed by GitHub
parent 7939af4737
commit 4a5eaaf15e
8 changed files with 160 additions and 0 deletions

View 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));

View File

@@ -7,4 +7,5 @@ export const blockTypes = StrictDict({
problem: 'problem',
// ADDED_EDITORS GO BELOW
video_upload: 'video_upload',
game: 'game',
});

View File

@@ -0,0 +1,2 @@
export { actions, reducer } from './reducers';
export { default as selectors } from './selectors';

View 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,
};

View 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,
};

View File

@@ -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(

View File

@@ -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 } });
};

View File

@@ -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;