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

View file

@ -27,6 +27,7 @@
cornerStyle === 'rounded' ? 'rounded-pill' : '', cornerStyle === 'rounded' ? 'rounded-pill' : '',
]" ]"
:validationRules="validationRules" :validationRules="validationRules"
@input="handleChange"
@change="handleChange" @change="handleChange"
@blur="handleChange" @blur="handleChange"
:maxlength="maxLength ? maxLength : '999'" :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"; import textBlock from "@/digital-components/text-block/text-block";
// Supporting Files // Supporting Files
import { useForm } from "vee-validate";
// Define Validation Rules // Define Validation Rules
export default { export default {
name: "mobile-location-modal-questions", name: "mobile-location-modal-questions",
emits: ["update:modelValue"], // The component emits an event emits: ["update:modelValue"], // The component emits an event
data() {
return {
answers: [],
};
},
setup() {
const modalForm = useForm();
return {
modalForm,
};
},
props: { props: {
modelValue: { modelValue: {
type: Object, type: Object,
@ -75,11 +62,12 @@ export default {
state: "", state: "",
zipCode: "", zipCode: "",
}, },
isVehicleProtected: Boolean,
isZipServiceableMobile: Boolean, isZipServiceableMobile: Boolean,
isZipServiceableInShop: Boolean, isZipServiceableInShop: Boolean,
isVehicleProtected: Boolean,
}), }),
}, },
serviceZipCode: String,
linkWidgetName: String, linkWidgetName: String,
modalWidgetName: String, modalWidgetName: String,
mobileFeeDisclaimerWidgetName: String, mobileFeeDisclaimerWidgetName: String,
@ -88,10 +76,21 @@ export default {
alertInvalidZipWidgetName: String, alertInvalidZipWidgetName: String,
}, },
computed: { computed: {
getModalId() {
return "#" + this.modalWidgetName;
},
mobileLocationLinkPromptText() { mobileLocationLinkPromptText() {
return this.getCmsContent(this.linkWidgetName, "HeaderText"); return this.getCmsContent(this.linkWidgetName, "HeaderText");
}, },
mobileLocationLinkText() { 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"); return this.getCmsContent(this.linkWidgetName, "BodyText");
}, },
modalHeaderText() { modalHeaderText() {
@ -111,6 +110,19 @@ export default {
this.$emit("update:modelValue", newValue); 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: { methods: {
openModal() { openModal() {
@ -119,10 +131,29 @@ export default {
closeModal() { closeModal() {
this.$refs[this.modalName].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() { async setMobileLocation() {
this.closeModal(); this.closeModal();
}, },
}, },
watch: {
serviceZipCode: {
handler() {
// if they modify the Service Zip Code, clear the model
this.resetModel();
},
},
},
components: { components: {
textLink, textLink,
modal, modal,
@ -148,4 +179,8 @@ export default {
.address-questions { .address-questions {
margin-top: 0em; margin-top: 0em;
} }
#mobileLocationLinkPromptId {
white-space: pre-line;
}
</style> </style>

View file

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

View file

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

View file

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