@elice/material-quiz 1.240130.1 → 1.240206.0-template.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/cjs/components/material-quiz/context/MaterialQuizContext.js +13 -5
  2. package/cjs/components/material-quiz-edit/MaterialQuizEdit.d.ts +1 -1
  3. package/cjs/components/material-quiz-edit/MaterialQuizEditContent.js +64 -30
  4. package/cjs/components/material-quiz-edit/locales.d.ts +4 -0
  5. package/cjs/components/material-quiz-edit/locales.js +8 -0
  6. package/cjs/components/material-quiz-edit/options/OptionEditor.d.ts +1 -0
  7. package/cjs/components/material-quiz-edit/options/OptionEditor.js +25 -11
  8. package/cjs/components/material-quiz-edit/options/OptionSelectMultiple.js +42 -12
  9. package/cjs/components/material-quiz-edit/options/OptionSelectMultipleOrder.js +41 -13
  10. package/cjs/components/material-quiz-edit/options/OptionSelectOne.js +43 -13
  11. package/cjs/components/material-quiz-edit/options/OptionText.js +24 -5
  12. package/cjs/components/material-quiz-edit/options/options-group/OptionGroupAnswerInfo.js +19 -14
  13. package/cjs/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.d.ts +1 -0
  14. package/cjs/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.js +27 -15
  15. package/cjs/components/material-quiz-edit/options/options-group/OptionGroupGroupInfo.js +19 -8
  16. package/cjs/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.d.ts +1 -0
  17. package/cjs/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.js +9 -5
  18. package/cjs/components/material-quiz-edit/utils/editValue.d.ts +2 -2
  19. package/cjs/components/material-quiz-edit/utils/editValue.js +3 -3
  20. package/es/components/material-quiz/context/MaterialQuizContext.js +14 -6
  21. package/es/components/material-quiz-edit/MaterialQuizEdit.d.ts +1 -1
  22. package/es/components/material-quiz-edit/MaterialQuizEditContent.js +64 -30
  23. package/es/components/material-quiz-edit/locales.d.ts +4 -0
  24. package/es/components/material-quiz-edit/locales.js +8 -0
  25. package/es/components/material-quiz-edit/options/OptionEditor.d.ts +1 -0
  26. package/es/components/material-quiz-edit/options/OptionEditor.js +25 -11
  27. package/es/components/material-quiz-edit/options/OptionSelectMultiple.js +44 -14
  28. package/es/components/material-quiz-edit/options/OptionSelectMultipleOrder.js +43 -15
  29. package/es/components/material-quiz-edit/options/OptionSelectOne.js +45 -15
  30. package/es/components/material-quiz-edit/options/OptionText.js +26 -7
  31. package/es/components/material-quiz-edit/options/options-group/OptionGroupAnswerInfo.js +19 -14
  32. package/es/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.d.ts +1 -0
  33. package/es/components/material-quiz-edit/options/options-group/OptionGroupAnswerListItem.js +29 -17
  34. package/es/components/material-quiz-edit/options/options-group/OptionGroupGroupInfo.js +20 -9
  35. package/es/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.d.ts +1 -0
  36. package/es/components/material-quiz-edit/options/options-group/OptionGroupGroupListItem.js +10 -6
  37. package/es/components/material-quiz-edit/utils/editValue.d.ts +2 -2
  38. package/es/components/material-quiz-edit/utils/editValue.js +3 -3
  39. package/package.json +25 -7
@@ -26,11 +26,19 @@ function MaterialQuizProvider({
26
26
  materialQuiz,
27
27
  materialLecturePage,
28
28
  refetch: refreshOrgMaterialQuiz
29
- } = materialSharedUtils.useMaterialFetchRaw(types.enums.LectureMaterialType.Quiz, React.useCallback(signal => apiClient.getOrgMaterialQuizGet({
30
- materialQuizId
31
- }, {
32
- signal
33
- }), [materialQuizId]), canInit);
29
+ } = materialSharedUtils.useMaterialFetchRaw(types.enums.LectureMaterialType.Quiz, React.useCallback(async signal => {
30
+ await apiClient.postOrgMaterialQuizOptionsSetSelect({
31
+ materialQuizId
32
+ }, {
33
+ signal
34
+ });
35
+ return await apiClient.getOrgMaterialQuizGet({
36
+ materialQuizId,
37
+ userId
38
+ }, {
39
+ signal
40
+ });
41
+ }, [materialQuizId, userId]), canInit);
34
42
  const init = React.useCallback(async () => {
35
43
  const controller = new AbortController();
36
44
  const {
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import type { MarkdownEditorFileUploadReqFn } from '@elice/markdown';
3
3
  import type { GetOrgMaterialQuizGetResponses } from '@elice/types';
4
4
  import type { FormState } from 'react-hook-form';
5
- export type MaterialQuizEditValue = Pick<GetOrgMaterialQuizGetResponses['materialQuiz'], 'id' | 'questionTitle' | 'questionDescription' | 'optionType' | 'options' | 'answerInfo' | 'answerHint' | 'isAutoGrade' | 'explanationInfo' | 'groups'>;
5
+ export type MaterialQuizEditValue = Pick<GetOrgMaterialQuizGetResponses['materialQuiz'], 'id' | 'questionTitle' | 'questionDescription' | 'optionType' | 'optionsDefault' | 'answerInfoDefault' | 'answerHint' | 'isAutoGrade' | 'explanationInfo' | 'groups' | 'optionsSetEnabled'>;
6
6
  export type MaterialQuizEditFormState = Pick<FormState<Record<string, any>>, 'isDirty' | 'isValid'>;
7
7
  export interface MaterialQuizEditProps {
8
8
  /** Value of material quiz edit form. */
@@ -9,8 +9,8 @@ var reactTransitionGroup = require('react-transition-group');
9
9
  var blocks = require('@elice/blocks');
10
10
  var markdown = require('@elice/markdown');
11
11
  var types = require('@elice/types');
12
+ var material = require('@mui/material');
12
13
  var flattenDeep = require('lodash-es/flattenDeep');
13
- var styled = require('styled-components');
14
14
  var OptionGroup = require('./options/options-group/OptionGroup.js');
15
15
  var OptionSelectMultiple = require('./options/OptionSelectMultiple.js');
16
16
  var OptionSelectMultipleOrder = require('./options/OptionSelectMultipleOrder.js');
@@ -22,9 +22,6 @@ var context = require('./context.js');
22
22
 
23
23
  const MIN_TEXT_LENGTH = 1;
24
24
  const MAX_TEXT_LENGTH = 128;
25
- const StyledQuizOptionTypeSelectWrap = styled.div.withConfig({
26
- componentId: "sc-1cf4b99-0"
27
- })(["display:flex;max-width:12rem;"]);
28
25
  const MaterialQuizEditContent = () => {
29
26
  const intl = reactIntl.useIntl();
30
27
  const {
@@ -36,13 +33,13 @@ const MaterialQuizEditContent = () => {
36
33
  watch,
37
34
  setValue
38
35
  } = reactHookForm.useFormContext();
39
- const [watchedOptionType, watchedOptionInfo, watchedAnswerInfo, watchedAnswerHint, watchedExplanationInfo, watchedIsAutoGrade, watchedGroups] = watch(['optionType', 'options', 'answerInfo', 'answerHint', 'explanationInfo', 'isAutoGrade', 'groups']);
36
+ const [watchedOptionType, watchedOptionInfo, watchedAnswerInfo, watchedAnswerHint, watchedExplanationInfo, watchedIsAutoGrade, watchedGroups, optionsSetEnabled] = watch(['optionType', 'optionsDefault', 'answerInfoDefault', 'answerHint', 'explanationInfo', 'isAutoGrade', 'groups', 'optionsSetEnabled']);
40
37
  //
41
38
  // Change `options` according to `optionType`.
42
39
  //
43
40
  React.useEffect(() => {
44
41
  const get = () => {
45
- const filteredNotMarkdownOptions = watchedOptionInfo.filter(option => {
42
+ const filteredNotMarkdownOptions = watchedOptionInfo === null || watchedOptionInfo === void 0 ? void 0 : watchedOptionInfo.filter(option => {
46
43
  var _a;
47
44
  return !((_a = option.content) === null || _a === void 0 ? void 0 : _a.includes('![]'));
48
45
  });
@@ -84,7 +81,7 @@ const MaterialQuizEditContent = () => {
84
81
  }
85
82
  return watchedOptionInfo;
86
83
  case types.enums.QuizOptionType.Group:
87
- if (!watchedOptionInfo.length) {
84
+ if (!(watchedOptionInfo === null || watchedOptionInfo === void 0 ? void 0 : watchedOptionInfo.length)) {
88
85
  // add default option info
89
86
  return [{
90
87
  id: randomId.createRandomId(),
@@ -123,7 +120,7 @@ const MaterialQuizEditContent = () => {
123
120
  return [];
124
121
  }
125
122
  };
126
- setValue('options', get());
123
+ setValue('optionsDefault', get());
127
124
  },
128
125
  // eslint-disable-next-line react-hooks/exhaustive-deps
129
126
  [watchedOptionType, setValue, intl]);
@@ -159,7 +156,7 @@ const MaterialQuizEditContent = () => {
159
156
  return [];
160
157
  }
161
158
  };
162
- setValue('answerInfo', get());
159
+ setValue('answerInfoDefault', get());
163
160
  },
164
161
  // eslint-disable-next-line react-hooks/exhaustive-deps
165
162
  [watchedOptionType, setValue, intl]);
@@ -252,10 +249,10 @@ const MaterialQuizEditContent = () => {
252
249
  return OptionSelectMultiple.default;
253
250
  case types.enums.QuizOptionType.SelectMultipleOrder:
254
251
  return OptionSelectMultipleOrder.default;
255
- case types.enums.QuizOptionType.Text:
256
- return OptionText.default;
257
252
  case types.enums.QuizOptionType.Group:
258
253
  return OptionGroup.default;
254
+ case types.enums.QuizOptionType.Text:
255
+ return OptionText.default;
259
256
  default:
260
257
  return React.Fragment;
261
258
  }
@@ -361,56 +358,93 @@ const MaterialQuizEditContent = () => {
361
358
  name: "optionType",
362
359
  render: ({
363
360
  field
364
- }) => React.createElement(blocks.Tooltip, {
365
- title: disabled ? intl.formatMessage({
366
- id: 'content.option.tooltip.disabled'
367
- }) : undefined,
361
+ }) => React.createElement(material.Tooltip, {
362
+ title: disabled && React.createElement(reactIntl.FormattedMessage, {
363
+ id: "content.option.tooltip.disabled"
364
+ }),
368
365
  placement: "top-end"
369
- }, React.createElement(StyledQuizOptionTypeSelectWrap, null, React.createElement(blocks.Select, Object.assign({
370
- size: "small",
371
- width: "small",
372
- readOnly: disabled
366
+ }, React.createElement(material.Stack, {
367
+ direction: "row",
368
+ justifyContent: "space-between",
369
+ marginBottom: "0.5rem"
370
+ }, React.createElement(material.TextField, Object.assign({
371
+ select: true,
372
+ disabled: disabled
373
373
  }, field, {
374
- onChange: v => field.onChange(Number(v))
375
- }), React.createElement("option", {
374
+ onChange: event => {
375
+ const isTextQuizOption = Number(event.target.value) === types.enums.QuizOptionType.Text;
376
+ if (isTextQuizOption) {
377
+ setValue('optionsSetEnabled', false);
378
+ }
379
+ field.onChange(event);
380
+ }
381
+ }), React.createElement(material.MenuItem, {
376
382
  value: types.enums.QuizOptionType.SelectOne,
377
383
  children: intl.formatMessage({
378
384
  id: 'content.option.select.items.selectOne'
379
385
  })
380
- }), React.createElement("option", {
386
+ }), React.createElement(material.MenuItem, {
381
387
  value: types.enums.QuizOptionType.SelectMultiple,
382
388
  children: intl.formatMessage({
383
389
  id: 'content.option.select.items.selectMultiple'
384
390
  })
385
- }), React.createElement("option", {
391
+ }), React.createElement(material.MenuItem, {
386
392
  value: types.enums.QuizOptionType.SelectMultipleOrder,
387
393
  children: intl.formatMessage({
388
394
  id: 'content.option.select.items.selectMultipleOrder'
389
395
  })
390
- }), React.createElement("option", {
396
+ }), React.createElement(material.MenuItem, {
391
397
  value: types.enums.QuizOptionType.Group,
392
398
  children: intl.formatMessage({
393
399
  id: 'content.option.select.items.group'
394
400
  })
395
- }), React.createElement("option", {
401
+ }), React.createElement(material.MenuItem, {
396
402
  value: types.enums.QuizOptionType.Text,
397
403
  children: intl.formatMessage({
398
404
  id: 'content.option.select.items.text'
399
405
  })
400
- }))))
401
- }), React.createElement(reactTransitionGroup.Transition, {
406
+ })), watchedOptionType !== types.enums.QuizOptionType.Text ? React.createElement(reactHookForm.Controller, {
407
+ name: "optionsSetEnabled",
408
+ control: control,
409
+ render: ({
410
+ field
411
+ }) => React.createElement(material.Tooltip, {
412
+ title: disabled ? '' : React.createElement(reactIntl.FormattedMessage, {
413
+ id: "content.option.optionsSetEnabled.tooltip"
414
+ }),
415
+ placement: "top"
416
+ }, React.createElement(material.FormControlLabel, {
417
+ disabled: disabled,
418
+ label: React.createElement(reactIntl.FormattedMessage, {
419
+ id: "content.option.optionsSetEnabled.label"
420
+ }),
421
+ control: React.createElement(material.Switch, Object.assign({}, field, {
422
+ checked: field.value
423
+ }))
424
+ }))
425
+ }) : null))
426
+ }), watchedOptionType !== types.enums.QuizOptionType.Text && optionsSetEnabled ? React.createElement(material.Alert, {
427
+ severity: "info",
428
+ sx: {
429
+ marginBottom: '1rem'
430
+ }
431
+ }, React.createElement(material.AlertTitle, null, React.createElement(reactIntl.FormattedMessage, {
432
+ id: "content.option.alert.randomized.title"
433
+ })), React.createElement(reactIntl.FormattedMessage, {
434
+ id: "content.option.alert.randomized.description"
435
+ })) : null, React.createElement(reactTransitionGroup.Transition, {
402
436
  in: watchedOptionType === types.enums.QuizOptionType.SelectMultipleOrder || watchedOptionType === types.enums.QuizOptionType.Group,
403
437
  timeout: 0,
404
438
  mountOnEnter: true,
405
439
  unmountOnExit: true
440
+ }, React.createElement(material.Box, {
441
+ marginBottom: "0.5rem"
406
442
  }, React.createElement(blocks.StatusText, {
407
443
  role: "description",
408
444
  preWrap: true
409
445
  }, React.createElement(reactIntl.FormattedMessage, {
410
446
  id: watchedOptionType === types.enums.QuizOptionType.SelectMultipleOrder ? 'content.option.statusText.dragNDrop' : 'content.option.statusText.dragNDropGroup'
411
- }))), React.createElement(blocks.Vspace, {
412
- height: 0.5
413
- }), React.createElement(Option, null))
447
+ })))), React.createElement(Option, null))
414
448
  });
415
449
  };
416
450
  /**
@@ -13,6 +13,10 @@ export declare const en: {
13
13
  'content.option.select.items.selectMultiple': string;
14
14
  'content.option.select.items.selectMultipleOrder': string;
15
15
  'content.option.select.items.text': string;
16
+ 'content.option.optionsSetEnabled.label': string;
17
+ 'content.option.optionsSetEnabled.tooltip': string;
18
+ 'content.option.alert.randomized.title': string;
19
+ 'content.option.alert.randomized.description': string;
16
20
  'content.option.select.items.group': string;
17
21
  'content.option.statusText.dragNDrop': string;
18
22
  'content.option.statusText.dragNDropGroup': string;
@@ -15,6 +15,10 @@ const en = {
15
15
  'content.option.select.items.selectMultiple': 'Multiple Choice (Multiple Answers)',
16
16
  'content.option.select.items.selectMultipleOrder': 'Drag and Drop',
17
17
  'content.option.select.items.text': 'Subjective',
18
+ 'content.option.optionsSetEnabled.label': 'Shuffle answer order',
19
+ 'content.option.optionsSetEnabled.tooltip': 'When the feature is enabled, the order of answers is shuffled for each student',
20
+ 'content.option.alert.randomized.title': 'Shuffling the order of answers is enabled',
21
+ 'content.option.alert.randomized.description': 'Students will see the order of their answers shuffled',
18
22
  'content.option.select.items.group': 'Drag and Drop (Group Type)',
19
23
  'content.option.statusText.dragNDrop': "After entering the options, click in the order of the correct answers.\nYou can check the configured problem in the Learner's Materials tab on the left.",
20
24
  'content.option.statusText.dragNDropGroup': "You can check the configured problem in the Learner's Materials tab on the left.",
@@ -70,6 +74,10 @@ const ko = {
70
74
  'content.option.select.items.selectMultiple': '객관식 (다중 선택)',
71
75
  'content.option.select.items.selectMultipleOrder': '드래그 앤 드롭',
72
76
  'content.option.select.items.text': '주관식',
77
+ 'content.option.optionsSetEnabled.label': '답안 순서 섞기',
78
+ 'content.option.optionsSetEnabled.tooltip': '기능 활성화 시 학생마다 답안의 순서가 섞여서 표시됩니다.',
79
+ 'content.option.alert.randomized.title': '답안 순서 섞기가 활성화 되어있습니다.',
80
+ 'content.option.alert.randomized.description': '학생에게 답안의 순서가 섞여서 표시됩니다.',
73
81
  'content.option.select.items.group': '드래그 앤 드롭 (그룹형)',
74
82
  'content.option.statusText.dragNDrop': '보기를 입력한 후 정답 순서대로 클릭하세요.\n구성된 문제는 좌측 학습자료 탭에서 확인하실 수 있습니다.',
75
83
  'content.option.statusText.dragNDropGroup': '구성된 문제는 좌측 학습자료 탭에서 확인하실 수 있습니다.',
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  interface OptionTextareaProps extends Omit<React.HTMLAttributes<HTMLTextAreaElement>, 'prefix' | 'onChange'> {
3
+ index: number;
3
4
  prefix?: React.ReactNode;
4
5
  suffix?: React.ReactNode;
5
6
  invalid?: boolean;
@@ -6,21 +6,26 @@ var tslib = require('tslib');
6
6
  var React = require('react');
7
7
  var blocks = require('@elice/blocks');
8
8
  var designTokens = require('@elice/design-tokens');
9
+ var material = require('@mui/material');
9
10
  var classNames = require('classnames');
10
11
  var styled = require('styled-components');
11
12
 
12
13
  //
13
14
  //
14
15
  //
16
+ const SHEET_Z_INDEX = 982; // prevent override blocks components.
15
17
  const PREFIX = 'em-option-editor';
16
18
  //
17
19
  //
18
20
  //
19
- const StyledTextarea = styled(blocks.Textarea).withConfig({
21
+ const StyledSortedListItem = styled(blocks.SortableListItem).withConfig({
20
22
  componentId: "sc-50ghuz-0"
21
- })(["padding:0.75rem 3rem;&.focus{border:1px solid ", ";}", ";", ";", ";"], designTokens.base.color.primary6, props => props.invalid ? styled.css(["border:1px solid ", " !important;"], designTokens.base.color.red8) : null, props => props.disabled ? styled.css(["background-color:", ";cursor:not-allowed;"], designTokens.base.color.gray2) : null, props => props.readOnly ? styled.css(["background-color:#f0f1f3;"]) : null);
22
- const StyledTextareaWrap = styled.div.withConfig({
23
+ })(["display:flex;padding:0;flex:1;z-index:", ";padding:0;background:transparent;box-shadow:none;margin:0;"], SHEET_Z_INDEX + 1);
24
+ const StyledTextarea = styled(blocks.Textarea).withConfig({
23
25
  componentId: "sc-50ghuz-1"
26
+ })(["padding:0.75rem 3rem;&.focus{border:1px solid ", ";}", ";", ";", ";"], designTokens.base.color.primary6, props => props.invalid ? styled.css(["border:1px solid ", " !important;"], designTokens.base.color.red8) : null, props => props.disabled ? styled.css(["background-color:", ";cursor:not-allowed;"], designTokens.base.color.gray2) : null, props => props.readOnly ? styled.css(["background-color:", ";"], designTokens.base.color.gray1) : null);
27
+ const StyledTextareaWrap = styled.div.withConfig({
28
+ componentId: "sc-50ghuz-2"
24
29
  })(["display:flex;position:relative;.em-option-editor-adornment{position:absolute;top:50%;transform:translateY(-50%);z-index:1;&.prefix{left:1rem;}&.suffix{right:1rem;}}"]);
25
30
  //
26
31
  //
@@ -31,9 +36,10 @@ const OptionEditor = React.forwardRef((_a, ref) => {
31
36
  prefix,
32
37
  invalid,
33
38
  invalidText,
34
- readOnly
39
+ readOnly,
40
+ index
35
41
  } = _a,
36
- props = tslib.__rest(_a, ["suffix", "prefix", "invalid", "invalidText", "readOnly"]);
42
+ props = tslib.__rest(_a, ["suffix", "prefix", "invalid", "invalidText", "readOnly", "index"]);
37
43
  /**
38
44
  * Extract textarea element from legacy TextArea ref prop.
39
45
  */
@@ -45,8 +51,12 @@ const OptionEditor = React.forwardRef((_a, ref) => {
45
51
  const textAreaInput = (_a = textAreaApi === null || textAreaApi === void 0 ? void 0 : textAreaApi.input) !== null && _a !== void 0 ? _a : null;
46
52
  typeof ref === 'function' ? ref(textAreaInput) : ref.current = textAreaInput;
47
53
  }, [ref]);
48
- return React.createElement("div", {
49
- className: classNames(PREFIX, props.className)
54
+ return React.createElement(StyledSortedListItem, {
55
+ index: index,
56
+ disabled: readOnly
57
+ }, React.createElement(material.Box, {
58
+ className: classNames(PREFIX, props.className),
59
+ flex: 1
50
60
  }, React.createElement(StyledTextareaWrap, {
51
61
  className: `${PREFIX}-textarea-wrapper`
52
62
  }, prefix ? React.createElement("div", {
@@ -56,18 +66,22 @@ const OptionEditor = React.forwardRef((_a, ref) => {
56
66
  invalid: invalid,
57
67
  readOnly: readOnly,
58
68
  resetFocus: props.onBlur,
69
+ disabled: readOnly,
59
70
  "aria-disabled": props.disabled
60
71
  })), suffix ? React.createElement("div", {
61
- className: `${PREFIX}-adornment suffix`
62
- }, suffix) : null), invalid ? React.createElement(blocks.Box, {
72
+ className: `${PREFIX}-adornment suffix`,
73
+ onDragStart: e => e.stopPropagation(),
74
+ onDragCapture: e => e.stopPropagation(),
75
+ onTouchStart: e => e.stopPropagation()
76
+ }, suffix) : null), invalid ? React.createElement(material.Box, {
63
77
  padding: "0 0.75rem",
64
- margintop: "0.25rem",
78
+ marginTop: "0.25rem",
65
79
  className: `${PREFIX}-helperText-wrap`
66
80
  }, React.createElement(blocks.Text, {
67
81
  role: "red",
68
82
  size: "tiny",
69
83
  className: `${PREFIX}-helperText`
70
- }, invalidText !== null && invalidText !== void 0 ? invalidText : '')) : null);
84
+ }, invalidText !== null && invalidText !== void 0 ? invalidText : '')) : null));
71
85
  });
72
86
 
73
87
  exports.default = OptionEditor;
@@ -5,9 +5,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var React = require('react');
6
6
  var reactHookForm = require('react-hook-form');
7
7
  var reactIntl = require('react-intl');
8
+ var reactSortableHoc = require('react-sortable-hoc');
8
9
  var reactTransitionGroup = require('react-transition-group');
9
10
  var blocks = require('@elice/blocks');
10
11
  var icons = require('@elice/icons');
12
+ var lodashEs = require('lodash-es');
11
13
  var styled = require('styled-components');
12
14
  var context = require('../context.js');
13
15
  var randomId = require('../utils/randomId.js');
@@ -17,8 +19,8 @@ const MIN_OPTION_INFO_COUNT = 2;
17
19
  const MAX_OPTION_INFO_COUNT = 20;
18
20
  const StyledWrap = styled.div.withConfig({
19
21
  componentId: "sc-1nbx9b8-0"
20
- })([""]);
21
- const StyledInputGroup = styled.div.withConfig({
22
+ })(["& > ul{display:flex;flex-direction:column;gap:0.75rem;}"]);
23
+ const StyledInputGroup = styled(blocks.SortableListGroup).withConfig({
22
24
  componentId: "sc-1nbx9b8-1"
23
25
  })(["width:100%;.em-option-editor{margin-bottom:0.5rem;&:last-of-type{margin-bottom:0;}}"]);
24
26
  const OptionSelectMultiple = () => {
@@ -29,29 +31,36 @@ const OptionSelectMultiple = () => {
29
31
  const {
30
32
  control,
31
33
  getValues,
32
- setValue,
33
- watch
34
+ setValue
34
35
  } = reactHookForm.useFormContext();
35
36
  const {
36
37
  fields: optionInfoFields,
37
38
  append: appendOptionInfoFieldItem,
38
- remove: removeOptionInfoFieldItem
39
+ remove: removeOptionInfoFieldItem,
40
+ move: moveOptionInfoFieldItem
39
41
  } = reactHookForm.useFieldArray({
40
42
  control,
41
- name: 'options',
43
+ name: 'optionsDefault',
42
44
  keyName: 'id',
43
45
  shouldUnregister: true
44
46
  });
45
- const watchedAnswerInfo = watch('answerInfo');
47
+ const watchedAnswerInfo = reactHookForm.useWatch({
48
+ control,
49
+ name: 'answerInfoDefault'
50
+ });
51
+ const watchedOptions = reactHookForm.useWatch({
52
+ control,
53
+ name: 'optionsDefault'
54
+ });
46
55
  /**
47
56
  * Update answer info.
48
57
  */
49
58
  const updateAnswerInfo = option => {
50
- const prevAnswerInfo = getValues('answerInfo');
59
+ const prevAnswerInfo = getValues('answerInfoDefault');
51
60
  if (!Array.isArray(prevAnswerInfo)) {
52
61
  return;
53
62
  }
54
- setValue('answerInfo', !option.checked ? prevAnswerInfo.filter(answerIndex => answerIndex !== option.index).map(answerIndex => option.removed ?
63
+ setValue('answerInfoDefault', !option.checked ? prevAnswerInfo.filter(answerIndex => answerIndex !== option.index).map(answerIndex => option.removed ?
55
64
  // if answer removed, re-calculate answer index
56
65
  answerIndex < option.index ? answerIndex : answerIndex - 1 :
57
66
  // or maintain current answer index
@@ -81,6 +90,22 @@ const OptionSelectMultiple = () => {
81
90
  });
82
91
  removeOptionInfoFieldItem(index);
83
92
  };
93
+ /**
94
+ * Sort options based on the old and new index.
95
+ */
96
+ const handleSortEnd = ({
97
+ oldIndex,
98
+ newIndex
99
+ }) => {
100
+ const prevAnswerInfo = lodashEs.cloneDeep(watchedAnswerInfo);
101
+ const prevOptions = lodashEs.cloneDeep(watchedOptions).map((option, index) => Object.assign(Object.assign({}, option), {
102
+ isAnswer: prevAnswerInfo.includes(index)
103
+ }));
104
+ const updatedOptions = reactSortableHoc.arrayMove(prevOptions, oldIndex, newIndex);
105
+ const updatedAnswerInfo = updatedOptions.map((option, index) => option.isAnswer ? index : null).filter(option => option !== null);
106
+ setValue('answerInfoDefault', updatedAnswerInfo);
107
+ moveOptionInfoFieldItem(oldIndex, newIndex);
108
+ };
84
109
  //
85
110
  //
86
111
  //
@@ -88,7 +113,7 @@ const OptionSelectMultiple = () => {
88
113
  return null;
89
114
  }
90
115
  return React.createElement(StyledWrap, null, React.createElement(reactHookForm.Controller, {
91
- name: "answerInfo",
116
+ name: "answerInfoDefault",
92
117
  control: control,
93
118
  rules: {
94
119
  validate: v => {
@@ -116,12 +141,16 @@ const OptionSelectMultiple = () => {
116
141
  height: 0.5
117
142
  })));
118
143
  }
119
- }), React.createElement(StyledInputGroup, null, optionInfoFields.map(({
144
+ }), React.createElement(StyledInputGroup, {
145
+ pressDelay: 100,
146
+ useDragHandle: true,
147
+ onSortEnd: handleSortEnd
148
+ }, optionInfoFields.map(({
120
149
  id
121
150
  }, index) => React.createElement(reactHookForm.Controller, {
122
151
  key: id,
123
152
  control: control,
124
- name: `options.${index}.content`,
153
+ name: `optionsDefault.${index}.content`,
125
154
  rules: {
126
155
  required: {
127
156
  value: true,
@@ -136,6 +165,7 @@ const OptionSelectMultiple = () => {
136
165
  }) => {
137
166
  var _a;
138
167
  return React.createElement(OptionEditor.default, Object.assign({
168
+ index: index,
139
169
  invalid: fieldState.invalid,
140
170
  invalidText: (_a = fieldState === null || fieldState === void 0 ? void 0 : fieldState.error) === null || _a === void 0 ? void 0 : _a.message,
141
171
  readOnly: disabled,
@@ -5,9 +5,11 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var React = require('react');
6
6
  var reactHookForm = require('react-hook-form');
7
7
  var reactIntl = require('react-intl');
8
+ var reactSortableHoc = require('react-sortable-hoc');
8
9
  var reactTransitionGroup = require('react-transition-group');
9
10
  var blocks = require('@elice/blocks');
10
11
  var icons = require('@elice/icons');
12
+ var lodashEs = require('lodash-es');
11
13
  var styled = require('styled-components');
12
14
  var context = require('../context.js');
13
15
  var randomId = require('../utils/randomId.js');
@@ -17,8 +19,8 @@ const MIN_OPTION_INFO_COUNT = 2;
17
19
  const MAX_OPTION_INFO_COUNT = 20;
18
20
  const StyledWrap = styled.div.withConfig({
19
21
  componentId: "sc-1xufc1p-0"
20
- })([""]);
21
- const StyledInputGroup = styled.div.withConfig({
22
+ })(["& > ul{display:flex;flex-direction:column;gap:0.75rem;}"]);
23
+ const StyledInputGroup = styled(blocks.SortableListGroup).withConfig({
22
24
  componentId: "sc-1xufc1p-1"
23
25
  })(["width:100%;.em-option-editor{margin-bottom:0.5rem;&:last-of-type{margin-bottom:0;}}"]);
24
26
  const OptionSelectMultipleOrder = () => {
@@ -29,28 +31,35 @@ const OptionSelectMultipleOrder = () => {
29
31
  const {
30
32
  control,
31
33
  getValues,
32
- setValue,
33
- watch
34
+ setValue
34
35
  } = reactHookForm.useFormContext();
35
36
  const {
36
37
  fields: optionInfoFields,
37
38
  append: appendOptionInfoFieldItem,
38
- remove: removeOptionInfoFieldItem
39
+ remove: removeOptionInfoFieldItem,
40
+ move: moveOptionInfoFieldItem
39
41
  } = reactHookForm.useFieldArray({
40
- name: 'options',
42
+ name: 'optionsDefault',
41
43
  keyName: 'id',
42
44
  shouldUnregister: true
43
45
  });
44
- const watchedAnswerInfo = watch('answerInfo');
46
+ const watchedAnswerInfo = reactHookForm.useWatch({
47
+ control,
48
+ name: 'answerInfoDefault'
49
+ });
50
+ const watchedOptions = reactHookForm.useWatch({
51
+ control,
52
+ name: 'optionsDefault'
53
+ });
45
54
  /**
46
55
  * Update answer info.
47
56
  */
48
57
  const updateAnswerInfo = option => {
49
- const prevAnswerInfo = getValues('answerInfo');
58
+ const prevAnswerInfo = getValues('answerInfoDefault');
50
59
  if (!Array.isArray(prevAnswerInfo)) {
51
60
  return;
52
61
  }
53
- setValue('answerInfo', !option.checked ? prevAnswerInfo.filter(answerIndex => answerIndex !== option.index).map(answerIndex => option.removed ?
62
+ setValue('answerInfoDefault', !option.checked ? prevAnswerInfo.filter(answerIndex => answerIndex !== option.index).map(answerIndex => option.removed ?
54
63
  // if answer removed, re-calculate answer index
55
64
  answerIndex < option.index ? answerIndex : answerIndex - 1 :
56
65
  // or maintain current answer index
@@ -80,6 +89,21 @@ const OptionSelectMultipleOrder = () => {
80
89
  });
81
90
  removeOptionInfoFieldItem(index);
82
91
  };
92
+ /**
93
+ * Sort options based on the old and new index.
94
+ */
95
+ const handleSortEnd = ({
96
+ oldIndex,
97
+ newIndex
98
+ }) => {
99
+ const prevOptions = lodashEs.cloneDeep(watchedOptions).map((option, index) => Object.assign(Object.assign({}, option), {
100
+ originIndex: index
101
+ }));
102
+ const updatedOptions = reactSortableHoc.arrayMove(prevOptions, oldIndex, newIndex);
103
+ const updatedAnswerInfo = watchedAnswerInfo.map(answerIndex => updatedOptions.findIndex(option => option.originIndex === answerIndex));
104
+ setValue('answerInfoDefault', updatedAnswerInfo);
105
+ moveOptionInfoFieldItem(oldIndex, newIndex);
106
+ };
83
107
  //
84
108
  //
85
109
  //
@@ -87,7 +111,7 @@ const OptionSelectMultipleOrder = () => {
87
111
  return null;
88
112
  }
89
113
  return React.createElement(StyledWrap, null, React.createElement(reactHookForm.Controller, {
90
- name: "answerInfo",
114
+ name: "answerInfoDefault",
91
115
  control: control,
92
116
  rules: {
93
117
  validate: v => {
@@ -115,12 +139,15 @@ const OptionSelectMultipleOrder = () => {
115
139
  height: 0.5
116
140
  })));
117
141
  }
118
- }), React.createElement(StyledInputGroup, null, optionInfoFields.map(({
142
+ }), React.createElement(StyledInputGroup, {
143
+ useDragHandle: true,
144
+ onSortEnd: handleSortEnd
145
+ }, optionInfoFields.map(({
119
146
  id
120
147
  }, index) => React.createElement(reactHookForm.Controller, {
121
148
  key: id,
122
149
  control: control,
123
- name: `options.${index}.content`,
150
+ name: `optionsDefault.${index}.content`,
124
151
  rules: {
125
152
  required: {
126
153
  value: true,
@@ -135,12 +162,13 @@ const OptionSelectMultipleOrder = () => {
135
162
  }) => {
136
163
  var _a;
137
164
  return React.createElement(OptionEditor.default, Object.assign({
165
+ index: index,
138
166
  placeholder: intl.formatMessage({
139
167
  id: 'option.common.select.placeholder'
140
168
  }),
141
169
  prefix: React.createElement(blocks.Checkbox, {
142
- checked: watchedAnswerInfo.includes(index),
143
170
  disabled: disabled,
171
+ checked: watchedAnswerInfo.includes(index),
144
172
  altChar: watchedAnswerInfo.indexOf(index) + 1,
145
173
  onChange: checked => updateAnswerInfo({
146
174
  index,