@webitel/ui-sdk 3.0.4 → 3.0.5

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 (29) hide show
  1. package/dist/ui-sdk.common.js +2 -2
  2. package/dist/ui-sdk.common.js.map +1 -1
  3. package/dist/ui-sdk.umd.js +2 -2
  4. package/dist/ui-sdk.umd.js.map +1 -1
  5. package/dist/ui-sdk.umd.min.js +1 -1
  6. package/dist/ui-sdk.umd.min.js.map +1 -1
  7. package/package.json +4 -1
  8. package/src/locale/en/en.js +12 -0
  9. package/src/locale/ru/ru.js +12 -0
  10. package/src/locale/ua/ua.js +12 -0
  11. package/src/mixins/validationMixin/validationMixin.js +12 -12
  12. package/src/modules/AuditForm/components/__tests__/audit-form-question-read-wrapper.spec.js +14 -0
  13. package/src/modules/AuditForm/components/__tests__/audit-form-question-write-wrapper.spec.js +59 -0
  14. package/src/modules/AuditForm/components/__tests__/audit-form-question.spec.js +14 -0
  15. package/src/modules/AuditForm/components/__tests__/audit-form.spec.js +66 -0
  16. package/src/modules/AuditForm/components/audit-form-question-read-wrapper.vue +100 -0
  17. package/src/modules/AuditForm/components/audit-form-question-write-wrapper.vue +151 -0
  18. package/src/modules/AuditForm/components/audit-form-question.vue +102 -0
  19. package/src/modules/AuditForm/components/audit-form.vue +142 -0
  20. package/src/modules/AuditForm/components/questions/__tests__/audit-form-question-options.spec.js +46 -0
  21. package/src/modules/AuditForm/components/questions/__tests__/audit-form-question-score.spec.js +30 -0
  22. package/src/modules/AuditForm/components/questions/audit-form-question-options.vue +124 -0
  23. package/src/modules/AuditForm/components/questions/audit-form-question-score.vue +89 -0
  24. package/src/modules/AuditForm/composables/useDestroyableSortable.js +66 -0
  25. package/src/modules/AuditForm/schemas/AuditFormQuestionOptionsSchema.js +11 -0
  26. package/src/modules/AuditForm/schemas/AuditFormQuestionSchema.js +8 -0
  27. package/src/modules/AuditForm/schemas/AuditFormQuestionScoreSchema.js +6 -0
  28. package/src/scripts/__tests__/updateObject.spec.js +19 -0
  29. package/src/scripts/updateObject.js +6 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webitel/ui-sdk",
3
- "version": "3.0.4",
3
+ "version": "3.0.5",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve-lib": "vue-cli-service serve",
@@ -28,6 +28,8 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "@vue/compat": "^3.2.47",
31
+ "@vuelidate/core": "^2.0.0",
32
+ "@vuelidate/validators": "^2.0.0",
31
33
  "clipboard-copy": "^4.0.1",
32
34
  "core-js": "^3.6.5",
33
35
  "csv-stringify": "^5.5.3",
@@ -39,6 +41,7 @@
39
41
  "jszip-utils": "^0.1.0",
40
42
  "node-polyfill-webpack-plugin": "^1.1.4",
41
43
  "plyr": "3.6.2",
44
+ "sortablejs": "^1.15.0",
42
45
  "tiny-emitter": "^2.1.0",
43
46
  "vue": "^3.2.47",
44
47
  "vue-i18n": "^9.2.2",
@@ -46,6 +46,8 @@ export default {
46
46
  downloadAll: 'Download all',
47
47
  warning: 'Warning',
48
48
  doNotSave: 'Don\'t save',
49
+ required: 'Required',
50
+ copy: 'Copy',
49
51
  },
50
52
  // yak zhe ya zaebalsya povtoriaty odni i ti sami slova!!!!
51
53
  vocabulary: {
@@ -280,5 +282,15 @@ export default {
280
282
  copy: 'Copy',
281
283
  copied: 'Copied to clipboard!',
282
284
  },
285
+ auditForm: {
286
+ question: 'Criteria',
287
+ option: 'Option | Options',
288
+ score: 'Score | Scores',
289
+ addQuestion: 'Add criteria',
290
+ type: {
291
+ options: 'Options',
292
+ score: 'Score',
293
+ },
294
+ },
283
295
  },
284
296
  };
@@ -45,6 +45,8 @@ export default {
45
45
  downloadAll: 'Скачать всё',
46
46
  warning: 'Предупреждение',
47
47
  doNotSave: 'Не сохранять',
48
+ required: 'Обязательный',
49
+ copy: 'Скопировать',
48
50
  },
49
51
  vocabulary: {
50
52
  language: 'Язык',
@@ -276,5 +278,15 @@ export default {
276
278
  copy: 'Копировать',
277
279
  copied: 'Скопировано!',
278
280
  },
281
+ auditForm: {
282
+ question: 'Критерий',
283
+ option: 'Вариант | Варианты',
284
+ score: 'Бал | Балы',
285
+ addQuestion: 'Добавить критерий',
286
+ type: {
287
+ options: 'Критерии',
288
+ score: 'Бал',
289
+ },
290
+ },
279
291
  },
280
292
  };
@@ -46,6 +46,8 @@ export default {
46
46
  downloadAll: 'Завантажити все',
47
47
  warning: 'Попередження',
48
48
  doNotSave: 'Не зберігати',
49
+ required: 'Обов\'язковий',
50
+ copy: 'Скопіювати',
49
51
  },
50
52
  vocabulary: {
51
53
  language: 'Мова',
@@ -276,5 +278,15 @@ export default {
276
278
  copy: 'Копіювати',
277
279
  copied: 'Скопійовано!',
278
280
  },
281
+ auditForm: {
282
+ question: 'Критерій',
283
+ option: 'Варіант | Варіанти',
284
+ score: 'Бал | Бали',
285
+ addQuestion: 'Додати критерій',
286
+ type: {
287
+ options: 'Критерії',
288
+ score: 'Бал',
289
+ },
290
+ },
279
291
  },
280
292
  };
@@ -19,21 +19,21 @@ export default {
19
19
  validationText() {
20
20
  let validationText = '';
21
21
  if (this.isValidation && this.invalid) {
22
- if (this.v.required === false) validationText = this.$t('validation.required');
23
- else if (this.v.numeric === false) validationText = this.$t('validation.numeric');
24
- else if (this.v.email === false) validationText = this.$t('validation.email');
25
- else if (this.v.gatewayHostValidator === false) validationText = this.$t('validation.gatewayHostValidator');
26
- else if (this.v.ipValidator === false) validationText = this.$t('validation.ipValidator');
27
- else if (this.v.macValidator === false) validationText = this.$t('validation.macValidator');
28
- else if (this.v.minValue === false) validationText = `${this.$t('validation.minValue')} ${this.v.$params.minValue.min}`;
29
- else if (this.v.maxValue === false) validationText = `${this.$t('validation.maxValue')} ${this.v.$params.maxValue.max}`;
30
- else if (this.v.sipAccountValidator === false) validationText = this.$t('validation.sipAccountValidator');
31
- else if (this.v.minLength === false) validationText = `${this.$t('validation.minLength')} ${this.v.$params.minLength.min}`;
32
- else if (this.v.url === false) validationText = `${this.$t('validation.url')}`;
22
+ if (this.v.required.$invalid) validationText = this.$t('validation.required');
23
+ else if (this.v.numeric.$invalid) validationText = this.$t('validation.numeric');
24
+ else if (this.v.email.$invalid) validationText = this.$t('validation.email');
25
+ else if (this.v.gatewayHostValidator.$invalid) validationText = this.$t('validation.gatewayHostValidator');
26
+ else if (this.v.ipValidator.$invalid) validationText = this.$t('validation.ipValidator');
27
+ else if (this.v.macValidator.$invalid) validationText = this.$t('validation.macValidator');
28
+ else if (this.v.minValue.$invalid) validationText = `${this.$t('validation.minValue')} ${this.v.$params.minValue.min}`;
29
+ else if (this.v.maxValue.$invalid) validationText = `${this.$t('validation.maxValue')} ${this.v.$params.maxValue.max}`;
30
+ else if (this.v.sipAccountValidator.$invalid) validationText = this.$t('validation.sipAccountValidator');
31
+ else if (this.v.minLength.$invalid) validationText = `${this.$t('validation.minLength')} ${this.v.$params.minLength.min}`;
32
+ else if (this.v.url.$invalid) validationText = `${this.$t('validation.url')}`;
33
33
  }
34
34
  // eslint-disable-next-line no-restricted-syntax
35
35
  for (const { name, text } of this.customValidators) {
36
- if (this.v[name] === false) validationText = text;
36
+ if (this.v[name].$invalid) validationText = text;
37
37
  }
38
38
  return validationText;
39
39
  },
@@ -0,0 +1,14 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import AuditFormQuestionReadWrapper from '../audit-form-question-read-wrapper.vue';
3
+
4
+ describe('AuditFormQuestionReadWrapper', () => {
5
+ it('renders a component', () => {
6
+ const wrapper = shallowMount(AuditFormQuestionReadWrapper, {
7
+ props: {
8
+ question: {},
9
+ result: {},
10
+ },
11
+ });
12
+ expect(wrapper.isVisible()).toBe(true);
13
+ });
14
+ });
@@ -0,0 +1,59 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import {
3
+ generateQuestionOptionsSchema
4
+ } from '../../schemas/AuditFormQuestionOptionsSchema';
5
+ import AuditFormQuestionWriteWrapper from '../audit-form-question-write-wrapper.vue';
6
+ import { generateQuestionSchema } from '../../schemas/AuditFormQuestionSchema';
7
+ import { generateQuestionScoreSchema } from '../../schemas/AuditFormQuestionScoreSchema';
8
+
9
+ const v = { question: {} };
10
+
11
+ describe('AuditFormQuestionWriteWrapper', () => {
12
+ it('renders a component', () => {
13
+ const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
14
+ props: {
15
+ question: {},
16
+ v,
17
+ },
18
+ });
19
+ expect(wrapper.isVisible()).toBe(true);
20
+ });
21
+ it('correctly changes question', () => {
22
+ const question = generateQuestionSchema();
23
+ const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
24
+ props: {
25
+ question,
26
+ v,
27
+ },
28
+ });
29
+ wrapper.findComponent({ name: 'wt-switcher' }).vm.$emit('change', !question.required);
30
+ expect(wrapper.emitted()['change:question'][0][0].required)
31
+ .toBe(!question.required);
32
+ });
33
+ it('correctly changes question type to Score', () => {
34
+ const question = {};
35
+ const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
36
+ props: {
37
+ question,
38
+ v,
39
+ },
40
+ });
41
+ wrapper.find('.audit-form-question-write-content-question')
42
+ .findComponent({ name: 'wt-select' }).vm.$emit('input', { value: 'score' });
43
+ expect(wrapper.emitted()['change:question'][0][0])
44
+ .toEqual(generateQuestionScoreSchema());
45
+ });
46
+ it('correctly changes question type to Options', () => {
47
+ const question = {};
48
+ const wrapper = shallowMount(AuditFormQuestionWriteWrapper, {
49
+ props: {
50
+ question,
51
+ v,
52
+ },
53
+ });
54
+ wrapper.find('.audit-form-question-write-content-question')
55
+ .findComponent({ name: 'wt-select' }).vm.$emit('input', { value: 'options' });
56
+ expect(wrapper.emitted()['change:question'][0][0])
57
+ .toEqual(generateQuestionOptionsSchema());
58
+ });
59
+ });
@@ -0,0 +1,14 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import AuditFormQuestion from '../audit-form-question.vue';
3
+
4
+ describe('AuditFormQuestion', () => {
5
+ it('renders a component', () => {
6
+ const wrapper = shallowMount(AuditFormQuestion, {
7
+ props: {
8
+ question: {},
9
+ result: {},
10
+ },
11
+ });
12
+ expect(wrapper.isVisible()).toBe(true);
13
+ });
14
+ });
@@ -0,0 +1,66 @@
1
+ import { shallowMount } from '@vue/test-utils';
2
+ import AuditForm from '../audit-form.vue';
3
+ import { generateQuestionSchema } from '../../schemas/AuditFormQuestionSchema';
4
+
5
+ import {
6
+ useDestroyableSortable,
7
+ } from '../../composables/useDestroyableSortable';
8
+
9
+ jest.mock('../../composables/useDestroyableSortable');
10
+
11
+ useDestroyableSortable.mockImplementation(() => ({}));
12
+
13
+ describe('AuditForm', () => {
14
+ it('renders a component', () => {
15
+ const wrapper = shallowMount(AuditForm, {
16
+ props: {
17
+ mode: '',
18
+ questions: [],
19
+ },
20
+ });
21
+ expect(wrapper.isVisible()).toBe(true);
22
+ });
23
+ it('add question button triggers update question event', () => {
24
+ const wrapper = shallowMount(AuditForm, {
25
+ props: {
26
+ mode: 'create',
27
+ questions: [],
28
+ },
29
+ });
30
+ wrapper.findComponent('.audit-form__add-button').vm.$emit('click');
31
+ expect(wrapper.emitted()['update:questions'][0][0])
32
+ .toEqual([generateQuestionSchema()]);
33
+ });
34
+ it('delete event from child question emits update without passed question', () => {
35
+ const wrapper = shallowMount(AuditForm, {
36
+ props: {
37
+ mode: 'create',
38
+ questions: [generateQuestionSchema()],
39
+ },
40
+ });
41
+ wrapper.findComponent({ name: 'audit-form-question' }).vm.$emit('delete', { key: 0 });
42
+ expect(wrapper.emitted()['update:questions'][0][0])
43
+ .toEqual([]);
44
+ });
45
+ it('copy event from child question emits update with duplicated questions', () => {
46
+ const question = generateQuestionSchema();
47
+ const wrapper = shallowMount(AuditForm, {
48
+ props: {
49
+ mode: 'create',
50
+ questions: [question],
51
+ },
52
+ });
53
+ wrapper.findComponent({ name: 'audit-form-question' }).vm.$emit('copy', { question, key: 0 });
54
+ expect(wrapper.emitted()['update:questions'][0][0])
55
+ .toEqual([question, question]);
56
+ });
57
+ it('initializes result depending on passed questions', () => {
58
+ const wrapper = shallowMount(AuditForm, {
59
+ props: {
60
+ mode: 'fill',
61
+ questions: [generateQuestionSchema(), generateQuestionSchema(), generateQuestionSchema()],
62
+ },
63
+ });
64
+ expect(wrapper.emitted()['update:result'][0][0]).toEqual([null, null, null]);
65
+ });
66
+ });
@@ -0,0 +1,100 @@
1
+ <template>
2
+ <article
3
+ class="audit-form-question-read"
4
+ :class="{
5
+ 'audit-form-question-read--filled': result && result.score != null,
6
+ }"
7
+ @keyup.enter="emit('activate')"
8
+ @click="emit('activate')"
9
+ >
10
+ <header class="audit-form-question-read-header">
11
+ <p
12
+ class="audit-form-question-read-text"
13
+ :class="{
14
+ 'audit-form-question-read-text--required': question.required,
15
+ }"
16
+ >{{ question.text }}</p>
17
+ <wt-icon
18
+ class="audit-form-question-read__drag-icon"
19
+ v-if="!disableDragging"
20
+ icon="move"
21
+ color="secondary"
22
+ ></wt-icon>
23
+ </header>
24
+ <section class="audit-form-question-read-content">
25
+ <component
26
+ :is="QuestionTypeComponent"
27
+ :question="question"
28
+ :result="result"
29
+ mode="read"
30
+ @change:result="emit('change:result', $event)"
31
+ ></component>
32
+ </section>
33
+ </article>
34
+ </template>
35
+
36
+ <script setup>
37
+ import { computed } from 'vue';
38
+ import AuditFormQuestionOptions from './questions/audit-form-question-options.vue';
39
+ import AuditFormQuestionScore from './questions/audit-form-question-score.vue';
40
+ import WtIcon from '../../../components/atoms/wt-icon/wt-icon.vue';
41
+
42
+ const props = defineProps({
43
+ question: {
44
+ type: Object,
45
+ required: true,
46
+ },
47
+ result: {
48
+ type: Object,
49
+ required: true,
50
+ },
51
+ disableDragging: {
52
+ type: Boolean,
53
+ default: false,
54
+ },
55
+ });
56
+
57
+ const emit = defineEmits([
58
+ 'change:result',
59
+ 'activate',
60
+ ]);
61
+
62
+ const QuestionTypeComponent = computed(() => {
63
+ if (props.question.type === 'options') return AuditFormQuestionOptions;
64
+ if (props.question.type === 'score') return AuditFormQuestionScore;
65
+ return null;
66
+ });
67
+ </script>
68
+
69
+ <style lang="scss" scoped>
70
+ .audit-form-question-read {
71
+ position: relative;
72
+ display: flex;
73
+ flex-direction: column;
74
+ gap: var(--spacing-sm);
75
+
76
+ &--filled {
77
+ background: var(--secondary-color-50);
78
+ }
79
+ }
80
+
81
+ .audit-form-question-read__drag-icon {
82
+ position: absolute;
83
+ top: 0;
84
+ left: 50%;
85
+ transform: translateX(-50%);
86
+ }
87
+
88
+ .audit-form-question-read-header {
89
+ margin-bottom: var(--spacing-xs);
90
+ }
91
+
92
+ .audit-form-question-read-text {
93
+ &--required {
94
+ &:after {
95
+ content: '*';
96
+ color: var(--false-color);
97
+ }
98
+ }
99
+ }
100
+ </style>
@@ -0,0 +1,151 @@
1
+ <template>
2
+ <article class="audit-form-question-write">
3
+ <header class="audit-form-question-write-header">
4
+ <wt-switcher
5
+ :value="question.required"
6
+ :label="$t('reusable.required')"
7
+ @change="updateQuestion({ path: 'required', value: $event })"
8
+ ></wt-switcher>
9
+ <div class="audit-form-question-write-header__actions">
10
+ <wt-tooltip>
11
+ <template v-slot:activator>
12
+ <wt-icon-btn
13
+ icon="copy"
14
+ @click="emit('copy')"
15
+ ></wt-icon-btn>
16
+ </template>
17
+ {{ $t('reusable.copy') }}
18
+ </wt-tooltip>
19
+ <wt-tooltip>
20
+ <template v-slot:activator>
21
+ <wt-icon-btn
22
+ icon="bucket"
23
+ :disabled="disableDelete"
24
+ @click="emit('delete')"
25
+ ></wt-icon-btn>
26
+ </template>
27
+ {{ $t('reusable.delete') }}
28
+ </wt-tooltip>
29
+ </div>
30
+ </header>
31
+ <section class="audit-form-question-write-content">
32
+ <div class="audit-form-question-write-content-question">
33
+ <wt-input
34
+ :value="question.text"
35
+ :label="$t('webitelUI.auditForm.question')"
36
+ :v="v.question.text"
37
+ required
38
+ @input="updateQuestion({ path: 'text', value: $event })"
39
+ ></wt-input>
40
+ <wt-select
41
+ :value="prettifiedQuestionType"
42
+ :options="QuestionType"
43
+ track-by="value"
44
+ :clearable="false"
45
+ :label="$t('vocabulary.type')"
46
+ @input="handleQuestionTypeChange($event.value)"
47
+ ></wt-select>
48
+ </div>
49
+ <component
50
+ :is="QuestionTypeComponent"
51
+ :question="question"
52
+ mode="write"
53
+ @change:question="emit('change:question', $event)"
54
+ ></component>
55
+ </section>
56
+ </article>
57
+ </template>
58
+
59
+ <script setup>
60
+ import set from 'lodash/set';
61
+ import cloneDeep from 'lodash/cloneDeep';
62
+ import { computed } from 'vue';
63
+ import WtTooltip from '../../../components/atoms/wt-tooltip/wt-tooltip.vue';
64
+ import WtSwitcher from '../../../components/molecules/wt-switcher/wt-switcher.vue';
65
+ import WtIconBtn from '../../../components/molecules/wt-icon-btn/wt-icon-btn.vue';
66
+ import WtInput from '../../../components/molecules/wt-input/wt-input.vue';
67
+ import WtSelect from '../../../components/molecules/wt-select/wt-select.vue';
68
+
69
+ import AuditFormQuestionOptions from './questions/audit-form-question-options.vue';
70
+ import AuditFormQuestionScore from './questions/audit-form-question-score.vue';
71
+
72
+ import { generateQuestionScoreSchema } from '../schemas/AuditFormQuestionScoreSchema';
73
+ import { generateQuestionOptionsSchema } from '../schemas/AuditFormQuestionOptionsSchema';
74
+
75
+ const props = defineProps({
76
+ question: {
77
+ type: Object,
78
+ required: true,
79
+ },
80
+ disableDelete: {
81
+ type: Boolean,
82
+ default: true,
83
+ },
84
+ v: {
85
+ type: Object,
86
+ },
87
+ });
88
+
89
+ const emit = defineEmits([
90
+ 'change:question',
91
+ 'copy',
92
+ 'delete',
93
+ ]);
94
+
95
+ const QuestionType = [
96
+ { value: 'options', locale: 'webitelUI.auditForm.type.options' },
97
+ { value: 'score', locale: 'webitelUI.auditForm.type.score' },
98
+ ];
99
+
100
+ const prettifiedQuestionType = computed(() => QuestionType.find(({ value }) => value === props.question.type));
101
+
102
+ const QuestionTypeComponent = computed(() => {
103
+ if (props.question.type === 'options') return AuditFormQuestionOptions;
104
+ if (props.question.type === 'score') return AuditFormQuestionScore;
105
+ return null;
106
+ });
107
+
108
+ function updateQuestion({ path, value }) {
109
+ const question = set(cloneDeep(props.question), path, value);
110
+ emit('change:question', question);
111
+ }
112
+
113
+ function handleQuestionTypeChange(type) {
114
+ const question = cloneDeep(props.question);
115
+ if (type === 'options') {
116
+ Object.assign(question, generateQuestionOptionsSchema());
117
+ } else if (type === 'score') {
118
+ Object.assign(question, generateQuestionScoreSchema());
119
+ }
120
+ emit('change:question', question);
121
+ }
122
+
123
+ </script>
124
+
125
+ <style lang="scss" scoped>
126
+ .audit-form-question.audit-form-question-write {
127
+ display: flex;
128
+ flex-direction: column;
129
+ gap: var(--spacing-sm);
130
+ box-shadow: var(--elevation-3);
131
+ }
132
+
133
+ .audit-form-question-write-header {
134
+ display: flex;
135
+ justify-content: space-between;
136
+ align-items: center;
137
+
138
+ &__actions {
139
+ display: flex;
140
+ gap: var(--spacing-sm);
141
+ }
142
+ }
143
+
144
+ .audit-form-question-write-content-question {
145
+ display: grid;
146
+ grid-template-columns: 3fr 1fr;
147
+ gap: var(--spacing-sm);
148
+ margin-right: calc(24px + var(--spacing-sm)); // delete icon action for type "options"
149
+ margin-bottom: var(--spacing-sm);
150
+ }
151
+ </style>
@@ -0,0 +1,102 @@
1
+ <template>
2
+ <component
3
+ class="audit-form-question"
4
+ :class="[
5
+ `audit-form-question--mode-${mode}`
6
+ ]"
7
+ v-clickaway="saveQuestion"
8
+ :is="component"
9
+ :question="question"
10
+ :result="result"
11
+ :v="v$"
12
+ :disable-dragging="mode === 'fill'"
13
+ :disable-delete="disableDelete"
14
+ @copy="emits('copy')"
15
+ @delete="emits('delete')"
16
+ @activate="activateQuestion"
17
+ @change:question="emits('update:question', $event)"
18
+ @change:result="emits('update:result', $event)"
19
+ ></component>
20
+ </template>
21
+
22
+ <script setup>
23
+ import { useVuelidate } from '@vuelidate/core';
24
+ import { required } from '@vuelidate/validators';
25
+ import { computed, ref, toRefs } from 'vue';
26
+ import vClickaway from '../../../directives/clickaway/clickaway';
27
+ import QuestionWrite from './audit-form-question-write-wrapper.vue';
28
+ import QuestionRead from './audit-form-question-read-wrapper.vue';
29
+
30
+ const props = defineProps({
31
+ question: {
32
+ type: Object,
33
+ required: true,
34
+ },
35
+ result: {
36
+ type: Object,
37
+ },
38
+ mode: {
39
+ type: String,
40
+ },
41
+ disableDelete: {
42
+ type: Boolean,
43
+ default: true,
44
+ },
45
+ });
46
+
47
+ const emits = defineEmits([
48
+ 'copy',
49
+ 'delete',
50
+ 'update:question',
51
+ 'update:result',
52
+ ]);
53
+
54
+ const QuestionState = {
55
+ SAVED: 'saved',
56
+ EDIT: 'edit',
57
+ };
58
+
59
+ const state = ref(QuestionState.SAVED);
60
+
61
+ const { question } = toRefs(props);
62
+
63
+ // validate only "create" mode
64
+ const v$ = useVuelidate(computed(() => (
65
+ (props.mode === 'create')
66
+ ? {
67
+ question: {
68
+ text: { required },
69
+ },
70
+ $autoDirty: true,
71
+ } : {})), { question });
72
+
73
+ const component = computed(() => {
74
+ if (props.mode === 'create') {
75
+ if (state.value === QuestionState.SAVED) return QuestionRead;
76
+ return QuestionWrite;
77
+ }
78
+ return QuestionRead;
79
+ });
80
+
81
+ function saveQuestion() {
82
+ state.value = QuestionState.SAVED;
83
+ }
84
+
85
+ function activateQuestion() {
86
+ if (props.mode !== 'create') return;
87
+ state.value = QuestionState.EDIT;
88
+ }
89
+ </script>
90
+
91
+ <style lang="scss" scoped>
92
+ .audit-form-question {
93
+ padding: var(--spacing-sm);
94
+ background: var(--main-color);
95
+ border-radius: var(--border-radius);
96
+ box-shadow: var(--elevation-1);
97
+
98
+ &--mode-create.audit-form-question-read {
99
+ cursor: pointer;
100
+ }
101
+ }
102
+ </style>