From ede69ecdb99d40e1326b09dcd68db2160c4fe24a Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Tue, 21 Mar 2023 19:12:35 +0800 Subject: [PATCH] enhancement(nc-gui): validation logic in survey form --- .../form/[viewId]/index/survey.vue | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/packages/nc-gui/pages/[projectType]/form/[viewId]/index/survey.vue b/packages/nc-gui/pages/[projectType]/form/[viewId]/index/survey.vue index 771edf786c..d50732806e 100644 --- a/packages/nc-gui/pages/[projectType]/form/[viewId]/index/survey.vue +++ b/packages/nc-gui/pages/[projectType]/form/[viewId]/index/survey.vue @@ -4,15 +4,19 @@ import { RelationTypes, UITypes, isVirtualCol } from 'nocodb-sdk' import { SwipeDirection, breakpointsTailwind } from '@vueuse/core' import { DropZoneRef, + IsSurveyFormInj, computed, + isValidURL, onKeyStroke, onMounted, provide, ref, useBreakpoints, + useI18n, usePointerSwipe, useSharedFormStoreOrThrow, useStepper, + validateEmail, } from '#imports' enum TransitionDirection { @@ -32,6 +36,8 @@ const { md } = useBreakpoints(breakpointsTailwind) const { v$, formState, formColumns, submitForm, submitted, secondsRemain, sharedFormView, sharedViewMeta, onReset } = useSharedFormStoreOrThrow() +const { t } = useI18n() + const isTransitioning = ref(false) const transitionName = ref(TransitionDirection.Left) @@ -40,10 +46,14 @@ const animationTarget = ref(AnimationTarget.ArrowRight) const isAnimating = ref(false) +const editEnabled = ref([]) + const el = ref() provide(DropZoneRef, el) +provide(IsSurveyFormInj, ref(true)) + const transitionDuration = computed(() => sharedViewMeta.value.transitionDuration || 50) const steps = computed(() => { @@ -64,6 +74,8 @@ const { index, goToPrevious, goToNext, isFirst, isLast, goTo } = useStepper(step const field = computed(() => formColumns.value?.[index.value]) +const columnValidationError = ref(false) + function isRequired(column: ColumnType, required = false) { let columnObj = column if ( @@ -105,7 +117,29 @@ function animate(target: AnimationTarget) { }, transitionDuration.value / 2) } +async function validateColumn() { + const f = field.value! + if (parseProp(f.meta)?.validate && formState.value[f.title!]) { + if (f.uidt === UITypes.Email) { + if (!validateEmail(formState.value[f.title!])) { + columnValidationError.value = true + message.error(t('msg.error.invalidEmail')) + return false + } + } else if (f.uidt === UITypes.URL) { + if (!isValidURL(formState.value[f.title!])) { + columnValidationError.value = true + message.error(t('msg.error.invalidURL')) + return false + } + } + } + return true +} + async function goNext(animationTarget?: AnimationTarget) { + columnValidationError.value = false + if (isLast.value || submitted.value) return if (!field.value || !field.value.title) return @@ -117,6 +151,8 @@ async function goNext(animationTarget?: AnimationTarget) { if (!isValid) return } + if (!(await validateColumn())) return + animate(animationTarget || AnimationTarget.ArrowRight) setTimeout( @@ -159,9 +195,8 @@ function resetForm() { goTo(steps.value[0]) } -function submit() { - if (submitted.value) return - +async function submit() { + if (submitted.value || !(await validateColumn())) return submitForm() } @@ -177,7 +212,7 @@ onKeyStroke(['Enter', 'Space'], () => { if (isLast.value) { submit() } else { - goNext(AnimationTarget.OkButton) + goNext(AnimationTarget.OkButton, true) } }) @@ -263,7 +298,10 @@ onMounted(() => { class="nc-input" :data-testid="`nc-survey-form__input-${field.title.replaceAll(' ', '')}`" :column="field" - :edit-enabled="true" + :edit-enabled="editEnabled[index]" + @click="editEnabled[index] = true" + @cancel="editEnabled[index] = false" + @update:edit-enabled="editEnabled[index] = $event" />
@@ -315,7 +353,7 @@ onMounted(() => { class="bg-opacity-100 scaling-btn flex items-center gap-1" data-testid="nc-survey-form__btn-next" :class="[ - v$.localState[field.title]?.$error ? 'after:!bg-gray-100 after:!ring-red-500' : '', + v$.localState[field.title]?.$error || columnValidationError ? 'after:!bg-gray-100 after:!ring-red-500' : '', animationTarget === AnimationTarget.OkButton && isAnimating ? 'transform translate-y-[2px] translate-x-[2px] after:(!ring !ring-accent !ring-opacity-100)' : '', @@ -327,7 +365,10 @@ onMounted(() => { - +