Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const AnswerOption = ({
const dispatch = useDispatch();

const problemType = useSelector(selectors.problem.problemType);
const isNumericInputValid = useSelector(selectors.problem.isNumericInputValid);
const images = useSelector(selectors.app.images);
const isLibrary = useSelector(selectors.app.isLibrary);
const learningContextId = useSelector(selectors.app.learningContextId);
Expand Down Expand Up @@ -71,15 +72,23 @@ const AnswerOption = ({
}
if (problemType !== ProblemTypeKeys.NUMERIC || !answer.isAnswerRange) {
return (
<Form.Control
as="textarea"
className="answer-option-textarea text-gray-500 small"
autoResize
rows={1}
value={answer.title}
onChange={setAnswerTitle}
placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)}
/>
<Form.Group isInvalid={!isNumericInputValid}>
<Form.Control
as="textarea"
className="answer-option-textarea text-gray-500 small"
autoResize
rows={1}
value={answer.title}
onChange={setAnswerTitle}
placeholder={intl.formatMessage(messages.answerTextboxPlaceholder)}

/>
{!isNumericInputValid && (
<Form.Control.Feedback type="invalid">
<FormattedMessage {...messages.answerNumericErrorText} />
</Form.Control.Feedback>
)}
</Form.Group>
);
}
// Return Answer Range View
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { StrictDict } from '../../../../../utils';
// should be re-thought and cleaned up to avoid this pattern.
// eslint-disable-next-line import/no-self-import
import * as module from './hooks';
import { actions } from '../../../../../data/redux';
import { actions, thunkActions } from '../../../../../data/redux';
import { ProblemTypeKeys } from '../../../../../data/constants/problem';
import { fetchEditorContent } from '../hooks';

Expand All @@ -29,6 +29,17 @@ export const setAnswer = ({ answer, hasSingleAnswer, dispatch }) => (payload) =>
dispatch(actions.problem.updateAnswer({ id: answer.id, hasSingleAnswer, ...payload }));
};

export const validateInputBlock = ({
title, dispatch,
}) => {
if (!title) {
return;
}
dispatch(thunkActions.problem.validateBlockNumericInput({
title,
}));
};

export const setAnswerTitle = ({
answer,
hasSingleAnswer,
Expand All @@ -43,6 +54,11 @@ export const setAnswerTitle = ({
if (isDirty !== undefined) {
dispatch(actions.problem.setDirty(isDirty));
}

// For numeric problems, validate input on title change
if (problemType === ProblemTypeKeys.NUMERIC) {
validateInputBlock({ title, dispatch });
}
};

export const setSelectedFeedback = ({ answer, hasSingleAnswer, dispatch }) => (value) => {
Expand Down Expand Up @@ -106,5 +122,12 @@ export const useAnswerContainer = ({ answers, updateField }) => {
};

export default {
state, removeAnswer, setAnswer, setAnswerTitle, useFeedback, isSingleAnswerProblem, useAnswerContainer,
state,
removeAnswer,
setAnswer,
setAnswerTitle,
useFeedback,
isSingleAnswerProblem,
useAnswerContainer,
validateInputBlock,
};
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ const messages = defineMessages({
defaultMessage: 'Error: Invalid range format. Use brackets or parentheses with values separated by a comma.',
description: 'Error text describing wrong format of answer ranges',
},
answerNumericErrorText: {
id: 'authoring.answerwidget.answer.answerNumericErrorText',
defaultMessage: 'Error: This input type only supports numeric answers. Did you mean to make a Text input or Math expression input problem?',
description: 'Error message when user provides wrong format',
},
});

export default messages;
1 change: 0 additions & 1 deletion src/editors/containers/ProblemEditor/data/OLXParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export const responseKeys = [
* []
*/
export const answerRangeFormatRegex = /^[([]\s*-?(?:\d+(?:\.\d+)?|\d+\/\d+)\s*,\s*-?(?:\d+(?:\.\d+)?|\d+\/\d+)\s*[)\]]$/m;

export const stripNonTextTags = ({ input, tag }) => {
const stripedTags = {};
Object.entries(input).forEach(([key, value]) => {
Expand Down
1 change: 1 addition & 0 deletions src/editors/data/constants/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ export const RequestKeys = StrictDict({
fetchAdvancedSettings: 'fetchAdvancedSettings',
fetchVideoFeatures: 'fetchVideoFeatures',
getHandlerUrl: 'getHandlerUrl',
validateBlockNumericInput: 'validateBlockNumericInput',
} as const);
Binary file modified src/editors/data/images/numericalInput.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/editors/data/redux/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export interface EditorState {
rawOLX: string;
rawMarkdown: string;
problemType: null | ProblemType | AdvancedProblemType;
isNumericInputValid: boolean;
/**
* Is the "markdown" editor currently active (as opposed to visual or advanced editors)
* This is confusingly named, and different from `isMarkdownEditorEnabledForContext`
Expand Down
1 change: 1 addition & 0 deletions src/editors/data/redux/problem/reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const initialState: EditorState['problem'] = {
rawMarkdown: '',
isMarkdownEditorEnabled: false,
problemType: null,
isNumericInputValid: true,
question: '',
answers: [],
correctAnswerCount: 0,
Expand Down
1 change: 1 addition & 0 deletions src/editors/data/redux/problem/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const simpleSelectors = {
defaultSettings: mkSimpleSelector(problemData => problemData.defaultSettings),
completeState: mkSimpleSelector(problemData => problemData),
isDirty: mkSimpleSelector(problemData => problemData.isDirty),
isNumericInputValid: mkSimpleSelector(problemData => problemData.isNumericInputValid),
};

export default simpleSelectors;
15 changes: 14 additions & 1 deletion src/editors/data/redux/thunkActions/problem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,19 @@ export const initializeProblem = (blockValue) => (dispatch, getState) => {
}
};

export const validateBlockNumericInput = ({ title, ...rest }) => (dispatch) => {
dispatch(requests.validateNumericInput({
title,
...rest,
onSuccess: (response) => {
dispatch(actions.problem.updateField({ isNumericInputValid: response.data.is_valid }));
},
onFailure: () => {
dispatch(actions.problem.updateField({ isNumericInputValid: false }));
},
}));
};

export default {
initializeProblem, switchEditor, switchToAdvancedEditor, fetchAdvancedSettings,
initializeProblem, switchEditor, switchToAdvancedEditor, fetchAdvancedSettings, validateBlockNumericInput,
};
16 changes: 16 additions & 0 deletions src/editors/data/redux/thunkActions/requests.js
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,21 @@ export const uploadVideo = ({ data, ...rest }) => (dispatch, getState) => {
}));
};

export const validateNumericInput = ({ title, ...rest }) => (dispatch, getState) => {
Comment thread
bradenmacdonald marked this conversation as resolved.
Outdated
dispatch(module.networkRequest({
requestKey: RequestKeys.validateBlockNumericInput,
promise: api.validateBlockNumericInput({
blockId: selectors.app.blockId(getState()),
blockType: selectors.app.blockType(getState()),
learningContextId: selectors.app.learningContextId(getState()),
data: { formula: title },
studioEndpointUrl: selectors.app.studioEndpointUrl(getState()),
title: selectors.app.blockTitle(getState()),
}),
...rest,
}));
};

export default StrictDict({
fetchBlock,
fetchStudioView,
Expand All @@ -507,4 +522,5 @@ export default StrictDict({
fetchVideoFeatures,
uploadVideo,
getHandlerlUrl,
validateNumericInput,
});
8 changes: 8 additions & 0 deletions src/editors/data/services/cms/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,14 @@ export const apiMethods = {
}) => get(
urls.handlerUrl({ studioEndpointUrl, blockId, handlerName }),
),
validateBlockNumericInput: ({
studioEndpointUrl,
blockId,
data,
}) => post(
urls.validateNumericInputUrl({ studioEndpointUrl, blockId }),
data,
),
};

export default apiMethods;
4 changes: 4 additions & 0 deletions src/editors/data/services/cms/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,7 @@ export const courseVideos = (({ studioEndpointUrl, learningContextId }) => (
export const handlerUrl = (({ studioEndpointUrl, blockId, handlerName }) => (
`${studioEndpointUrl}/api/xblock/v2/xblocks/${blockId}/handler_url/${handlerName}/`
)) satisfies UrlFunction;

export const validateNumericInputUrl = (({ studioEndpointUrl }) => (
`${studioEndpointUrl}/api/courses/v1/validate/numerical-input/`
)) satisfies UrlFunction;
Loading