Skip to content

Commit f3ae225

Browse files
authored
feat: improve asset loading (#484)
* fix: update initialize to only call required functions * feat: update asset urls without asset object * feat: add pagination to select image modal * fix: lint errors * chore: update tests * fix: asset pattern regex match * feat: update pagination to be button to prevent page skipping * fix: e.target.error for feedback fields * fix: failing snapshots
1 parent 252ad6a commit f3ae225

File tree

47 files changed

+635
-404
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+635
-404
lines changed

src/editors/containers/ProblemEditor/components/EditProblemView/AnswerWidget/hooks.js

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,23 @@ export const setAnswerTitle = ({
3939
};
4040

4141
export const setSelectedFeedback = ({ answer, hasSingleAnswer, dispatch }) => (e) => {
42-
dispatch(actions.problem.updateAnswer({
43-
id: answer.id,
44-
hasSingleAnswer,
45-
selectedFeedback: e.target.value,
46-
}));
42+
if (e.target) {
43+
dispatch(actions.problem.updateAnswer({
44+
id: answer.id,
45+
hasSingleAnswer,
46+
selectedFeedback: e.target.value,
47+
}));
48+
}
4749
};
4850

4951
export const setUnselectedFeedback = ({ answer, hasSingleAnswer, dispatch }) => (e) => {
50-
dispatch(actions.problem.updateAnswer({
51-
id: answer.id,
52-
hasSingleAnswer,
53-
unselectedFeedback: e.target.value,
54-
}));
52+
if (e.target) {
53+
dispatch(actions.problem.updateAnswer({
54+
id: answer.id,
55+
hasSingleAnswer,
56+
unselectedFeedback: e.target.value,
57+
}));
58+
}
5559
};
5660

5761
export const useFeedback = (answer) => {

src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/__snapshots__/index.test.jsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ exports[`SolutionWidget render snapshot: renders correct default 1`] = `
2323
/>
2424
</div>
2525
<[object Object]
26-
editorContentHtml="This is my question"
26+
editorContentHtml="This is my solution"
2727
editorType="solution"
2828
id="solution"
2929
minHeight={150}

src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.jsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@ import { selectors } from '../../../../../data/redux';
66
import messages from './messages';
77

88
import TinyMceWidget from '../../../../../sharedComponents/TinyMceWidget';
9-
import { prepareEditorRef } from '../../../../../sharedComponents/TinyMceWidget/hooks';
9+
import { prepareEditorRef, replaceStaticWithAsset } from '../../../../../sharedComponents/TinyMceWidget/hooks';
1010

1111
export const ExplanationWidget = ({
1212
// redux
1313
settings,
14+
learningContextId,
1415
// injected
1516
intl,
1617
}) => {
1718
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
19+
const solutionContent = replaceStaticWithAsset({
20+
initialContent: settings?.solutionExplanation,
21+
learningContextId,
22+
});
1823
if (!refReady) { return null; }
1924
return (
2025
<div className="tinyMceWidget mt-4 text-primary-500">
@@ -28,7 +33,7 @@ export const ExplanationWidget = ({
2833
id="solution"
2934
editorType="solution"
3035
editorRef={editorRef}
31-
editorContentHtml={settings?.solutionExplanation}
36+
editorContentHtml={solutionContent}
3237
setEditorRef={setEditorRef}
3338
minHeight={150}
3439
placeholder={intl.formatMessage(messages.placeholder)}
@@ -41,11 +46,13 @@ ExplanationWidget.propTypes = {
4146
// redux
4247
// eslint-disable-next-line
4348
settings: PropTypes.any.isRequired,
49+
learningContextId: PropTypes.string.isRequired,
4450
// injected
4551
intl: intlShape.isRequired,
4652
};
4753
export const mapStateToProps = (state) => ({
4854
settings: selectors.problem.settings(state),
55+
learningContextId: selectors.app.learningContextId(state),
4956
});
5057

5158
export default injectIntl(connect(mapStateToProps)(ExplanationWidget));

src/editors/containers/ProblemEditor/components/EditProblemView/ExplanationWidget/index.test.jsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ jest.mock('../../../../../data/redux', () => ({
1212
problem: {
1313
settings: jest.fn(state => ({ question: state })),
1414
},
15+
app: {
16+
learningContextId: jest.fn(state => ({ learningContextId: state })),
17+
},
1518
},
1619
thunkActions: {
1720
video: {
@@ -25,11 +28,13 @@ jest.mock('../../../../../sharedComponents/TinyMceWidget/hooks', () => ({
2528
refReady: true,
2629
setEditorRef: jest.fn().mockName('prepareEditorRef.setEditorRef'),
2730
})),
31+
replaceStaticWithAsset: jest.fn(() => 'This is my solution'),
2832
}));
2933

3034
describe('SolutionWidget', () => {
3135
const props = {
32-
settings: { solutionExplanation: 'This is my question' },
36+
settings: { solutionExplanation: 'This is my solution' },
37+
learningContextId: 'course+org+run',
3338
// injected
3439
intl: { formatMessage },
3540
};
@@ -40,8 +45,11 @@ describe('SolutionWidget', () => {
4045
});
4146
describe('mapStateToProps', () => {
4247
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
43-
test('question from problem.question', () => {
48+
test('settings from problem.settings', () => {
4449
expect(mapStateToProps(testState).settings).toEqual(selectors.problem.settings(testState));
4550
});
51+
test('learningContextId from app.learningContextId', () => {
52+
expect(mapStateToProps(testState).learningContextId).toEqual(selectors.app.learningContextId(testState));
53+
});
4654
});
4755
});

src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.jsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,20 @@ import { selectors } from '../../../../../data/redux';
66
import messages from './messages';
77

88
import TinyMceWidget from '../../../../../sharedComponents/TinyMceWidget';
9-
import { prepareEditorRef } from '../../../../../sharedComponents/TinyMceWidget/hooks';
9+
import { prepareEditorRef, replaceStaticWithAsset } from '../../../../../sharedComponents/TinyMceWidget/hooks';
1010

1111
export const QuestionWidget = ({
1212
// redux
1313
question,
14+
learningContextId,
1415
// injected
1516
intl,
1617
}) => {
1718
const { editorRef, refReady, setEditorRef } = prepareEditorRef();
19+
const questionContent = replaceStaticWithAsset({
20+
initialContent: question,
21+
learningContextId,
22+
});
1823
if (!refReady) { return null; }
1924
return (
2025
<div className="tinyMceWidget">
@@ -25,7 +30,7 @@ export const QuestionWidget = ({
2530
id="question"
2631
editorType="question"
2732
editorRef={editorRef}
28-
editorContentHtml={question}
33+
editorContentHtml={questionContent}
2934
setEditorRef={setEditorRef}
3035
minHeight={150}
3136
placeholder={intl.formatMessage(messages.placeholder)}
@@ -37,11 +42,13 @@ export const QuestionWidget = ({
3742
QuestionWidget.propTypes = {
3843
// redux
3944
question: PropTypes.string.isRequired,
45+
learningContextId: PropTypes.string.isRequired,
4046
// injected
4147
intl: intlShape.isRequired,
4248
};
4349
export const mapStateToProps = (state) => ({
4450
question: selectors.problem.question(state),
51+
learningContextId: selectors.app.learningContextId(state),
4552
});
4653

4754
export default injectIntl(connect(mapStateToProps)(QuestionWidget));

src/editors/containers/ProblemEditor/components/EditProblemView/QuestionWidget/index.test.jsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ jest.mock('../../../../../data/redux', () => ({
1515
},
1616
selectors: {
1717
app: {
18-
isLibrary: jest.fn(state => ({ isLibrary: state })),
19-
lmsEndpointUrl: jest.fn(state => ({ lmsEndpointUrl: state })),
20-
studioEndpointUrl: jest.fn(state => ({ studioEndpointUrl: state })),
18+
learningContextId: jest.fn(state => ({ learningContextId: state })),
2119
},
2220
problem: {
2321
question: jest.fn(state => ({ question: state })),
@@ -35,13 +33,14 @@ jest.mock('../../../../../sharedComponents/TinyMceWidget/hooks', () => ({
3533
refReady: true,
3634
setEditorRef: jest.fn().mockName('prepareEditorRef.setEditorRef'),
3735
})),
38-
// problemEditorConfig: jest.fn(args => ({ problemEditorConfig: args })),
36+
replaceStaticWithAsset: jest.fn(() => 'This is my question'),
3937
}));
4038

4139
describe('QuestionWidget', () => {
4240
const props = {
4341
question: 'This is my question',
4442
updateQuestion: jest.fn(),
43+
learningContextId: 'course+org+run',
4544
// injected
4645
intl: { formatMessage },
4746
};
@@ -55,5 +54,8 @@ describe('QuestionWidget', () => {
5554
test('question from problem.question', () => {
5655
expect(mapStateToProps(testState).question).toEqual(selectors.problem.question(testState));
5756
});
57+
test('learningContextId from app.learningContextId', () => {
58+
expect(mapStateToProps(testState).learningContextId).toEqual(selectors.app.learningContextId(testState));
59+
});
5860
});
5961
});

src/editors/containers/ProblemEditor/components/EditProblemView/hooks.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,13 @@ export const parseState = ({
5656
problem,
5757
isAdvanced,
5858
ref,
59-
assets,
6059
lmsEndpointUrl,
6160
}) => () => {
6261
const rawOLX = ref?.current?.state.doc.toString();
6362
const editorObject = fetchEditorContent({ format: '' });
6463
const reactOLXParser = new ReactStateOLXParser({ problem, editorObject });
6564
const reactSettingsParser = new ReactStateSettingsParser({ problem, rawOLX });
66-
const reactBuiltOlx = setAssetToStaticUrl({ editorValue: reactOLXParser.buildOLX(), assets, lmsEndpointUrl });
65+
const reactBuiltOlx = setAssetToStaticUrl({ editorValue: reactOLXParser.buildOLX(), lmsEndpointUrl });
6766
return {
6867
settings: isAdvanced ? reactSettingsParser.parseRawOlxSettings() : reactSettingsParser.getSettings(),
6968
olx: isAdvanced ? rawOLX : reactBuiltOlx,
@@ -143,7 +142,6 @@ export const getContent = ({
143142
openSaveWarningModal,
144143
isAdvancedProblemType,
145144
editorRef,
146-
assets,
147145
lmsEndpointUrl,
148146
}) => {
149147
const problem = problemState;
@@ -161,7 +159,6 @@ export const getContent = ({
161159
isAdvanced: isAdvancedProblemType,
162160
ref: editorRef,
163161
problem,
164-
assets,
165162
lmsEndpointUrl,
166163
})();
167164
return data;

src/editors/containers/ProblemEditor/components/EditProblemView/index.jsx

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ export const EditProblemView = ({
2929
// redux
3030
problemType,
3131
problemState,
32-
assets,
3332
lmsEndpointUrl,
3433
returnUrl,
3534
analytics,
@@ -48,7 +47,6 @@ export const EditProblemView = ({
4847
openSaveWarningModal,
4948
isAdvancedProblemType,
5049
editorRef,
51-
assets,
5250
lmsEndpointUrl,
5351
})}
5452
returnFunction={returnFunction}
@@ -70,7 +68,6 @@ export const EditProblemView = ({
7068
problem: problemState,
7169
isAdvanced: isAdvancedProblemType,
7270
ref: editorRef,
73-
assets,
7471
lmsEndpointUrl,
7572
})(),
7673
returnFunction,
@@ -118,7 +115,6 @@ export const EditProblemView = ({
118115
};
119116

120117
EditProblemView.defaultProps = {
121-
assets: null,
122118
lmsEndpointUrl: null,
123119
returnFunction: null,
124120
};
@@ -128,7 +124,6 @@ EditProblemView.propTypes = {
128124
returnFunction: PropTypes.func,
129125
// eslint-disable-next-line
130126
problemState: PropTypes.any.isRequired,
131-
assets: PropTypes.shape({}),
132127
analytics: PropTypes.shape({}).isRequired,
133128
lmsEndpointUrl: PropTypes.string,
134129
returnUrl: PropTypes.string.isRequired,
@@ -137,7 +132,6 @@ EditProblemView.propTypes = {
137132
};
138133

139134
export const mapStateToProps = (state) => ({
140-
assets: selectors.app.assets(state),
141135
analytics: selectors.app.analytics(state),
142136
lmsEndpointUrl: selectors.app.lmsEndpointUrl(state),
143137
returnUrl: selectors.app.returnUrl(state),

src/editors/containers/ProblemEditor/index.jsx

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,17 @@ export const ProblemEditor = ({
1616
problemType,
1717
blockFinished,
1818
blockFailed,
19-
studioViewFinished,
2019
blockValue,
2120
initializeProblemEditor,
22-
assetsFinished,
2321
advancedSettingsFinished,
2422
}) => {
2523
React.useEffect(() => {
26-
if (blockFinished && studioViewFinished && assetsFinished && !blockFailed) {
24+
if (blockFinished && !blockFailed) {
2725
initializeProblemEditor(blockValue);
2826
}
29-
}, [blockFinished, studioViewFinished, assetsFinished, blockFailed]);
27+
}, [blockFinished, blockFailed]);
3028

31-
if (!blockFinished || !studioViewFinished || !assetsFinished || !advancedSettingsFinished) {
29+
if (!blockFinished || !advancedSettingsFinished) {
3230
return (
3331
<div className="text-center p-6">
3432
<Spinner
@@ -55,18 +53,15 @@ export const ProblemEditor = ({
5553
};
5654

5755
ProblemEditor.defaultProps = {
58-
assetsFinished: null,
5956
returnFunction: null,
6057
};
6158
ProblemEditor.propTypes = {
6259
onClose: PropTypes.func.isRequired,
6360
returnFunction: PropTypes.func,
6461
// redux
65-
assetsFinished: PropTypes.bool,
6662
advancedSettingsFinished: PropTypes.bool.isRequired,
6763
blockFinished: PropTypes.bool.isRequired,
6864
blockFailed: PropTypes.bool.isRequired,
69-
studioViewFinished: PropTypes.bool.isRequired,
7065
problemType: PropTypes.string.isRequired,
7166
initializeProblemEditor: PropTypes.func.isRequired,
7267
blockValue: PropTypes.objectOf(PropTypes.shape({})).isRequired,
@@ -75,10 +70,8 @@ ProblemEditor.propTypes = {
7570
export const mapStateToProps = (state) => ({
7671
blockFinished: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchBlock }),
7772
blockFailed: selectors.requests.isFailed(state, { requestKey: RequestKeys.fetchBlock }),
78-
studioViewFinished: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchStudioView }),
7973
problemType: selectors.problem.problemType(state),
8074
blockValue: selectors.app.blockValue(state),
81-
assetsFinished: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchAssets }),
8275
advancedSettingsFinished: selectors.requests.isFinished(state, { requestKey: RequestKeys.fetchAdvancedSettings }),
8376
});
8477

0 commit comments

Comments
 (0)