Merged from CSR-1088 and made changes needed to support validation within the modal

This commit is contained in:
Leah Schumann 2023-02-10 08:36:00 -05:00
commit d606bb6b72
7 changed files with 134 additions and 42 deletions

View file

@ -32,7 +32,8 @@
ref="buttonMain"
loaderColor="white"
:buttonText="footerButtonText"
@click-event="validateAndEmit" />
@click-event="validateAndEmit"
:class="isFooterButtonDisabled && 'form-test-invalid'" />
</div>
</div>
</div>
@ -42,16 +43,13 @@
<script>
import buttonMain from "@/ux-components/button-main/button-main";
import { Modal } from "bootstrap";
import { checkPropertyChange } from "json-schema";
import { useIsFormTouched, useIsFormDirty, useIsFormValid } from "vee-validate";
export default {
name: "modal",
props: {
headerText: String,
footerButtonText: String,
modalForm: {
type: Object,
},
onModalOpenedCallback: {
type: Function,
},
@ -59,21 +57,22 @@ export default {
setup() {
const modalId = `modal-${crypto.randomUUID()}`;
const isTouched = useIsFormTouched();
const isDirty = useIsFormDirty();
const isValid = useIsFormValid();
return {
modalId,
isTouched,
isDirty,
isValid,
};
},
methods: {
async validateAndEmit() {
if (this.modalForm) {
const validationResult = await this.modalForm.validate();
if (validationResult.valid) {
this.$emit("footer-button-event");
}
} else {
if (!this.isFooterButtonDisabled) {
this.$emit("footer-button-event");
}
this.resetButtonStyle();
},
resetButtonStyle() {
@ -88,6 +87,14 @@ export default {
modal.hide();
},
},
computed: {
isFooterButtonDisabled() {
if (!this.isTouched) {
return !this.isValid;
}
return !this.isDirty || !this.isValid;
},
},
components: {
buttonMain,
},

View file

@ -27,6 +27,7 @@
cornerStyle === 'rounded' ? 'rounded-pill' : '',
]"
:validationRules="validationRules"
@input="handleChange"
@change="handleChange"
@blur="handleChange"
:maxlength="maxLength ? maxLength : '999'"

View file

@ -45,25 +45,12 @@ import vehicleProtectedQuestion from "@/layouts/service-location/mobile-location
import textBlock from "@/digital-components/text-block/text-block";
// Supporting Files
import { useForm } from "vee-validate";
// Define Validation Rules
export default {
name: "mobile-location-modal-questions",
emits: ["update:modelValue"], // The component emits an event
data() {
return {
answers: [],
};
},
setup() {
const modalForm = useForm();
return {
modalForm,
};
},
props: {
modelValue: {
type: Object,
@ -75,11 +62,12 @@ export default {
state: "",
zipCode: "",
},
isVehicleProtected: Boolean,
isZipServiceableMobile: Boolean,
isZipServiceableInShop: Boolean,
isVehicleProtected: Boolean,
}),
},
serviceZipCode: String,
linkWidgetName: String,
modalWidgetName: String,
mobileFeeDisclaimerWidgetName: String,
@ -88,10 +76,21 @@ export default {
alertInvalidZipWidgetName: String,
},
computed: {
getModalId() {
return "#" + this.modalWidgetName;
},
mobileLocationLinkPromptText() {
return this.getCmsContent(this.linkWidgetName, "HeaderText");
},
mobileLocationLinkText() {
if (
this.addressModel.streetAddress != "" &&
this.addressModel.city != "" &&
this.addressModel.state != "" &&
this.addressModel.zipCode != ""
) {
return `${this.addressModel.streetAddress}\n${this.addressModel.city}, ${this.addressModel.state} ${this.addressModel.zipCode}`;
}
return this.getCmsContent(this.linkWidgetName, "BodyText");
},
modalHeaderText() {
@ -111,6 +110,19 @@ export default {
this.$emit("update:modelValue", newValue);
},
},
addressModel: {
get: function () {
return this.mobileLocationQuestionModel.addressQuestions;
},
},
_isVehicleProtected: {
get: function () {
return this.modelValue.isVehicleProtected;
},
set: function (newValue) {
this.$emit("update:modelValue.isVehicleProtected", newValue);
},
},
},
methods: {
openModal() {
@ -119,10 +131,29 @@ export default {
closeModal() {
this.$refs[this.modalName].closeModal();
},
resetModel() {
// Address
this.addressModel.streetAddress = "";
this.addressModel.apartmentNumberOrBusinessName = "";
this.addressModel.city = "";
this.addressModel.state = "";
this.addressModel.zipCode = "";
// Is Vehicle Protected
this._isVehicleProtected = null;
},
async setMobileLocation() {
this.closeModal();
},
},
watch: {
serviceZipCode: {
handler() {
// if they modify the Service Zip Code, clear the model
this.resetModel();
},
},
},
components: {
textLink,
modal,
@ -148,4 +179,8 @@ export default {
.address-questions {
margin-top: 0em;
}
#mobileLocationLinkPromptId {
white-space: pre-line;
}
</style>

View file

@ -23,7 +23,9 @@ defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
export default {
name: "vehicle-protected-question",
props: {
modelValue: String,
modelValue: {
isVehicleProtected: Boolean,
},
cmsWidgetName: String,
},
components: {

View file

@ -1,4 +1,3 @@
fmg
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<div class="page-container-grouped-styles">
@ -12,6 +11,7 @@ fmg
alertInvalidZipWidgetName="AlertInvalidZipWidget" />
<mobileLocationModalQuestions
v-model="mobileLocationQuestions"
:serviceZipCode="serviceZipQuestion.serviceZipCode"
linkWidgetName="MobileLocationLinkWidget"
modalWidgetName="MobileLocationModalWidget"
mobileFeeDisclaimerWidgetName="MobileFeeDisclaimerWidget"
@ -55,6 +55,9 @@ export default {
state: "",
zipCode: "",
},
isVehicleProtected: null,
isZipServiceableMobile: null,
isZipServiceableInShop: null,
},
};
},
@ -81,7 +84,9 @@ export default {
arePagePrerequisitesValid() {
return true;
},
resetMobileLocationTest() {
this.serviceZipQuestion.serviceZipCode = "43054";
},
backButtonAction() {},
forwardButtonAction() {},
},

View file

@ -16,16 +16,10 @@
:onModalOpenedCallback="onModalOpened"
:footerButtonText="modalFooterText"
@footer-button-event="setZipCode">
<textboxQuestion
ref="zipInputTextQuestion"
<serviceZipQuestion
ref="serviceZipQuestion"
:cmsWidgetName="textboxQuestionWidgetName"
v-model="serviceZipModel.serviceZipCode"
inputId="serviceZipCode"
questionAlignment="center"
mask="#####"
:displayQuestionText="false"
isRequired
validationRules="zip-required|zip-format" />
v-model="serviceZipModel.serviceZipCode" />
<alert
ref="alertInvalidZip"
v-if="displayInvalidZipAlert"
@ -39,9 +33,9 @@
<script>
// Components
import textLink from "@/ux-components/text-link/text-link";
import serviceZipQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-question";
import modal from "@/digital-components/modal/modal";
import alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
//Supporting Files
import { defineRule, useForm } from "vee-validate";
@ -66,7 +60,7 @@ export default {
default: () => ({
serviceZipQuestion: {
serviceState: "",
serviceZipCode: "",
serviceZipCode: "1234",
isServiceable: null,
},
}),
@ -120,7 +114,7 @@ export default {
},
focusOnZipInput() {
const input = document.getElementById("serviceZipCode");
const input = document.getElementById("serviceZipCodeTextBoxQuestion");
input.focus();
},
@ -165,9 +159,9 @@ export default {
},
components: {
textLink,
serviceZipQuestion,
modal,
alert,
textboxQuestion,
},
};
</script>

View file

@ -0,0 +1,48 @@
<template>
<textboxQuestion
ref="zipInputTextQuestion"
:cmsWidgetName="cmsWidgetName"
v-model="value"
inputId="serviceZipCodeTextBoxQuestion"
questionAlignment="center"
mask="#####"
:displayQuestionText="false"
isRequired
validationRules="zip-required|zip-format" />
</template>
<script>
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
//Supporting Files
import { defineRule } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
// Define Validation Rules
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
export default {
name: "service-zip-question",
props: {
modelValue: {
serviceZipCode: String,
},
cmsWidgetName: String,
},
computed: {
value: {
get: function () {
return this.modelValue;
},
set: function (newValue) {
this.$emit("update:modelValue", newValue);
},
},
},
components: {
textboxQuestion,
},
};
</script>