Fixing merge conflicts

This commit is contained in:
brydon1 2023-06-30 13:59:22 -04:00
commit 7880b86485
40 changed files with 1546 additions and 896 deletions

View file

@ -175,17 +175,11 @@ stages:
indexDeployVariables:
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(apiCfDistributionId)
paths: /*
awsProfile: $(qaDeploymentProfile)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(cfDistributionId)
paths: /iss/*
paths: /*
awsProfile: $(qaDeploymentProfile)
# Prod Build/Deploy
@ -230,17 +224,11 @@ stages:
indexDeployVariables:
__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__: $(__VUE_APP_GOOGLE_TAG_MANAGER_SCRIPT_BODY__)
__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__: $(__VUE_APP_GOOGLE_TAG_MANAGER_NOSCRIPT_FRAME_SRC__)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(apiCfDistributionId)
paths: /*
awsProfile: $(prodDeploymentProfile)
- template: templates/digital/invalidate-cloudfront-cache.yml@AzureDevOps
parameters:
awsCliContainer: awscli
distributionId: $(cfDistributionId)
paths: /iss/*
paths: /*
awsProfile: $(prodDeploymentProfile)
- template: templates/digital/auto-tag.yml@AzureDevOps
parameters:

6
package-lock.json generated
View file

@ -3250,9 +3250,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.7.15",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz",
"integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==",
"version": "20.3.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.2.tgz",
"integrity": "sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw==",
"dev": true
},
"node_modules/@types/normalize-package-data": {

View file

@ -0,0 +1,7 @@
const coverageStatuses = {
PENDING: "Pending",
NO_COMP: "No Comp",
VERIFIED: "Verified",
};
export { coverageStatuses };

View file

@ -0,0 +1,9 @@
const endorsementOptions = {
EDUCATOR: "Educator",
OEM_APPROVED: "OEM Approved",
FULL_GLASS: "Full Glass Coverage",
PARKING_GUARD: "Parking Guard",
REPAIR_WAIVED: "Repair Waived"
};
export { endorsementOptions };

View file

@ -125,7 +125,11 @@ const endpoints = {
CoveragePolicyInfo: {
url: '/coverage/api/v1/coverage/get-policy-information',
method: 'POST'
}
},
RegisterClaim: {
url: '/coverage/api/v1/coverage/register-claim',
method: 'POST'
}
};
export { endpoints };

View file

@ -147,6 +147,7 @@ export default {
&:disabled,
&.disabled {
background-color: $gray-100;
color: $gray-500;
filter: grayscale(100%);
&:hover {
box-shadow: 0 0 0 4px transparent;

View file

@ -14,9 +14,8 @@
]">
<input
class="form-control"
v-model.trim="value"
v-model.trim.lazy="value"
v-maska="mask"
@keydown="preventDateInput"
:type="type"
:ref="inputId"
:id="inputId"
@ -138,17 +137,6 @@ export default {
this.$emit("update:modelValue", value);
},
preventDateInput(evt) {
if (this.type === "date") {
if (/\d/.test(evt.key)) {
evt.stopPropagation();
evt.preventDefault();
return false;
}
}
}
},
computed: {
questionText() {
@ -203,18 +191,6 @@ export default {
<style lang="scss">
input[type="date"]:invalid::-webkit-datetime-edit-year-field,
input[type="date"]:invalid::-webkit-datetime-edit-month-field,
input[type="date"]:invalid::-webkit-datetime-edit-day-field,
input[type="date"]:invalid::-webkit-datetime-edit-text
{
color: white;
background-color: white;
::placeholder {
content: " "
}
}
input[type="date"]::-webkit-inner-spin-button{
display: none;
}

View file

@ -0,0 +1,28 @@
import { randomUUID } from "crypto";
export function getRandomString(minLength = 1, maxLength = 100) {
const length = getRandomInt(minLength, maxLength + 1);
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
export function getRandomInt(min = 0, max = 1000) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive
}
export function getRandomGuid() {
return randomUUID();
}
export function getRandomBoolean() {
const bools = [true, false];
const index = getRandomInt(0,2);
return bools[index];
}

View file

@ -16,7 +16,7 @@
alertClass="alert-warning"
:manualHeadline="alertFewMoreQuestionsHeader"
:manualCopy="alertFewMoreQuestionsCopy"
v-bind:isDismissible="false"
v-bind:isDismissible="false"
class="mt-5"/>
<div v-for="(questionsDatum, i) in questionsData" :key="questionsDatum.key">
<questionChain
@ -29,6 +29,7 @@
:validationRules="validationRules" />
</div>
<siteFooter
class="mt-3"
ref="siteFooter"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!isMetaValid"

View file

@ -1,9 +1,9 @@
<template>
<footer class="footer container-fluid g-5 px-0 py-3 " id="infoBox">
<div class="row d-flex flex-row-reverse align-items-center vw-100 mx-0">
<div class="col button-col d-flex px-0" id="stacked" >
<buttonMain
<div>
<footer class="footer container-fluid g-5 px-0" id="infoBox">
<div class="row d-flex flex-row-reverse align-items-center vw-100 mx-0">
<div class="col button-col d-flex px-0" id="stacked" >
<buttonMain
v-if="!isForwardButtonHidden"
ref="buttonMain"
isPrimary
@ -16,9 +16,9 @@
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-main-button" />
</div>
<div v-if="!isBackButtonHidden" class="col-auto link-col py-1 px-0 text-break">
<textLink
</div>
<div v-if="!isBackButtonHidden" class="col-auto link-col py-1 px-0 text-break">
<textLink
linkType="navigation"
:text="backLink"
@click-event="linkClick"
@ -26,11 +26,12 @@
data-bs-target="#footerModal"
data-bs-dismiss="modal"
data-test-id="site-footer-back-button" />
</div>
</div>
</footer>
<div class="footerImage" id="imgCity" v-if="footerImageURL" >
<img id="siteFooterImage" :src="footerImageURL" />
</div>
</footer>
<div class="footerImage" id="imgCity" v-if="footerImageURL" >
<img id="siteFooterImage" :src="footerImageURL" />
</div>
</template>
@ -77,8 +78,8 @@ export default {
},
buttonText() {
return this.customButtontext
? this.customButtontext
: this.getCmsContent(this.cmsWidgetName, "ForwardButtonText");
? this.customButtontext
: this.getCmsContent(this.cmsWidgetName, "ForwardButtonText");
},
footerImageURL()
{
@ -126,6 +127,7 @@ export default {
<style lang="scss" scoped>
.footer {
display: flex;
overflow: visible;
a {
display: flex;
justify-content: center;

View file

@ -1,13 +1,13 @@
<template>
<div class="menu-modal-container">
<button class="menu-button" type="button" :class="[isActive ? 'active' : '']" data-bs-toggle="modal" data-bs-target="#footerModal" aria-label="Hamburger Menu (modal window)">
<button class="menu-button" type="button" :class="[isActive ? 'active' : '']" aria-label="Hamburger Menu (modal window)" @click="toggle()">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
</button>
</div>
<!-- Modal -->
<div class="modal menu-modal fade" data-bs-backdrop="false" id="footerModal" tabindex="-1" aria-labelledby="footerModalLabel" aria-hidden="true" v-on="{ 'show.bs.modal' : show, 'hide.bs.modal' : hide }">
<div class="modal menu-modal fade" data-bs-backdrop="false" id="footerModal" tabindex="-1" aria-labelledby="footerModalLabel" aria-hidden="true">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header visually-hidden">
@ -53,6 +53,8 @@
<script>
import textLink from "@/ux-components/text-link/text-link";
import { Modal } from "bootstrap";
export default {
name: 'menuModal',
data() {
@ -62,17 +64,25 @@ export default {
};
},
methods: {
show() {
this.currentFooterAndHeaderHeight = this.getFooterInfoBoxHeight() + 56;
this.isActive = true;
document.querySelector('.fade-on-route-transition').scrollTo({
top: 0, behavior: 'instant'
});
},
hide() {
var self = this;
self.isActive = false;
},
toggle() {
if(this.isActive){
//hide modal
this.isActive = false;
const modal = Modal.getInstance(document.getElementById("footerModal"));
modal?.hide();
}
else
{
//show modal
this.currentFooterAndHeaderHeight = this.getFooterInfoBoxHeight() + 56;
this.isActive = true;
const modal = Modal.getOrCreateInstance(document.getElementById("footerModal"));
modal?.show();
document.querySelector('.fade-on-route-transition').scrollTo({
top: 0, behavior: 'instant'
});
}
}
},
components: {
textLink,
@ -99,7 +109,6 @@ export default {
justify-content: center;
align-items: center;
padding: 0;//Required to prevent 'squish' on iPhone
z-index: 1060;
.bar1,
.bar2,
.bar3 {
@ -128,6 +137,7 @@ export default {
border-top: 1px solid $gray-300;
overflow-x: visible;
overflow-y: visible;
z-index: 2;
.modal-body {
padding: 2rem;
.ccpa-icon {

View file

@ -96,6 +96,7 @@ export default({
<style lang="scss" scoped>
.site-header {
height: 56px;
position: relative;
}
.alert {
left: 0;

View file

@ -31,7 +31,8 @@ import buttonBack from "@/iss-components/site-sub-header/button-back/button-back
cmsWidgetName: String,
hasBackButton: Boolean,
justification: String,
issContainingPage: String
issContainingPage: String,
darkGraySubText: Boolean,
},
computed: {
content() {
@ -53,9 +54,15 @@ import buttonBack from "@/iss-components/site-sub-header/button-back/button-back
'justify-content-center';
},
alternateFormatting() {
return (this.issContainingPage?.toLowerCase() === 'service-packages') ?
'service-packages-subtext mt-4 mb-2 px-5' :
'small';
//override for service-packages unique style
if (this.issContainingPage?.toLowerCase() === 'service-packages')
{
return 'service-packages-subtext mt-4 mb-2 px-5';
}
else
{
return this.darkGraySubText ? "dark-gray" : "light-gray";
}
}
},
methods: {
@ -84,9 +91,14 @@ import buttonBack from "@/iss-components/site-sub-header/button-back/button-back
color: inherit;
}
}
p.small {
p.light-gray {
color: $gray-550;
}
p.dark-gray {
color: $darker-gray;
}
p.service-packages-subtext {
font-weight: 500 !important;
line-height: 24px;

View file

@ -41,14 +41,13 @@
<alert
ref="alertVinLookupsByHomeAddressNotAllowed"
v-if="displayVinLookupByHomeAddressNotAllowedAlert"
class="mb-4 mt-4"
class="mt-4"
cmsWidgetName="AlertVinLookupsByHomeAddressNotAllowedWidget"
alertClass="alert-danger"
v-bind:isDismissible="false" />
<customerQuestions ref="customerQuestions" v-model="customerQuestions" />
<siteFooter
class="mt-5"
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isDisabled="!meta.valid"
@ -234,7 +233,7 @@ export default {
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo:
Object.keys(vehicleInfoToCommit).length === 0
? useMainStore().order.vehicle
? null
: vehicleInfoToCommit,
registrationInfo: {
firstName: this.customerQuestions.firstName,

View file

@ -10,6 +10,8 @@ import vehicleQuestionsMixin from "@/mixins/vehicle-questions-mixin";
import { applicationConfig } from "@/constants/application-config";
import { fetchCmsContentForPage, setupModalLinks } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { createTestingPinia } from '@pinia/testing';
import { getRandomString } from '@/helpers/data-generation.js';
jest.mock("@/helpers/damage-helper", () => ({
getDamageString: jest.fn(),
@ -31,7 +33,8 @@ describe("coverage-statement.vue...", () => {
test("Should return true for valid page requisites if vin exists", () => {
// Arrange
const { wrapper } = setupMocks({});
useMainStore().order.vehicle.vin = getRandomString(5,20);
// Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
@ -76,7 +79,7 @@ describe("coverage-statement.vue...", () => {
useMainStore().order.damage.isRepair = true;
// Assert
expect(wrapper.vm.unverifiedNonADASRepairBodyText).toEqual("NonADASRepairTestReturn");
expect(wrapper.vm.bodyText).toEqual("NonADASRepairTestReturn");
})
test("If damage is NonADAS Replace, display NonADASReplace coverage statement", async () => {
@ -85,8 +88,16 @@ describe("coverage-statement.vue...", () => {
mixins: [mockMixin],
});
useMainStore().lineItems.glassParts =
[
{
requiresRecalibration: false,
}
];
useMainStore().order.damage.isRepair = false;
// Assert
expect(wrapper.vm.unverifiedNonADASNextStepsBodyText).toEqual("NonADASReplaceTestReturn");
expect(wrapper.vm.bodyText).toEqual("NonADASReplaceTestReturn");
})
test("If damage is ADAS Replace, display ADASReplace coverage statement", async () => {
@ -94,12 +105,55 @@ describe("coverage-statement.vue...", () => {
const wrapper = shallowMount(coverageStatement, {
mixins: [mockMixin],
});
useMainStore().order.lineItems.requiresRecalibration = true;
useMainStore().lineItems.glassParts = [
{
requiresRecalibration: true,
}
];
useMainStore().order.damage.isRepair = false;
// Assert
expect(wrapper.vm.unverifiedADASNextStepsBodyText).toEqual("ADASReplaceTestReturn");
expect(wrapper.vm.bodyText).toEqual("ADASReplaceTestReturn");
})
});
describe("claim registration api call", () => {
it("claim registration not required => method not called", async () => {
// Arrange
const wrapper = setupMocks({});
const store = useMainStore();
store.isClaimRegistrationRequired = false;
const to = {
query: { issPage: getRandomString(4,10) }
};
const next = jest.fn();
// SUT
coverageStatement.beforeRouteEnter.call(wrapper.vm, to, undefined, next)
// Assert
expect(store.registerClaim).not.toHaveBeenCalled();
});
it("claim registration required => register claim method called", async () => {
// Arrange
const wrapper = setupMocks({});
const store = useMainStore();
store.isClaimRegistrationRequired = true;
const to = {
query: { issPage: getRandomString(4,10) }
};
const next = jest.fn();
// SUT
coverageStatement.beforeRouteEnter.call(wrapper.vm, to, undefined, next)
// Assert
expect(store.registerClaim).toHaveBeenCalled();
});
})
});
@ -122,8 +176,7 @@ const mockMixin = {
function setupMocks({
pageHeaderWidgetHeaderText,
// cmsPageContent = "CMS content goes here",
// unverifiedNonADASRepairBodyText = "repair body text",
mountOptionsMockData = {},
}) {
//Mock api responses
const apiResponses = {
@ -142,52 +195,23 @@ pageHeaderWidgetHeaderText,
unverifiedNonADASRepairBodyText: "Repair body text",
},
};
useMainStore().order = {
vehicle: {
vin: "TESTVIN",
},
lineItems: {
glassParts: [
{
canSafeliteRecalibrate: false,
childParts: null,
color: "Green Tint",
description: "solar, driver side, encap",
partNumber: "DQ12204GTYNOEM",
partType: "DRIVER REAR QUARTER GLASS",
recalibrationType: null,
requiresCapabilityQuestions: false,
requiresRecalibration: false,
}
]
},
damage: {
isRepair: false,
}
};
const apiPromise = Promise.resolve(apiResponses);
settleAllPromises.mockImplementation(() => apiPromise);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
const mountOptions = getMountOptions({
});
const mountOptions = getMountOptions({});
mountOptions.mixins = [baseMixin, vehicleQuestionsMixin];
mountOptions.global = {
plugins: [createTestingPinia()]
}
const wrapper = shallowMount(coverageStatement, mountOptions);
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
// //Mock CMS content
// const cmsContent = {
// PageContent: cmsPageContent,
// NonADASRepairBodyText: unverifiedNonADASRepairBodyText,
// };
return { wrapper };
}

View file

@ -9,34 +9,29 @@
<div class="col">
<div class="select-car-form rounded pb-1">
<textBlock
cmsWidgetName="verifyingCoverageStatement"
typeStyle="h5"
justifyText="center"
class="mt-4 mb-4"
id="coverage-statement-text-block"
/>
cmsWidgetName="verifyingCoverageStatement"
typeStyle="h5"
justifyText="center"
class="mt-4 mb-4"
id="coverage-statement-text-block" />
<div>
<p v-html="continueWithSchedulingBodyText" class="mt-0 small" ></p>
<p v-html="continueWithSchedulingBodyText" class="mt-0 small" ></p>
</div>
<textBlock
cmsWidgetName="whatHappensNextCopy"
class="mt-4 mb-2 fw-bold"
id="coverage-statement-text-block"
/>
cmsWidgetName="whatHappensNextCopy"
class="mt-4 mb-2 fw-bold"
id="coverage-statement-text-block" />
<div>
<p class="small" v-html="bodyText" ref="coverageStatementBodyText"></p>
<p class="small" v-html="bodyText" ref="coverageStatementBodyText"></p>
</div>
<steeringText cmsWidgetName="MASteeringText" ></steeringText>
</div>
<siteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
ref="siteFooter"
/>
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction"
ref="siteFooter" />
</div>
</div>
</div>
@ -81,14 +76,14 @@ export default {
},
computed: {
bodyText() {
if (useMainStore().order.damage.isRepair) {
if (useMainStore().damage.isRepair) {
return this.unverifiedNonADASRepairBodyText;
}
else {
let parts = useMainStore().order.lineItems.glassParts;
let parts = useMainStore().lineItems.glassParts;
// if ADAS, display ADASNextSteps
if (parts.filter(part => part.requiresRecalibration).length > 0) {
if (parts != null && parts.filter(part => part.requiresRecalibration).length > 0) {
return this.unverifiedADASNextStepsBodyText;
}
// if non-ADAS, display NonADASNextSteps
@ -126,20 +121,28 @@ export default {
},
];
if (useMainStore().isClaimRegistrationRequired){
const registerClaimResponse = await useMainStore().registerClaim();
promiseResultMap.push({
resultKey: 'registerClaim',
promise: registerClaimResponse,
});
}
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setCmsContent(resultMap.cmsContent);
});
},
methods: {
arePagePrerequisitesValid() {
if (useMainStore().order.vehicle.vin) {
if (useMainStore().vehicle.vin) {
return true;
}
return false;
},
async forwardButtonAction() {
return this.navigateForward();
},

View file

@ -53,6 +53,7 @@
validationRules="state-required"
class="mt-4 mb-2"/>
<siteFooter
class="mt-5"
:isForwardActionDisabled="!meta.valid"
cms-widget-name="SiteFooterWidget"
@back-clicked="backButtonAction"

View file

@ -28,6 +28,7 @@
</div>
</div>
<siteFooter
class="mt-5"
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isForwardActionDisabled="!meta.valid"
@ -66,7 +67,7 @@ export default {
data() {
return {
customerQuestions: this.getPolicyHolderDetailsFromStore(),
vehiclesFound: [],
vehiclesFound: [],
};
},
setup() {
@ -91,8 +92,8 @@ export default {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
});
},
methods:
{
@ -101,8 +102,8 @@ export default {
},
async forwardButtonAction()
{
this.mainStore.updatePolicyHolderDetails(this.customerQuestions);
{
this.mainStore.updatePolicyHolderDetails(this.customerQuestions);
return this.navigateForward();
},
@ -114,7 +115,7 @@ export default {
{},
{},
this.vehiclesFound
);
);
else
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_UNVERIFIED,
@ -135,7 +136,7 @@ export default {
firstName : this.mainStore.order.customer.firstName,
lastName : this.mainStore.order.customer.lastName,
}
},
},
},
computed:{
isCoverageEnabled(){
@ -143,7 +144,7 @@ export default {
},
vehiclesCount(){
return this.vehiclesFound.length;
}
}
},
components: {
siteHeader,

View file

@ -1,39 +1,34 @@
import policyVehicles from "@/layouts/policy-vehicles/policy-vehicles";
import { settleAllPromises } from "@/helpers/layout-helper.js";
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
import { useMainStore } from "@/store";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import {vehicleSelectionOptions} from "@/constants/vehicle-selection-options";
import { navigationScenarios } from "@/router/router-constants/navigation-scenarios";
import policyVehicles from '@/layouts/policy-vehicles/policy-vehicles.vue';
import { settleAllPromises } from '@/helpers/layout-helper';
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper';
import { useMainStore } from '@/store';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
import baseMixin from '@/mixins/base-mixin';
import { getRandomString, getRandomInt } from '@/helpers/data-generation';
import { endorsementOptions } from '@/constants/endorsement-options';
import { createTestingPinia } from '@pinia/testing';
import { issPageValues } from "@/router/router-constants/issPage-values";
import { vehicleSelectionOptions } from "@/constants/vehicle-selection-options";
// Mock fetchCmsContentForPage
jest.mock("@/helpers/cms-content-helper", () => ({
jest.mock('@/helpers/cms-content-helper', () => ({
fetchCmsContentForPage: jest.fn(),
doesCopyContainRouterLink: jest.fn(),
splitCopyOnCMSPlaceHolder: jest.fn().mockImplementation(() => "test"),
splitCopyOnCMSPlaceHolder: jest.fn().mockImplementation(() => 'test'),
getRouterLinkRouteFromCopy: jest.fn(),
getRouterLinkDisplayTextFromCopy: jest.fn(),
splitCMSCopyOnParagraphTag: jest.fn(),
}));
// Mock our module for promises.
jest.mock("@/helpers/layout-helper.js", () => ({
jest.mock('@/helpers/layout-helper.js', () => ({
settleAllPromises: jest.fn(),
}));
describe("policy-vehicles.vue", () => {
test("Should navigate to CLICKED_BACK if backButtonAction is run", async () => {
// Arrange
const { wrapper } = setupMocks({});
// Act
await wrapper.vm.backButtonAction();
//Assert
expect(wrapper.vm.$router.navigate).toBeCalled();
});
test("Should navigate to CLICKED_BACK if backButtonAction is run", async () => {
describe('policy-vehicles.vue', () => {
test('Should navigate to CLICKED_BACK if backButtonAction is run', async () => {
// Arrange
const { wrapper } = setupMocks({});
@ -44,116 +39,375 @@ describe("policy-vehicles.vue", () => {
expect(wrapper.vm.$router.navigate).toBeCalled();
});
test("Selected vehicle VIN do match vehicles listed in our system (CarIDs) found then navigate forward to vehicle-damage page.", async () => {
//Arrange
const { wrapper } = setupMocks({});
// Act
await wrapper.setData({
selectedVehicleVin: "5NMS3CADXLH233004"
});
await wrapper.vm.forwardButtonAction();
describe('forwardButtonAction', () => {
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
undefined,
{},
{}
);
});
test("Selected vehicle VIN do not match vehicles listed in our system (CarIDs) found then navigate forward to bailout page.", async () => {
//Arrange
const { wrapper } = setupMocks({});
test('Selected VIN matches vehicle listed in system => update vehicle and navigate forward with CLICKED_FORWARD_LISTED_VEHICLE scenario.', async () => {
//Arrange
const { wrapper } = setupMocks({});
// Act
await wrapper.setData({
selectedVehicleVin: "5NMS3CADXLH233004",
bailout: true
const vin = getRandomString(17,17);
await wrapper.setData({
selectedVehicleVin: vin,
policyVehicles: [
{ vin: vin },
],
bailout: false
});
const year = getRandomInt(1998, 2023);
const lookupVehicleResponse = {
data: {
year: year,
}
};
const store = useMainStore();
store.lookupVehicleByVin.mockReturnValue(Promise.resolve(lookupVehicleResponse));
const expectedInput = {
year: year,
vin: vin,
noCompensation: true,
deductible: 0,
repairWaived: false
}
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.bailout).toBeFalsy();
expect(store.updateVehicle).toHaveBeenCalledWith(expectedInput);
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_LISTED_VEHICLE,
undefined,
{},
{}
);
});
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
undefined,
{},
{}
);
test('Error in lookupVehicleByVin call => bailout true and navigate forward with CLICKED_FORWARD_WITH_BAILOUT scenario.', async () => {
//Arrange
const { wrapper } = setupMocks({});
const vin = getRandomString(17,17);
await wrapper.setData({
selectedVehicleVin: vin,
bailout: false
});
const store = useMainStore();
store.lookupVehicleByVin.mockReturnValue(Promise.reject());
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.bailout).toBeTruthy();
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
undefined,
{},
{}
);
});
test('vehicle not listed => navigate forward with CLICKED_FORWARD_NON_LISTED_VEHICLE scenario.', async () => {
// Arrange
const { wrapper } = setupMocks({});
await wrapper.setData({
selectedVehicleVin: vehicleSelectionOptions.VEHICLE_NOT_LISTED,
});
// Act
await wrapper.vm.forwardButtonAction();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
undefined,
{},
{}
);
});
})
describe('noCompensationForSelectedVehicle computed property', () => {
it('No vehicle match => returns true', async () => {
// Arrange
const selectedVin = getRandomString(17,17);
const otherVin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: selectedVin,
policyVehicles: [
{
vin: otherVin,
},
],
}
// Act
const result = policyVehicles.computed.noCompensationForSelectedVehicle.call(testValues);
// Assert
expect(result).toBeTruthy();
});
it('Coverages list empty => true', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: []
},
],
}
// Act
const result = policyVehicles.computed.noCompensationForSelectedVehicle.call(testValues);
// Assert
expect(result).toBeTruthy();
});
it('Coverages list non-empty => false', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: [
{
deductible: 0
}
]
},
],
}
// Act
const result = policyVehicles.computed.noCompensationForSelectedVehicle.call(testValues);
// Assert
expect(result).toBeFalsy();
});
})
describe('deductibleForSelectedVehicle computed property', () => {
it('No vehicle match => undefined returned', () => {
// Arrange
const selectedVin = getRandomString(17,17);
const otherVin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: selectedVin,
policyVehicles: [
{
vin: otherVin,
},
],
}
// Act
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(undefined);
});
it('Vehicle match with empty coverages list => 0 returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: []
},
],
}
// Act
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(0);
});
it('Coverages list non empty => deductible from first coverage returned', () => {
// Arrange
const vin = getRandomString(17,17);
const firstDeductible = getRandomInt(1,1000);
const secondDeductible = getRandomInt(1,1000);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
coverages: [
{
deductible: firstDeductible
},
{
deductible: secondDeductible
}
]
},
],
}
// Act
const result = policyVehicles.computed.deductibleForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(firstDeductible);
});
});
test("if user select vehicle not listed option then navigate forward to vehicle-selection page.", async () => {
//Arrange
const { wrapper } = setupMocks({});
describe('repairWaivedForSelectedVehicle computed property', () => {
it('No vehicle match => false returned', () => {
// Arrange
const selectedVin = getRandomString(17,17);
const otherVin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: selectedVin,
policyVehicles: [
{
vin: otherVin,
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(false);
});
it('Endorsements list empty => false returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
endorsements: []
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(false);
});
it('Endorsements list non-empty, not containing repair waived => false returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
endorsements: [ endorsementOptions.EDUCATOR, endorsementOptions.PARKING_GUARD ]
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(false);
});
it('Endorsements list contains repair waived => true returned', () => {
// Arrange
const vin = getRandomString(17,17);
const testValues = {
selectedVehicleVin: vin,
policyVehicles: [
{
vin: vin,
endorsements: [
endorsementOptions.EDUCATOR,
endorsementOptions.REPAIR_WAIVED,
endorsementOptions.PARKING_GUARD
]
},
],
}
// Act
const result = policyVehicles.computed.repairWaivedForSelectedVehicle.call(testValues);
// Assert
expect(result).toBe(true);
});
});
test('first vehicle is auto-selected if only one vehicle on policy', async () => {
// Arrange
const vin = getRandomString(17,17);
useMainStore().applicationUser = {
pageData: {
[issPageValues.POLICY_VEHICLES]: [ { vin: vin } ],
}
};
const { wrapper } = setupMocks();
// Act
await wrapper.setData({
selectedVehicleVin: vehicleSelectionOptions.VEHICLE_NOT_LISTED,
});
await wrapper.vm.forwardButtonAction();
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_FORWARD_NON_LISTED_VEHICLE,
undefined,
{},
{}
);
expect(wrapper.vm.selectedVehicleVin).toBe(vin);
});
});
function setupMocks({
route = null,
lookupVehicleByVinResponse
})
{
useMainStore().applicationUser = {
pageData: {
"policy-vehicles":
[
{
vehicleMake: "Hyundai",
vehicleModel: "Santa Fe",
vehicleStyle: "4 door utility",
vehicleYear: 2020,
vin: "5NMS3CADXLH233004",
},
],
}
};
useMainStore().lookupVehicleByVin = jest.fn().mockImplementation(() => {
return Promise.resolve({
data: lookupVehicleByVinResponse
? lookupVehicleByVinResponse : {
vehicle: {
carId: "CARID"
},
},
})
});
const mockMixin = {
methods: {
getCmsContent: jest.fn(),
},
computed: {
dynamicStrings() {
return { ROUTER_LINK: 'routerLink:' };
},
},
};
function setupMocks()
{
const mountOptions = getMountOptions({
route: route ? route : undefined,
router: {
navigate: jest.fn(),
},
mainStore: {
order: {
vehicle: {
carId: "CR00069309",
category: "SUV",
imageUrl:
"https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13769/13769_cc0320_032_WW8.jpg",
imageVifColor: "white",
imageVifNumber: "13769",
make: "Hyundai",
model: "Santa Fe",
style: "4 door utility",
year: 2020,
mixins: [mockMixin],
global: {
mocks: {
$route: {
params: {
id: 1
}
},
vin: "5NMS3CADXLH233004",
$router: {
navigate: jest.fn()
}
},
},
},
);
plugins: [createTestingPinia()]
}
});
const apiResponses = {
cmsContent: {},
@ -161,24 +415,11 @@ function setupMocks({
settleAllPromises.mockImplementation(() => apiResponses);
fetchCmsContentForPage.mockImplementation(() => Promise.resolve());
//Mock props
const mockMixin = {
methods: {
getCmsContent: jest.fn(),
},
computed: {
dynamicStrings() {
return { ROUTER_LINK: "routerLink:" };
},
},
};
mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(policyVehicles,mountOptions);
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => "");
const wrapper = shallowMount(policyVehicles, mountOptions);
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => '');
wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
return { wrapper };

View file

@ -8,7 +8,7 @@
<div class="row">
<div class="col">
<div class="select-car-form rounded text-center">
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="true" class="mt-2 mb-4" />
<vehicleBanner cmsWidgetName="VehicleBannerWidget" :displayGenericVehicleImage="displayGeneric" class="mt-2 mb-4" />
<policyVehiclesQuestion
class="px-4"
cmsWidgetName="PolicyVehiclesQuestion"
@ -41,7 +41,8 @@ import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { issPageValues } from "@/router/router-constants/issPage-values";
import { useMainStore } from '@/store';
import { errorMessages } from "@/constants/error-messages";
import {vehicleSelectionOptions} from "@/constants/vehicle-selection-options";
import { vehicleSelectionOptions } from "@/constants/vehicle-selection-options";
import { endorsementOptions } from "@/constants/endorsement-options";
// DEFINE VALIDATION RULES
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
@ -49,9 +50,14 @@ export default {
name: "policy-vehicles",
mixins: [BaseFormMixin],
data() {
return {
selectedVehicleVin: "",
bailout: false
const policyVehicles = useMainStore().pageData(issPageValues.POLICY_VEHICLES);
return {
policyVehicles: policyVehicles,
selectedVehicleVin: (policyVehicles?.length ?? 0) == 1
? policyVehicles[0].vin
: "",
displayGeneric: true,
bailout: false
}
},
async beforeRouteEnter(to, from, next)
@ -63,28 +69,36 @@ export default {
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},];
//use resultMap to populate layout content.
let resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
},
];
//use resultMap to populate layout content.
let resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods:
{
backButtonAction() {
this.mainStore.issConfig.disabledFields.policyNumber = true;
useMainStore().issConfig.disabledFields.policyNumber = true;
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {
if(this.selectedVehicleVin != vehicleSelectionOptions.VEHICLE_NOT_LISTED){
async forwardButtonAction() {
if (this.selectedVehicleVin != vehicleSelectionOptions.VEHICLE_NOT_LISTED){
const vehicleLookupResponse = await this.lookupVehicleByVin(this.selectedVehicleVin);
if (vehicleLookupResponse.error) {
this.bailout = true;
this.bailout = true;
return this.navigateForward();
}
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, { vin: this.selectedVehicleVin });
this.mainStore.updateVehicle(this.vehicleFromLookup);
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
vin: this.selectedVehicleVin,
noCompensation: this.noCompensationForSelectedVehicle,
deductible: this.deductibleForSelectedVehicle,
repairWaived: this.repairWaivedForSelectedVehicle
});
useMainStore().updateVehicle(this.vehicleFromLookup);
}
return this.navigateForward();
},
@ -112,24 +126,21 @@ export default {
);
},
async lookupVehicleByVin(vin) {
try {
return await this.mainStore.lookupVehicleByVin(vin);
}
catch (responseError) {
return {
error: {
status: responseError.status,
},
};
}
},
try {
return await useMainStore().lookupVehicleByVin(vin);
}
catch (responseError) {
return {
error: true,
};
}
},
},
computed:{
VehiclesForQuestions() {
// Map API result data, to address-vehicles data structure
const vehicles = this.VehiclesFromApi;
const mappedData = vehicles.map((v) => {
const vehicles = this.policyVehicles;
const mappedData = vehicles?.map((v) => {
const maskSymbol = "X";
const vinStart = maskSymbol.repeat(v.vin.length - 6);
const vinEnd = v.vin.substring(v.vin.length - 6);
@ -140,13 +151,70 @@ export default {
Name: v.vin,
SubText: "VIN " + vinStart + vinEnd,
};
});
}) ?? [];
return mappedData;
},
noCompensationForSelectedVehicle() {
const vehicle = this.policyVehicles.find((vehicle) => { return vehicle.vin == this.selectedVehicleVin; });
return (vehicle?.coverages?.length ?? 0) == 0;
},
deductibleForSelectedVehicle() {
const vehicle = this.policyVehicles.find((vehicle) => { return vehicle?.vin == this.selectedVehicleVin; });
if (!vehicle){
return undefined;
}
return vehicle.coverages?.length ?? false
? vehicle?.coverages[0].deductible
: 0;
},
repairWaivedForSelectedVehicle() {
const vehicle = this.policyVehicles.find((vehicle) => { return vehicle.vin == this.selectedVehicleVin; });
return vehicle?.endorsements?.includes(endorsementOptions.REPAIR_WAIVED) ?? false;
},
VehiclesFromApi() {
return useMainStore().pageData(issPageValues.POLICY_VEHICLES);
},
},
},
selectedVehicle() {
const vehicle = this.mainStore.lookupVehicleByVin(this.selectedVehicleVin);
return vehicle;
},
},
watch: {
async selectedVehicleVin(value) {
if (value === vehicleSelectionOptions.VEHICLE_NOT_LISTED) {
// clear previously selected vehicle and image
this.mainStore.resetVehicleState();
this.displayGeneric = true;
}
else {
// get vehicle details from selected VIN
const vehicle = await this.lookupVehicleByVin(value);
// handle error in case vehicle info doesn't come back for selected VIN
if (vehicle?.error ?? true) {
this.mainStore.resetVehicleState();
this.displayGeneric = true;
return;
}
// save selected vehicle to the store
this.mainStore.updateVehicle(vehicle.data);
this.displayGeneric = true;
// get the style(s) associated with the selected YMM
const styleOptions = await this.mainStore.getVehicleStyles(
vehicle.data.year,
vehicle.data.make,
vehicle.data.model
)
// if there is more than 1 style for the selected vehicle, display generic/blurred image
this.displayGeneric = styleOptions?.data?.length > 1;
}
}
},
components: {
siteHeader,
siteFooter,

View file

@ -16,6 +16,7 @@
class="mx-5" />
<div class="px-5">
<siteFooter
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
@backClicked="backButtonAction"
@ -26,16 +27,16 @@
</div>
<recalModal ref="recalModal" cmsWidgetName="RecalModal" />
<steeringModal cmsWidgetName="StateSteeringModal" ref="StateSteeringModal" />
<shopPreferenceModal
cmsWidgetName="ShopPreferenceDrawer"
ref="ShopPreferenceDrawer"
<shopPreferenceModal
cmsWidgetName="ShopPreferenceDrawer"
ref="ShopPreferenceDrawer"
@openSteering="openStateSteeringModal"
:showSteeringLink="showSteeringLink"/>
<tpaRecalModal cmsWidgetName="TPARecalModal"
<tpaRecalModal cmsWidgetName="TPARecalModal"
ref="TPARecalModal"
:ackError="ackError"
:ackError="ackError"
@buttonClick="navigateWithTPAAck"
/>
/>
</Form>
</template>
@ -159,12 +160,12 @@ export default {
this.$router.navigate(scenario, this.$route);
},
navigateWithTPAAck() {
this.mainStore.saveProviderPreferenceData({selectedProvider: this.selectedProvider, tpaAcknowledgement: this.tpaAcknowledgement});
this.mainStore.saveProviderPreferenceData({selectedProvider: this.selectedProvider, tpaAcknowledgement: this.tpaAcknowledgement});
this.navigateForward(this.navigationScenarios.CLICKED_FORWARD_WITH_TPA_ENABLED);
},
forwardButtonAction() {
if(this.selectedProvider) {
let scenario = null;
let scenario = null;
switch (this.selectedProvider) {
case options.SAFELITE:
scenario = this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE;
@ -186,7 +187,7 @@ export default {
break;
};
this.navigateForward(scenario);
this.mainStore.saveProviderPreferenceData({selectedProvider: this.selectedProvider, tpaAcknowledgement: this.tpaAcknowledgement});
this.mainStore.saveProviderPreferenceData({selectedProvider: this.selectedProvider, tpaAcknowledgement: this.tpaAcknowledgement});
}
},
openStateSteeringModal() {

View file

@ -6,6 +6,7 @@
<div class="container-fluid pb-2">
<p>Placeholder for schedule page</p>
<siteFooter
class="mt-5"
cmsWidgetName="SiteFooterWidget"
ref="siteFooter"
:isForwardActionDisabled="!meta.valid"

View file

@ -31,11 +31,12 @@
validationRules="selection-required"
class="service-location-button-question mb-1"/>
<div class="select-car">
<div class="container-fluid pb-2">
<div class="container-fluid pb-2 g-0">
<div class="row">
<div class="col px-0">
<div class="select-car-form rounded">
<siteFooter
class="mt-4"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@ -89,7 +90,7 @@ export default {
const zipCodeData = getZipCodeData(serviceZipCode);
const serviceabilityDetailsPromise = getServiceabilityDetails(serviceZipCode);
// Settle promises and get results
const promiseResultMap = [
{
@ -107,7 +108,7 @@ export default {
];
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.setData(
@ -161,7 +162,7 @@ export default {
},
displayMilitaryZipAlert() {
return this.zipContainsMilitaryBase && this.isServiceableMobile;
}
}
},
methods: {
arePagePrerequisiteValid() {
@ -258,11 +259,11 @@ export default {
.service-location-button-question {
.question-text {
margin-top: 1.5rem;
span {
text-align: center;
}
}
}
</style>

View file

@ -63,20 +63,28 @@
},
servicePackageAnswers() {
if (!this.cmsWidgetName) return [];
const cmsAnswersContent = [
const cmsAnswersContent = [];
cmsAnswersContent.push(
{
Name: 'TierOne',
cmsWidgetName: 'EconomyServicePackage'
},
{
Name: 'TierTwo',
cmsWidgetName: 'StandardServicePackage'
},
}
);
if(this.shouldDisplayTierTwoPackage)
{
cmsAnswersContent.push(
{
Name: 'TierTwo',
cmsWidgetName: 'StandardServicePackage'
},
);
}
cmsAnswersContent.push(
{
Name: 'TierThree',
cmsWidgetName: 'PremiumServicePackage'
}
];
);
//if cms content has not yet loaded, skip
if (this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText') == '') {
return {};
@ -96,27 +104,18 @@
return this.lineItemsContainsPartType(partTypeStrings.RECALIBRATION);
},
frontWipersApplicableForTierTwo() {
const store = useMainStore();
const frontWipersAreAvailable = this.lineItemsContainsPartType(
partTypeStrings.FRONT_WIPER
);
const isRepair = store.order.damage.isRepair;
const glassToReplaceContainsWindshield = this.glassToReplaceContainsGlassLocation(
glassLocations.WINDSHIELD
);
if (frontWipersAreAvailable) {
if (isRepair) {
return true;
} else {
if (glassToReplaceContainsWindshield) {
return true;
} else {
return false;
}
}
} else {
return false;
const glassToReplaceContainsWindshield = this.glassToReplaceContainsGlassLocation(glassLocations.WINDSHIELD);
if(frontWipersAreAvailable && (useMainStore().order.damage.isRepair || glassToReplaceContainsWindshield))
{
return true;
}
return false;
},
rearWiperApplicableForTierTwo() {
const rearWiperIsAvailable = this.lineItemsContainsPartType(partTypeStrings.REAR_WIPER);

View file

@ -51,6 +51,7 @@
groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" />
<site-footer
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="backButtonAction"
@ -315,170 +316,170 @@ export default {
this.selectedGlassToReplace(),
this.selectedWindshieldOptions.selectedWindshieldChipCount);
return this.navigateForward();
},
},
navigateForward() {
if (this.mainStore.damage.isRepair) {
navigateForward() {
if (this.mainStore.damage.isRepair) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.$route
);
}
else {
// If vin already exists, navigate directly to vin-lookup
if (this.mainStore.order.vehicle.vin) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_REPAIR,
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.$route
);
}
else {
// If vin already exists, navigate directly to vin-lookup
if (this.mainStore.order.vehicle.vin) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
this.$route
);
} else {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
this.$route
);
}
}
},
selectedGlassToReplace() {
const selectedGlassToReplace = [];
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
(wsItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: wsItem,
});
}
);
}
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem,
});
});
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem,
});
}
);
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions,
});
}
return selectedGlassToReplace;
},
},
computed: {
isWindshieldDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
});
},
isSideDoorDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
});
},
isRearWindowDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
});
},
isWindshieldRepair() {
return (
this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR
);
},
isDriverSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedDriverSide) => {
return selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE;
});
},
isPassengerSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedPassengerSide) => {
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
});
},
hasRepairReplaceConflict() {
return (
this.isWindshieldDamageLocation &&
this.selectedDamageLocations.length > 1 &&
this.isWindshieldRepair
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR ||
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
)
return false;
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedSingleWindshield) => {
return (
selectedSingleWindshield.toUpperCase() ===
damageLocationsSelected.SINGLE.toUpperCase()
);
}
) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedDriverWindshield) => {
return (
selectedDriverWindshield.toUpperCase() ===
damageLocationsSelected.DRIVER.toUpperCase()
);
}
) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedPassengerWindshield) => {
return (
selectedPassengerWindshield.toUpperCase() ===
damageLocationsSelected.PASSENGER.toUpperCase()
);
}
))
);
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
}
},
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
windshieldOptions,
replaceOptionsQuestion,
Form,
alert,
selectedGlassToReplace() {
const selectedGlassToReplace = [];
if (this.isWindshieldDamageLocation && !this.isWindshieldRepair) {
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions.forEach(
(wsItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: wsItem,
});
}
);
}
if (this.isDriverSideReplace) {
this.sideDoorOptionsData.selectedDriverSideReplaceOptions.forEach((driverItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.DRIVER,
glassName: driverItem,
});
});
}
if (this.isPassengerSideReplace) {
this.sideDoorOptionsData.selectedPassengerSideReplaceOptions.forEach(
(passengerItem) => {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.PASSENGER,
glassName: passengerItem,
});
}
);
}
if (this.isRearWindowDamageLocation) {
selectedGlassToReplace.push({
glassLocation: damageLocationsSelected.REAR,
glassName: this.selectedRearReplaceOptions,
});
}
return selectedGlassToReplace;
},
};
</script>
},
computed: {
isWindshieldDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.WINDSHIELD;
});
},
isSideDoorDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.SIDEDOOR;
});
},
isRearWindowDamageLocation() {
return this.selectedDamageLocations.some((selectedDamages) => {
return selectedDamages.toUpperCase() === damageLocationsCms.REARWINDOW;
});
},
isWindshieldRepair() {
return (
this.isWindshieldDamageLocation &&
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR
);
},
isDriverSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedDriverSide) => {
return selectedDriverSide.toUpperCase() === damageLocationsCms.DRIVERSIDE;
});
},
isPassengerSideReplace() {
if (!this.isSideDoorDamageLocation) return false;
return this.sideDoorOptionsData.selectedDoorSides.some((selectedPassengerSide) => {
return selectedPassengerSide.toUpperCase() === damageLocationsCms.PASSENGERSIDE;
});
},
hasRepairReplaceConflict() {
return (
this.isWindshieldDamageLocation &&
this.selectedDamageLocations.length > 1 &&
this.isWindshieldRepair
);
},
hasSplitSingleConflict() {
if (
!this.selectedDamageLocations?.includes("Windshield") ||
this.selectedWindshieldOptions.selectedWindshieldDamageType ===
damageLocationsSelected.REPAIR ||
!this.selectedWindshieldOptions.selectedWindshieldReplaceOptions
)
return false;
return (
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedSingleWindshield) => {
return (
selectedSingleWindshield.toUpperCase() ===
damageLocationsSelected.SINGLE.toUpperCase()
);
}
) &&
(this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedDriverWindshield) => {
return (
selectedDriverWindshield.toUpperCase() ===
damageLocationsSelected.DRIVER.toUpperCase()
);
}
) ||
this.selectedWindshieldOptions.selectedWindshieldReplaceOptions?.some(
(selectedPassengerWindshield) => {
return (
selectedPassengerWindshield.toUpperCase() ===
damageLocationsSelected.PASSENGER.toUpperCase()
);
}
))
);
},
shouldDisplayVehicleChangeAlert() {
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
}
},
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
windshieldOptions,
replaceOptionsQuestion,
Form,
alert,
},
};
</script>

View file

@ -1,12 +1,11 @@
/* eslint-env jest */
import { mount } from '@vue/test-utils';
import { navigationScenarios } from '@/router/router-constants/navigation-scenarios';
import { issPageValues } from '@/router/router-constants/issPage-values';
import { queryStrings } from '@/constants/query-strings';
import { GaActions } from "@/constants/analytics";
import VehicleLookup from './vehicle-lookup.vue';
import {vinLookupMethodSelections} from '@/constants/vin-lookup-methods';
import { useMainStore } from '../../store';
import { useMainStore } from '@/store';
import { createTestingPinia } from '@pinia/testing';
import { mapStores } from "pinia";

View file

@ -11,7 +11,7 @@
<VehicleBanner class="mt-2 mb-4" cms-widget-name="VehicleBannerWidget" :display-generic-vehicle-image="false" />
<SiteSubHeader cms-widget-name="SiteSubHeaderWidget" class="mt-5 mb-2" />
<VinLookupMethods v-model="selectedVinLookupMethod" cms-widget-name="VINLookupMethod" group-name="VinLookupMethods" ref="VinLookupMethods" />
<SiteFooter cms-widget-name="SiteFooterWidget" :is-forward-action-disabled="isForwardActionDisabled" @back-clicked="backButtonAction" @forward-clicked="forwardButtonAction" />
<SiteFooter cms-widget-name="SiteFooterWidget" :is-forward-action-disabled="isForwardActionDisabled" @back-clicked="backButtonAction" @forward-clicked="forwardButtonAction" class="mt-3"/>
</div>
</div>
</div>

View file

@ -181,12 +181,12 @@ export default {
},
AutoSelectIfSinglePart() {
if (this.partsForSelectedTint?.length > 0)
if (this.partsForSelectedTint?.length > 0)
{
// Check if only a single part is present for the tint and set the v-model if it is.
if (this.partsForSelectedTint?.length == 1) {
this.selectedPartNumber = { value: this.partsForSelectedTint[0].partNumber };
// //select element with matching partNumber
this.$nextTick(() => {
const radioInput = document.querySelector('input[value=' + this.selectedPartNumber + ']');
@ -199,7 +199,7 @@ export default {
}
}
},
// Loads the preselected values from the store.
LoadPreselectedValues() {
this.$nextTick(() => {
@ -208,7 +208,7 @@ export default {
{
this.selectedTint = this.modelValue.color;
}
});
});
},
replaceAllSpaceWithDash(str) {

View file

@ -1,5 +1,5 @@
<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 position-relative">
<div class="fade-on-route-transition position-relative">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
@ -8,57 +8,59 @@
<div class="row">
<div class="col">
<div class="select-car-form rounded">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="siteSubHeader"
justification="left"
justification="center"
darkGraySubText
/>
<vehicleQuestion
ref="vehicleYearQuestion"
class="mb-2 mt-4"
v-model="selectedYear"
cmsWidgetName="VehicleYearQuestion"
:updateValues="updateYearValues"
validationRules="year-required"
<vehicleQuestion
ref="vehicleYearQuestion"
class="mb-2 mt-4"
v-model="selectedYear"
cmsWidgetName="VehicleYearQuestion"
:updateValues="updateYearValues"
validationRules="year-required"
inputId="yearQuestionField"
/>
<vehicleQuestion
ref="vehicleMakeQuestion"
class="mb-2 mt-4"
<vehicleQuestion
ref="vehicleMakeQuestion"
class="mb-2 mt-4"
v-model="selectedMake"
cmsWidgetName="VehicleMakeQuestion"
:updateValues="updateMakeValues"
validationRules="make-required"
cmsWidgetName="VehicleMakeQuestion"
:updateValues="updateMakeValues"
validationRules="make-required"
inputId="makeQuestionField"
/>
<vehicleQuestion
ref="vehicleModelQuestion"
class="mb-2 mt-4"
<vehicleQuestion
ref="vehicleModelQuestion"
class="mb-2 mt-4"
v-model="selectedModel"
cmsWidgetName="VehicleModelQuestion"
:updateValues="updateModelValues"
validationRules="model-required"
cmsWidgetName="VehicleModelQuestion"
:updateValues="updateModelValues"
validationRules="model-required"
inputId="modelQuestionField"
/>
<vehicleQuestion
ref="vehicleStyleQuestion"
class="mb-2 mt-4"
<vehicleQuestion
ref="vehicleStyleQuestion"
class="mb-2 mt-4"
v-model="selectedStyle"
cmsWidgetName="VehicleStyleQuestion"
:updateValues="updateStyleValues"
validationRules="style-required"
cmsWidgetName="VehicleStyleQuestion"
:updateValues="updateStyleValues"
validationRules="style-required"
inputId="styleQuestionField"
/>
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric"
class="mt-5 mb-3"
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric"
class="mt-5 mb-3"
ref="banner"
/>
<siteFooter
class="mt-5"
cmsWidgetName="SiteFooterWidget"
@ForwardClicked="forwardButtonAction"
:isForwardActionDisabled="!meta.valid"
@ -106,33 +108,33 @@ export default {
selectedYear: null,
selectedMake: null,
selectedModel: null,
selectedStyle: null,
selectedStyle: null,
};
},
props:{
cmsWidgetName:String,
validationRules:String,
},
mounted(){
mounted(){
this.$refs["vehicleYearQuestion"].getNewValues();
},
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
},
];
let resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
@ -140,33 +142,28 @@ export default {
watch: {
selectedYear(value) {
this.mainStore.updateVehicleYear(value);
this.$refs["vehicleMakeQuestion"].clearValues();
if(value)
{
{
this.$refs["vehicleMakeQuestion"].getNewValues();
}
else{
this.$refs["vehicleMakeQuestion"].clearValues();
}
},
selectedMake(value) {
this.mainStore.updateVehicleMake(value);
this.$refs["vehicleModelQuestion"].clearValues();
if(value)
{
{
this.$refs["vehicleModelQuestion"].getNewValues();
}
else{
this.$refs["vehicleModelQuestion"].clearValues();
}
},
selectedModel(value) {
this.mainStore.updateVehicleModel(value);
this.$refs["vehicleStyleQuestion"].clearValues();
if(value)
{
{
this.$refs["vehicleStyleQuestion"].getNewValues();
}
else{
this.$refs["vehicleStyleQuestion"].clearValues();
}
},
selectedStyle(value) {
this.mainStore.updateVehicleStyle(value);
@ -191,7 +188,7 @@ export default {
this.$route
);
});
},
},
async updateYearValues() {
return await useMainStore().getVehicleYears();
},
@ -207,7 +204,7 @@ export default {
},
computed: {
displayGeneric() {
return !useMainStore().order.vehicle.imageUrl || !this.selectedStyle;
return !this.selectedStyle;
}
},
components: {
@ -232,6 +229,6 @@ export default {
.subheader-secondary {
margin-top: .5rem;
padding: 0px;
padding: 0px;
}
</style>

View file

@ -119,6 +119,11 @@ const vehicleWithNoAdditionalPartsOrQuestionsMockResponse = {
},
};
jest.mock("bootstrap", () => ({
getInstance: jest.fn(),
getOrCreateInstance: jest.fn(),
}));
const mockRoute = {
query: {
// Needed inside vehicle-questions-mixin

View file

@ -13,7 +13,7 @@
<vinLookupAlerts class="mt-5" :activeAlertType="activeVehicleLookupAlertType" />
<vinQuestion v-model="vin" :mask="vinMask" :isDisabled="vinPopulatedOnPageLoad" textPosition="left" />
<vinLocationInformation />
<siteFooter cmsWidgetName="SiteFooterWidget" :isForwardActionDisabled="!meta.valid" @backClicked="backButtonAction" @forwardClicked="forwardButtonAction" ref="siteFooter" />
<siteFooter cmsWidgetName="SiteFooterWidget" :isForwardActionDisabled="!meta.valid" @backClicked="backButtonAction" @forwardClicked="forwardButtonAction" ref="siteFooter" class="mt-5" />
</div>
</div>
</div>
@ -152,7 +152,7 @@ export default {
this.bailout=true
}
if(this.bailout){
if(this.bailout){
return this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route);
@ -188,6 +188,7 @@ export default {
// navigate back to vehicle-damage
if (this.isCarIdDifferentFromTheStore && !isSelectedGlassAvailableForVehicle) {
this.mainStore.updateVehicle(this.vehicleFromLookup);
this.mainStore.resetDamageState();
this.$router.navigate(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,

View file

@ -140,7 +140,8 @@
</div>
<div class="row position-sticky top-100" id="welcomeFooter">
<div class="col">
<site-footer
<siteFooter
class="mt-3"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ -259,12 +260,12 @@ export default {
const policyLookupResultMap = await settleAllPromises(promisePolicyLookupResultMap);
const policyInfo = policyLookupResultMap.policyLookupResponse;
// if policy lookup fails, navigate directly to policy-holder-details page
if (!policyInfo) {
this.navigateForward();
}
const policy = policyInfo.policies?.[0];
if (policy) {
//populate policy holder details from policy lookup
@ -274,8 +275,8 @@ export default {
this.mainStore.order.customer.address.zipCode = policy.insureds?.[0]?.zipCode;
this.mainStore.order.customer.firstName = policy.insureds?.[0]?.firstName;
this.mainStore.order.customer.lastName = policy.insureds?.[0]?.lastName;
//populate vehicles
//populate vehicles
this.vehiclesFound = policy.vehicles;
}
return this.navigateForward(policy);
@ -289,7 +290,7 @@ export default {
// if policy lookup is successful and vehicles are found, navigate to policy-vehicles page
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_POLICY_VERIFIED_WITH_VEHICLES,
this.$route,
this.$route,
{},
{},
this.vehiclesFound
@ -312,7 +313,7 @@ export default {
);
}
},
getWelcomePageModelFromStore() {
return {
policyNumber: this.mainStore.order.policy.policyNumber,

View file

@ -452,9 +452,15 @@ export default {
this.hasGlassLocationWithMultipleParts(partsOrQuestions);
const hasChildPartQuestions = this.hasChildPartQuestions(partsOrQuestions);
const hasCapabilityQuestions = this.hasCapabilityQuestions(partsOrQuestions);
let backNavigationScenario = self.mainStore.vehicle.vin
? navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS
: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS;
let backNavigationScenario = "";
if (self.mainStore.order.damage.isRepair) {
backNavigationScenario = navigationScenarios.CLICKED_BACK_WITH_REPAIR;
}
else {
backNavigationScenario = self.mainStore.vehicle.vin
? navigationScenarios.CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS
: navigationScenarios.CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS;
}
const currentPage = self.$route.query.issPage;
if (

View file

@ -2080,6 +2080,21 @@ describe("vehicle-questions-mixin", () => {
});
describe("navigateBack", () => {
test("current page is coverage-statement and damage is repair => go to vehicle-damage", () => {
// Arrange
const { wrapper } = setupMocks({ issPage: issPageValues.COVERAGE_STATEMENT });
useMainStore().order.damage.isRepair = true;
// Act
wrapper.vm.navigateBack();
// Assert
expect(wrapper.vm.$router.navigate).toHaveBeenCalledWith(
navigationScenarios.CLICKED_BACK_WITH_REPAIR,
{ query: { issPage: issPageValues.COVERAGE_STATEMENT } }
);
});
test("current page is molding questions and there are part questions, multiple parts to choose, and capability questions => go to vehicle-parts", () => {
// Arrange
const { wrapper } = setupMocks({ issPage: issPageValues.MOLDING_QUESTIONS });

View file

@ -24,11 +24,7 @@ export const issPageValues = {
SCHEDULE_PAGE: 'schedule-page',
VEHICLE_DAMAGE: 'vehicle-damage',
VEHICLE_LOOKUP: 'vehicle-lookup',
VEHICLE_MAKE: 'vehicle-make',
VEHICLE_MODEL: 'vehicle-model',
VEHICLE_PARTS: 'vehicle-parts',
VEHICLE_STYLE: 'vehicle-style',
VEHICLE_YEAR: 'vehicle-year',
VEHICLE_SELECTION: 'vehicle-selection',
VIN_LOOKUP: 'vin-lookup',
TPA_SUBMIT: 'tpa-submit',

View file

@ -52,6 +52,9 @@ const navigationScenarios = {
CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS: "CLICKED_BACK_WITH_VIN_AND_NO_MORE_QUESTIONS",
CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS: "CLICKED_BACK_WITH_NO_VIN_NOR_QUESTIONS",
// Coverage Statement
CLICKED_BACK_WITH_REPAIR: "CLICKED_BACK_WITH_REPAIR",
//Provider Preference
CLICKED_FORWARD_WITH_SAFELITE: "CLICKED_FORWARD_WITH_SAFELITE",
CLICKED_FORWARD_WITH_TPA_ENABLED: "CLICKED_FORWARD_WITH_TPA_ENABLED",

View file

@ -17,58 +17,6 @@ const routingTable = function(store) {
}
]
},
{
issPageValue: issPageValues.VEHICLE_YEAR,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationIssPageValue: issPageValues.POLICY_HOLDER_DETAILS
},
{
scenario: navigationScenarios.SELECTED_YEAR,
destinationIssPageValue: issPageValues.VEHICLE_MAKE
}
]
},
{
issPageValue: issPageValues.VEHICLE_MAKE,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationIssPageValue: issPageValues.VEHICLE_YEAR
},
{
scenario: navigationScenarios.SELECTED_MAKE,
destinationIssPageValue: issPageValues.VEHICLE_MODEL
}
]
},
{
issPageValue: issPageValues.VEHICLE_MODEL,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationIssPageValue: issPageValues.VEHICLE_MAKE
},
{
scenario: navigationScenarios.SELECTED_MODEL,
destinationIssPageValue: issPageValues.VEHICLE_STYLE
}
]
},
{
issPageValue: issPageValues.VEHICLE_STYLE,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationIssPageValue: issPageValues.VEHICLE_MODEL
},
{
scenario: navigationScenarios.SELECTED_STYLE,
destinationIssPageValue: issPageValues.VEHICLE_DAMAGE
}
]
},
{
issPageValue: issPageValues.VEHICLE_DAMAGE,
maps: [
@ -474,10 +422,14 @@ const routingTable = function(store) {
scenario: navigationScenarios.CLICKED_BACK_WITH_CAPABILITY_QUESTIONS,
destinationIssPageValue: issPageValues.CAPABILITY_QUESTIONS
},
{
scenario: navigationScenarios.CLICKED_BACK_WITH_REPAIR,
destinationIssPageValue: issPageValues.VEHICLE_DAMAGE
},
{
scenario: navigationScenarios.CLICKED_FORWARD,
destinationIssPageValue: issPageValues.PROVIDER_PREFERENCE
}
},
]
},
{

View file

@ -6,6 +6,7 @@ import { experimentTriggers } from '@/constants/experiments';
import { applicationConfig } from '@/constants/application-config';
import { issPageValues } from '@/router/router-constants/issPage-values';
import { damageLocationsSelected } from '@/constants/damage-locations-selected';
import { coverageStatuses } from '@/constants/coverage-statuses';
const storeId = 'main';
@ -48,7 +49,12 @@ const getDefaultState = () => {
damageCause: null,
damageState: null,
damageCity: null,
isDamageGlassOnly: null
isDamageGlassOnly: null,
noCompensation: null,
deductible: {
repair: null, // numerical value; how much customer owes on deductible in repair case
replace: null // numerical value; how much customer owes on deductible in replace case,
}
},
customer: {
address: {
@ -79,7 +85,8 @@ const getDefaultState = () => {
payment: {
isInsurance: true,
insuranceCoverage: {
isVerified: false
isVerified: false,
coverageStatus: coverageStatuses.PENDING
}
},
referralNumber: null,
@ -125,7 +132,10 @@ export const useMainStore = defineStore({
vehicle: (state) => state.order.vehicle,
damage: (state) => state.order.damage,
lineItems: (state) => state.order.lineItems,
payment: (state) => state.order.payment,
policy: (state) => state.order.policy,
hasAnyNonWindshieldGlassParts: (state) => !state.order.policy.isDamageGlassOnly,
isClaimRegistrationRequired: (state) => state.issConfig.isClaimRegistrationRequired,
eventBusItem: (state) => ( eventCategory, eventSubCategory) => {
const matchedEvent = state.applicationUser.eventBus.find(
@ -327,6 +337,8 @@ export const useMainStore = defineStore({
}
},
getCoveragePolicyInfo({accountNumber, policyNumber, dateOfLoss, zipCode}){
//TODO: replace place holder correlationId with the real thing
const placeHolderCorrelationId = "00000000-0000-0000-0000-000000000000";
try{
const response = globalMethods.callHttpClient({
method:endpoints.CoveragePolicyInfo.method,
@ -335,7 +347,8 @@ export const useMainStore = defineStore({
accountNumber: accountNumber,
policyNumber: policyNumber,
dateOfLoss: dateOfLoss,
zipCode: zipCode
zipCode: zipCode,
correlationId: placeHolderCorrelationId
}
});
return response;
@ -347,6 +360,69 @@ export const useMainStore = defineStore({
};
}
},
registerClaim() {
// TODO: replace place holder correlationId with the real thing
const placeHolderCorrelationId = "00000000-0000-0000-0000-000000000000";
globalMethods.callHttpClient({
method: endpoints.RegisterClaim.method,
endpoint: endpoints.RegisterClaim.url,
payload:
{
correlationId: placeHolderCorrelationId,
accountNumber: this.issConfig.accountNumber?.toString() ?? "",
insured: {
firstName: this.order.customer.firstName,
lastName: this.order.customer.lastName,
address: {
addressLine1: this.order.customer.address.streetAddress,
addressLine2: this.order.customer.address.streetAddress2,
city: this.order.customer.address.city,
state: this.order.customer.address.state,
zipCode: this.order.customer.address.zipCode,
country: "US" // TODO set from store
},
homePhone: {
number: this.order.customer.phoneNumber
}
},
caller: {
homePhone: {}
},
policyInfo: {
policyNumber: this.order.policy.policyNumber,
safelitePolicy: {
policies: []
}
},
lossInfo: {
dateOfLoss: this.order.policy.dateOfLoss,
location: {
city: this.order.policy.damageCity,
state: this.order.policy.damageState,
country: "US" // TODO set from store
},
vehicle: {
year: this.order.vehicle.year?.toString() ?? "",
make: this.order.vehicle.make,
model: this.order.vehicle.model,
vin: this.order.vehicle.vin
},
},
damageDescription: this.order.policy.damageCause
}
}).then((response) => {
const registerClaimFailed = response.data.isError;
this.order.payment.insuranceCoverage.isVerified = !registerClaimFailed;
this.order.payment.insuranceCoverage.coverageStatus = registerClaimFailed
? coverageStatuses.PENDING
: this.policy.noCompensation
? coverageStatuses.NO_COMP
: coverageStatuses.VERIFIED;
},(error) => {
this.order.payment.insuranceCoverage.isVerified = false;
this.order.payment.insuranceCoverage.coverageStatus = coverageStatuses.PENDING;
});
},
async lookupVinByPlate(licensePlate, licenseState) {
try {
const response = await globalMethods.callHttpClient({
@ -480,7 +556,7 @@ export const useMainStore = defineStore({
console.error(error);
return [];
});
},
},
async getRainDefense() {
return globalMethods
@ -590,18 +666,18 @@ export const useMainStore = defineStore({
}
});
},
setVehicle() {
return globalMethods
.callHttpClient({
methods: endpoints.GetVehicle.method,
endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}/${this.order.vehicle.style}`,
payload: {}
})
.then((response) => {
this.updateVehicle(response.data);
return response;
});
.callHttpClient({
methods: endpoints.GetVehicle.method,
endpoint: `${endpoints.GetVehicle.url}/${this.order.vehicle.year}/${this.order.vehicle.make}/${this.order.vehicle.model}/${this.order.vehicle.style}`,
payload: {}
})
.then((response) => {
this.updateVehicle(response.data);
return response;
});
},
saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, selectedWindshieldChipCount) {
@ -678,8 +754,7 @@ export const useMainStore = defineStore({
updateVehicle(vehicle) {
// Assuming that the method caller pass all the properties.
// otherwise need to check for undefined for every property.
this.order.vehicle.carId = vehicle.carId;
this.vehicle.carId = vehicle.carId;
this.order.vehicle.category = vehicle.category;
this.order.vehicle.year = vehicle.year;
this.order.vehicle.make = vehicle.make;
@ -690,6 +765,11 @@ export const useMainStore = defineStore({
this.order.vehicle.imageVifNumber = vehicle.imageVifNumber;
this.order.vehicle.imageColor = vehicle.imageVifColor;
// These could be undefined
this.order.policy.noCompensation = vehicle.noCoverage;
this.order.policy.deductible.replace = vehicle.deductible;
this.order.policy.deductible.repair = vehicle?.repairWaived ?? false ? 0 : vehicle.deductible;
this.resetSupportingItemsState();
this.resetVapsState();
},
@ -907,7 +987,8 @@ export const useMainStore = defineStore({
);
if (haveMoldingQuestionAnswersChanged) {
this.resetPartsAndDependencies();
this.updateGlassParts(null);
this.updateSupportingItems(null);
this.updateCapabilityQuestionAnswers(null);
this.updatePageData({ page: issPageValues.CAPABILITY_QUESTIONS, data: null });
}
@ -932,7 +1013,8 @@ export const useMainStore = defineStore({
);
if (haveCapabilityQuestionAnswersChanged) {
this.resetPartsAndDependencies();
this.updateGlassParts(null);
this.updateSupportingItems(null);
}
// Save new values
@ -1155,9 +1237,7 @@ export const useMainStore = defineStore({
registrationInfo?.firstName !== this.order.vehicle.registration?.firstName ||
registrationInfo?.lastName !== this.order.vehicle.registration?.lastName
)
{
this.resetRegistrationAndDependencies();
{
if (!isSelectedGlassAvailableForVehicle) {
this.resetDamageState();
this.resetGlassPartsState();
@ -1167,7 +1247,11 @@ export const useMainStore = defineStore({
this.updateRegistration(registrationInfo);
};
this.updateVehicle(vehicleInfo);
if(vehicleInfo)
{
this.updateVehicle(vehicleInfo);
}
},
saveVin({ isSelectedGlassAvailableForVehicle, vehicleInfo }) {
//Reset dependent state when changing

View file

@ -1,19 +1,21 @@
import { useMainStore } from '@/store';
import { createApp } from 'vue';
import { createPinia } from "pinia";
import { setActivePinia, createPinia } from "pinia";
import globalMethods from "@/global-methods";
import App from '@/App.vue';
import { getRandomString, getRandomGuid, getRandomInt, getRandomBoolean } from '@/helpers/data-generation';
import { coverageStatuses } from "@/constants/coverage-statuses.js";
describe("Store", () => {
let store;
const vueApp = createApp(App);
const pinia = createPinia();
vueApp.use(pinia);
beforeEach(() => {
const pinia = createPinia();
setActivePinia(pinia);
vueApp.use(pinia);
store = useMainStore();
store.applicationUser.eventBus = [];
jest.resetAllMocks();
@ -27,31 +29,47 @@ describe("Store", () => {
});
it("Should add events to the bus", () => {
// Arrange
const category = getRandomString(1, 25);
const subCategory = getRandomString(5, 20);
const isDismissible = getRandomBoolean();
const copy = getRandomString(5, 25);
const headline = getRandomString(5, 25);
const type = getRandomString(5, 15);
let event = {
category: "TestCategory",
subCategory: "TestSubCategory",
category: category,
subCategory: subCategory,
eventValue: {
isDismissible: true,
messageCopy: "You can get a quote by starting on this page.",
messageHeadline: "We're sorry, something went wrong.",
type: "testType",
isDismissible: isDismissible,
messageCopy: copy,
messageHeadline: headline,
type: type,
},
};
// Act
store.addEventToBus(event);
// Assert
expect(store.applicationUser.eventBus[0]).toEqual(event);
});
it("Should remove events from the bus", () => {
// Arrange
const category = getRandomString(1, 25);
const subCategory = getRandomString(5, 20);
const isDismissible = getRandomBoolean();
const copy = getRandomString(5, 25);
const headline = getRandomString(5, 25);
const type = getRandomString(5, 15);
let event = {
category: "TestCategory",
subCategory: "TestSubCategory",
category: category,
subCategory: subCategory,
eventValue: {
isDismissible: true,
messageCopy: "You can get a quote by starting on this page.",
messageHeadline: "We're sorry, something went wrong.",
type: "testType",
isDismissible: isDismissible,
messageCopy: copy,
messageHeadline: headline,
type: type,
},
};
@ -59,164 +77,350 @@ describe("Store", () => {
expect(store.applicationUser.eventBus.length).toBe(1);
// Act
store.removeEventFromBus({ category: event.category, subCategory: event.subCategory })
// Assert
expect(store.applicationUser.eventBus.length).toBe(0);
});
it("Should return correct event using the getter function eventBusItem", () => {
// Arrange
const category = getRandomString(1, 25);
const subCategory = getRandomString(5, 20);
const isDismissible = getRandomBoolean();
const copy = getRandomString(5, 25);
const headline = getRandomString(5, 25);
const type = getRandomString(5, 15);
let event = {
category: "TestCategory",
subCategory: "TestSubCategory",
category: category,
subCategory: subCategory,
eventValue: {
isDismissible: true,
messageCopy: "You can get a quote by starting on this page.",
messageHeadline: "We're sorry, something went wrong.",
type: "testType",
isDismissible: isDismissible,
messageCopy: copy,
messageHeadline: headline,
type: type,
},
};
store.addEventToBus(event);
// Act
const actual = store.eventBusItem(event.category, event.subCategory)
// Assert
expect(actual).toEqual(event.eventValue);
});
it("UpdateVehicle should merge vehicle with response object", () => {
store.order.vehicle = {
year: 2020,
make: "Honda",
model: "Civic",
style: "4 door sedan",
carId: null,
category: null,
vin: null,
imageUrl: null,
imageVifNumber: null,
imageColor: null,
// Arrange
const carId = getRandomString(10,14);
const category = getRandomString(3,7);
const year = getRandomInt(1960, 2023);
const make = getRandomString(4,10);
const model = getRandomString(4,10);
const style = getRandomString(4,15);
const imageUrl = getRandomString(50,100);
const imageVifNumber = getRandomInt(10000,99999).toString();
const imageColor = getRandomString(4,10);
const providedVehicle = {
carId: carId,
category: category,
year: year,
make: make,
model: model,
style: style,
imageUrl: imageUrl,
imageVifNumber: imageVifNumber,
imageVifColor: imageColor
};
const response = {data: {
"carId": "CR00069299",
"category": "CAR",
"year": 2020,
"make": "Honda",
"model": "Civic",
"style": "4 door sedan",
"imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13996/13996_cc0320_032_WX.jpg",
"imageVifNumber": "13996",
"imageVifColor": "white"
const expectedVehicle = {
carId: carId,
category: category,
year: year,
make: make,
model: model,
style: style,
imageUrl: imageUrl,
imageVifNumber: imageVifNumber,
imageColor: imageColor
}
// Act
store.updateVehicle(providedVehicle);
// Assert
expect(store.order.vehicle).toMatchObject(expectedVehicle);
});
it("UpdateVehicle should set policy values appropriately with repair waived", () => {
// Arrange
const noCompensation = getRandomBoolean();
const deductible = getRandomInt(1,500);
const vehicle = {
noCoverage: noCompensation,
deductible: deductible,
repairWaived: true
};
const expectedPolicy = {
noCompensation: noCompensation,
deductible: {
replace: deductible,
repair: 0
}
};
store.updateVehicle(response.data);
// Act
store.updateVehicle(vehicle);
expect(store.order.vehicle.imageUrl).toEqual(response.data.imageUrl);
expect(store.order.vehicle.imageVifNumber).toEqual(response.data.imageVifNumber);
expect(store.order.vehicle.style).toEqual(response.data.style);
// Assert
expect(store.order.policy).toMatchObject(expectedPolicy);
});
it("setVehicle should call globalMethods.callHttpClient", () => {
store.order.vehicle = jest.fn();
it("UpdateVehicle should set policy values appropriately with repair not waived", () => {
// Arrange
const noCompensation = getRandomBoolean();
const deductible = getRandomInt(1,500);
const vehicle = {
noCoverage: noCompensation,
deductible: deductible,
repairWaived: false
};
const response = {data: {
"carId": "CR00069299",
"category": "CAR",
"year": 2020,
"make": "Honda",
"model": "Civic",
"style": "4 door sedan",
"imageUrl": "https://dbhdyzvm8lm25.cloudfront.net/color_0320_032/MY2020/13996/13996_cc0320_032_WX.jpg",
"imageVifNumber": "13996",
"imageVifColor": "white"
const expectedPolicy = {
noCompensation: noCompensation,
deductible: {
replace: deductible,
repair: deductible
}
};
// Act
store.updateVehicle(vehicle);
// Assert
expect(store.order.policy).toMatchObject(expectedPolicy);
});
// TODO update test to work also checking store values
it("setVehicle should call globalMethods.callHttpClient", () => {
// Arrange
const carId = getRandomString(10,14);
const category = getRandomString(3,7);
const year = getRandomInt(1960, 2023);
const make = getRandomString(4,10);
const model = getRandomString(4,10);
const style = getRandomString(4,15);
const imageUrl = getRandomString(50,100);
const imageVifNumber = getRandomInt(10000,99999).toString();
const imageColor = getRandomString(4,10);
const response = {
data: {
carId: carId,
category: category,
year: year,
make: make,
model: model,
style: style,
imageUrl: imageUrl,
imageVifNumber: imageVifNumber,
imageVifColor: imageColor
}
};
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
store.setVehicle();
expect(globalMethods.callHttpClient).toHaveBeenCalled();
});
it("saveVehicleDamage, should update damage", () => {
// Arrange
store.order.damage = {
glassToReplace: [{ glassName: "Single", glassLocation: "Windshield" }],
};
// Act
store.saveVehicleDamage( false,
[{ glassName: "Rear", glassLocation: "quarter" }],
0);
const returned = store.setVehicle();
// Assert
expect(store.order.damage.glassToReplace).toEqual([{ glassName: "Rear", glassLocation: "quarter" }]);
expect(store.order.damage.isRepair).toEqual(false);
expect(store.order.damage.numberOfChips).toEqual(null);
expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(returned).resolves.toMatchObject(response);
});
it("saveVehicleDamage with windshield repair should update damage with number of chips not null", () => {
// Arrange
const glassName = getRandomString(4,10);
const glassLocation = getRandomString(5,15);
const isWindshieldRepair = true;
const selectedGlassToReplace = [{
glassName: glassName,
glassLocation: glassLocation
}];
const chipCount = getRandomInt(0,3);
// Act
store.saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, chipCount);
// Assert
expect(store.order.damage.glassToReplace).toEqual(selectedGlassToReplace);
expect(store.order.damage.isRepair).toEqual(isWindshieldRepair);
expect(store.order.damage.numberOfChips).toEqual(chipCount);
});
it("saveVehicleDamage without windshield repair should update damage with number of chips null", () => {
// Arrange
const glassName = getRandomString(4,10);
const glassLocation = getRandomString(5,15);
const isWindshieldRepair = false;
const selectedGlassToReplace = [{
glassName: glassName,
glassLocation: glassLocation
}];
const chipCount = getRandomInt(0,3);
const expectedChipCount = null;
// Act
store.saveVehicleDamage(isWindshieldRepair, selectedGlassToReplace, chipCount);
// Assert
expect(store.order.damage.glassToReplace).toEqual(selectedGlassToReplace);
expect(store.order.damage.isRepair).toEqual(isWindshieldRepair);
expect(store.order.damage.numberOfChips).toEqual(expectedChipCount);
});
it("should return registration data if available", () => {
//Arrange
const streetAddress = getRandomString(5,15);
const city = getRandomString(5,15);
const state = getRandomString(5,10);
const zipCode = getRandomInt(10000,99999).toString();
const firstName = getRandomString(5,20);
const lastName = getRandomString(5,20);
const expected = {
addressQuestions: {
streetAddress: "test",
city: "city",
state: "state",
zipCode: "zip",
streetAddress: streetAddress,
city: city,
state: state,
zipCode: zipCode,
},
firstName: "1stName",
lastName: "Surname",
firstName: firstName,
lastName: lastName,
}
store.order.vehicle.registration = {
licensePlate: null,
address: "test",
city: "city",
state: "state",
zipCode: "zip",
firstName: "1stName",
lastName: "Surname",
address: streetAddress,
city: city,
state: state,
zipCode: zipCode,
firstName: firstName,
lastName: lastName,
};
//Act
const actual = store.customerData;
//Assert
//Assert
expect(actual).toEqual(expected);
});
it("should return customer data if registration data unavailable", () => {
//Arrange
const address = getRandomString(1,25);
const city = getRandomString(5,20);
const state = getRandomString(4,20);
const zipCode = getRandomInt(10000, 99999).toString();
const firstName = getRandomString(5,25);
const lastName = getRandomString(5,25);
const expected = {
addressQuestions: {
streetAddress: "test",
city: "city",
state: "state",
zipCode: "zip",
streetAddress: address,
city: city,
state: state,
zipCode: zipCode,
},
firstName: "1stName",
lastName: "Surname",
firstName: firstName,
lastName: lastName,
}
store.order.vehicle.registration.address = null;
store.order.customer = {
licensePlate: null,
address: "test",
city: "city",
state: "state",
zipCode: "zip",
firstName: "1stName",
lastName: "Surname",
address: {
streetAddress: address,
city: city,
state: state,
zipCode: zipCode
},
firstName: firstName,
lastName: lastName
};
//Act
const actual = store.customerData;
//Assert
expect(actual).toEqual(expected);
//Assert
expect(actual).toMatchObject(expected);
});
describe("registerClaim method", () => {
it("successful response with no coverage => isVerified true and coverage status no comp", async () => {
// Arrange
const response = {
data: {
claimantId: null,
claimNumber: getRandomString(9, 9),
correlationId: getRandomGuid(),
isSuccess: true,
isError: false,
successMessage: getRandomString(9, 9),
deductible: 0
}
};
store.policy.noCompensation = true;
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
// Act
await store.registerClaim();
// Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(store.payment.insuranceCoverage.isVerified).toBe(true);
expect(store.payment.insuranceCoverage.coverageStatus).toBe(coverageStatuses.NO_COMP);
});
it("successful response with coverage => isVerified true and coverage status verified", async () => {
// Arrange
const response = {
data: {
claimantId: null,
claimNumber: getRandomString(9, 9),
correlationId: getRandomGuid(),
isSuccess: true,
isError: false,
successMessage: getRandomString(9, 9),
deductible: 0
}
};
store.policy.noCompensation = false;
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
// Act
await store.registerClaim();
// Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(store.payment.insuranceCoverage.isVerified).toBe(true);
expect(store.payment.insuranceCoverage.coverageStatus).toBe(coverageStatuses.VERIFIED);
})
it("Call to client returns exception, resulting in object with error property being returned", async () => {
// Arrange
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.reject());
// Act
await store.registerClaim();
// Asserts
expect(globalMethods.callHttpClient).toHaveBeenCalled();
expect(store.payment.insuranceCoverage.isVerified).toBe(false);
expect(store.payment.insuranceCoverage.coverageStatus).toBe(coverageStatuses.PENDING);
});
})
});

View file

@ -1,144 +1,152 @@
<template>
<!-- Checkbox groups MUST be wrapped in a <fieldset> and <legend> tag and must contain tabindex -->
<div class="ui-radio form-check" :class="[(errors.length > 0 || hasError) ? 'has-error' : '']">
<input
type="radio"
class="form-check-input"
aria-checked="false"
:name="groupName"
:id="buttonID"
:aria-required="isRequired"
:value="value"
:v-model="checkValue"
@change="handleCheckChange"
:checked="checkValue"
:validationRules="validationRules"
/>
<label class="d-flex align-items-start form-check-label" :for="buttonID">
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
<span v-if="screenReaderOnlyText" class="sr-only">{{
screenReaderOnlyText
}}</span>
</label>
<label class="d-inline-flex align-items-start form-check-label" :for="buttonID">
<input
type="radio"
class="form-check-input"
aria-checked="false"
:name="groupName"
:id="buttonID"
:aria-required="isRequired"
:value="value"
:v-model="checkValue"
@change="handleCheckChange"
:checked="checkValue"
:validationRules="validationRules"
/>
<p v-if="buttonLabel" class="m-0">{{ buttonLabel }}</p>
<span v-if="screenReaderOnlyText" class="sr-only">{{
screenReaderOnlyText
}}</span>
</label>
</div>
</template>
<script>
import { useField } from "vee-validate";
export default {
</template>
<script>
import { useField } from "vee-validate";
export default {
name: "radio",
props: {
groupName: String,
buttonLabel: String,
buttonID: String,
isRequired: Boolean,
value: {
type: [String, Number],
default: "",
},
screenReaderOnlyText: String,
selectedValues: String,
hasError: Boolean,
validationRules: String,
valueToLogType: String,
groupName: String,
buttonLabel: String,
buttonID: String,
isRequired: Boolean,
value: {
type: [String, Number],
default: "",
},
screenReaderOnlyText: String,
selectedValues: String,
hasError: Boolean,
validationRules: String,
valueToLogType: String,
},
data() {
return {
checkValue: Boolean,
};
return {
checkValue: Boolean,
};
},
created() {
if (this.selectedValues) {
this.checkValue = this.selectedValues === this.value;
this.handleCheckChange();
} else{
this.checkValue = false;
}
if (this.selectedValues) {
this.checkValue = this.selectedValues === this.value;
this.handleCheckChange();
} else{
this.checkValue = false;
}
},
methods: {
handleCheckChange() {
this.handleChange(this.value);
const emitEvent = {
checkValue: this.checkValue,
value: this.value.toString(),
buttonID: this.buttonID && this.buttonID.toString(),
};
this.$emit("isCheckedChanged", emitEvent);
this.$emit("update:modelValue", emitEvent);
},
handleCheckChange() {
this.handleChange(this.value);
const emitEvent = {
checkValue: this.checkValue,
value: this.value.toString(),
buttonID: this.buttonID && this.buttonID.toString(),
};
this.$emit("isCheckedChanged", emitEvent);
this.$emit("update:modelValue", emitEvent);
},
},
setup(props) {
const inputType = "radio";
const {
value: inputValue,
handleChange,
errors,
resetField
} = useField(props.groupName, props.validationRules,
{
type: inputType,
checkedValue: props.value,
});
return {
handleChange,
errors,
resetField
};
const inputType = "radio";
const {
value: inputValue,
handleChange,
errors,
resetField
} = useField(props.groupName, props.validationRules,
{
type: inputType//,
//checkedValue: props.value,
});
return {
handleChange,
errors,
resetField
};
},
unmounted(){
this.resetField();
this.resetField();
}
};
</script>
<style lang="scss" scoped>
.form-check {
};
</script>
<style lang="scss" scoped>
.form-check {
position: relative;
.form-check-input {
border: 1px solid $gray-500;
border-radius: 50%;
margin-right: 0.5rem;
&:checked {
background-color: $white;
background-size: 71%;
background-position: center;
border: 1px solid $blue;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50' xml:space='preserve'%3e%3ccircle cx='25' cy='25' r='25' fill='%231574A1'/%3e%3c/svg%3e");
+ label {
p {
font-weight: 500;
font-size: .875rem;
color: $black;
}
label {
&:hover {
cursor: pointer;
}
}
&:focus {
box-shadow: 0 0 0 2.5px $blue;
}
&, & + label {
margin-top: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
}
.form-check-input {
border: 1px solid $gray-500;
border-radius: 50%;
margin-right: 0.5rem;
&:checked {
background-color: $white;
background-size: 71%;
background-position: center;
border: 1px solid $blue;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 50' xml:space='preserve'%3e%3ccircle cx='25' cy='25' r='25' fill='%231574A1'/%3e%3c/svg%3e");
+ label {
p {
font-weight: 500;
font-size: .875rem;
color: $black;
}
}
}
&:focus {
box-shadow: 0 0 0 2.5px $blue;
}
&, & + label {
margin-top: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
}
&:hover {
.form-check-input {
box-shadow: 0 0 0 4px $blue-300;
}
.form-check-input {
box-shadow: 0 0 0 4px $blue-300;
}
}
p {
font-weight: 400;
font-size: .875rem;
color: $gray-600;
font-weight: 400;
font-size: .875rem;
color: $gray-600;
}
}
</style>
}
</style>