Merged from feature/CSR-1012
This commit is contained in:
commit
0517b7072a
11 changed files with 174 additions and 92 deletions
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<div class="dropdown-question" :class="errorMessage || hasError ? 'has-error' : ''">
|
||||
<div
|
||||
class="dropdown-question"
|
||||
:class="(errors && errors.length) || hasError ? 'has-error' : ''">
|
||||
<label
|
||||
:for="inputId"
|
||||
:aria-label="questionText"
|
||||
|
|
@ -13,7 +15,9 @@
|
|||
:aria-disabled="isDisabled"
|
||||
:disabled="isDisabled"
|
||||
:aria-required="isRequired"
|
||||
:validationRules="validationRules">
|
||||
:validationRules="validationRules"
|
||||
:placeHolderText="placeHolderText">
|
||||
<option v-if="placeHolderText" value="" selected>{{ placeHolderText }}</option>
|
||||
<option v-for="(value, name, index) in options" :value="name" :key="index">
|
||||
{{ value }}
|
||||
</option>
|
||||
|
|
@ -38,9 +42,11 @@ export default {
|
|||
},
|
||||
isDisabled: Boolean,
|
||||
isRequired: Boolean,
|
||||
disableAutoFill: Boolean,
|
||||
validationRules: String,
|
||||
cmsWidgetName: String,
|
||||
hasError: Boolean,
|
||||
placeHolderText: String,
|
||||
},
|
||||
setup(props) {
|
||||
const propsClone = Object.assign({}, props);
|
||||
|
|
@ -62,7 +68,7 @@ export default {
|
|||
initialValue: initialValue,
|
||||
};
|
||||
|
||||
const { errorMessage, handleBlur, handleChange, meta } = useField(
|
||||
const { errorMessage, handleBlur, handleChange, meta, errors } = useField(
|
||||
props.inputId,
|
||||
props.validationRules,
|
||||
fieldOptions
|
||||
|
|
@ -73,6 +79,7 @@ export default {
|
|||
handleBlur,
|
||||
handleChange,
|
||||
meta,
|
||||
errors,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -81,7 +88,7 @@ export default {
|
|||
},
|
||||
selectedOption: {
|
||||
get: function () {
|
||||
return this.modelValue;
|
||||
return !this.modelValue ? "" : this.modelValue;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
|
|
|
|||
|
|
@ -1,68 +1,31 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import Modal from "./modal";
|
||||
|
||||
const modalId = "modal-one";
|
||||
const footerButtonText = "Sample footer text here.";
|
||||
const headerText = "Sample header text here.";
|
||||
|
||||
describe("modal.vue", () => {
|
||||
it("Should display header text when HeaderText is defined in the CMS", async () => {
|
||||
// Act
|
||||
it("Should display footer button text when footerButtonText is defined", async () => {
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
modalId: modalId,
|
||||
footerButtonText: footerButtonText,
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"]));
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(footerButtonText));
|
||||
});
|
||||
|
||||
it("Should display subheader text when SubheaderText is defined in the CMS", async () => {
|
||||
// Act
|
||||
it("Should display modal header text when headerText is defined", async () => {
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
modalId: modalId,
|
||||
footerButtonText: footerButtonText,
|
||||
headerText: headerText,
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["SubheaderText"]));
|
||||
});
|
||||
|
||||
it("Should insert image url when Image is defined in the CMS", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["Image"]));
|
||||
});
|
||||
|
||||
it("Should display body text when BodyText is defined in the CMS", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(Modal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"]));
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(headerText));
|
||||
});
|
||||
});
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return mockCmsContent[cmsFieldName];
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const mockCmsContent = {
|
||||
HeaderText: "Sample header text here.",
|
||||
SubheaderText: "Sample subheader text here.",
|
||||
Image: "https://www.sampleImage.sample",
|
||||
BodyText: "Sample body text here.",
|
||||
FooterText: "Sample footer text here.",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
isPrimary
|
||||
class="w-100"
|
||||
ref="buttonMain"
|
||||
suppressLoader
|
||||
loaderColor="white"
|
||||
:buttonText="footerButtonText"
|
||||
@click-event="validateAndEmit"
|
||||
:class="isFooterButtonDisabled && 'form-test-invalid'" />
|
||||
|
|
@ -44,11 +44,11 @@
|
|||
import buttonMain from "@/ux-components/button-main/button-main";
|
||||
import { Modal } from "bootstrap";
|
||||
import { useIsFormTouched, useIsFormDirty, useIsFormValid } from "vee-validate";
|
||||
import { checkPropertyChange } from "json-schema";
|
||||
|
||||
export default {
|
||||
name: "modal",
|
||||
props: {
|
||||
modalId: String,
|
||||
headerText: String,
|
||||
footerButtonText: String,
|
||||
onModalOpenedCallback: {
|
||||
|
|
@ -56,11 +56,14 @@ export default {
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const modalId = `modal-${crypto.randomUUID()}`;
|
||||
|
||||
const isTouched = useIsFormTouched();
|
||||
const isDirty = useIsFormDirty();
|
||||
const isValid = useIsFormValid();
|
||||
|
||||
return {
|
||||
modalId,
|
||||
isTouched,
|
||||
isDirty,
|
||||
isValid,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,64 @@
|
|||
import { mount } from "@vue/test-utils";
|
||||
import contentGroupModal from "./content-group-modal";
|
||||
|
||||
describe("content-group-modal.vue", () => {
|
||||
test.todo("test this");
|
||||
it("Should display header text when HeaderText is defined in the CMS", async () => {
|
||||
const wrapper = mount(contentGroupModal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["HeaderText"]));
|
||||
});
|
||||
|
||||
it("Should display subheader text when SubheaderText is defined in the CMS", async () => {
|
||||
const wrapper = mount(contentGroupModal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["SubheaderText"]));
|
||||
});
|
||||
|
||||
it("Should insert image url when Image is defined in the CMS", async () => {
|
||||
const wrapper = mount(contentGroupModal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["Image"]));
|
||||
});
|
||||
|
||||
it("Should display body text when BodyText is defined in the CMS", async () => {
|
||||
const wrapper = mount(contentGroupModal, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
cmsWidgetName: "test",
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
expect(wrapper.html()).toEqual(expect.stringContaining(mockCmsContent["BodyText"]));
|
||||
});
|
||||
});
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return mockCmsContent[cmsFieldName];
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
const mockCmsContent = {
|
||||
HeaderText: "Sample header text here.",
|
||||
SubheaderText: "Sample subheader text here.",
|
||||
Image: "https://www.sampleImage.sample",
|
||||
BodyText: "Sample body text here.",
|
||||
FooterText: "Sample footer text here.",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -277,25 +277,23 @@ export default {
|
|||
}
|
||||
});
|
||||
|
||||
// addressField1.addEventListener("change", () => {
|
||||
// // If a match has been previously attempted then do nothing
|
||||
// if (self.matchFound !== null) {
|
||||
// return;
|
||||
// }
|
||||
addressField1.addEventListener("change", () => {
|
||||
// If a match has been previously attempted then do nothing
|
||||
if (self.matchFound !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// // Get the address that the user clicked on (if any)
|
||||
// const clickedAddress = document.querySelector(
|
||||
// ".pac-container .pac-item:hover"
|
||||
// );
|
||||
// Get the address that the user clicked on (if any)
|
||||
const clickedAddress = document.querySelector(
|
||||
".pac-container .pac-item:hover"
|
||||
);
|
||||
|
||||
// // If the Street Address field changed without clicking (i.e. by pressing Tab, or clicking outside the field)
|
||||
// if (clickedAddress === null) {
|
||||
// // Fill-in the address using first item in the list.
|
||||
// fillInAddressUsingFirstItem();
|
||||
// }
|
||||
|
||||
// console.log("change");
|
||||
// });
|
||||
// If the Street Address field changed without clicking (i.e. by pressing Tab, or clicking outside the field)
|
||||
if (clickedAddress === null) {
|
||||
// Fill-in the address using first item in the list.
|
||||
fillInAddressUsingFirstItem();
|
||||
}
|
||||
});
|
||||
|
||||
function fillInAddressUsingFirstItem() {
|
||||
// Fill-in the address using first item in the list.
|
||||
|
|
@ -328,10 +326,6 @@ export default {
|
|||
self.matchFound = true;
|
||||
|
||||
self.$nextTick(function () {
|
||||
//self.addressModel.streetAddress = "";
|
||||
|
||||
//self.$nextTick();
|
||||
|
||||
self.showAddressFields = true;
|
||||
|
||||
for (const component of place.address_components) {
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ export default {
|
|||
line-height: 1.4;
|
||||
|
||||
a {
|
||||
text-underline-offset: 0.2em;
|
||||
text-underline-offset: 4px; //Per Devyn. This can't be documented in Figma so there is a comment with the Prototype mocks on the Quote page in Figma
|
||||
line-height: inherit;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ import cashOrInsuranceQuestion from "./cash-or-insurance-question/cash-or-insura
|
|||
import servicePackageQuestion from "./service-package-question/service-package-question";
|
||||
import textBlock from "@/digital-components/text-block/text-block";
|
||||
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
||||
//import modal from "@/digital-components/modal/modal";
|
||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
|
||||
|
|
|
|||
|
|
@ -245,7 +245,6 @@ export default {
|
|||
a {
|
||||
line-height: 1.714;
|
||||
padding: 0;
|
||||
text-underline-offset: 0.1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ fmg
|
|||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
|
||||
<serviceZipModalQuestion
|
||||
v-model="serviceZipQuestion"
|
||||
cmsWidgetName="ServiceZipModalWidget"
|
||||
textboxQuestionWidgetName="ServiceZipQuestionWidget"
|
||||
alertNonServiceableZipWidgetName="AlertNonServiceableZipWidget"
|
||||
|
|
@ -41,6 +42,10 @@ export default {
|
|||
name: "service-location",
|
||||
data() {
|
||||
return {
|
||||
serviceZipQuestion: {
|
||||
serviceState: "",
|
||||
serviceZipCode: "",
|
||||
},
|
||||
mobileLocationQuestions: {
|
||||
addressQuestions: {
|
||||
streetAddress: "",
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
<template>
|
||||
<div class="text-center">
|
||||
<label
|
||||
:for="displayModalLink"
|
||||
:aria-label="questionText"
|
||||
:for="serviceLocationLinkPromptId"
|
||||
:aria-label="serviceLocationLinkPromptText"
|
||||
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="serviceLocationLinkPromptText"></label>
|
||||
<div class="update-zip-text-link">
|
||||
<textLink
|
||||
id="displayModalLink"
|
||||
id="serviceLocationLinkPromptId"
|
||||
linkType="text"
|
||||
:text="this.serviceZipDisplayText"
|
||||
:text="this.serviceZipLinkText"
|
||||
href="#!"
|
||||
@click-event="openZipCodeModal"
|
||||
aria-label="Modal window" />
|
||||
|
|
@ -22,13 +22,13 @@
|
|||
:onModalOpenedCallback="onModalOpened"
|
||||
:footerButtonText="footerButtonText"
|
||||
:headerText="textboxQuestionPrompt"
|
||||
@footer-button-event="setZip"
|
||||
@footer-button-event="setZipCode"
|
||||
:modalForm="modalForm">
|
||||
<textboxQuestion
|
||||
ref="zipInputTextQuestion"
|
||||
:cmsWidgetName="this.textboxQuestionWidgetName"
|
||||
v-model="serviceZipCodeInput"
|
||||
inputId="serviceZipCodeInput"
|
||||
v-model="serviceZipCode"
|
||||
inputId="serviceZipCode"
|
||||
questionAlignment="center"
|
||||
mask="#####"
|
||||
:displayQuestionText="false"
|
||||
|
|
@ -81,6 +81,15 @@ export default {
|
|||
};
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
serviceZipQuestion: {
|
||||
serviceState: "",
|
||||
serviceZipCode: "",
|
||||
},
|
||||
}),
|
||||
},
|
||||
cmsWidgetName: String,
|
||||
textboxQuestionWidgetName: String,
|
||||
alertNonServiceableZipWidgetName: String,
|
||||
|
|
@ -94,6 +103,10 @@ export default {
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
mobileLocationLinkPromptText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "HeaderText");
|
||||
},
|
||||
|
||||
openZipCodeModal() {
|
||||
this.$refs[this.modalName].openModal();
|
||||
},
|
||||
|
|
@ -128,7 +141,11 @@ export default {
|
|||
this.focusOnZipInput();
|
||||
},
|
||||
|
||||
async setZip() {
|
||||
closeModal() {
|
||||
this.$refs[this.modalName].closeModal();
|
||||
},
|
||||
|
||||
async setZipCode() {
|
||||
this.resetAlerts();
|
||||
|
||||
const zipCodeData = await this.getZipCodeData(this.serviceZipCodeInput);
|
||||
|
|
@ -141,11 +158,30 @@ export default {
|
|||
this.serviceZip = this.serviceZipCodeInput;
|
||||
this.serviceZipState = zipCodeData.state;
|
||||
|
||||
this.$refs[this.modalName].closeModal();
|
||||
this.closeModal();
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
serviceZipLinkPromptText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "HeaderText");
|
||||
},
|
||||
serviceZipLinkText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "BodyText");
|
||||
},
|
||||
modalHeaderText() {
|
||||
return this.getCmsContent(this.textboxQuestionWidgetName, "QuestionText");
|
||||
},
|
||||
modalFooterText() {
|
||||
return this.getCmsContent(this.modalWidgetName, "FooterText");
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
textboxQuestionPrompt() {
|
||||
return this.getCmsContent(this.textboxQuestionWidgetName, "QuestionText");
|
||||
},
|
||||
|
|
@ -174,6 +210,21 @@ export default {
|
|||
).replaceAll("{custom:serviceZipCodeInput}", zipCode);
|
||||
return text;
|
||||
},
|
||||
serviceZipModel: {
|
||||
get: function () {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
serviceZipModel: {
|
||||
handler() {
|
||||
this.displayNonServiceableZipAlert = false;
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$watch(
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export default {
|
|||
<style lang="scss">
|
||||
a {
|
||||
color: $blue;
|
||||
text-underline-offset: 5px;
|
||||
text-underline-offset: 4px; //Per Devyn. This can't be documented in Figma so there is a comment with the Prototype mocks on the Quote page in Figma
|
||||
line-height: 2;
|
||||
padding: 0 0 4px 0;
|
||||
font-weight: 500;
|
||||
|
|
|
|||
Loading…
Reference in a new issue