Skip to content

Commit ea41cc2

Browse files
committed
[Quiz] fixes form validation for tag picking
1 parent f698214 commit ea41cc2

3 files changed

Lines changed: 70 additions & 60 deletions

File tree

src/plugin/exo/Resources/modules/resources/quiz/editor/components/parameters.jsx

Lines changed: 62 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {PropTypes as T} from 'prop-types'
33
import get from 'lodash/get'
44
import cloneDeep from 'lodash/cloneDeep'
55
import omit from 'lodash/omit'
6+
import set from 'lodash/set'
67

78
import {trans} from '#/main/app/intl/translation'
89
import {CALLBACK_BUTTON} from '#/main/app/buttons'
@@ -18,6 +19,8 @@ import ScoreNone from '#/plugin/exo/scores/none'
1819
import ScoreSum from '#/plugin/exo/scores/sum'
1920
import {Step} from '#/plugin/exo/resources/quiz/prop-types'
2021

22+
import {chainSync, gtZero, notBlank, number} from '#/main/app/data/types/validators'
23+
2124
const hasEnd = (quiz) => get(quiz, 'parameters.showEndPage')
2225

2326
const supportedScores = [
@@ -46,25 +49,21 @@ const QuizEditorParameters = props => {
4649
type: 'string',
4750
required: true,
4851
hideLabel: true,
49-
render: (quiz) => {
50-
const CurrentType = (
51-
<QuizType
52-
type={get(quiz, 'parameters.type')}
53-
selectAction={(type) => ({
54-
type: CALLBACK_BUTTON,
55-
callback: () => {
56-
props.update(setTypePresets(type, quiz))
57-
},
58-
confirm: {
59-
message: trans('change_quiz_type_message', {}, 'quiz'),
60-
button: trans('change', {}, 'actions')
61-
}
62-
})}
63-
/>
64-
)
65-
66-
return CurrentType
67-
}
52+
render: (quiz) => (
53+
<QuizType
54+
type={get(quiz, 'parameters.type')}
55+
selectAction={(type) => ({
56+
type: CALLBACK_BUTTON,
57+
callback: () => {
58+
props.update(setTypePresets(type, quiz))
59+
},
60+
confirm: {
61+
message: trans('change_quiz_type_message', {}, 'quiz'),
62+
button: trans('change', {}, 'actions')
63+
}
64+
})}
65+
/>
66+
)
6867
}, {
6968
name: 'parameters.hasExpectedAnswers',
7069
label: trans('has_expected_answers', {}, 'quiz'),
@@ -95,6 +94,7 @@ const QuizEditorParameters = props => {
9594
}, {
9695
icon: 'fa fa-fw fa-dice',
9796
title: trans('attempts_pick', {}, 'quiz'),
97+
primary: true,
9898
fields: [
9999
{
100100
name: 'parameters.mandatoryQuestions',
@@ -175,36 +175,42 @@ const QuizEditorParameters = props => {
175175
required: true,
176176
options: {
177177
placeholder: trans('no_picked_tag', {}, 'quiz'),
178-
button: trans('add-tag', {}, 'actions'),
179-
render: (pickedTag = {}, pickedTagErrors, pickedTagIndex) => {
180-
const TagPicking = (
181-
<div className="tag-control">
182-
<ChoiceInput
183-
id={`picking-pick-tag-${pickedTagIndex}`}
184-
size="sm"
185-
multiple={false}
186-
noEmpty={false}
187-
condensed={true}
188-
placeholder={trans('quiz_select_picking_tags', {}, 'quiz')}
189-
choices={props.tags.reduce((acc, current) => Object.assign(acc, {
190-
[current]: current
191-
}), {})}
192-
value={pickedTag[0]}
193-
onChange={value => props.updateProp(`picking.pick[${pickedTagIndex}][0]`, value)}
194-
/>
178+
button: trans('add_tag', {}, 'actions'),
179+
render: (pickedTag = {}, pickedTagErrors, pickedTagIndex) => (
180+
<div className="tag-control">
181+
<ChoiceInput
182+
id={`picking-pick-tag-${pickedTagIndex}`}
183+
multiple={false}
184+
noEmpty={false}
185+
condensed={true}
186+
placeholder={trans('quiz_select_picking_tags', {}, 'quiz')}
187+
choices={props.tags.reduce((acc, current) => Object.assign(acc, {
188+
[current]: current
189+
}), {})}
190+
value={pickedTag[0]}
191+
onChange={value => {
192+
const newErrors = props.errors ? cloneDeep(props.errors) : {}
193+
set(newErrors, `resource.picking.pick[${pickedTagIndex}]`, notBlank(value))
194+
props.setErrors(newErrors)
195195

196-
<NumberInput
197-
id={`picking-pick-count-${pickedTagIndex}`}
198-
size="sm"
199-
min={1}
200-
value={pickedTag[1]}
201-
onChange={value => props.updateProp(`picking.pick[${pickedTagIndex}][1]`, value)}
202-
/>
203-
</div>
204-
)
196+
props.updateProp(`picking.pick[${pickedTagIndex}][0]`, value)
197+
}}
198+
/>
205199

206-
return TagPicking
207-
}
200+
<NumberInput
201+
id={`picking-pick-count-${pickedTagIndex}`}
202+
min={1}
203+
value={pickedTag[1]}
204+
onChange={value => {
205+
const newErrors = props.errors ? cloneDeep(props.errors) : {}
206+
set(newErrors, `resource.picking.pick[${pickedTagIndex}]`, chainSync(value, {}, [notBlank, number, gtZero]))
207+
props.setErrors(newErrors)
208+
209+
props.updateProp(`picking.pick[${pickedTagIndex}][1]`, value)
210+
}}
211+
/>
212+
</div>
213+
)
208214
}
209215
}
210216
]
@@ -230,6 +236,7 @@ const QuizEditorParameters = props => {
230236
}, {
231237
icon: ' fa fa-fw fa-play',
232238
title: trans('attempts_play', {}, 'quiz'),
239+
primary: true,
233240
fields: [
234241
{
235242
name: 'parameters.progressionDisplayed',
@@ -294,6 +301,7 @@ const QuizEditorParameters = props => {
294301
}, {
295302
icon: 'fa fa-fw fa-flag-checkered',
296303
title: trans('end_page'),
304+
primary: true,
297305
fields: [
298306
{
299307
name: 'parameters.showEndPage',
@@ -409,6 +417,7 @@ const QuizEditorParameters = props => {
409417
}, {
410418
icon: 'fa fa-fw fa-check-double',
411419
title: trans('results', {}, 'quiz'),
420+
primary: true,
412421
fields: [
413422
{
414423
name: 'parameters.anonymizeAttempts',
@@ -480,6 +489,7 @@ const QuizEditorParameters = props => {
480489
}, {
481490
icon: 'fa fa-fw fa-percentage',
482491
title: trans('score'),
492+
primary: true,
483493
displayed: (quiz) => get(quiz, 'parameters.hasExpectedAnswers'),
484494
fields: [
485495
{
@@ -531,6 +541,7 @@ const QuizEditorParameters = props => {
531541
}, {
532542
icon: 'fa fa-fw fa-award',
533543
title: trans('evaluation'),
544+
primary: true,
534545
displayed: (quiz) => get(quiz, 'parameters.hasExpectedAnswers'),
535546
fields: [
536547
{
@@ -566,6 +577,7 @@ const QuizEditorParameters = props => {
566577
}, {
567578
icon: 'fa fa-fw fa-key',
568579
title: trans('access_restrictions'),
580+
primary: true,
569581
fields: [
570582
{
571583
name: 'parameters._maxAttempts',
@@ -609,6 +621,7 @@ const QuizEditorParameters = props => {
609621
}
610622

611623
QuizEditorParameters.propTypes = {
624+
errors: T.object,
612625
quizType: T.string.isRequired,
613626
score: T.shape({
614627
type: T.string.isRequired
@@ -621,7 +634,8 @@ QuizEditorParameters.propTypes = {
621634
tags: T.array.isRequired,
622635
workspace: T.object,
623636
update: T.func.isRequired,
624-
updateProp: T.func.isRequired
637+
updateProp: T.func.isRequired,
638+
setErrors: T.func.isRequired
625639
}
626640

627641
export {

src/plugin/exo/Resources/modules/resources/quiz/editor/containers/parameters.jsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {connect} from 'react-redux'
22

33
import {withRouter} from '#/main/app/router'
44

5+
import {actions as formActions, selectors as formSelectors} from '#/main/app/content/form'
56
import {selectors as resourceSelectors} from '#/main/core/resource/store'
67
import {actions as editorActions} from '#/main/core/resource/editor/store'
78

@@ -17,7 +18,8 @@ const QuizEditorParameters = withRouter(
1718
randomPick: selectors.randomPick(state),
1819
tags: selectors.tags(state),
1920
workspace: resourceSelectors.workspace(state),
20-
steps: selectors.steps(state)
21+
steps: selectors.steps(state),
22+
errors: formSelectors.errors(formSelectors.form(state, selectors.FORM_NAME))
2123
}),
2224
(dispatch) => ({
2325
/**
@@ -31,6 +33,9 @@ const QuizEditorParameters = withRouter(
3133
},
3234
update(value) {
3335
dispatch(editorActions.updateResource(value))
36+
},
37+
setErrors(errors) {
38+
dispatch(formActions.setErrors(selectors.FORM_NAME, errors))
3439
}
3540
})
3641
)(QuizEditorParametersComponent)

src/plugin/exo/Resources/styles/quiz/_editor.scss

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,8 @@
1010
flex: 1;
1111
}
1212

13-
.form-control {
14-
min-width: 0; // hack to avoid overflow in FF
15-
16-
+ .form-control {
17-
margin-left: ($grid-gutter-width * .5);
18-
}
19-
}
20-
21-
// todo find better selector
2213
input[type=number] {
23-
text-align: right;
24-
max-width: 80px;
14+
width: $score-input-size;
15+
margin-left: ($grid-gutter-width * .5);
2516
}
2617
}

0 commit comments

Comments
 (0)