Merge branch 'develop' into feature/jzimmerman/INSR-8742

This commit is contained in:
Jeremy-Z 2026-03-10 13:46:01 -04:00
commit 97528e8b4f
11 changed files with 267 additions and 15 deletions

View file

@ -281,8 +281,13 @@ export default {
border-color: $blue;
font-weight: 400;
&:hover {
background-color: #167cac;
background-color: $heritage-blue-secondary;
color: $white;
border-color: $heritage-blue-secondary;
}
&:active,
&:focus {
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $heritage-blue-secondary;
}
}
}

View file

@ -7,6 +7,7 @@
<img
:src="ModalImage"
class="mw-100 d-flex"
:class="imgClass"
alt="" />
<h5
class="header-text"
@ -59,7 +60,13 @@ export default {
},
ModalCloseButtonText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
}
},
imgClass() {
if (this.cmsWidgetName === 'RainDefenseModal') {
return 'rain-repel';
}
return '';
},
},
methods: {
openModal() {
@ -104,4 +111,7 @@ export default {
}
}
}
.rain-repel {
height: 3.5rem;
}
</style>

View file

@ -74,8 +74,14 @@ export default {
button {
&:hover {
background-color: $white;
color: #167cac;
color: $heritage-blue-secondary;
}
&:focus, &:active {
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $heritage-blue-secondary;
}
font-weight: 600;
color: $heritage-blue-secondary;
border-color: $heritage-blue-secondary;
}
}
}

View file

@ -3,6 +3,7 @@
exports[`coverageStatement.vue returns the initial data 1`] = `
Object {
"CANCEL_CLAIM_REF_NAME": "CancelClaimModal",
"OEM_ENDORSEMENT_REF_NAME": "OEMModal",
"RECAL_MODAL_REF_NAME": "RecalModal",
"baseServiceLineItems": Array [],
"isPageLoading": true,

View file

@ -108,6 +108,9 @@
:ref="CANCEL_CLAIM_REF_NAME"
@cancelClaimConfirmation="cancelClaim"
@returnToClaim="navigateForward" />
<oemEndorsementModal
:ref="OEM_ENDORSEMENT_REF_NAME"
cmsWidgetName="OEMEndorsementModal" />
</Form>
</template>
@ -143,9 +146,11 @@ import showIssLoadingModal from '@/helpers/loading-modal-helper';
import { getPriceOfLineItems } from '@/helpers/price-calculator';
import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';
import oemEndorsementModal from '@/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue';
const RECAL_MODAL_REF_NAME = 'RecalModal';
const CANCEL_CLAIM_REF_NAME = 'CancelClaimModal';
const OEM_ENDORSEMENT_REF_NAME = 'OEMModal';
export default {
name: 'coverage-statement',
@ -158,7 +163,8 @@ export default {
siteFooter,
cancelClaimModal,
afterpayModalBanner,
recalModal
recalModal,
oemEndorsementModal
},
mixins: [baseFormMixin, vehicleQuestionsMixin],
async beforeRouteEnter(to, from, next) {
@ -221,7 +227,8 @@ export default {
nextStep: 'NextStepsWidget'
},
RECAL_MODAL_REF_NAME,
CANCEL_CLAIM_REF_NAME
CANCEL_CLAIM_REF_NAME,
OEM_ENDORSEMENT_REF_NAME
};
},
computed: {
@ -356,6 +363,7 @@ export default {
nextStepsBody(newValue, oldValue) {
if (newValue !== oldValue) {
setupModalLink(this, RECAL_MODAL_REF_NAME);
setupModalLink(this, OEM_ENDORSEMENT_REF_NAME);
}
}
},
@ -424,6 +432,7 @@ export default {
},
getCustomValueFromString(str) {
const { isRepair } = useMainStore().damage;
switch (str) {
case 'coverageUnverified':
return this.isUnverifiedVisible;
@ -449,6 +458,8 @@ export default {
return !isRepair && this.isDeductibleVisible && this.deductibleValue <= 0;
case 'verifiedReplaceDeductibleOverZero':
return !isRepair && this.isDeductibleVisible && this.deductibleValue > 0;
case 'hasOEMEndorsement':
return this.mainStore.hasOemEndorsement;
default:
return null;
}

View file

@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`returns the initial data 1`] = `Object {}`;

View file

@ -0,0 +1,126 @@
import { shallowMount } from '@vue/test-utils';
import oemEndorsementModal from '@/layouts/coverage-statement/oem-endorsement-modal/oem-endorsement-modal.vue';
const mockDataStrings = {
cmsBodyText: `Some Body Text from CMS`,
cmsHeaderText: 'Some Header Text from CMS',
cmsFooterText: 'Some Footer Text from CMS'
};
const mockCmsContent = {
BodyText: mockDataStrings.cmsBodyText,
HeaderText: mockDataStrings.cmsHeaderText,
FooterText: mockDataStrings.cmsFooterText
};
const mockMixin = {
methods: {
getCmsContent: jest.fn((_, cmsFieldName) => mockCmsContent[cmsFieldName])
},
};
function setupMocks() {
const wrapper = shallowMount(oemEndorsementModal, {
mixins: [mockMixin],
props: {
cmsWidgetName: 'OEMEndorsementModal'
},
attachTo: document.body
});
return { wrapper };
}
test('returns the initial data', () => {
// Arrange
const { wrapper } = setupMocks();
// Assert
expect(wrapper.vm.$data).toMatchSnapshot();
});
describe('Computed', () => {
test('Should get modal header text from Widget CMS', () => {
// Arrange
const { wrapper } = setupMocks();
// Act
const result = wrapper.vm.modalHeaderText;
// Assert
expect(result).toBe(mockDataStrings.cmsHeaderText);
});
test('Should get modal close button text from Widget CMS', () => {
// Arrange
const { wrapper } = setupMocks();
// Act
const result = wrapper.vm.modalCloseButtonText;
// Assert
expect(result).toBe(mockDataStrings.cmsFooterText);
});
test('Should call getCmsContent with the correct widget name and field name for body text', () => {
// Arrange
const { wrapper } = setupMocks();
// Act
wrapper.vm.modalBodyText;
// Assert
expect(mockMixin.methods.getCmsContent).toHaveBeenCalledWith('OEMEndorsementModal', 'BodyText');
});
test('Should call getCmsContent with the correct widget name and field name for header text', () => {
// Arrange
const { wrapper } = setupMocks();
// Act
wrapper.vm.modalHeaderText;
// Assert
expect(mockMixin.methods.getCmsContent).toHaveBeenCalledWith('OEMEndorsementModal', 'HeaderText');
});
test('Should call getCmsContent with the correct widget name and field name for footer text', () => {
// Arrange
const { wrapper } = setupMocks();
// Act
wrapper.vm.modalCloseButtonText;
// Assert
expect(mockMixin.methods.getCmsContent).toHaveBeenCalledWith('OEMEndorsementModal', 'FooterText');
});
});
describe('Props', () => {
test('Should use the default cmsWidgetName prop value of OEMEndorsementModal', () => {
// Arrange
const wrapper = shallowMount(oemEndorsementModal, {
mixins: [mockMixin],
attachTo: document.body
});
// Assert
expect(wrapper.vm.cmsWidgetName).toBe('OEMEndorsementModal');
});
test('Should accept a custom cmsWidgetName prop', () => {
// Arrange
const customWidgetName = 'CustomOEMModal';
const wrapper = shallowMount(oemEndorsementModal, {
mixins: [mockMixin],
props: {
cmsWidgetName: customWidgetName
},
attachTo: document.body
});
// Assert
expect(wrapper.vm.cmsWidgetName).toBe(customWidgetName);
});
});

View file

@ -0,0 +1,79 @@
<template>
<div class="recal-modal-container">
<modal
ref="oemEndorsementModal"
:footerButtonText="modalCloseButtonText"
@footerButtonEvent="footerButtonClick">
<h5
class="header-text"
v-html="modalHeaderText"></h5>
<div v-html="modalBodyText" class="oem-endorsement-modal-body"></div>
</modal>
</div>
</template>
<script>
import modal from '@/digital-components/modal/modal.vue';
export default {
name: 'oem-endorsement-modal',
components: {
modal
},
props: {
cmsWidgetName: {
type: String,
default: 'OEMEndorsementModal'
}
},
computed: {
modalBodyText() {
return this.getCmsContent(this.cmsWidgetName, 'BodyText');
},
modalHeaderText() {
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
},
modalCloseButtonText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
},
},
methods: {
openModal() {
this.$refs.oemEndorsementModal.openModal();
},
footerButtonClick() {
this.$refs.oemEndorsementModal.closeModal();
},
}
};
</script>
<style lang="scss" scoped>
:deep(.modal) {
&.modal-component {
.modal-dialog {
.modal-content {
.modal-body {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
}
}
.modal-footer {
button {
&:hover {
background-color: $heritage-blue-primary;
color: $white;
}
}
}
}
.oem-endorsement-modal-body {
padding: 10px 0 10px 0;
p:first-child {
margin-bottom: 10px;
}
}
}
</style>

View file

@ -81,7 +81,7 @@ export default {
.modal-footer {
justify-content: center;
button {
background-color: #167cac;
background-color: $heritage-blue-secondary;
color: $white;
width: 71%;
}

View file

@ -32,7 +32,7 @@
isRequired>
</buttonQuestion>
<checkBox
v-if="showAcknowledgementCheckbox"
v-if="showAcknowledgementCheckbox"
ref="tpaAcknowledgement"
v-model="acknowledged"
class="mb-2 mt-4"
@ -171,6 +171,9 @@ export default {
background-color: $green;
color: $white;
font-weight: $font-weight-bold;
&:hover {
background-color: $green;
}
}
}
.tpa-recal-question > div:first-of-type {

View file

@ -1342,19 +1342,27 @@ export const useMainStore = defineStore({
},
getServiceabilityDetails(serviceZipCode) {
const { damage, lineItems, parentAccountNumber, vehicle } = this.order;
const { vehicle, damage, parentAccountNumber, referralSequenceNumber, lineItems } = this.order;
const { carId } = vehicle;
const flattenedGlassParts = getLineItemsFlattened(lineItems.glassParts);
const lineItemsList = flattenedGlassParts.map((part) => part.partNumber).join(',');
const glassArray = convertGlassPieceNamingForApi(damage.glassToReplace);
const lineItemParts = [...(lineItems.glassParts || []), ...(lineItems.supportingItems || [])].map((part) => ({
partNumber: part.partNumber,
recalibrationType: part.recalibrationType
}));
let endPoint = `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&parentAccountNumber=${parentAccountNumber}&isRepair=${damage.isRepair}`;
if (lineItemsList) {
endPoint += `&lineItems=${lineItemsList}`;
}
const params = buildURLSearchParams({
applicationName: applicationConfig.APPLICATION_NAME,
parentAccountNumber,
referralSequenceNumber,
zip: serviceZipCode,
carId,
glassPieces: glassArray,
lineItems: lineItemParts
});
return globalMethods.callHttpClient({
method: endpoints.GetServiceabilityDetails.method,
endpoint: endPoint
endpoint: `${endpoints.GetServiceabilityDetails.url}?${params.toString()}`
});
},
lookupVehicleByVin(vin) {