Modal stuff, including validation for localized fields, modal header, etc

This commit is contained in:
Leah Schumann 2023-02-03 16:01:43 -05:00
parent 9e762ac770
commit 55f49606f7
7 changed files with 124 additions and 59 deletions

View file

@ -9,15 +9,18 @@
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<div class="modal-header mb-2 mt-2">
<label v-if="headerText" class="modal-title d-flex justify-content-center pb-0 w-100">
{{ headerText }}
</label>
<button
ref="closeButton"
type="button"
class="btn-close"
data-bs-dismiss="modal"
aria-label="Close"></button>
aria-label="Close"></button>
</div>
<div class="modal-body ps-5 pe-5 pt-5 pb-4">
<div class="modal-body ps-5 pe-5 pb-4 pt-0">
<slot></slot>
</div>
<div class="modal-footer px-5 py-4">
@ -27,7 +30,7 @@
ref="buttonMain"
suppressLoader
:buttonText="footerButtonText"
@click="$emit('footerButtonEvent')" />
@click-event="$emit('footer-button-event')" />
</div>
</div>
</div>
@ -42,6 +45,7 @@ export default {
name: "modal",
props: {
modalId: String,
headerText: String,
footerButtonText: String,
onModalOpenedCallback: {
type: Function,
@ -82,10 +86,19 @@ export default {
color: $black;
}
.modal-header {
border-bottom: none;
border-bottom: none;
.btn-close {
position: absolute;
right: 1rem;
top: 1rem;
background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M15.6874 1.82179L9.50889 8L15.6874 14.1782C16.1042 14.595 16.1042 15.2707 15.6874 15.6875C15.4843 15.8907 15.2146 16 14.9328 16C14.6514 16 14.3818 15.8906 14.1787 15.6875L8.00017 9.50934L1.82171 15.6875C1.6182 15.8907 1.34876 16 1.06708 16C0.785733 16 0.516056 15.8906 0.312965 15.6875C-0.10429 15.2706 -0.10429 14.5952 0.312797 14.1784L6.03276 8.45867L6.49146 8L0.312945 1.82177C-0.10429 1.40483 -0.10429 0.729418 0.312797 0.31262C0.728936 -0.104145 1.40489 -0.104051 1.82185 0.31262L7.54152 6.03202L8.00017 6.49065L14.1786 0.312472C14.5955 -0.104107 15.2707 -0.104201 15.6874 0.312452C16.1042 0.729289 16.1042 1.40496 15.6874 1.82179Z' fill='%231574A1'/%3E%3C/svg%3E%0A");
opacity: 1;
};
.modal-title {
font-weight: 500;
color: rgb(0, 0, 0);
}
}
&.modal-component {

View file

@ -1,6 +1,6 @@
<template>
<div class="textbox-question" :class="(errors && errors.length) || hasError ? 'has-error' : ''">
<label
<label v-if="displayQuestionText"
:for="inputId"
:aria-label="questionText"
class="form-label"
@ -53,6 +53,10 @@ export default {
type: String,
default: "",
},
displayQuestionText: {
type: Boolean,
default: true
},
modelValue: String,
inputId: String,
isDisabled: Boolean,

View file

@ -1,6 +1,6 @@
<template>
<div role="application">
<div class="row mt-2 mb-4">
<div class="address-questions" role="application">
<div class="row mb-4">
<div class="col">
<textboxQuestion
id="streetAddressField"
@ -83,6 +83,7 @@
alertClass="alert-warning"
v-bind:isDismissible="false" />
</div>
</template>
<script>
@ -425,6 +426,11 @@ export default {
</script>
<style lang="scss">
.address-questions {
margin-top: 0.5rem;
}
#streetAddressField {
position: relative;
@ -433,4 +439,5 @@ export default {
left: 0 !important;
}
}
</style>

View file

@ -1,34 +1,39 @@
<template>
<div class="text-center">
<label
:for="displayModalLink"
:aria-label="questionText"
for="mobileLocationLinkPromptId"
:aria-label="mobileLocationLinkPromptText"
class="form-label fw-bold w-100 ps-4 pe-4 pt-4"
:class="[questionAlignment === 'center' ? 'text-center w-100 mb-5' : '']"
v-html="questionText"></label>
v-html="mobileLocationLinkPromptText"></label>
<div class="update-mobile-location-text-link">
<textLink
id="displayModalLink"
id="mobileLocationLinkPromptId"
linkType="text"
:text="this.mobileLocationDisplayText"
:text="this.mobileLocationLinkText"
href="#!"
@click-event="openModal"
:data-bs-target="getModalId"
aria-label="Modal window" />
</div>
<textBlock cmsWidgetName="MobileFeeDisclaimerWidget" typeStyle="caption" />
</div>
<modal
ref="mobileServiceModal"
ref="mobileLocationModal"
:headerText="modalHeaderText"
:modalId="this.modalWidgetName"
:onModalOpenedCallback="onModalOpened"
:footerButtonText="mobileLocationDisplayText"
:footerButtonText="modalFooterText"
@footer-button-event="saveMobileLocationData">
<addressQuestions
ref="addressQuestions"
v-model="mobileQuestionModel.addressQuestions"
v-model="mobileLocationQuestionModel.addressQuestions"
captureApartmentNumberOrBusinessName="true" />
<vehicleProtectedQuestion v-model="mobileQuestionModel.selectedValue" />
<textBlock cmsWidgetName="QuoteEmailTextBlockWidget" typeStyle="caption" />
<vehicleProtectedQuestion
ref="vehicleProtectedQuestion"
v-model="mobileLocationQuestionModel.isVehicleProtected"
cmsWidgetName="VehicleProtectedQuestionWidget" />
<textBlock cmsWidgetName="WorkspaceRequirementsWidget" typeStyle="caption" />
</modal>
</template>
@ -36,33 +41,36 @@
// Components
import textLink from "@/ux-components/text-link/text-link";
import modal from "@/digital-components/modal/modal";
import buttonQuestion from "@/digital-components/button-question/button-question";
import alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
import addressQuestions from "@/layouts/address-lookup/customer-questions/address-questions/address-questions";
import vehicleProtectedQuestion from "@/layouts/service-location/mobile-location-modal-questions/vehicle-protected-question/vehicle-protected-question";
import textBlock from "@/digital-components/text-block/text-block";
// Supporting Files
import { defineRule } from "vee-validate";
import { defineRule, useForm } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
import { storeActions } from "@/constants/store-actions.js";
import baseMixin from "@/mixins/base-mixin.js";
import TextBlock from "../../../digital-components/text-block/text-block.vue";
// 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: "mobile-location-modal-questions",
emits: ["update:modelValue"], // The component emits an event
data() {
return {
isVehicleProtectedAnswers: [],
answers: [],
};
},
setup() {
const modalForm = useForm();
return {
modalForm,
}
},
props: {
modelValue: {
type: Object,
@ -81,43 +89,28 @@ export default {
},
cmsWidgetName: String,
modalWidgetName: String,
textboxQuestionWidgetName: String,
mobileFeeDisclaimerWidgetName: String,
workspaceRequirementsWidgetName: String,
alertNonServiceableZipWidgetName: String,
alertInvalidZipWidgetName: String,
},
methods: {
loadInitialData() {
return baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_YEARS, {});
},
initializeComponent(initialData) {
this.isVehicleProtectedAnswers = initialData;
},
openModal() {
this.$refs.mobileServiceModal.openModal();
},
closeModal() {
this.$refs.mobileServiceModal.closeModal();
},
focusOnZipInput() {
this.$nextTick(() => {
console.log(this.$refs);
const input = this.$refs.streetAddressField;
input.focus();
});
},
saveMobileLocationData() {},
},
computed: {
mobileLocationLinkPromptText() {
return this.getCmsContent(this.cmsWidgetName, "HeaderText");
},
mobileLocationLinkText() {
return this.getCmsContent(this.cmsWidgetName, "BodyText");
},
getModalId() {
return "#" + this.modalWidgetName;
},
questionText() {
return this.getCmsContent(this.cmsWidgetName, "HeaderText");
modalHeaderText() {
return this.getCmsContent(this.modalWidgetName, "HeaderText");
},
mobileLocationDisplayText() {
return this.getCmsContent(this.cmsWidgetName, "FooterText");
modalFooterText() {
return this.getCmsContent(this.modalWidgetName, "FooterText");
},
mobileQuestionModel: {
mobileLocationQuestionModel: {
get: function () {
return this.modelValue;
},
@ -126,6 +119,30 @@ export default {
},
},
},
methods: {
loadInitialData() {
return baseMixin.methods.dispatchStoreAction(storeActions.GET_VEHICLE_YEARS, {});
},
initializeComponent(initialData) {
this.answers = initialData;
},
openModal() {
this.$refs.mobileLocationModal.openModal();
},
closeModal() {
this.$refs.mobileLocationModal.closeModal();
},
async saveMobileLocationData() {
const componentValidation = await this.modalForm.validate();
if (componentValidation.valid) {
this.closeModal();
} else {
this.$refs.mobileLocationModal.resetButtonStyle();
}
},
},
mounted() {},
components: {
textLink,
@ -148,4 +165,9 @@ export default {
vertical-align: middle;
margin-right: 0.5em;
}
.address-questions {
margin-top: 0em;
}
</style>

View file

@ -6,14 +6,24 @@
groupName="isVehicleProtected"
textPosition="text-center"
v-model="selectedValue"
validationRules="option-required"
isRequired />
</template>
<script>
import buttonQuestion from "@/digital-components/button-question/button-question";
// Supporting files
import { storeActions } from "@/constants/store-actions.js";
import baseMixin from "@/mixins/base-mixin.js";
import { defineRule } from "vee-validate";
import { required } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
export default {
name: "vehicle-protected-question",
props: {

View file

@ -10,10 +10,11 @@ fmg
alertNonServiceableZipWidgetName="AlertNonServiceableZipWidget"
alertInvalidZipWidgetName="AlertInvalidZipWidget" />
<mobileLocationModalQuestions
v-model="mobileLocationQuestion"
cmsWidgetName="MobileLocationModalWidget"
modalWidgetName="LocationModalWidget"
textboxQuestionWidgetName="MobileLocationQuestionWidget" />
v-model="mobileLocationQuestions"
cmsWidgetName="MobileLocationLinkWidget"
modalWidgetName="MobileLocationModalWidget"
mobileFeeDisclaimerWidgetName="MobileFeeDisclaimerWidget"
workspaceRequirementsWidgetName="WorkspaceRequirementsWidget" />
<funnel-footer
cmsWidgetName="FunnelFooterWidget"
:isForwardActionDisabled="!meta.valid"
@ -35,12 +36,14 @@ import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-heade
import { Form } from "vee-validate";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { validator } from "vee-validate"
import { provide } from 'vue';
export default {
name: "service-location",
data() {
return {
mobileLocationQuestion: {
mobileLocationQuestions: {
addressQuestions: {
streetAddress: "",
apartmentNumberOrBusinessName: "",

View file

@ -21,6 +21,7 @@
:modalId="modalName"
:onModalOpenedCallback="onModalOpened"
:footerButtonText="footerButtonText"
:headerText="textboxQuestionPrompt"
@footer-button-event="setZip">
<textboxQuestion
ref="zipInputTextQuestion"
@ -29,6 +30,7 @@
inputId="serviceZipCodeInput"
questionAlignment="center"
mask="#####"
:displayQuestionText="false"
isRequired
disableAutoFill
validationRules="zip-required|zip-format" />
@ -58,7 +60,7 @@ import alert from "@/ux-components/alert/alert";
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
//Supporting Files
import { defineRule } from "vee-validate";
import { defineRule, useForm } from "vee-validate";
import { required, regex } from "@/helpers/validation-rules";
import { errorMessages } from "@/constants/error-messages";
@ -142,6 +144,9 @@ export default {
},
},
computed: {
textboxQuestionPrompt() {
return this.getCmsContent(this.textboxQuestionWidgetName, "QuestionText");
},
modalName() {
return this.cmsWidgetName;
},
@ -198,4 +203,5 @@ export default {
vertical-align: middle;
margin-right: 0.5em;
}
</style>