Added validation to address-lookup

This commit is contained in:
Leah Schumann 2022-03-21 10:39:35 -04:00
parent 8bd0df4917
commit b769f95d56
7 changed files with 162 additions and 41 deletions

View file

@ -8,14 +8,16 @@
:aria-disabled="isDisabled" :aria-disabled="isDisabled"
:disabled="isDisabled" :disabled="isDisabled"
:aria-required="isRequired" :aria-required="isRequired"
:validationRules="validationRules" > :validationRules="validationRules"
@input="handleChange"
@blur="handleBlur" >
<option v-for="(value, name, index) in options" :value="name" :key="index"> <option v-for="(value, name, index) in options" :value="name" :key="index">
{{ value }} {{ value }}
</option> </option>
</select> </select>
<p class="mt-2 form-test-error" v-if="!suppressError"> <div v-show="errorMessage" class="row mt-2 form-test-error">
There has been an error! <span role="alert">{{ errorMessage }}</span>
</p> </div>
</div> </div>
</template> </template>
@ -36,6 +38,26 @@ export default {
disableAutoFill: Boolean, disableAutoFill: Boolean,
validationRules: String, validationRules: String,
}, },
setup(props) {
const fieldOptions = {
type: "text",
value: props.modelValue,
};
const {
errorMessage,
handleBlur,
handleChange,
meta,
} = useField(props.inputId, props.validationRules, fieldOptions);
return {
errorMessage,
handleBlur,
handleChange,
meta,
};
},
data() { data() {
return { return {
labelText: "", labelText: "",
@ -65,6 +87,11 @@ export default {
} }
}, },
}, },
watch: {
selectedOption(newValue) {
this.handleChange(newValue);
}
}
}; };
</script> </script>

View file

@ -14,15 +14,19 @@
:aria-required="isRequired" :aria-required="isRequired"
autocomplete="off" autocomplete="off"
:class="[hasIcon ? 'has-icon' : '', iconRight ? 'icon-right' : '']" :class="[hasIcon ? 'has-icon' : '', iconRight ? 'icon-right' : '']"
:validationRules="validationRules" /> :validationRules="validationRules"
<p class="mt-2 form-test-error" v-if="!suppressError"> @input="handleChange"
There has been an error! @blur="handleBlur" />
</p> <div v-show="errorMessage" class="row mt-2 form-test-error">
<span role="alert">{{ errorMessage }}</span>
</div>
</div> </div>
</template> </template>
<script> <script>
import { useField } from "vee-validate";
export default { export default {
name: "textbox-question", name: "textbox-question",
props: { props: {
@ -48,6 +52,35 @@ export default {
}, },
validationRules: String, validationRules: String,
}, },
setup(props) {
const fieldOptions = {
type: "text",
value: props.modelValue, // EX: "Single" or "Passenger"
//potentialInitialValue: props.selectedValues,
};
// Set initialValue for validation setup if pre-selected
// NOTE: props.selectedValues could be an array of strings, or an array of integers...
//if (props.selectedValues && (props.selectedValues.includes(props.value) || props.selectedValues.includes(parseInt(props.value)))) {
//fieldOptions['initialValue'] = fieldOptions.potentialInitialValue;
//}
const {
errorMessage,
handleBlur,
handleChange,
meta,
validate
} = useField(props.inputId, props.validationRules, fieldOptions);
return {
errorMessage,
handleBlur,
handleChange,
validate,
meta,
};
},
data() { data() {
return { return {
labelText: "", labelText: "",
@ -65,7 +98,7 @@ export default {
this.labelText = labelText; this.labelText = labelText;
this.ariaLabelText = cmsContent; this.ariaLabelText = cmsContent;
} },
}, },
computed: { computed: {
value: { value: {
@ -77,6 +110,11 @@ export default {
} }
}, },
}, },
watch: {
value(newValue) {
this.handleChange(newValue);
}
}
}; };
</script> </script>

View file

@ -14,6 +14,7 @@ const errorMessages = {
FIRST_NAME_REQUIRED: "Please enter your first name", FIRST_NAME_REQUIRED: "Please enter your first name",
LAST_NAME_REQUIRED: "Please enter your last name", LAST_NAME_REQUIRED: "Please enter your last name",
EMAIL_ADDRESS_REQUIRED: "Please enter your email address", EMAIL_ADDRESS_REQUIRED: "Please enter your email address",
EMAIL_ADDRESS_FORMAT: "Please enter a valid email address",
}; };
export { errorMessages }; export { errorMessages };

View file

@ -6,3 +6,20 @@ export function required(errorMessage) {
return true; return true;
}; };
} }
export function regex(expression, errorMessage) {
return (value) => {
// Field is empty, should pass
if (!value || !value.length) {
return true;
}
// Check if email
if (!expression.test(value)) {
return errorMessage;
}
return true;
}
}

View file

@ -1,13 +1,21 @@
<template> <template>
<Form
@submit="onSubmit"
@invalid-submit="onInvalidSubmit"
ref="theForm"
v-slot="{ meta }"
autocomplete="off" >
<div class="container-fluid shadow rounded-3 p-2 position-relative make-tall"> <div class="container-fluid shadow rounded-3 p-2 position-relative make-tall">
<funnelHeader ref="funnelHeader" /> <funnelHeader ref="funnelHeader" />
<vehicleBanner ref="vehicleBanner" :displayGenericVehicleImage=false /> <vehicleBanner ref="vehicleBanner" :displayGenericVehicleImage=false />
<funnelSubHeader ref="funnelSubHeader" /> <funnelSubHeader ref="funnelSubHeader" />
<form autocomplete="off">
<customerQuestions ref="customerQuestions" v-model="customerQuestions" /> <customerQuestions ref="customerQuestions" v-model="customerQuestions" />
<funnelFooter ref="funnelFooter" /> <funnel-footer
</form> ref="funnelFooter"
:isDisabled="!meta.valid"
/>
</div> </div>
</Form>
</template> </template>
<script> <script>
@ -18,6 +26,7 @@ import funnelFooter from "@/common-components/funnel-footer/funnel-footer";
import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/common-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header"; import funnelSubHeader from "@/common-components/funnel-sub-header/funnel-sub-header";
import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions"; import customerQuestions from "@/layouts/address-lookup/customer-questions/customer-questions";
import { Form } from "vee-validate";
// Supporting files // Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
@ -101,6 +110,7 @@ export default {
vehicleBanner, vehicleBanner,
funnelSubHeader, funnelSubHeader,
customerQuestions, customerQuestions,
Form
}, },
}; };
</script> </script>

View file

@ -1,22 +1,22 @@
<template> <template>
<div class="row my-4"> <div class="row my-4">
<div class="col"> <div class="col">
<textboxQuestion v-model="addressModel.streetAddress" ref="autocomplete" inputId="autocomplete" placeholderText="Search" aria-haspopup="" hasIcon disableAutoFill /> <textboxQuestion v-model="addressModel.streetAddress" ref="autocomplete" inputId="autocomplete" placeholderText="Search" aria-haspopup="" hasIcon disableAutoFill validationRules="street-address-required" />
</div> </div>
</div> </div>
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
<div class="address-fields" v-show="showAddressFields" aria-live="polite"> <div class="address-fields" v-show="showAddressFields" aria-live="polite">
<div class="row my-4"> <div class="row my-4">
<div class="col"> <div class="col">
<textboxQuestion v-model="addressModel.city" ref="city" inputId="cbf28188fdf2436688fd735915f7ee56" disableAutoFill /> <textboxQuestion v-model="addressModel.city" ref="city" inputId="cbf28188fdf2436688fd735915f7ee56" disableAutoFill validationRules="city-required"/>
</div> </div>
</div> </div>
<div class="row my-4"> <div class="row my-4">
<div class="col-6"> <div class="col-6">
<dropdownQuestion v-model="addressModel.state" ref="state" inputId="8fdf9dc2e13e430eb57529499dceb3eb" :options="stateOptions" disableAutoFill /> <dropdownQuestion v-model="addressModel.state" ref="state" inputId="8fdf9dc2e13e430eb57529499dceb3eb" :options="stateOptions" disableAutoFill validationRules="state-required" />
</div> </div>
<div class="col-6"> <div class="col-6">
<textboxQuestion v-model="addressModel.zip" ref="zip" inputId="01a9a1c2de0b4c9da8e023c9ae3be498" mask="#####" disableAutoFill /> <textboxQuestion v-model="addressModel.zip" ref="zip" inputId="01a9a1c2de0b4c9da8e023c9ae3be498" mask="#####" disableAutoFill validationRules="zip-required"/>
</div> </div>
</div> </div>
</div> </div>
@ -36,13 +36,23 @@
</template> </template>
<script> <script>
import textboxQuestion from "@/common-components/textbox-question/textbox-question"; import textboxQuestion from "@/common-components/textbox-question/textbox-question";
import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question"; import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question";
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
import { applicationConfig } from "@/constants/application-config.js"; import { applicationConfig } from "@/constants/application-config.js";
import { computed } from 'vue'; import { computed } from 'vue';
import { defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
//import store from "@/store"; //import store from "@/store";
// DEFINE VALIDATION RULES
defineRule("street-address-required", required(errorMessages.STREET_ADDRESS_REQUIRED));
defineRule("city-required", required(errorMessages.CITY_REQUIRED));
defineRule("state-required", required(errorMessages.STATE_REQUIRED));
defineRule("zip-required", required(errorMessages.ZIP_REQUIRED));
export default ({ export default ({
name: "address-questions", name: "address-questions",
emits: ['update:modelValue'], // The component emits an event emits: ['update:modelValue'], // The component emits an event
@ -59,12 +69,16 @@ export default ({
validationRules: String, validationRules: String,
}, },
setup(props, { emit }) { setup(props, { emit }) {
// Please do not modify, this "computed" is used to track and report
// this object's property changes to the parent component
const addressModel = computed({ // Use computed to wrap the object const addressModel = computed({ // Use computed to wrap the object
get: () => props.modelValue, get: () => props.modelValue,
set: (value) => emit('update:modelValue', value), set: (value) => emit('update:modelValue', value),
}); });
return { addressModel }; return {
addressModel,
};
}, },
data() { data() {
return { return {
@ -236,6 +250,8 @@ export default ({
} }
} }
self.displayVerificationWarning = false; self.displayVerificationWarning = false;
self.displayNoMatchWarning = false; self.displayNoMatchWarning = false;
} }

View file

@ -2,17 +2,17 @@
<addressQuestions ref="addressQuestions" v-model="customerModel.addressQuestions" /> <addressQuestions ref="addressQuestions" v-model="customerModel.addressQuestions" />
<div class="row my-4"> <div class="row my-4">
<div class="col"> <div class="col">
<textboxQuestion v-model="customerModel.firstName" ref="firstName" inputId="08497a2efd9a4a73a70360ab47b4838d" disableAutoFill /> <textboxQuestion v-model="customerModel.firstName" ref="firstName" inputId="08497a2efd9a4a73a70360ab47b4838d" disableAutoFill validationRules="first-name-required" />
</div> </div>
</div> </div>
<div class="row my-4"> <div class="row my-4">
<div class="col"> <div class="col">
<textboxQuestion v-model="customerModel.lastName" ref="lastName" inputId="0030e56a57e74a4ab92de7fb8e97fec5" disableAutoFill /> <textboxQuestion v-model="customerModel.lastName" ref="lastName" inputId="0030e56a57e74a4ab92de7fb8e97fec5" disableAutoFill validationRules="last-name-required" />
</div> </div>
</div> </div>
<div class="row my-4"> <div class="row my-4">
<div class="col"> <div class="col">
<textboxQuestion v-model="customerModel.emailAddress" ref="emailAddress" inputId="00450a91b8964a768ce3992e6feb890f" disableAutoFill /> <textboxQuestion v-model="customerModel.emailAddress" ref="emailAddress" inputId="00450a91b8964a768ce3992e6feb890f" disableAutoFill validationRules="email-address-required|email-address-format"/>
</div> </div>
</div> </div>
</template> </template>
@ -21,8 +21,20 @@
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions"; import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
import textboxQuestion from "@/common-components/textbox-question/textbox-question"; import textboxQuestion from "@/common-components/textbox-question/textbox-question";
import { computed } from 'vue'; import { computed } from 'vue';
import { defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
//import store from "@/store"; //import store from "@/store";
// DEFINE VALIDATION RULES
defineRule("first-name-required", required(errorMessages.FIRST_NAME_REQUIRED));
defineRule("last-name-required", required(errorMessages.LAST_NAME_REQUIRED));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule("email-address-format", regex(/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9_\-.]+).([a-zA-Z]{2,4})$/, errorMessages.EMAIL_ADDRESS_FORMAT));
//EMAIL_ADDRESS_FORMAT
export default ({ export default ({
name: "customer-questions", name: "customer-questions",
emits: ['update:modelValue'], // The component emits an event emits: ['update:modelValue'], // The component emits an event