Skip to content

Commit a24c29a

Browse files
committed
fix(task): fixed form validation on task form
1 parent cfd98dd commit a24c29a

File tree

3 files changed

+74
-14
lines changed

3 files changed

+74
-14
lines changed

src/ux/UserTest/components/FormTask.vue

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@
4040

4141
<!-- Content Area with v-if for forced re-rendering -->
4242
<div class="stepper-content">
43-
<v-card-text v-if="step === '1'">
43+
<v-card-text v-show="step === '1'">
4444
<TaskBasicInfo
45+
ref="taskBasicInfoRef"
4546
:model-value="localTask"
4647
:validation-rules="requiredRule"
4748
@update:model-value="handleTaskUpdate"
@@ -93,6 +94,8 @@ const props = defineProps({
9394
},
9495
});
9596
97+
const taskBasicInfoRef = ref(null);
98+
9699
const emit = defineEmits(['validate', 'update:task', 'complete']);
97100
98101
const step = ref("1");
@@ -131,8 +134,18 @@ const goToPreviousStep = () => {
131134
};
132135
133136
const valida = () => {
134-
emit('validate', localTask.value);
135-
return true;
137+
const descOk = taskBasicInfoRef.value?.checkDescriptionValidation();
138+
const nameOk = taskBasicInfoRef.value?.checkTaskNameValidation();
139+
140+
// trigger visual validator for task name
141+
taskBasicInfoRef.value?.isValid?.value;
142+
143+
if (nameOk && descOk) {
144+
emit('validate', localTask.value);
145+
return true;
146+
}
147+
148+
return false;
136149
};
137150
138151
const resetVal = () => {

src/ux/UserTest/components/task-steps/TaskBasicInfo.vue

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template>
22
<div class="task-basic-info">
3+
<v-form ref="basicInfoForm">
34
<div class="step-header mb-6">
45
<h3 class="text-h6 font-weight-bold mb-2">Step 1: Task Basic Information</h3>
56
<p class="text-body-2 text-grey-darken-1 mb-0">
@@ -35,14 +36,18 @@
3536
<v-icon size="14" class="mr-1">mdi-information-outline</v-icon>
3637
Provide detailed instructions for participants. Include the goal, context, and any specific steps they should follow.
3738
</p>
38-
<div class="description-editor">
39+
<div class="description-editor" :class="{ 'editor-error': showDescriptionError && !localTask.taskDescription?.trim() }">
3940
<quill-editor
4041
v-model:value="localTask.taskDescription"
4142
:options="editorOptions"
4243
class="custom-editor"
43-
@change="validateStep"
44+
@change="onChangeEditor"
45+
@blur="checkDescriptionValidation"
4446
/>
4547
</div>
48+
<span v-if="showDescriptionError && !localTask.taskDescription?.trim()" class="error-text ml-4">
49+
{{ t('Field Required') }}
50+
</span>
4651
</v-col>
4752

4853
<v-col cols="12">
@@ -63,8 +68,7 @@
6368
/>
6469
</v-col>
6570
</v-row>
66-
67-
71+
</v-form>
6872
</div>
6973
</template>
7074

@@ -87,6 +91,8 @@ const emit = defineEmits(['update:modelValue', 'validate']);
8791
const { t } = useI18n();
8892
8993
const localTask = ref({ ...props.modelValue });
94+
const basicInfoForm = ref(null);
95+
const showDescriptionError = ref(false);
9096
9197
const editorOptions = {
9298
theme: 'snow',
@@ -113,13 +119,36 @@ const completionPercentage = computed(() => {
113119
});
114120
115121
const isValid = computed(() => {
116-
return !!(localTask.value.taskName?.trim() && localTask.value.taskDescription?.trim());
122+
basicInfoForm.value?.validate?.();
123+
124+
const nameOk = !!localTask.value.taskName?.trim();
125+
const descOk = !!localTask.value.taskDescription?.trim();
126+
return nameOk && descOk;
117127
});
118128
129+
const onChangeEditor = (content) => {
130+
localTask.value.taskDescription = content.html
131+
validateStep();
132+
};
133+
134+
const checkTaskNameValidation = () => {
135+
const nameOk = !!localTask.value.taskName?.trim();
136+
return nameOk;
137+
};
138+
139+
const checkDescriptionValidation = () => {
140+
const descOk = !!localTask.value.taskDescription?.trim();
141+
if(!descOk) showDescriptionError.value = true;
142+
else showDescriptionError.value = false;
143+
return descOk;
144+
};
145+
119146
const validateStep = () => {
120147
emit('validate', isValid.value);
121148
};
122149
150+
defineExpose({ isValid, checkDescriptionValidation, checkTaskNameValidation });
151+
123152
// Watch for local changes and emit
124153
watch(
125154
localTask,
@@ -132,6 +161,18 @@ watch(
132161
</script>
133162
134163
<style scoped>
164+
.editor-error {
165+
border: 1px solid red !important;
166+
}
167+
168+
.error-text {
169+
color: red;
170+
font-size: 12px;
171+
margin-top: 4px;
172+
display: block;
173+
font-weight: 300;
174+
}
175+
135176
.task-basic-info {
136177
max-width: 100%;
137178
}
@@ -146,7 +187,7 @@ watch(
146187
147188
.description-editor {
148189
border: 1px solid rgba(var(--v-theme-outline), 0.3);
149-
border-radius: 8px;
190+
border-radius: 0px;
150191
overflow: hidden;
151192
transition: border-color 0.2s ease;
152193
}
@@ -159,6 +200,7 @@ watch(
159200
min-height: 120px;
160201
font-size: 14px;
161202
line-height: 1.5;
203+
padding: 8px;
162204
}
163205
164206
:deep(.custom-editor .ql-toolbar) {

src/ux/UserTest/components/task-steps/TaskConfiguration.vue

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
md="4"
1616
>
1717
<p class="text-subtitle-2 font-weight-medium mb-2">
18-
Task Link (URL) <span class="text-error">*</span>
18+
Task Link (URL)
19+
<!-- <span class="text-error">*</span> -->
1920
</p>
2021
<p class="text-caption text-grey-darken-1 mb-3">
2122
<v-icon
@@ -42,7 +43,8 @@
4243
md="4"
4344
>
4445
<p class="text-subtitle-2 font-weight-medium mb-2">
45-
Estimated Time (minutes) <span class="text-error">*</span>
46+
Estimated Time (minutes)
47+
<!-- <span class="text-error">*</span> -->
4648
</p>
4749
<p class="text-caption text-grey-darken-1 mb-3">
4850
<v-icon
@@ -70,7 +72,8 @@
7072
md="4"
7173
>
7274
<p class="text-subtitle-2 font-weight-medium mb-2">
73-
{{ $t('titles.answerType') }} <span class="text-error">*</span>
75+
{{ $t('titles.answerType') }}
76+
<!-- <span class="text-error">*</span> -->
7477
</p>
7578
<p class="text-caption text-grey-darken-1 mb-3">
7679
<v-icon
@@ -115,7 +118,8 @@
115118
cols="12"
116119
>
117120
<p class="text-subtitle-2 font-weight-medium mb-2">
118-
{{ $t('switches.postTest') }} <span class="text-error">*</span>
121+
{{ $t('switches.postTest') }}
122+
<!-- <span class="text-error">*</span> -->
119123
</p>
120124
<p class="text-caption text-grey-darken-1 mb-3">
121125
<v-icon
@@ -141,7 +145,8 @@
141145
cols="12"
142146
>
143147
<p class="text-subtitle-2 font-weight-medium mb-2">
144-
{{ $t('switches.postForm') }} <span class="text-error">*</span>
148+
{{ $t('switches.postForm') }}
149+
<!-- <span class="text-error">*</span> -->
145150
</p>
146151
<p class="text-caption text-grey-darken-1 mb-3">
147152
<v-icon

0 commit comments

Comments
 (0)