INSR-7759: Update review sections, move contact details drawer

This commit is contained in:
Alex Humphries 2026-02-18 16:22:35 -05:00
parent be4bed44fe
commit 4e996145c3
20 changed files with 219 additions and 1297 deletions

View file

@ -70,9 +70,7 @@ const errorMessages = Object.freeze({
TPA_SEARCH_SHOP_FORMAT: 'Please enter a valid shop name.',
TPA_SEARCH_REQUIRED: 'Please enter a shop name or ZIP code.',
SERVICE_ADDRESS_REQUIRED: 'Service street address is required.',
SERVICE_CITY_REQUIRED: 'Service city is required.',
PAYMENT_METHOD_PAGE_OPTION_REQUIRED: 'Please select an Option',
SERVICE_CITY_REQUIRED: 'Service city is required.'
});
export default errorMessages;

View file

@ -1,7 +1,7 @@
// Components
import { shallowMount } from '@vue/test-utils';
import { createTestingPinia } from '@pinia/testing';
import contactDetailsDrawer from '@/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue';
import contactDetailsDrawer from '@/iss-components/contact-details-drawer/contact-details-drawer.vue';
// Supporting Files
import { getMountOptions } from '@/helpers/unit-test-helper.js';

View file

@ -2,7 +2,7 @@
<baseInputButton
v-bind="$props"
v-model="selectedValue"
buttonWrapperClasses="list-group base-input-button list-button d-flex flex-column w-100 no-hover">
buttonWrapperClasses="list-group base-input-button list-button payment-method d-flex flex-column w-100 no-hover">
<div class="button-content list-button-content d-flex flex-row">
<div>
<span
@ -72,7 +72,7 @@ export default {
</script>
<style lang="scss" scoped>
.list-button {
.list-button.payment-method.list-group {
outline: none;
input[type="radio"],
input[type="checkbox"] {
@ -83,7 +83,19 @@ export default {
color: $black;
}
}
margin-bottom: .75rem;
border: none;
&.has-error {
input[type="radio"],
input[type="checkbox"] {
&:focus + .list-button-content {
box-shadow: none;
}
}
}
}
.list-button-content {
color: $darker-gray;
font-weight: 400;
@ -96,6 +108,5 @@ export default {
outline: none;
padding: .625rem 2rem;
height: 2.875rem;
margin-bottom: .75rem;
}
</style>

View file

@ -21,8 +21,10 @@
cmsWidgetName="SiteSubHeaderWidget" />
<div class="main-content-container">
<hr class="section-divider" />
<reviewDropdown ref="reviewDropdown" />
<hr class="section-divider" />
<reviewDropdown
ref="reviewDropdown"
@edit-clicked="handleEditClicked"
/>
<div class="cart-header">
<span class="cart-label">{{ cartHeaderText }}</span>
<span v-if="showCartTotal" class="cart-value">{{ cartTotal }}</span>
@ -104,6 +106,7 @@ import paymentMethodQuestion from '@/layouts/payment-method/payment-method-quest
import alert from '@/ux-components/alert/alert.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
// Supporting Items
import settleAllPromises from '@/helpers/layout-helper';
@ -112,7 +115,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { paymentMethods } from '@/constants/payment-method-constants';
import queryStrings from '@/constants/query-strings';
import globalRules from '@/constants/global-rules';
import { defineRule, Form } from 'vee-validate';
import { Form } from 'vee-validate';
import issPageValues from '@/router/router-constants/issPage-values';
import bailoutMessage from '@/constants/bailoutMessage';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
@ -124,13 +127,8 @@ import { supportsApplePay } from '@/helpers/browser-helper';
import { getCartTotal } from '@/helpers/cart-helper';
import { formatAmountInDollars } from '@/helpers/text-helper';
import widgetFields from '@/constants/cms-widget-fields';
import errorMessages from '@/constants/error-messages';
import { required } from '@/helpers/validation-rules';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import MaskaFormattedMasks from '@/constants/maska-masks';
defineRule('option-required', required(errorMessages.PAYMENT_METHOD_PAGE_OPTION_REQUIRED));
export default {
name: 'payment-method',
components: {
@ -391,13 +389,43 @@ export default {
const scenario = this.mainStore.isMobileAppointment
? this.navigationScenarios.CLICKED_BACK_MOBILE
: this.navigationScenarios.CLICKED_BACK_INSHOP;
this.$router.navigate(
this.$router.navigateWithSpinner(
scenario,
this.$route
);
},
getSMSPhoneFromStore() {
return useMainStore().contactInfo.servicePhone;
},
handleEditClicked(section) {
switch (section) {
case 'location':
this.$router.navigateWithSpinner(
this.navigationScenarios.EDIT_SERVICE_LOCATION,
this.$route
);
break;
case 'schedule':
this.$router.navigateWithSpinner(
this.navigationScenarios.EDIT_SCHEDULE,
this.$route
);
break;
case 'vehicle':
this.$router.navigateWithSpinner(
this.navigationScenarios.EDIT_VEHICLE,
this.$route
);
break;
case 'customer':
break;
case 'wipers':
this.$router.navigateWithSpinner(
this.navigationScenarios.EDIT_WIPERS,
this.$route
);
break;
}
}
}
};

View file

@ -1,34 +1,55 @@
<template>
<div class="py-3">
<div class="block-container">
<div class="d-flex">
<textBlock
:cmsWidgetName="headerCmsWidgetName"
:customText="customHeaderText"
typeStyle="body small dark"
typeStyle="body dark"
fontWeight="bold"
:marginTopSizeOverride="0" />
</div>
<div
v-for="item in content"
:key="item"
class="small review-block-content"
data-test="contentLine"
v-html="item"></div>
<div class="review-block-body-container">
<div
v-for="item in content"
:key="item"
class="review-block-content"
data-test="contentLine"
v-html="item"></div>
<div
class="link-container"
:class="{ 'expanded': linkVisible }">
<textLink
linkType="text"
:text="editLinkText"
useLoadingModal
href="javascript:void(0)"
class="link"
@clickEvent="linkClicked">
</textLink>
</div>
</div>
</div>
</template>
<script>
import textBlock from '@/digital-components/text-block/text-block.vue';
import textLink from '@/ux-components/text-link/text-link.vue';
export default {
name: 'review-block',
components: {
textBlock
textBlock,
textLink
},
props: {
headerCmsWidgetName: String,
customHeaderText: String,
content: Array // Specifically an array of strings.
content: Array, // Specifically an array of strings.
editLinkText: {
type: String,
default: 'Edit'
},
linkVisible: Boolean
},
emits: ['edit-clicked'],
data() {
@ -51,7 +72,17 @@ export default {
:deep(.review-block-content > ul) {
margin-bottom: 0rem;
}
.review-block-content {
width: 90%;
.review-block-body-container {
margin-top: .625rem;
}
.link-container {
max-height: 0;
transition: $transition-swing;
overflow: hidden;
&.expanded {
margin-top: .625rem;
max-height: 2rem;
}
}
</style>

View file

@ -11,35 +11,29 @@
<span class="label">Appointment details</span>
</a>
</div>
<div class="review-table px-4">
<vehicleReview
cmsWidgetName="VehicleReviewWidget"
:vehicle="vehicleInfo" />
<hr class="review-divider" />
<damageReview
cmsWidgetName="DamageReviewWidget"
damageLocationsWidgetName="DamageLocationsWidget"
:damage="damageInfo" />
<hr class="review-divider" />
<servicePackageReview
ref="servicePackageReview"
servicePackageOptionsCmsName="ServicePackageTitle"
defaultPackageItemsCmsName="DefaultPackageItemDescriptions"
vapsItemsCmsName="VapsItemDescriptions"
:damage="damageInfo"
:lineItems="lineItems" />
<hr class="review-divider" />
<div class="review-table">
<serviceLocationReview
cmsWidgetName="ServiceLocationTitleWidget"
:serviceLocation="serviceLocationInfo" />
<hr class="review-divider" />
:linkVisible="isExpanded"
cmsWidgetName="ServiceLocationWidget"
:serviceLocation="serviceLocationInfo"
@edit-clicked="editServiceLocation" />
<scheduleReview
:linkVisible="isExpanded"
cmsWidgetName="ScheduleWidget"
:appointmentType="appointmentType" />
<hr class="review-divider" />
<customerReview
cmsWidgetName="CustomerReviewWidget"
:customer="customerInfo" />
@edit-clicked="editSchedule" />
<hr class="section-divider" />
<div class="review-table-expander">
<vehicleReview
:linkVisible="true"
cmsWidgetName="VehicleReviewWidget"
@edit-clicked="editVehicle" />
<hr class="section-divider" />
<customerReview
:linkVisible="true"
cmsWidgetName="CustomerReviewWidget"
@edit-clicked="editCustomer" />
<hr class="section-divider" />
</div>
</div>
</div>
</template>
@ -47,26 +41,18 @@
<script>
// import textBlock from '@/digital-components/text-block/text-block.vue';
import customerReview from '@/layouts/payment-method/review-dropdown/review-sections/customer-review/customer-review.vue';
import damageReview from '@/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue';
import scheduleReview from '@/layouts/payment-method/review-dropdown/review-sections/schedule-review/schedule-review.vue';
import
serviceLocationReview from '@/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.vue';
import
servicePackageReview
from '@/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue';
import serviceLocationReview from '@/layouts/payment-method/review-dropdown/review-sections/service-location-review/service-location-review.vue';
import vehicleReview from '@/layouts/payment-method/review-dropdown/review-sections/vehicle-review/vehicle-review.vue';
import { useMainStore } from '@/store';
import settleAllPromises from '@/helpers/layout-helper';
export default {
name: 'review-dropdown',
components: {
customerReview,
damageReview,
scheduleReview,
serviceLocationReview,
servicePackageReview,
vehicleReview
},
props: {},
@ -79,12 +65,6 @@ export default {
vehicleInfo() {
return useMainStore().vehicle;
},
damageInfo() {
return useMainStore().damage;
},
lineItems() {
return useMainStore().lineItems;
},
serviceLocationInfo() {
return useMainStore().order.serviceLocation;
},
@ -95,9 +75,22 @@ export default {
return useMainStore().contactInfo;
}
},
emits: ['edit-clicked'],
methods: {
toggleIsExpanded() {
this.isExpanded = !this.isExpanded;
},
editServiceLocation() {
this.$emit('edit-clicked', 'location');
},
editSchedule() {
this.$emit('edit-clicked', 'schedule');
},
editVehicle() {
this.$emit('edit-clicked', 'vehicle');
},
editCustomer() {
this.$emit('edit-clicked', 'customer');
}
}
};
@ -111,14 +104,19 @@ export default {
line-height: 1.6;
}
.review-table {
.review-table-expander {
max-height: 0;
transition: all 350ms ease-in;
transition: $transition-swing;
overflow: hidden;
visibility: hidden;
}
.section-divider {
margin-top: 1.5rem;
margin-bottom: 1.875rem;
}
.review-toggle {
margin-bottom: .625rem;
&:after {
content: "";
transition: transform none;
@ -129,17 +127,13 @@ export default {
width: 1.25rem;
height: 1.25rem;
display: inline-flex;
position: relative;
right: 0.75rem;
margin: 0.5rem 0 0.5rem 1rem;
cursor: pointer;
}
&.expanded:after {
transform: rotate(180deg);
}
&.expanded + .review-table {
max-height: 800px;
transition: all 150ms ease-in;
&.expanded + .review-table .review-table-expander {
max-height: 24rem;
overflow: hidden;
visibility: visible;
}

View file

@ -1,7 +1,8 @@
<template>
<reviewBlock
:customHeaderText="header"
:content="displayContent" />
:content="displayContent"
:editLinkText="editLinkText" />
</template>
<script>
@ -13,30 +14,20 @@ export default {
reviewBlock
},
props: {
cmsWidgetName: String,
customer: Object
cmsWidgetName: String
},
data() {
return {};
},
computed: {
displayContent() {
return [this.fullName, this.email, this.phoneNumber, this.smsOptIn];
return [this.getCmsContent(this.cmsWidgetName, 'BodyText')];
},
header() {
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
},
fullName() {
return `${this.customer?.firstName} ${this.customer?.lastName}`;
},
email() {
return this.customer?.emailAddress;
},
phoneNumber() {
return this.customer?.servicePhone;
},
smsOptIn() {
return this.getCmsContent(this.cmsWidgetName, 'SubheaderText');
editLinkText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
}
}
};

View file

@ -1,80 +0,0 @@
// Components
import damageReview from '@/layouts/payment-method/review-dropdown/review-sections/damage-review/damage-review.vue';
// Supporting Files
import { createTestingPinia } from '@pinia/testing';
import { useMainStore } from '@/store';
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { getDamageDisplayContent } from '@/helpers/damage-review-content-generator.js';
import baseMixin from '@/mixins/base-mixin';
jest.mock('@/helpers/damage-review-content-generator.js', () => ({
getDamageDisplayContent: jest.fn(),
getLocationAnswer: jest.fn()
}));
let cmsContent;
const mockMixin = {
methods: {
...baseMixin.methods,
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
}
};
function getShallowMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn()
}
});
const testingPinia = createTestingPinia({
initialState: {
main: mainInitialState
}
});
useMainStore(testingPinia);
methodToRun();
mountOptions.global.plugins = [testingPinia];
mountOptions.data = () => (
initialData
);
mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(damageReview, mountOptions);
return { wrapper };
}
beforeEach(() => {
getDamageDisplayContent.mockClear();
});
describe('Damage Review Block', () => {
test('computed displayContent calls getDamageDisplayContent with expected', () => {
// Arrange
const glassToReplace = ['front-window', 'side-window'];
const isRepair = false;
const initialStore = {
order: {
damage: {
glassToReplace,
isRepair
}
}
};
const expected = ['a', 'v', 'n'];
getDamageDisplayContent.mockImplementationOnce(() => expected);
const { wrapper } = getShallowMountedComponent(initialStore, {});
// Act
const result = wrapper.vm.displayContent;
// Assert
expect(result).toStrictEqual(expected);
expect(getDamageDisplayContent).toBeCalledTimes(1);
expect(getDamageDisplayContent).toBeCalledWith([], [], [], glassToReplace, isRepair);
});
});

View file

@ -1,47 +0,0 @@
<template>
<reviewBlock
:headerCmsWidgetName="cmsWidgetName"
:content="displayContent" />
</template>
<script>
import damageLocationsSelected from '@/constants/damage-locations-selected.js';
import { useMainStore } from '@/store';
import { getDamageDisplayContent, getLocationAnswer } from '@/helpers/damage-review-content-generator.js';
import reviewBlock from '@/layouts/payment-method/review-dropdown/review-block/review-block.vue';
export default {
name: 'damage-review',
components: {
reviewBlock
},
props: {
cmsWidgetName: String,
damageLocationsWidgetName: String,
damage: Object
},
computed: {
displayContent() {
const { glassToReplace, isRepair } = useMainStore().order.damage;
return getDamageDisplayContent(
this.locationAnswers,
this.driverSideDamageAnswers,
this.passengerSideDamageAnswers,
glassToReplace,
isRepair
);
},
driverSideDamageAnswers() {
const answerContent = getLocationAnswer(damageLocationsSelected.DRIVER, this.locationAnswers);
return this.getInputQuestionWidgetAnswersNullSafe(answerContent?.SubWidgetName);
},
passengerSideDamageAnswers() {
const answerContent = getLocationAnswer(damageLocationsSelected.PASSENGER, this.locationAnswers);
return this.getInputQuestionWidgetAnswersNullSafe(answerContent?.SubWidgetName);
},
locationAnswers() {
return this.getInputQuestionWidgetAnswersNullSafe(this.damageLocationsWidgetName);
}
}
};
</script>

View file

@ -1,7 +1,8 @@
<template>
<reviewBlock
:customHeaderText="headerText"
:content="displayContent" />
:content="displayContent"
:editLinkText="editLinkText" />
</template>
<script>
@ -13,8 +14,7 @@ export default {
reviewBlock
},
props: {
cmsWidgetName: String,
appointmentType: String
cmsWidgetName: String
},
data() {
return {};
@ -28,6 +28,9 @@ export default {
},
headerText() {
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
},
editLinkText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
}
}
};

View file

@ -1,11 +1,13 @@
<template>
<reviewBlock
:headerCmsWidgetName="cmsWidgetName"
:content="displayContent" />
:customHeaderText="headerText"
:content="displayContent"
:editLinkText="editLinkText" />
</template>
<script>
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import { toTitleCase } from '@/helpers/text-helper';
import reviewBlock from '@/layouts/payment-method/review-dropdown/review-block/review-block.vue';
export default {
@ -21,11 +23,14 @@ export default {
return {};
},
computed: {
headerText() {
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
},
displayContent() {
return [
`${this.addressInfo.address}${this.addressInfo.address2 ? ', ' : ''}${
this.addressInfo.address2
}, ${this.addressInfo.city}, ${this.addressInfo.state} ${this.addressInfo.zipCode}`
}, ${toTitleCase(this.addressInfo.city)}, ${this.addressInfo.state} ${this.addressInfo.zipCode}`
];
},
addressInfo() {
@ -46,6 +51,9 @@ export default {
state: this.serviceLocation?.provider?.address?.state,
zipCode: this.serviceLocation?.provider?.address?.zipCode
};
},
editLinkText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
}
}
};

View file

@ -1,965 +0,0 @@
// Components
import
servicePackageReview from '@/layouts/payment-method/review-dropdown/review-sections/service-package-review/service-package-review.vue';
// Supporting Files
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import packageNames from '@/constants/package-names';
import partTypeStrings from '@/constants/part-type-strings';
import damageLocationsSelected from '@/constants/damage-locations-selected';
import { useMainStore } from '@/store';
const testConstants = {
cmsPropValues: {
servicePackageOptionsCmsName: 'ServicePackageTitle',
defaultPackageItemsCmsName: 'DefaultPackageItemDescriptions',
vapsItemsCmsName: 'VapsItemDescriptions'
},
widgetNames: {
tierOneTitle: 'EconomyServiceTitle',
tierTwoTitle: 'StandardServiceTitle',
tierThreeTitle: 'PremiumServiceTitle'
},
defaultItemCopy: {
itemOne: 'Item Description 1',
itemTwo: 'Item Description 2',
itemThree: 'Item Description 3',
itemFour: 'Item Description 4',
defaultItemCopyArray: ['Item Description 1', 'Item Description 2', 'Item Description 3']
},
vapsCopy: {
frontWiperCopy: 'Front Wiper copy',
rearWiperCopy: 'Rear Wiper copy',
rainDefenseCopy: 'Rain repel copy'
},
parts: {
frontWiperPart: {
partNumber: 'SBB16',
description: 'SAFELITE BEAM BLADE 16',
partType: 'FRONT WIPER',
price: 32.64
},
rearWiperPart: {
partNumber: 'SBBR12A',
description: 'SAFELITE REAR BLADE 12A',
partType: 'REAR WIPER',
price: 24.48
},
rainDefensePart: {
partNumber: 'RAIN REPEL',
description: null,
partType: 'RAIN REPEL',
price: 35.5
},
recalPart: {
partNumber: 'RECAL STATIC',
Description: 'Recalibration',
partType: 'recalibration',
Quantity: '1',
price: 150.0
}
},
damages: {
frontWindshield: {
glassLocation: damageLocationsSelected.WINDSHIELD,
glassName: damageLocationsSelected.SINGLE
},
rearWindshield: {
glassLocation: damageLocationsSelected.REAR,
glassName: damageLocationsSelected.STATIONARY
},
sideGlass: {
glassLocation: damageLocationsSelected.PASSENGER,
glassName: damageLocationsSelected.QUARTER
}
},
imageId: '00000000-0000-0000-0000-000000000000'
};
const figmaScenarios = [
{
name: '05_01_CSR_Quote_Cash',
params: {
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [testConstants.damages.frontWindshield]
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Standard',
vapsCombo: [testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy
]
}
},
{
name: 'Premium',
vapsCombo: [
testConstants.parts.rainDefensePart,
testConstants.parts.frontWiperPart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Standard+RearWiper',
vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy
]
}
}
]
},
{
name: '05_01_CSR_Quote_Standard_Repair',
params: {
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: true,
glassToReplace: []
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Standard',
vapsCombo: [testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy
]
}
},
{
name: 'Premium',
vapsCombo: [
testConstants.parts.rainDefensePart,
testConstants.parts.frontWiperPart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Standard+RearWiper',
vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy
]
}
}
]
},
{
name: '05_01_CSR_Quote_Recal',
params: {
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [testConstants.damages.frontWindshield]
},
glassParts: [],
supportingItems: [testConstants.parts.recalPart]
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Standard',
vapsCombo: [testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy
]
}
},
{
name: 'Premium',
vapsCombo: [
testConstants.parts.rainDefensePart,
testConstants.parts.frontWiperPart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Standard+RearWiper',
vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy
]
}
}
]
},
// 05_01_CSR_Quote_RearGlass omitted as a duplicate of below.
{
name: '05_01_CSR_Quote_RearGlass+NonWindshield',
params: {
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [testConstants.damages.rearWindshield]
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Economy+Frontwiper',
vapsCombo: [testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy
]
}
},
{
name: 'Standard',
vapsCombo: [testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rearWiperCopy
]
}
},
{
name: 'Standard+RainDefense',
vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rearWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Premium',
vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy
]
}
}
]
},
{
name: '05_01_CSR_Quote_RearGlass+Windshield',
params: {
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [
testConstants.damages.frontWindshield,
testConstants.damages.rearWindshield
]
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Economy+Frontwiper',
vapsCombo: [testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy
]
}
},
{
name: 'Economy+Rearwiper',
vapsCombo: [testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rearWiperCopy
]
}
},
{
name: 'Economy+RainDefense',
vapsCombo: [testConstants.parts.rainDefensePart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Economy+Frontwiper+RainDefense',
vapsCombo: [
testConstants.parts.frontWiperPart,
testConstants.parts.rainDefensePart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Economy+Rearwiper+RainDefense',
vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rearWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Standard',
vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy
]
}
},
{
name: 'Premium',
vapsCombo: [
testConstants.parts.rearWiperPart,
testConstants.parts.frontWiperPart,
testConstants.parts.rainDefensePart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
}
]
},
{
name: '05_01_CSR_Quote_RearGlassNoFrontFit',
params: {
wiperResponse: [testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [testConstants.damages.rearWindshield]
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Economy+Raindefense',
vapsCombo: [testConstants.parts.rainDefensePart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Standard',
vapsCombo: [testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rearWiperCopy
]
}
},
{
name: 'Premium',
vapsCombo: [testConstants.parts.rearWiperPart, testConstants.parts.rainDefensePart],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rearWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
}
]
},
// 05_01_CSR_Quote_Windshield+SideGlass has identical outcomes to 05_01_CSR_Quote_Cash, but included in case that changes in the future.
{
name: '05_01_CSR_Quote_Windshield+SideGlass',
params: {
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [
testConstants.damages.frontWindshield,
testConstants.damages.sideGlass
]
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Standard',
vapsCombo: [testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy
]
}
},
{
name: 'Premium',
vapsCombo: [
testConstants.parts.rainDefensePart,
testConstants.parts.frontWiperPart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Standard+RearWiper',
vapsCombo: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierTwoTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy
]
}
}
]
},
// Has no standard package
{
name: '05_01_CSR_Quote_SideGlass',
params: {
wiperResponse: [testConstants.parts.frontWiperPart, testConstants.parts.rearWiperPart],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [testConstants.damages.sideGlass]
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Economy+Frontwiper',
vapsCombo: [testConstants.parts.frontWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy
]
}
},
{
name: 'Economy+RainDefense',
vapsCombo: [testConstants.parts.rainDefensePart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Economy+Rearwiper',
vapsCombo: [testConstants.parts.rearWiperPart],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rearWiperCopy
]
}
},
{
name: 'Premium',
vapsCombo: [
testConstants.parts.rainDefensePart,
testConstants.parts.frontWiperPart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
},
{
name: 'Premium+Rearwiper',
vapsCombo: [
testConstants.parts.rainDefensePart,
testConstants.parts.frontWiperPart,
testConstants.parts.rearWiperPart
],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.frontWiperCopy,
testConstants.vapsCopy.rearWiperCopy,
testConstants.vapsCopy.rainDefenseCopy
]
}
}
]
},
// Has no standard package
{
name: '05_01_CSR_Quote_NoWiperFit',
params: {
wiperResponse: [],
rainDefenseResponse: testConstants.parts.rainDefensePart,
damage: {
isRepair: false,
glassToReplace: [testConstants.damages.frontWindshield]
},
glassParts: [],
supportingItems: []
},
iterations: [
{
name: 'Economy',
vapsCombo: [],
expected: {
packageNameWidget: testConstants.widgetNames.tierOneTitle,
displayContent: testConstants.defaultItemCopy.defaultItemCopyArray
}
},
{
name: 'Premium',
vapsCombo: [testConstants.parts.rainDefensePart],
expected: {
packageNameWidget: testConstants.widgetNames.tierThreeTitle,
displayContent: [
...testConstants.defaultItemCopy.defaultItemCopyArray,
testConstants.vapsCopy.rainDefenseCopy
]
}
}
]
}
];
function generateDefaultProps() {
return {
servicePackageOptionsCmsName: testConstants.cmsPropValues.servicePackageOptionsCmsName,
defaultPackageItemsCmsName: testConstants.cmsPropValues.defaultPackageItemsCmsName,
vapsItemsCmsName: testConstants.cmsPropValues.vapsItemsCmsName,
lineItems: {
glassParts: [],
supportingItems: [],
vaps: [testConstants.parts.frontWiperPart]
},
damage: {
isRepair: false,
glassToReplace: [testConstants.damages.frontWindshield]
}
};
}
let cmsContent;
const mockMixin = {
methods: {
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
}
};
function initializeWithDefault() {
useMainStore().order.availableVaps = [testConstants.parts.frontWiperPart, testConstants.parts.rainDefensePart];
}
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
const mountOptions = getMountOptions({
router: {
navigate: jest.fn()
}
});
methodToRun();
mountOptions.data = () => (
initialData
);
mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(servicePackageReview, mountOptions);
wrapper.vm.setCmsContent = jest.fn();
return { wrapper };
}
beforeEach(() => {
cmsContent = {
ServicePackageTitle: {
Answers: [
{
Name: packageNames.TIER_ONE,
Text: '',
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: testConstants.widgetNames.tierOneTitle
},
{
Name: packageNames.TIER_TWO,
Text: '',
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: testConstants.widgetNames.tierTwoTitle
},
{
Name: packageNames.TIER_THREE,
Text: '',
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: testConstants.widgetNames.tierThreeTitle
}
]
},
DefaultPackageItemDescriptions: {
Answers: [
{
Name: 'Item1',
Text: testConstants.defaultItemCopy.itemOne,
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: ''
},
{
Name: 'Item2',
Text: testConstants.defaultItemCopy.itemTwo,
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: ''
},
{
Name: 'Item3',
Text: testConstants.defaultItemCopy.itemThree,
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: ''
}
]
},
VapsItemDescriptions: {
Answers: [
{
Name: partTypeStrings.FRONT_WIPER,
Text: testConstants.vapsCopy.frontWiperCopy,
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: ''
},
{
Name: partTypeStrings.REAR_WIPER,
Text: testConstants.vapsCopy.rearWiperCopy,
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: ''
},
{
Name: partTypeStrings.RAIN_DEFENSE,
Text: testConstants.vapsCopy.rainDefenseCopy,
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: ''
}
]
}
};
});
describe('Service Package Review Block', () => {
describe('General functionality', () => {
test('Should properly "Round Down" package tier', async () => {
// Slightly longer explanation:
// Should only return the highest tier where *every* offered VAP is part of the order.
// However, there may be vaps not offered in the qualifying tier. Hence rounding *down*.
//
// I.e. Economy=[], Standard=[front wipers], Premium=[front wipers, rain defense].
// Current vaps=[rain defense]. Though rain defense is in Premium, we don't satisfy it or standard.
// So our tier should still be Economy.
// Should still display extra vaps.
// Arrange
const props = generateDefaultProps();
props.lineItems.vaps = [testConstants.parts.rainDefensePart];
const { wrapper } = getShallowMountedComponent({
...props
});
initializeWithDefault();
// Act
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.packageNameWidget).toEqual(testConstants.widgetNames.tierOneTitle);
const containsRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy);
expect(containsRainDefenseCopy).toBe(true);
});
test('Should display all default items from cms', async () => {
// Arrange
cmsContent.DefaultPackageItemDescriptions.Answers.push({
Name: 'Item4',
Text: testConstants.defaultItemCopy.itemFour,
SubText: '',
ImageId: testConstants.imageId,
Image: '',
SubWidgetName: ''
});
const props = generateDefaultProps();
props.lineItems.vaps = [];
const { wrapper } = getShallowMountedComponent({
...props
});
initializeWithDefault();
// Act
await wrapper.vm.$nextTick();
// Assert
const expectedResult = [
testConstants.defaultItemCopy.itemOne,
testConstants.defaultItemCopy.itemTwo,
testConstants.defaultItemCopy.itemThree,
testConstants.defaultItemCopy.itemFour
];
expect(wrapper.vm.displayContent).toEqual(expectedResult);
});
test('Should display vaps if and only if they are added', async () => {
// Arrange
const props = generateDefaultProps();
const { wrapper } = getShallowMountedComponent({
...props
});
// Act
await wrapper.vm.$nextTick();
initializeWithDefault();
// Assert
const includesFrontWiperCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.frontWiperCopy);
const includesRainDefenseCopy = wrapper.vm.displayContent.includes(testConstants.vapsCopy.rainDefenseCopy);
expect(includesFrontWiperCopy).toBe(true);
expect(includesRainDefenseCopy).toBe(false);
});
test('Should not error if cms content is missing (though may display poorly).', async () => {
// Arrange
cmsContent = {};
const props = generateDefaultProps();
const { wrapper } = getShallowMountedComponent({
...props
});
initializeWithDefault();
// Act
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.packageNameWidget).toEqual('');
expect(wrapper.vm.displayContent).toEqual([]);
});
});
describe('Match Figma Scenarios', () => {
figmaScenarios.forEach((scenario) => {
scenario.iterations.forEach((iteration) => {
it(`Should match figma scenario "${scenario.name}", iteration "${iteration.name}"`, async () => {
// Arrange
const props = generateDefaultProps();
props.damage = scenario.params.damage;
props.glassParts = scenario.params.glassParts;
props.lineItems.supportingItems = scenario.params.supportingItems;
props.lineItems.vaps = iteration.vapsCombo;
const { wrapper } = getShallowMountedComponent({
...props
});
useMainStore().order.availableVaps = [scenario.params.rainDefenseResponse, ...scenario.params.wiperResponse];
// Act
await wrapper.vm.$nextTick();
// Assert
expect(wrapper.vm.packageNameWidget).toEqual(iteration.expected.packageNameWidget);
expect(wrapper.vm.displayContent).toEqual(iteration.expected.displayContent);
});
});
});
});
});

View file

@ -1,100 +0,0 @@
<template>
<reviewBlock
:headerCmsWidgetName="packageNameWidget"
:content="displayContent" />
</template>
<script>
import settleAllPromises from '@/helpers/layout-helper';
// import baseMixin from '@/mixins/base-mixin.js';
import { useMainStore } from '@/store';
import reviewBlock from '@/layouts/payment-method/review-dropdown/review-block/review-block.vue';
import {
getHighestFullySatisfiedTier,
containsLineItemWithPartType
} from '@/helpers/service-package-helper.js';
export default {
name: 'service-package-review',
components: {
reviewBlock
},
props: {
servicePackageOptionsCmsName: String,
defaultPackageItemsCmsName: String,
vapsItemsCmsName: String,
lineItems: Object,
damage: Object
},
emits: ['edit-clicked'],
data() {
return {
availableVaps: []
};
},
computed: {
displayContent() {
return [...this.defaultPackageText, ...this.vapsItemText];
},
packageNameWidget() {
const servicePackageNames = this.getCmsContent(
this.servicePackageOptionsCmsName,
'Answers'
);
if (!servicePackageNames) {
return '';
}
const currentPackage = servicePackageNames.find((entry) => entry.Name === this.packageLevel);
return currentPackage.SubWidgetName;
},
defaultPackageText() {
const defaultItems = this.getCmsContent(this.defaultPackageItemsCmsName, 'Answers');
if (!defaultItems) {
return [];
}
return defaultItems.map((answer) => answer.Text);
},
vapsItemText() {
const vapsDescriptions = this.getCmsContent(this.vapsItemsCmsName, 'Answers');
if (!vapsDescriptions) {
return [];
}
const vapsDescriptionsOnOrder = vapsDescriptions.filter((answer) =>
containsLineItemWithPartType(answer.Name, this.vaps));
return vapsDescriptionsOnOrder.map((answer) => answer.Text);
},
packageLevel() {
return getHighestFullySatisfiedTier(
this.glassToReplace,
this.availableLineItems,
this.isRepair,
this.vaps
);
},
glassToReplace() {
return this.damage.glassToReplace;
},
isRepair() {
return this.damage.isRepair;
},
vaps() {
return this.lineItems?.vaps;
},
availableLineItems() {
return [
...(this.lineItems?.glassParts ?? []),
...(this.lineItems?.supportingItems ?? []),
...(useMainStore().order.availableVaps ?? [])
];
}
}
};
</script>

View file

@ -1,10 +1,13 @@
<template>
<reviewBlock
:headerCmsWidgetName="cmsWidgetName"
:content="displayContent" />
:customHeaderText="header"
:content="displayContent"
:editLinkText="editLinkText" />
</template>
<script>
import { getStringWithCustomValues, processIfStatements } from '@/helpers/cms-content-helper';
import { getGlassList } from '@/helpers/damage-helper';
import reviewBlock from '@/layouts/payment-method/review-dropdown/review-block/review-block.vue';
export default {
@ -13,15 +16,40 @@ export default {
reviewBlock
},
props: {
cmsWidgetName: String,
vehicle: Object
cmsWidgetName: String
},
data() {
return {};
},
computed: {
header() {
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
},
displayContent() {
return [`${this.vehicle.year} ${this.vehicle.make} ${this.vehicle.model}`];
return [this.getCmsContentWithCustomValues(this.cmsWidgetName, 'BodyText')];
},
editLinkText() {
return this.getCmsContent(this.cmsWidgetName, 'FooterText');
},
customValueMap() {
return {
glassList: this.glassList,
};
},
glassList() {
const glassPieces = this.mainStore.lineItems.glassParts?.map((part) => part.partType.toLowerCase()) ?? [];
return getGlassList(glassPieces);
},
},
methods: {
getCmsContentWithCustomValues(widgetName, widgetField) {
const rawText = this.getCmsContent(widgetName, widgetField);
const processedIfStatements = processIfStatements(
rawText,
'custom',
(v) => this.customValueMap[v]
);
return getStringWithCustomValues(processedIfStatements, this.customValueMap);
}
}
};

View file

@ -99,7 +99,7 @@ import buttonMain from '@/ux-components/button-main/button-main.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import reviewBlock from '@/layouts/tpa-submit/review-block/review-block.vue';
import deductibleBox from '@/layouts/tpa-submit/deductible-box/deductible-box.vue';
import contactDetailsDrawer from '@/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue';
import contactDetailsDrawer from '@/iss-components/contact-details-drawer/contact-details-drawer.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import alert from '@/ux-components/alert/alert.vue';
import modal from '@/digital-components/modal/modal.vue';

View file

@ -110,6 +110,9 @@ const navigationScenarios = Object.freeze({
PAY_IN_ADVANCE_ERROR: 'PAY_IN_ADVANCE_ERROR',
PAY_IN_ADVANCE_CREDIT_CARD_ERROR: 'PAY_IN_ADVANCE_CREDIT_CARD_ERROR',
PAY_IN_ADVANCE_SUCCESS: 'PAY_IN_ADVANCE_SUCCESS',
EDIT_SERVICE_LOCATION: 'EDIT_SERVICE_LOCATION',
EDIT_SCHEDULE: 'EDIT_SCHEDULE',
EDIT_WIPERS: 'EDIT_WIPERS',
// Bailout
CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT',

View file

@ -696,6 +696,22 @@ const routingTable = () => [
{
scenario: navigationScenarios.SAVE_SESSION_FAILED,
destinationIssPageValue: issPageValues.BAILOUT_PAGE
},
{
scenario: navigationScenarios.EDIT_SERVICE_LOCATION,
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
},
{
scenario: navigationScenarios.EDIT_SCHEDULE,
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
},
{
scenario: navigationScenarios.EDIT_VEHICLE,
destinationIssPageValue: issPageValues.VEHICLE_DAMAGE,
},
{
scenario: navigationScenarios.EDIT_WIPERS,
destinationIssPageValue: issPageValues.SERVICE_PACKAGES
}
]
},

View file

@ -235,3 +235,6 @@ $border-input-focus: 2.5px solid $heritage-blue-primary;
$svg-calendar-error-fill-color: $alert-red-bg;
$svg-calendar-error-stroke-color: '%23db0020'; // URL encoded #db0020
// Swing easing to replicate Heritage's slideVisible
$transition-swing: all 400ms cubic-bezier(.02, .01, .47, 1);