Merge branch 'develop' of https://github.com/Safelite/DigitalConsumer.ISS into feature/digital/SSR-791
This commit is contained in:
commit
d4cf2f3d51
38 changed files with 3458 additions and 147 deletions
7
src/constants/package-names.js
Normal file
7
src/constants/package-names.js
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
const packageNames = Object.freeze({
|
||||||
|
TIER_ONE: 'TierOne',
|
||||||
|
TIER_TWO: 'TierTwo',
|
||||||
|
TIER_THREE: 'TierThree'
|
||||||
|
});
|
||||||
|
|
||||||
|
export default packageNames;
|
||||||
|
|
@ -2,7 +2,11 @@
|
||||||
FRONT_WIPER: 'FRONT WIPER',
|
FRONT_WIPER: 'FRONT WIPER',
|
||||||
REAR_WIPER: 'REAR WIPER',
|
REAR_WIPER: 'REAR WIPER',
|
||||||
RAIN_DEFENSE: 'RAIN DEFENSE',
|
RAIN_DEFENSE: 'RAIN DEFENSE',
|
||||||
RECALIBRATION: 'RECALIBRATION'
|
RECALIBRATION: 'RECALIBRATION',
|
||||||
|
REPLACE_FEE: 'REPLACE FEE',
|
||||||
|
RECYCLE_FEE: 'RECYCLE FEE',
|
||||||
|
MOBILE_FEE: 'MOBILE FEE',
|
||||||
|
REPAIR_FEE: 'REPAIR FEE'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default partTypeStrings;
|
export default partTypeStrings;
|
||||||
|
|
|
||||||
|
|
@ -106,10 +106,7 @@ import loader from '@/ux-components/loader/loader.vue';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
import { useField, ErrorMessage } from 'vee-validate';
|
import { useField, ErrorMessage } from 'vee-validate';
|
||||||
import { deepClone } from '@/helpers/object-helper';
|
import { deepClone } from '@/helpers/object-helper';
|
||||||
import {
|
import { convertDateStringToDate, convertDateToDateString } from '@/helpers/date-helper';
|
||||||
convertDateToDateString,
|
|
||||||
convertDateStringToDate
|
|
||||||
} from '@/layouts/schedule-page/helpers/schedule-helper';
|
|
||||||
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from './mixins/constants';
|
import { TIMINGFUNC_MAP, BUFFER_OFFSET, MONTHS_OF_YEAR } from './mixins/constants';
|
||||||
import { selectableDaysOptions, requiredParameter } from './mixins/helpers';
|
import { selectableDaysOptions, requiredParameter } from './mixins/helpers';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@
|
||||||
loaderColor="white"
|
loaderColor="white"
|
||||||
:buttonText="footerButtonText"
|
:buttonText="footerButtonText"
|
||||||
:class="(isButtonDisabled || isFooterButtonDisabled) && 'form-test-invalid'"
|
:class="(isButtonDisabled || isFooterButtonDisabled) && 'form-test-invalid'"
|
||||||
:isDisabled="(isButtonDisabled || isFooterButtonDisabled)"
|
|
||||||
@clickEvent="validateAndEmit" />
|
@clickEvent="validateAndEmit" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
/* eslint-disable no-use-before-define */
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
/* eslint-disable jsdoc/require-param-type */
|
||||||
|
/* eslint-disable jsdoc/require-param-description */
|
||||||
|
/* eslint-disable jsdoc/require-returns */
|
||||||
import dynamicStrings from '@/constants/dynamic-strings';
|
import dynamicStrings from '@/constants/dynamic-strings';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
|
||||||
|
|
@ -191,6 +196,45 @@ export function fetchCmsContentForPage(issPage) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchGlobalCmsContent(issComponent) {
|
||||||
|
const store = useMainStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
store.getPageData(issComponent)
|
||||||
|
.then((baseResponse) => processPageData(baseResponse, null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateCmsSiteHeader(cmsResponse) {
|
||||||
|
const clientCmsSiteHeader = getCmsSiteHeader(cmsResponse);
|
||||||
|
useMainStore().issConfig.clientHeader = clientCmsSiteHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCmsSiteHeader(cmsResponse) {
|
||||||
|
if (cmsResponse?.SiteHeaderWidget) {
|
||||||
|
const siteHeader = cmsResponse?.SiteHeaderWidget;
|
||||||
|
if (siteHeader.Answers) {
|
||||||
|
const { parentAccountNumber } = useMainStore().issConfig;
|
||||||
|
let headerAnswersToUse = siteHeader.Answers
|
||||||
|
.find((answer) => answer.AccountNumber === parentAccountNumber.toString());
|
||||||
|
if (headerAnswersToUse == null) {
|
||||||
|
headerAnswersToUse = siteHeader.Answers
|
||||||
|
.find((answer) => answer.AccountNumber === '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerAnswersToUse) {
|
||||||
|
return {
|
||||||
|
altText: headerAnswersToUse.AltText,
|
||||||
|
clientName: headerAnswersToUse.ClientName,
|
||||||
|
hexCode: headerAnswersToUse.HexCode,
|
||||||
|
imageId: headerAnswersToUse.ImageId,
|
||||||
|
imageUrl: headerAnswersToUse.AnswerImageUrl
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function mapStringToModal
|
* @function mapStringToModal
|
||||||
* @param str
|
* @param str
|
||||||
|
|
@ -493,6 +537,7 @@ export function doesCopyContainTextLink(copy) {
|
||||||
export function setupModalLinks(context) {
|
export function setupModalLinks(context) {
|
||||||
context.$nextTick(() => {
|
context.$nextTick(() => {
|
||||||
const elements = document.getElementsByClassName('modal-text');
|
const elements = document.getElementsByClassName('modal-text');
|
||||||
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
const target = element.getAttribute('modalTarget');
|
const target = element.getAttribute('modalTarget');
|
||||||
if (target) {
|
if (target) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,30 @@
|
||||||
const getDateDifferenceInDays = (startDate, endDate) => {
|
export function calcDaysBetweenDates(dateString1, dateString2) {
|
||||||
|
const date1 = new Date(dateString1);
|
||||||
|
const date2 = new Date(dateString2);
|
||||||
|
const timeDifference = Math.abs(date2 - date1); // Calculate the time difference in milliseconds
|
||||||
|
return Math.ceil(timeDifference / (1000 * 60 * 60 * 24)); // Convert milliseconds to days
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertDateToDateString(date) {
|
||||||
|
// returns YYYY-MM-DD format
|
||||||
|
if (date instanceof Date !== true) return null;
|
||||||
|
return (
|
||||||
|
`${date.getFullYear()
|
||||||
|
}-${
|
||||||
|
(`0${date.getMonth() + 1}`).slice(-2)
|
||||||
|
}-${
|
||||||
|
(`0${date.getDate()}`).slice(-2)}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertDateStringToDate(dateString) {
|
||||||
|
// dateString must be YYYY-MM-DD format
|
||||||
|
if (typeof dateString !== 'string') return null;
|
||||||
|
const dateParts = dateString.split('-');
|
||||||
|
return new Date(dateParts[0], parseInt(dateParts[1], 10) - 1, dateParts[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDateDifferenceInDays(startDate, endDate) {
|
||||||
const date1 = new Date(endDate);
|
const date1 = new Date(endDate);
|
||||||
date1.setHours(0, 0, 0, 0);
|
date1.setHours(0, 0, 0, 0);
|
||||||
const date2 = new Date(startDate);
|
const date2 = new Date(startDate);
|
||||||
|
|
@ -7,6 +33,42 @@ const getDateDifferenceInDays = (startDate, endDate) => {
|
||||||
const DifferenceInTime = date1.getTime() - date2.getTime();
|
const DifferenceInTime = date1.getTime() - date2.getTime();
|
||||||
// To calculate the no. of days between two dates
|
// To calculate the no. of days between two dates
|
||||||
return DifferenceInTime / (1000 * 3600 * 24);
|
return DifferenceInTime / (1000 * 3600 * 24);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default getDateDifferenceInDays;
|
export function getDisplayTextForDurationLength(durationMinimum, durationMaximum) {
|
||||||
|
const isLongAppointment = durationMaximum >= 120;
|
||||||
|
const isDurationRange = durationMinimum !== durationMaximum;
|
||||||
|
|
||||||
|
const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum;
|
||||||
|
const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum;
|
||||||
|
|
||||||
|
const durationText = isDurationRange
|
||||||
|
? `${adjustedMinimum} - ${adjustedMaximum}`
|
||||||
|
: adjustedMinimum;
|
||||||
|
|
||||||
|
const unitText = isLongAppointment ? 'hours' : 'minutes';
|
||||||
|
|
||||||
|
return `${durationText} ${unitText}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function militaryToTwelveHourTime(timeString) {
|
||||||
|
// Expected input: "HH:MM"
|
||||||
|
if (typeof timeString !== 'string') return null;
|
||||||
|
let hours = parseInt(timeString.split(':')[0], 10);
|
||||||
|
const minutes = timeString.split(':')[1];
|
||||||
|
const meridianNotation = hours > 11 ? 'PM' : 'AM';
|
||||||
|
|
||||||
|
if (hours > 12) {
|
||||||
|
hours -= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${hours}:${minutes} ${meridianNotation}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sumDateString(dateString, daysToAdd) {
|
||||||
|
// dateString must be YYYY-MM-DD format
|
||||||
|
if (typeof dateString !== 'string') return null;
|
||||||
|
const date = convertDateStringToDate(dateString);
|
||||||
|
date.setDate(date.getDate() + daysToAdd);
|
||||||
|
return convertDateToDateString(date);
|
||||||
|
}
|
||||||
|
|
|
||||||
238
src/helpers/service-package-helper.js
Normal file
238
src/helpers/service-package-helper.js
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
|
import damageLocationsSelected from '@/constants/damage-locations-selected';
|
||||||
|
import packageNames from '@/constants/package-names';
|
||||||
|
|
||||||
|
export function findLineItemsWithPartType(typeToFind, itemsToSearch) {
|
||||||
|
const partTypeMatches = itemsToSearch?.filter((lineItem) => lineItem.partType.toUpperCase() === typeToFind.toUpperCase());
|
||||||
|
return partTypeMatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function containsLineItemWithPartType(typeToFind, itemsToSearch) {
|
||||||
|
const partTypeMatches = findLineItemsWithPartType(typeToFind, itemsToSearch);
|
||||||
|
return !!partTypeMatches?.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVapsLineItems(availableLineItems, vapTypes) {
|
||||||
|
const lineItems = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < vapTypes.length; i++) {
|
||||||
|
lineItems.push(...findLineItemsWithPartType(vapTypes[i], availableLineItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
return lineItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function containsGlassPieceWithLocation(locationToFind, glassPiecesToSearch) {
|
||||||
|
const glassLocationMatches = glassPiecesToSearch?.filter((glassPiece) =>
|
||||||
|
glassPiece.glassLocation.toUpperCase() === locationToFind.toUpperCase());
|
||||||
|
|
||||||
|
return !!glassLocationMatches?.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldFrontWipersBeAvailable(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
targetTier
|
||||||
|
) {
|
||||||
|
const frontWiperIsAvailable = containsLineItemWithPartType(
|
||||||
|
partTypeStrings.FRONT_WIPER,
|
||||||
|
availableLineItems
|
||||||
|
);
|
||||||
|
|
||||||
|
const isFrontWindshieldTask =
|
||||||
|
isRepair || containsGlassPieceWithLocation(damageLocationsSelected.WINDSHIELD, glassToReplace);
|
||||||
|
switch (targetTier) {
|
||||||
|
case packageNames.TIER_TWO:
|
||||||
|
return frontWiperIsAvailable && isFrontWindshieldTask;
|
||||||
|
case packageNames.TIER_THREE:
|
||||||
|
return frontWiperIsAvailable;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldRearWipersBeAvailable(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
targetTier
|
||||||
|
) {
|
||||||
|
const rearWiperIsAvailable = containsLineItemWithPartType(
|
||||||
|
partTypeStrings.REAR_WIPER,
|
||||||
|
availableLineItems
|
||||||
|
);
|
||||||
|
const frontWiperIsAvailable = containsLineItemWithPartType(
|
||||||
|
partTypeStrings.FRONT_WIPER,
|
||||||
|
availableLineItems
|
||||||
|
);
|
||||||
|
const isRearWindshieldTask = containsGlassPieceWithLocation(
|
||||||
|
damageLocationsSelected.REAR,
|
||||||
|
glassToReplace
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (targetTier) {
|
||||||
|
case packageNames.TIER_TWO:
|
||||||
|
return rearWiperIsAvailable && isRearWindshieldTask;
|
||||||
|
case packageNames.TIER_THREE:
|
||||||
|
return rearWiperIsAvailable && (isRearWindshieldTask || !frontWiperIsAvailable);
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function shouldRainDefenseBeAvailable(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
targetTier
|
||||||
|
) {
|
||||||
|
const isTierThree = targetTier === packageNames.TIER_THREE;
|
||||||
|
const frontWipersInTierTwo = shouldFrontWipersBeAvailable(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
packageNames.TIER_TWO
|
||||||
|
);
|
||||||
|
const frontWipersInTierThree = shouldFrontWipersBeAvailable(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
packageNames.TIER_THREE
|
||||||
|
);
|
||||||
|
const rearWipersInTierTwo = shouldRearWipersBeAvailable(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
packageNames.TIER_TWO
|
||||||
|
);
|
||||||
|
|
||||||
|
return isTierThree && !(rearWipersInTierTwo && !frontWipersInTierTwo && frontWipersInTierThree);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPackageContents(glassToReplace, availableLineItems, isRepair, targetTier) {
|
||||||
|
const vaps = [];
|
||||||
|
|
||||||
|
if (shouldFrontWipersBeAvailable(glassToReplace, availableLineItems, isRepair, targetTier)) {
|
||||||
|
vaps.push(partTypeStrings.FRONT_WIPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldRearWipersBeAvailable(glassToReplace, availableLineItems, isRepair, targetTier)) {
|
||||||
|
vaps.push(partTypeStrings.REAR_WIPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldRainDefenseBeAvailable(glassToReplace, availableLineItems, isRepair, targetTier)) {
|
||||||
|
vaps.push(partTypeStrings.RAIN_DEFENSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAvailablePackages(glassToReplace, availableLineItems, isRepair) {
|
||||||
|
const tierOneVaps = getPackageContents(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
packageNames.TIER_ONE
|
||||||
|
);
|
||||||
|
|
||||||
|
const tierTwoVaps = getPackageContents(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
packageNames.TIER_TWO
|
||||||
|
);
|
||||||
|
|
||||||
|
const tierThreeVaps = getPackageContents(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
packageNames.TIER_THREE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tierTwoVaps.length === 0) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
packageName: packageNames.TIER_ONE,
|
||||||
|
vapTypes: tierOneVaps
|
||||||
|
},
|
||||||
|
{
|
||||||
|
packageName: packageNames.TIER_THREE,
|
||||||
|
vapTypes: tierThreeVaps
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
packageName: packageNames.TIER_ONE,
|
||||||
|
vapTypes: tierOneVaps
|
||||||
|
},
|
||||||
|
{
|
||||||
|
packageName: packageNames.TIER_TWO,
|
||||||
|
vapTypes: tierTwoVaps
|
||||||
|
},
|
||||||
|
{
|
||||||
|
packageName: packageNames.TIER_THREE,
|
||||||
|
vapTypes: tierThreeVaps
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLowestTierForType(glassToReplace, availableLineItems, isRepair, partType) {
|
||||||
|
const packages = getAvailablePackages(glassToReplace, availableLineItems, isRepair);
|
||||||
|
for (let i = 0; i < packages.length; i++) {
|
||||||
|
for (let j = 0; j < packages[i].vapTypes.length; j++) {
|
||||||
|
if (packages[i].vapTypes[j].toUpperCase() === partType.toUpperCase()) {
|
||||||
|
return packages[i].packageName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return packageNames.TIER_ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
function maxTier(tierA, tierB) {
|
||||||
|
if (tierA === packageNames.TIER_THREE || tierB === packageNames.TIER_THREE) {
|
||||||
|
return packageNames.TIER_THREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tierA === packageNames.TIER_TWO || tierB === packageNames.TIER_TWO) {
|
||||||
|
return packageNames.TIER_TWO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packageNames.TIER_ONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHighestRequiredTier(glassToReplace, availableLineItems, isRepair, vaps) {
|
||||||
|
let currentHighestTier = packageNames.TIER_ONE;
|
||||||
|
for (let i = 0; i < vaps.length; i++) {
|
||||||
|
const lowestTierForItem = getLowestTierForType(
|
||||||
|
glassToReplace,
|
||||||
|
availableLineItems,
|
||||||
|
isRepair,
|
||||||
|
vaps[i].partType
|
||||||
|
);
|
||||||
|
|
||||||
|
currentHighestTier = maxTier(currentHighestTier, lowestTierForItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentHighestTier;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHighestFullySatisfiedTier(glassToReplace, availableLineItems, isRepair, vaps) {
|
||||||
|
const packages = getAvailablePackages(glassToReplace, availableLineItems, isRepair);
|
||||||
|
let highestSatisfiedPackage = packageNames.TIER_ONE;
|
||||||
|
|
||||||
|
for (let i = 0; i < packages.length; i++) {
|
||||||
|
let isPackageSatisfied = true;
|
||||||
|
for (let j = 0; j < packages[i].vapTypes.length; j++) {
|
||||||
|
isPackageSatisfied =
|
||||||
|
isPackageSatisfied && containsLineItemWithPartType(packages[i].vapTypes[j], vaps);
|
||||||
|
}
|
||||||
|
if (isPackageSatisfied) {
|
||||||
|
highestSatisfiedPackage = packages[i].packageName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return highestSatisfiedPackage;
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
<script>
|
<script>
|
||||||
import menuModal from '@/iss-components/site-header/menu-modal/menu-modal.vue';
|
import menuModal from '@/iss-components/site-header/menu-modal/menu-modal.vue';
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
|
import { useMainStore } from '@/store';
|
||||||
import eventBus from '@/helpers/event-bus/event-bus';
|
import eventBus from '@/helpers/event-bus/event-bus';
|
||||||
import { globalEvents } from '@/constants/events';
|
import { globalEvents } from '@/constants/events';
|
||||||
|
|
||||||
|
|
@ -45,19 +46,19 @@ export default ({
|
||||||
messageHeadline: '',
|
messageHeadline: '',
|
||||||
type: ''
|
type: ''
|
||||||
},
|
},
|
||||||
headerAnswers: null
|
cmsClientHeader: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
imageSrc() {
|
imageSrc() {
|
||||||
return this.headerAnswers ? this.headerAnswers.AnswerImageUrl : '';
|
return this.cmsClientHeader ? this.cmsClientHeader.imageUrl : '';
|
||||||
},
|
},
|
||||||
altText() {
|
altText() {
|
||||||
return this.headerAnswers ? this.headerAnswers.AltText : '';
|
return this.cmsClientHeader ? this.cmsClientHeader.altText : '';
|
||||||
},
|
},
|
||||||
logoBackgroundStyle() {
|
logoBackgroundStyle() {
|
||||||
return {
|
return {
|
||||||
'background-color': this.headerAnswers ? this.headerAnswers.HexCode : '#FFFFFF'
|
'background-color': this.cmsClientHeader ? this.cmsClientHeader.hexCode : '#FFFFFF'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -85,10 +86,31 @@ export default ({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setupHeader() {
|
setupHeader() {
|
||||||
const answers = this.getCmsContent(this.cmsWidgetName, 'Answers');
|
const overrideCmsHeaderAnswers = this.getCmsContent(this.cmsWidgetName, 'Answers');
|
||||||
if (Array.isArray(answers)) {
|
if (overrideCmsHeaderAnswers && Array.isArray(overrideCmsHeaderAnswers)) {
|
||||||
this.headerAnswers = answers.filter((x) => x.AccountNumber == this.mainStore.issConfig.parentAccountNumber)[0];
|
const { parentAccountNumber } = useMainStore().issConfig;
|
||||||
this.headerAnswers = !this.headerAnswers ? answers.filter((x) => x.AccountNumber === '0')[0] : this.headerAnswers;
|
let headerOverrideToUse = overrideCmsHeaderAnswers
|
||||||
|
.find((answer) => answer.AccountNumber === parentAccountNumber.toString());
|
||||||
|
if (headerOverrideToUse == null) {
|
||||||
|
headerOverrideToUse = overrideCmsHeaderAnswers
|
||||||
|
.find((answer) => answer.AccountNumber === '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headerOverrideToUse) {
|
||||||
|
this.cmsClientHeader = {
|
||||||
|
altText: headerOverrideToUse.AltText,
|
||||||
|
clientName: headerOverrideToUse.ClientName,
|
||||||
|
hexCode: headerOverrideToUse.HexCode,
|
||||||
|
imageId: headerOverrideToUse.ImageId,
|
||||||
|
imageUrl: headerOverrideToUse.AnswerImageUrl
|
||||||
|
};
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const { clientHeader } = useMainStore().issConfig;
|
||||||
|
if (clientHeader) {
|
||||||
|
this.cmsClientHeader = clientHeader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,9 @@ export default {
|
||||||
const pageData = useMainStore().pageData(to.query.issPage);
|
const pageData = useMainStore().pageData(to.query.issPage);
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.setNotSeeingPreferShop(pageData[routerParams.NOT_SEEING_PREFERRED_SHOP]);
|
if (pageData && pageData[routerParams.NOT_SEEING_PREFERRED_SHOP]) {
|
||||||
|
vm.setNotSeeingPreferShop(pageData[routerParams.NOT_SEEING_PREFERRED_SHOP]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ import globalRules from '@/constants/global-rules.js';
|
||||||
import baseFormMixin from '@/mixins/base-form-mixin.js';
|
import baseFormMixin from '@/mixins/base-form-mixin.js';
|
||||||
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
|
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
|
||||||
import routerParams from '@/router/router-constants/router-params';
|
import routerParams from '@/router/router-constants/router-params';
|
||||||
|
import issPageValues from '@/router/router-constants/issPage-values';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'coverage-statement',
|
name: 'coverage-statement',
|
||||||
|
|
@ -170,9 +171,23 @@ export default {
|
||||||
];
|
];
|
||||||
|
|
||||||
let pricingResults = [];
|
let pricingResults = [];
|
||||||
if (useMainStore().order.policy.policyLookupSuccessful) {
|
if (useMainStore().order.policy.policyLookupSuccessful && useMainStore().order.vehicle.policyVehicleId >= 0) {
|
||||||
pricingResults = await useMainStore().getPriceOrderItems(availableLineItems);
|
|
||||||
await useMainStore().getFinalDeductible();
|
await useMainStore().getFinalDeductible();
|
||||||
|
pricingResults = await useMainStore().getPriceOrderItems(availableLineItems)
|
||||||
|
.catch((err) => {
|
||||||
|
const errorPageData = {
|
||||||
|
errorData: err.data,
|
||||||
|
functionLocation: 'beforeRouteEnter',
|
||||||
|
functionName: 'getPriceOrderItems',
|
||||||
|
functionParameters: {
|
||||||
|
availableLineItems
|
||||||
|
},
|
||||||
|
routeFrom: from,
|
||||||
|
routeTo: to
|
||||||
|
};
|
||||||
|
useMainStore().updatePageData({ page: issPageValues.BAILOUT_PAGE, data: errorPageData });
|
||||||
|
next(`/?issPage=${issPageValues.BAILOUT_PAGE}`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
|
|
@ -342,6 +357,7 @@ export default {
|
||||||
async initializeComponent() {
|
async initializeComponent() {
|
||||||
useMainStore().updatePolicyITACFlag(this.verifiedITAC);
|
useMainStore().updatePolicyITACFlag(this.verifiedITAC);
|
||||||
if (this.policyLookupSuccessful
|
if (this.policyLookupSuccessful
|
||||||
|
&& useMainStore().order.vehicle.policyVehicleId >= 0
|
||||||
&& useMainStore().isClaimRegistrationRequired
|
&& useMainStore().isClaimRegistrationRequired
|
||||||
&& (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)) {
|
&& (this.coveredAndServicePriceAboveOrEqualDeductible || this.verifiedITAC)) {
|
||||||
await useMainStore().registerClaim()?.catch(() => {});
|
await useMainStore().registerClaim()?.catch(() => {});
|
||||||
|
|
|
||||||
|
|
@ -64,12 +64,10 @@ export default {
|
||||||
|
|
||||||
if (resp?.data.active && resp?.data.accountName.length > 0) {
|
if (resp?.data.active && resp?.data.accountName.length > 0) {
|
||||||
if (resp.data.authentication === 'RSAToken') {
|
if (resp.data.authentication === 'RSAToken') {
|
||||||
const token = queryStringParams.token;
|
const { token, signature } = queryStringParams;
|
||||||
const signature = queryStringParams.signature;
|
|
||||||
|
|
||||||
const vsigResp = await validateISSClientSignature(clientTag, token, signature);
|
const vsigResp = await validateISSClientSignature(clientTag, token, signature);
|
||||||
this.mainStore.issConfig.isAuthenticated = vsigResp?.data?.valid ?? false;
|
|
||||||
|
|
||||||
|
this.mainStore.issConfig.isAuthenticated = vsigResp?.data?.valid ?? false;
|
||||||
if (this.mainStore.issConfig.isAuthenticated) {
|
if (this.mainStore.issConfig.isAuthenticated) {
|
||||||
authorized = true;
|
authorized = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ export default {
|
||||||
if (vehicleLookupResponse.status === 404) {
|
if (vehicleLookupResponse.status === 404) {
|
||||||
this.mainStore.resetVehicleState();
|
this.mainStore.resetVehicleState();
|
||||||
useMainStore().updateVehicle({
|
useMainStore().updateVehicle({
|
||||||
policyVehicleId: vehicle.fleetUnitNumber,
|
policyVehicleId: vehicle.id,
|
||||||
carId: '0',
|
carId: '0',
|
||||||
category: '',
|
category: '',
|
||||||
year: vehicle.vehicleYear || '',
|
year: vehicle.vehicleYear || '',
|
||||||
|
|
@ -202,7 +202,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
|
this.vehicleFromLookup = Object.assign(vehicleLookupResponse.data, {
|
||||||
policyVehicleId: vehicle.fleetUnitNumber,
|
policyVehicleId: vehicle.id,
|
||||||
vin: this.selectedVehicleVin,
|
vin: this.selectedVehicleVin,
|
||||||
noCoverage: this.noCoverageForSelectedVehicle,
|
noCoverage: this.noCoverageForSelectedVehicle,
|
||||||
deductible: this.deductibleForSelectedVehicle,
|
deductible: this.deductibleForSelectedVehicle,
|
||||||
|
|
|
||||||
44
src/layouts/review-page/review-block/review-block.spec.js
Normal file
44
src/layouts/review-page/review-block/review-block.spec.js
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Components
|
||||||
|
import reviewBlock from '@/layouts/review-page/review-block/review-block.vue';
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
|
|
||||||
|
// Mock fetchCmsContentForPage
|
||||||
|
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||||
|
fetchCmsContentForPage: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
methodToRun();
|
||||||
|
|
||||||
|
mountOptions.data = () => (
|
||||||
|
initialData
|
||||||
|
);
|
||||||
|
|
||||||
|
const wrapper = shallowMount(reviewBlock, mountOptions);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Review Content Block', () => {
|
||||||
|
test('Displays one new line of content for each element in the content prop.', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
headerCmsWidgetName: 'TestWidget',
|
||||||
|
content: ['a', 'b', 'c', 'd']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const contentLines = wrapper.findAll("[data-test='contentLine']");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(contentLines.length).toBe(4);
|
||||||
|
});
|
||||||
|
});
|
||||||
73
src/layouts/review-page/review-block/review-block.vue
Normal file
73
src/layouts/review-page/review-block/review-block.vue
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<div class="py-3">
|
||||||
|
<div class="d-flex">
|
||||||
|
<textBlock
|
||||||
|
:cmsWidgetName="headerCmsWidgetName"
|
||||||
|
:customText="customHeaderText"
|
||||||
|
typeStyle="body small bold dark"
|
||||||
|
:marginTopSizeOverride="0" />
|
||||||
|
<textLink
|
||||||
|
linkType="textSmall"
|
||||||
|
text="Edit"
|
||||||
|
class="ml-auto"
|
||||||
|
useLoadingModal
|
||||||
|
href="javascript:void(0)"
|
||||||
|
@click-event="linkClicked">
|
||||||
|
<template
|
||||||
|
v-if="editScreenReaderTextCmsWidgetName"
|
||||||
|
#after-text>
|
||||||
|
<span class="sr-only"> {{ screenReaderOnlyText }} </span>
|
||||||
|
</template>
|
||||||
|
</textLink>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="item in content"
|
||||||
|
:key="item"
|
||||||
|
class="small review-block-content"
|
||||||
|
data-test="contentLine"
|
||||||
|
v-html="item"></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,
|
||||||
|
textLink
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
headerCmsWidgetName: String,
|
||||||
|
customHeaderText: String,
|
||||||
|
// Specifically an array of strings.
|
||||||
|
content: Array,
|
||||||
|
editScreenReaderTextCmsWidgetName: String
|
||||||
|
},
|
||||||
|
emits: ['edit-clicked'],
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
screenReaderOnlyText() {
|
||||||
|
return this.getCmsContent(this.editScreenReaderTextCmsWidgetName, 'Text');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
linkClicked() {
|
||||||
|
this.$emit('edit-clicked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.review-block-content > ul) {
|
||||||
|
margin-bottom: 0rem;
|
||||||
|
}
|
||||||
|
.review-block-content {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
386
src/layouts/review-page/review-page.spec.js
Normal file
386
src/layouts/review-page/review-page.spec.js
Normal file
|
|
@ -0,0 +1,386 @@
|
||||||
|
// Components
|
||||||
|
import review from '@/layouts/review-page/review-page.vue';
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
|
import { useMainStore } from '@/store/index.js';
|
||||||
|
|
||||||
|
// Mock fetchCmsContentForPage
|
||||||
|
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||||
|
fetchCmsContentForPage: jest.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn().mockImplementation(() => ''),
|
||||||
|
setCmsContent: jest.fn()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const footerStub = {
|
||||||
|
render: () => {},
|
||||||
|
methods: {
|
||||||
|
updateButtonText: jest.fn()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadingModalStub = {
|
||||||
|
render: () => {},
|
||||||
|
methods: {
|
||||||
|
showModal: jest.fn(),
|
||||||
|
hideModal: jest.fn()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// mountOptions.global.mocks["$store"] = store;
|
||||||
|
|
||||||
|
mountOptions.global.stubs = {
|
||||||
|
siteFooter: footerStub,
|
||||||
|
loadingModal: loadingModalStub
|
||||||
|
};
|
||||||
|
|
||||||
|
methodToRun();
|
||||||
|
|
||||||
|
mountOptions.mixins = [mockMixin];
|
||||||
|
mountOptions.data = () => (
|
||||||
|
initialData
|
||||||
|
);
|
||||||
|
|
||||||
|
const wrapper = shallowMount(review, mountOptions);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const testingPinia = createTestingPinia({
|
||||||
|
initialState: {
|
||||||
|
main: {
|
||||||
|
order: {
|
||||||
|
vehicle: {
|
||||||
|
year: '2020',
|
||||||
|
make: 'Acura',
|
||||||
|
model: 'MDX',
|
||||||
|
style: '4 door sedan'
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: 2,
|
||||||
|
glassToReplace: ['dummy location value']
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: ['dummy part value'],
|
||||||
|
supportingItems: ['dummy supporting item'],
|
||||||
|
vaps: ['dummy vap']
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
address: 'address 1',
|
||||||
|
address2: 'address 2',
|
||||||
|
city: 'city',
|
||||||
|
state: 'state',
|
||||||
|
zipCode: 'zip code',
|
||||||
|
appointmentType: 'Mobile',
|
||||||
|
provider: {
|
||||||
|
providerNumber: 1,
|
||||||
|
address: {
|
||||||
|
streetAddress: 'provider address 1',
|
||||||
|
city: 'provider city',
|
||||||
|
state: 'provider state',
|
||||||
|
zipCode: 'provider zip code'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
date: 'date',
|
||||||
|
startTime: 'start',
|
||||||
|
endTime: 'end',
|
||||||
|
jobMinMinutes: '30',
|
||||||
|
jobMaxMinutes: '45'
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
firstName: 'first name',
|
||||||
|
lastName: 'last name',
|
||||||
|
emailAddress: 'builddigitaltest@safelite.com',
|
||||||
|
phoneNumber: '555-555-5555',
|
||||||
|
isSmsOptIn: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
useMainStore(testingPinia);
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Review Page', () => {
|
||||||
|
describe('arePagePrerequisitesValid', () => {
|
||||||
|
test('Returns true for baseline valid state', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(true);
|
||||||
|
});
|
||||||
|
test('Returns false for empty state', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order = {
|
||||||
|
vehicle: {
|
||||||
|
year: null,
|
||||||
|
make: null,
|
||||||
|
model: null,
|
||||||
|
style: null,
|
||||||
|
carId: null,
|
||||||
|
category: null,
|
||||||
|
vin: null,
|
||||||
|
imageUrl: null,
|
||||||
|
imageVifNumber: null,
|
||||||
|
imageColor: null,
|
||||||
|
registration: {
|
||||||
|
licensePlate: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
serviceLocation: {
|
||||||
|
address: null,
|
||||||
|
address2: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
zipCode: null,
|
||||||
|
zipCodeCtu: null,
|
||||||
|
appointmentType: null,
|
||||||
|
isVehicleProtected: null,
|
||||||
|
provider: {
|
||||||
|
providerNumber: null,
|
||||||
|
address: {
|
||||||
|
streetAddress: null,
|
||||||
|
city: null,
|
||||||
|
state: null,
|
||||||
|
zipCode: null,
|
||||||
|
zipCodeCtu: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
techNotes: null
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
firstName: null,
|
||||||
|
lastName: null,
|
||||||
|
emailAddress: null,
|
||||||
|
phoneNumber: null,
|
||||||
|
isSmsOptIn: null
|
||||||
|
},
|
||||||
|
damage: {
|
||||||
|
isRepair: null,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: null,
|
||||||
|
partQuestionAnswers: null,
|
||||||
|
moldingQuestionAnswers: null,
|
||||||
|
capabilityQuestionAnswers: null
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
glassParts: null,
|
||||||
|
supportingItems: null,
|
||||||
|
vaps: null,
|
||||||
|
serverData: null
|
||||||
|
},
|
||||||
|
payment: {
|
||||||
|
isInsurance: null,
|
||||||
|
insuranceCoverage: {
|
||||||
|
isVerified: null,
|
||||||
|
coverageStatus: null
|
||||||
|
},
|
||||||
|
parentAccountNumber: 0
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
date: null,
|
||||||
|
startTime: null,
|
||||||
|
endTime: null,
|
||||||
|
routeCode: null,
|
||||||
|
jobMaxMinutes: null,
|
||||||
|
jobMinMinutes: null
|
||||||
|
},
|
||||||
|
referralNumber: null,
|
||||||
|
referralSequenceNumber: null,
|
||||||
|
referralDate: null,
|
||||||
|
referralCorrelationId: null,
|
||||||
|
eon: null
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
describe('Damage requirements', () => {
|
||||||
|
test('Accepts null glassToReplace when is repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = true;
|
||||||
|
wrapper.vm.mainStore.order.damage.glassToReplace = null;
|
||||||
|
wrapper.vm.mainStore.order.damage.numberOfChips = 1;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(true);
|
||||||
|
});
|
||||||
|
test('Rejects 0 chips when repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = true;
|
||||||
|
wrapper.vm.mainStore.order.damage.numberOfChips = 0;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
test('Rejects null chips when repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = true;
|
||||||
|
wrapper.vm.mainStore.order.damage.numberOfChips = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
test('Accepts null chips when not repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = false;
|
||||||
|
wrapper.vm.mainStore.order.damage.numberOfChips = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(true);
|
||||||
|
});
|
||||||
|
test('Rejects empty glassToReplace when not repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = false;
|
||||||
|
wrapper.vm.mainStore.order.damage.glassToReplace = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
test('Rejects null glassToReplace when not repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = false;
|
||||||
|
wrapper.vm.mainStore.order.damage.glassToReplace = [];
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Package requirements', () => {
|
||||||
|
test('Accepts null glassParts when is repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = true;
|
||||||
|
wrapper.vm.mainStore.order.lineItems.glassParts = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(true);
|
||||||
|
});
|
||||||
|
test('Rejects null glassParts when not repair', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.damage.isRepair = false;
|
||||||
|
wrapper.vm.mainStore.order.lineItems.glassParts = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Service Location requirements', () => {
|
||||||
|
test('Accepts null provider address when mobile appointment', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Mobile';
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.provider.address = {};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(true);
|
||||||
|
});
|
||||||
|
test('Reject null provider address when non-mobile appointment', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Inshop';
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.provider.address = {};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
test('Accepts null service location address when non-mobile appointment', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Inshop';
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.address = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.address2 = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.zipCode = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.city = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.state = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(true);
|
||||||
|
});
|
||||||
|
test('Rejects null service location address when mobile appointment', () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent();
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.appointmentType = 'Mobile';
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.address = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.address2 = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.zipCode = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.city = null;
|
||||||
|
wrapper.vm.mainStore.order.serviceLocation.state = null;
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const isValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isValid).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,41 +1,134 @@
|
||||||
<template>
|
<template>
|
||||||
<Form
|
<Form
|
||||||
ref="theForm"
|
ref="theForm"
|
||||||
v-slot="{ meta }"
|
|
||||||
@submit="onSubmit"
|
@submit="onSubmit"
|
||||||
@invalidSubmit="onInvalidSubmit">
|
@invalidSubmit="onInvalidSubmit">
|
||||||
|
<!-- When customer-details is added: v-slot="{ meta }" -->
|
||||||
<div class="page-container-grouped-styles">
|
<div class="page-container-grouped-styles">
|
||||||
<div class="fade-on-route-transition position-relative">
|
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
<div class="main-content-container">
|
||||||
<div class="container-fluid pb-2 review">
|
<vehicleBanner
|
||||||
<p>Placeholder for review page</p>
|
cmsWidgetName="VehicleBannerWidget"
|
||||||
<siteFooter
|
class="mb-4"
|
||||||
ref="siteFooter"
|
:displayGenericVehicleImage="false" />
|
||||||
cmsWidgetName="SiteFooterWidget"
|
<textBlock
|
||||||
:isForwardActionDisabled="!meta.valid"
|
:customText="subHeaderTitle"
|
||||||
@ForwardClicked="navigateForward"
|
typeStyle="h5"
|
||||||
@backClicked="backButtonAction" />
|
justifyText="center"
|
||||||
|
margin="mt-1"
|
||||||
|
class="dark-header" />
|
||||||
|
<textBlock
|
||||||
|
:customText="subHeaderBody"
|
||||||
|
typeStyle="body"
|
||||||
|
justifyText="left"
|
||||||
|
class="mb-4"
|
||||||
|
margin="mt-0 mb-2" />
|
||||||
|
<buttonMain
|
||||||
|
ref="buttonMain"
|
||||||
|
:buttonText="forwardButtonText"
|
||||||
|
isPrimary
|
||||||
|
loaderColor="white"
|
||||||
|
class="mb-2 w-100"
|
||||||
|
@clickEvent="forwardButtonAction" />
|
||||||
|
<div>
|
||||||
|
<hr />
|
||||||
</div>
|
</div>
|
||||||
|
<textBlock
|
||||||
|
customText="Appointment Details"
|
||||||
|
typeStyle="label bold"
|
||||||
|
justifyText="justify-text-left"
|
||||||
|
margin="mt-0"
|
||||||
|
class="dark-header" />
|
||||||
|
<div class="px-4">
|
||||||
|
<vehicleReview
|
||||||
|
cmsWidgetName="VehicleReviewWidget"
|
||||||
|
:vehicle="vehicleInfo"
|
||||||
|
@editClicked="editVehicle" />
|
||||||
|
<hr class="my-0" />
|
||||||
|
<damageReview
|
||||||
|
cmsWidgetName="DamageReviewWidget"
|
||||||
|
damageLocationsWidgetName="DamageLocationsWidget"
|
||||||
|
:damage="damageInfo"
|
||||||
|
@editClicked="editDamage" />
|
||||||
|
<hr class="my-0" />
|
||||||
|
<servicePackageReview
|
||||||
|
ref="servicePackageReview"
|
||||||
|
servicePackageOptionsCmsName="ServicePackageTitle"
|
||||||
|
defaultPackageItemsCmsName="DefaultPackageItemDescriptions"
|
||||||
|
vapsItemsCmsName="VapsItemDescriptions"
|
||||||
|
:damage="damageInfo"
|
||||||
|
:lineItems="lineItems"
|
||||||
|
@editClicked="editServicePackage" />
|
||||||
|
<hr class="my-0" />
|
||||||
|
<serviceLocationReview
|
||||||
|
cmsWidgetName="ServiceLocationTitleWidget"
|
||||||
|
:serviceLocation="serviceLocationInfo"
|
||||||
|
@editClicked="editServiceLocation" />
|
||||||
|
<hr class="my-0" />
|
||||||
|
<scheduleReview
|
||||||
|
cmsWidgetName="ScheduleWidget"
|
||||||
|
:appointmentType="appointmentType"
|
||||||
|
@editClicked="editSchedule" />
|
||||||
|
<hr class="my-0" />
|
||||||
|
<customerReview
|
||||||
|
cmsWidgetName="CustomerReviewWidget"
|
||||||
|
:customer="customerInfo"
|
||||||
|
@editClicked="editCustomerDetails" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<hr class="my-0" />
|
||||||
|
</div>
|
||||||
|
<siteFooter
|
||||||
|
ref="siteFooter"
|
||||||
|
class="mt-5"
|
||||||
|
cmsWidgetName="SiteFooterWidget"
|
||||||
|
@ForwardClicked="forwardButtonAction"
|
||||||
|
@backClicked="backButtonAction" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Components
|
// Components
|
||||||
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
||||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||||
|
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
|
||||||
|
import buttonMain from '@/ux-components/button-main/button-main.vue';
|
||||||
|
import textBlock from '@/digital-components/text-block/text-block.vue';
|
||||||
|
|
||||||
|
import customerReview from '@/layouts/review-page/review-sections/customer-review/customer-review.vue';
|
||||||
|
import damageReview from '@/layouts/review-page/review-sections/damage-review/damage-review.vue';
|
||||||
|
import scheduleReview from '@/layouts/review-page/review-sections/schedule-review/schedule-review.vue';
|
||||||
|
import serviceLocationReview from '@/layouts/review-page/review-sections/service-location-review/service-location-review.vue';
|
||||||
|
import servicePackageReview from '@/layouts/review-page/review-sections/service-package-review/service-package-review.vue';
|
||||||
|
import vehicleReview from '@/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue';
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||||
|
import navigationScenarios from '@/router/router-constants/navigation-scenarios.js';
|
||||||
import settleAllPromises from '@/helpers/layout-helper';
|
import settleAllPromises from '@/helpers/layout-helper';
|
||||||
import { Form } from 'vee-validate';
|
|
||||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
|
||||||
|
// Validation
|
||||||
|
import { Form } from 'vee-validate';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'review-page',
|
name: 'review-page',
|
||||||
components: {
|
components: {
|
||||||
|
buttonMain,
|
||||||
|
customerReview,
|
||||||
|
damageReview,
|
||||||
|
scheduleReview,
|
||||||
|
servicePackageReview,
|
||||||
|
serviceLocationReview,
|
||||||
siteHeader,
|
siteHeader,
|
||||||
siteFooter,
|
siteFooter,
|
||||||
|
textBlock,
|
||||||
|
vehicleBanner,
|
||||||
|
vehicleReview,
|
||||||
// eslint-disable-next-line vue/no-reserved-component-names
|
// eslint-disable-next-line vue/no-reserved-component-names
|
||||||
Form
|
Form
|
||||||
},
|
},
|
||||||
|
|
@ -43,13 +136,13 @@ export default {
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||||
// Settle promises and get results
|
|
||||||
const promiseResultMap = [
|
const promiseResultMap = [
|
||||||
{
|
{
|
||||||
resultKey: 'cmsContent',
|
resultKey: 'cmsContent',
|
||||||
promise: cmsContentPromise
|
promise: cmsContentPromise
|
||||||
}];
|
}];
|
||||||
// use resultMap to populate layout content.
|
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
|
@ -61,23 +154,170 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
subHeaderTitle() {
|
||||||
|
return this.getCmsContent('SiteSubHeaderWidget', 'HeaderText');
|
||||||
|
},
|
||||||
|
subHeaderBody() {
|
||||||
|
return this.getCmsContent('SiteSubHeaderWidget', 'BodyText');
|
||||||
|
},
|
||||||
|
forwardButtonText() {
|
||||||
|
return this.getCmsContent('SiteFooterWidget', 'ForwardButtonText');
|
||||||
|
},
|
||||||
|
vehicleInfo() {
|
||||||
|
return useMainStore().vehicle;
|
||||||
|
},
|
||||||
|
damageInfo() {
|
||||||
|
return useMainStore().damage;
|
||||||
|
},
|
||||||
|
lineItems() {
|
||||||
|
return useMainStore().lineItems;
|
||||||
|
},
|
||||||
|
serviceLocationInfo() {
|
||||||
|
return useMainStore().order.serviceLocation;
|
||||||
|
},
|
||||||
|
appointmentType() {
|
||||||
|
return useMainStore().order.serviceLocation.appointmentType;
|
||||||
|
},
|
||||||
|
customerInfo() {
|
||||||
|
return useMainStore().order.customer;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
arePagePrerequisitesValid() {
|
||||||
|
// Vehicle
|
||||||
|
const { vehicle } = useMainStore().order;
|
||||||
|
const vehicleReqs = !!(vehicle.year && vehicle.make && vehicle.model && vehicle.style);
|
||||||
|
|
||||||
|
// Damage
|
||||||
|
const { damage } = useMainStore().order;
|
||||||
|
const damageReqs = !!(
|
||||||
|
(damage.isRepair && damage.numberOfChips)
|
||||||
|
|| (!damage.isRepair && damage.glassToReplace?.length)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Service Package
|
||||||
|
const { lineItems } = useMainStore().order;
|
||||||
|
// damageReqs handles checking for damage, even though it is also required for this section.
|
||||||
|
const packageReqs = !!(
|
||||||
|
(damage.isRepair || lineItems.glassParts)
|
||||||
|
&& lineItems.supportingItems
|
||||||
|
);
|
||||||
|
|
||||||
|
// Service Location
|
||||||
|
const { serviceLocation } = useMainStore().order;
|
||||||
|
const mobileReqs = !!(
|
||||||
|
serviceLocation.address
|
||||||
|
&& serviceLocation.city
|
||||||
|
&& serviceLocation.state
|
||||||
|
&& serviceLocation.zipCode
|
||||||
|
);
|
||||||
|
|
||||||
|
const providerLocation = serviceLocation.provider.address;
|
||||||
|
const dropOffInshopReqs = !!(
|
||||||
|
providerLocation.streetAddress
|
||||||
|
&& providerLocation.city
|
||||||
|
&& providerLocation.state
|
||||||
|
&& providerLocation.zipCode
|
||||||
|
);
|
||||||
|
|
||||||
|
const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
|
||||||
|
const serviceLocationReqs =
|
||||||
|
(isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs);
|
||||||
|
|
||||||
|
// Schedule
|
||||||
|
const { schedule } = useMainStore().order;
|
||||||
|
const scheduleReqs = !!(
|
||||||
|
schedule.date
|
||||||
|
&& schedule.startTime
|
||||||
|
&& schedule.endTime
|
||||||
|
&& schedule.jobMaxMinutes
|
||||||
|
&& schedule.jobMinMinutes
|
||||||
|
);
|
||||||
|
|
||||||
|
// Customer
|
||||||
|
const { customer } = useMainStore().order;
|
||||||
|
const customerReqs = !!(
|
||||||
|
customer.firstName
|
||||||
|
&& customer.lastName
|
||||||
|
&& customer.phoneNumber
|
||||||
|
&& customer.emailAddress
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
vehicleReqs
|
||||||
|
&& damageReqs
|
||||||
|
&& packageReqs
|
||||||
|
&& serviceLocationReqs
|
||||||
|
&& scheduleReqs
|
||||||
|
&& customerReqs
|
||||||
|
);
|
||||||
|
},
|
||||||
backButtonAction() {
|
backButtonAction() {
|
||||||
this.$router.navigate(this.navigationScenarios.CLICKED_BACK, this.$route);
|
this.$router.navigate(navigationScenarios.CLICKED_BACK, this.$route);
|
||||||
|
},
|
||||||
|
editVehicle() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
navigationScenarios.CLICKED_VEHICLE_EDIT,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
|
editDamage() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
navigationScenarios.CLICKED_DAMAGE_EDIT,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
|
editServicePackage() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
navigationScenarios.CLICKED_SERVICE_PACKAGE_EDIT,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
|
editServiceLocation() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
|
editSchedule() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
navigationScenarios.CLICKED_SCHEDULE_EDIT,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
},
|
||||||
|
editCustomerDetails() {
|
||||||
|
this.$router.navigateWithoutSaving(
|
||||||
|
navigationScenarios.CLICKED_CUSTOMER_EDIT,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
},
|
},
|
||||||
forwardButtonAction() {
|
forwardButtonAction() {
|
||||||
|
this.navigateForward();
|
||||||
},
|
},
|
||||||
navigateForward() {
|
navigateForward() {
|
||||||
this.$router.navigate(
|
this.$router.navigateWithoutSaving(
|
||||||
this.navigationScenarios.CLICKED_FORWARD,
|
navigationScenarios.CLICKED_FORWARD,
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.review p{
|
$page-side-padding: 1.5rem;
|
||||||
margin-bottom:0.75rem;
|
|
||||||
|
.page-container-grouped-styles {
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.main-content-container {
|
||||||
|
padding: 0 1.5rem !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark-header {
|
||||||
|
color: $black;
|
||||||
|
line-height: 1.6;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
// Components
|
||||||
|
import customerReview from '@/layouts/review-page/review-sections/customer-review/customer-review.vue';
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
|
|
||||||
|
const testConstants = {
|
||||||
|
cms: {
|
||||||
|
header: {
|
||||||
|
text: 'Header'
|
||||||
|
},
|
||||||
|
sms: {
|
||||||
|
text: 'Sms'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
customer: {
|
||||||
|
firstName: 'First',
|
||||||
|
lastName: 'Last',
|
||||||
|
phoneNumber: '111-111-1111',
|
||||||
|
emailAddress: 'builddigitaltest@safelite.com',
|
||||||
|
isSmsOptIn: false
|
||||||
|
},
|
||||||
|
displayContent: {
|
||||||
|
fullName: 'First Last',
|
||||||
|
phoneNumber: '111-111-1111',
|
||||||
|
emailAddress: 'builddigitaltest@safelite.com',
|
||||||
|
smsOptIn: 'Sms'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateDefaultProps() {
|
||||||
|
return {
|
||||||
|
cmsWidgetName: 'CustomerWidget',
|
||||||
|
customer: {
|
||||||
|
firstName: testConstants.customer.firstName,
|
||||||
|
lastName: testConstants.customer.lastName,
|
||||||
|
phoneNumber: testConstants.customer.phoneNumber,
|
||||||
|
emailAddress: testConstants.customer.emailAddress,
|
||||||
|
isSmsOptIn: testConstants.customer.isSmsOptIn
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmsContent;
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
methodToRun();
|
||||||
|
|
||||||
|
mountOptions.data = () => (
|
||||||
|
initialData
|
||||||
|
);
|
||||||
|
|
||||||
|
mountOptions.mixins = [mockMixin];
|
||||||
|
|
||||||
|
const wrapper = shallowMount(customerReview, mountOptions);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cmsContent = {
|
||||||
|
CustomerWidget: {
|
||||||
|
HeaderText: testConstants.cms.header.text,
|
||||||
|
SubheaderText: testConstants.cms.sms.text
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Customer Review Block', () => {
|
||||||
|
test('Should display header text from cms', async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.header).toEqual(testConstants.cms.header.text);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should display sms text from cms', async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.smsOptIn).toEqual(testConstants.cms.sms.text);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should render correct display content', async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual([
|
||||||
|
testConstants.displayContent.fullName,
|
||||||
|
testConstants.displayContent.emailAddress,
|
||||||
|
testConstants.displayContent.phoneNumber,
|
||||||
|
testConstants.displayContent.smsOptIn
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<reviewBlock
|
||||||
|
editScreenReaderTextCmsWidgetName="EditContactDetailsScreenReader"
|
||||||
|
:customHeaderText="header"
|
||||||
|
:content="displayContent"
|
||||||
|
@editClicked="editClicked" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import reviewBlock from '@/layouts/review-page/review-block/review-block.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'customer-review',
|
||||||
|
components: {
|
||||||
|
reviewBlock
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
customer: Object
|
||||||
|
},
|
||||||
|
emits: ['edit-clicked'],
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
displayContent() {
|
||||||
|
return [this.fullName, this.email, this.phoneNumber, this.smsOptIn];
|
||||||
|
},
|
||||||
|
header() {
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
|
||||||
|
},
|
||||||
|
fullName() {
|
||||||
|
return `${this.customer?.firstName} ${this.customer?.lastName}`;
|
||||||
|
},
|
||||||
|
email() {
|
||||||
|
return this.customer?.emailAddress;
|
||||||
|
},
|
||||||
|
phoneNumber() {
|
||||||
|
return this.customer?.phoneNumber;
|
||||||
|
},
|
||||||
|
smsOptIn() {
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, 'SubheaderText');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editClicked() {
|
||||||
|
this.$emit('edit-clicked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,436 @@
|
||||||
|
// Components
|
||||||
|
import damageReview from '@/layouts/review-page/review-sections/damage-review/damage-review.vue';
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
|
import damageLocationsSelected from '@/constants/damage-locations-selected';
|
||||||
|
|
||||||
|
const testConstants = {
|
||||||
|
cmsConstants: {
|
||||||
|
widgetNames: {
|
||||||
|
header: 'DamageReviewWidget',
|
||||||
|
locations: 'DamageLocationsWidget',
|
||||||
|
driverDamages: 'DriverDamagesWidget',
|
||||||
|
passengerDamages: 'PassengerDamagesWidget'
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
text: 'Damage'
|
||||||
|
},
|
||||||
|
damageLocations: {
|
||||||
|
windshield: damageLocationsSelected.WINDSHIELD,
|
||||||
|
driver: damageLocationsSelected.DRIVER,
|
||||||
|
passenger: damageLocationsSelected.PASSENGER,
|
||||||
|
rear: damageLocationsSelected.REAR
|
||||||
|
},
|
||||||
|
damageNames: {
|
||||||
|
vent: damageLocationsSelected.VENT,
|
||||||
|
front: damageLocationsSelected.FRONT,
|
||||||
|
back: damageLocationsSelected.BACK,
|
||||||
|
quarter: damageLocationsSelected.QUARTER,
|
||||||
|
side: damageLocationsSelected.SIDEDOOR
|
||||||
|
},
|
||||||
|
locationCopy: {
|
||||||
|
windshield: 'Windshield copy',
|
||||||
|
driver: 'Driver copy',
|
||||||
|
passenger: 'Passenger copy',
|
||||||
|
rear: 'Rear copy'
|
||||||
|
},
|
||||||
|
damageCopy: {
|
||||||
|
vent: 'Vent copy',
|
||||||
|
front: 'Front copy',
|
||||||
|
back: 'Back copy',
|
||||||
|
quarter: 'Quarter copy',
|
||||||
|
side: 'Side copy'
|
||||||
|
},
|
||||||
|
imageId: '00000000-0000-0000-0000-000000000000'
|
||||||
|
},
|
||||||
|
makeBulletedList: (items) => {
|
||||||
|
let list = '<ul>';
|
||||||
|
items.forEach((item) => {
|
||||||
|
list += `<li>${item}</li>`;
|
||||||
|
});
|
||||||
|
list += '</ul>';
|
||||||
|
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
glassItems: {
|
||||||
|
windshield: {
|
||||||
|
glassLocation: damageLocationsSelected.WINDSHIELD,
|
||||||
|
glassName: damageLocationsSelected.SINGLE
|
||||||
|
},
|
||||||
|
rear: {
|
||||||
|
glassLocation: damageLocationsSelected.REAR,
|
||||||
|
glassName: damageLocationsSelected.STATIONARY
|
||||||
|
},
|
||||||
|
passengerItems: {
|
||||||
|
vent: {
|
||||||
|
glassLocation: damageLocationsSelected.PASSENGER,
|
||||||
|
glassName: damageLocationsSelected.VENT
|
||||||
|
},
|
||||||
|
front: {
|
||||||
|
glassLocation: damageLocationsSelected.PASSENGER,
|
||||||
|
glassName: damageLocationsSelected.FRONT
|
||||||
|
},
|
||||||
|
back: {
|
||||||
|
glassLocation: damageLocationsSelected.PASSENGER,
|
||||||
|
glassName: damageLocationsSelected.BACK
|
||||||
|
},
|
||||||
|
quarter: {
|
||||||
|
glassLocation: damageLocationsSelected.PASSENGER,
|
||||||
|
glassName: damageLocationsSelected.QUARTER
|
||||||
|
},
|
||||||
|
side: {
|
||||||
|
glassLocation: damageLocationsSelected.PASSENGER,
|
||||||
|
glassName: damageLocationsSelected.SIDEDOOR
|
||||||
|
}
|
||||||
|
},
|
||||||
|
driverItems: {
|
||||||
|
vent: {
|
||||||
|
glassLocation: damageLocationsSelected.DRIVER,
|
||||||
|
glassName: damageLocationsSelected.VENT
|
||||||
|
},
|
||||||
|
front: {
|
||||||
|
glassLocation: damageLocationsSelected.DRIVER,
|
||||||
|
glassName: damageLocationsSelected.FRONT
|
||||||
|
},
|
||||||
|
back: {
|
||||||
|
glassLocation: damageLocationsSelected.DRIVER,
|
||||||
|
glassName: damageLocationsSelected.BACK
|
||||||
|
},
|
||||||
|
quarter: {
|
||||||
|
glassLocation: damageLocationsSelected.DRIVER,
|
||||||
|
glassName: damageLocationsSelected.QUARTER
|
||||||
|
},
|
||||||
|
side: {
|
||||||
|
glassLocation: damageLocationsSelected.DRIVER,
|
||||||
|
glassName: damageLocationsSelected.SIDEDOOR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let cmsContent;
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
methodToRun();
|
||||||
|
|
||||||
|
mountOptions.data = () => (
|
||||||
|
initialData
|
||||||
|
);
|
||||||
|
|
||||||
|
mountOptions.mixins = [mockMixin];
|
||||||
|
|
||||||
|
const wrapper = shallowMount(damageReview, mountOptions);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
cmsContent = {
|
||||||
|
DamageReviewWidget: {
|
||||||
|
Text: testConstants.cmsConstants.header.text
|
||||||
|
},
|
||||||
|
DamageLocationsWidget: {
|
||||||
|
Answers: [
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.windshield,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.windshield,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.driver,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.driver,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: testConstants.cmsConstants.widgetNames.driverDamages
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.passenger,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.passenger,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: testConstants.cmsConstants.widgetNames.passengerDamages
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageLocations.rear,
|
||||||
|
Text: testConstants.cmsConstants.locationCopy.rear,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
DriverDamagesWidget: {
|
||||||
|
Answers: [
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.vent,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.front,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.front,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.back,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.back,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.quarter,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.side,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.side,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
PassengerDamagesWidget: {
|
||||||
|
Answers: [
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.vent,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.front,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.front,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.back,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.back,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.quarter,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: testConstants.cmsConstants.damageNames.side,
|
||||||
|
Text: testConstants.cmsConstants.damageCopy.side,
|
||||||
|
SubText: '',
|
||||||
|
ImageId: testConstants.cmsConstants.imageId,
|
||||||
|
Image: '',
|
||||||
|
SubWidgetName: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Damage Review Block', () => {
|
||||||
|
describe('Correctly assembles damage info into a display string', () => {
|
||||||
|
test('Shows windshield copy when windshield damage is included', async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
glassToReplace: [testConstants.glassItems.windshield]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.windshield
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Windshield copy is shown when order is a repair', async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: true,
|
||||||
|
numberOfChips: 2,
|
||||||
|
glassToReplace: []
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.windshield
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Rear windshield copy shows when rear damage is present', async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [testConstants.glassItems.rear]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.rear
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Driver side copy and items are shown when driver side damage is present', async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [
|
||||||
|
testConstants.glassItems.driverItems.back,
|
||||||
|
testConstants.glassItems.driverItems.front
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.driver,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.front,
|
||||||
|
testConstants.cmsConstants.damageCopy.back
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Passenger side copy and items are shown when passenger side damage is present', async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [
|
||||||
|
testConstants.glassItems.passengerItems.quarter,
|
||||||
|
testConstants.glassItems.passengerItems.vent,
|
||||||
|
testConstants.glassItems.passengerItems.side
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.passenger,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
testConstants.cmsConstants.damageCopy.side
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('All relevant sections are shown in order in multiglass scenario', async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
cmsWidgetName: testConstants.cmsConstants.widgetNames.header,
|
||||||
|
damageLocationsWidgetName: testConstants.cmsConstants.widgetNames.locations,
|
||||||
|
damage: {
|
||||||
|
isRepair: false,
|
||||||
|
numberOfChips: null,
|
||||||
|
glassToReplace: [
|
||||||
|
testConstants.glassItems.windshield,
|
||||||
|
testConstants.glassItems.rear,
|
||||||
|
testConstants.glassItems.driverItems.vent,
|
||||||
|
testConstants.glassItems.driverItems.front,
|
||||||
|
testConstants.glassItems.driverItems.back,
|
||||||
|
testConstants.glassItems.passengerItems.quarter,
|
||||||
|
testConstants.glassItems.passengerItems.back,
|
||||||
|
testConstants.glassItems.passengerItems.side
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual([
|
||||||
|
testConstants.cmsConstants.locationCopy.windshield,
|
||||||
|
testConstants.cmsConstants.locationCopy.driver,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.vent,
|
||||||
|
testConstants.cmsConstants.damageCopy.front,
|
||||||
|
testConstants.cmsConstants.damageCopy.back
|
||||||
|
]),
|
||||||
|
testConstants.cmsConstants.locationCopy.passenger,
|
||||||
|
testConstants.makeBulletedList([
|
||||||
|
testConstants.cmsConstants.damageCopy.back,
|
||||||
|
testConstants.cmsConstants.damageCopy.quarter,
|
||||||
|
testConstants.cmsConstants.damageCopy.side
|
||||||
|
]),
|
||||||
|
testConstants.cmsConstants.locationCopy.rear
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
<template>
|
||||||
|
<reviewBlock
|
||||||
|
editScreenReaderTextCmsWidgetName="EditDamageScreenReader"
|
||||||
|
:headerCmsWidgetName="cmsWidgetName"
|
||||||
|
:content="displayContent"
|
||||||
|
@editClicked="editClicked" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import damageLocationsSelected from '@/constants/damage-locations-selected.js';
|
||||||
|
import reviewBlock from '@/layouts/review-page/review-block/review-block.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'damage-review',
|
||||||
|
components: {
|
||||||
|
reviewBlock
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
damageLocationsWidgetName: String,
|
||||||
|
damage: Object
|
||||||
|
},
|
||||||
|
emits: ['edit-clicked'],
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
displayContent() {
|
||||||
|
return [
|
||||||
|
...this.windshieldCopy,
|
||||||
|
...this.driverSideCopy,
|
||||||
|
...this.passengerSideCopy,
|
||||||
|
...this.rearCopy
|
||||||
|
];
|
||||||
|
},
|
||||||
|
hasWindshieldDamage() {
|
||||||
|
const windshieldPieces = this.getGlassPieces(damageLocationsSelected.WINDSHIELD);
|
||||||
|
|
||||||
|
return this.damage.isRepair || !!windshieldPieces?.length;
|
||||||
|
},
|
||||||
|
hasDriverSideDamage() {
|
||||||
|
const driverPieces = this.getGlassPieces(damageLocationsSelected.DRIVER);
|
||||||
|
|
||||||
|
return !!driverPieces?.length;
|
||||||
|
},
|
||||||
|
hasPassengerSideDamage() {
|
||||||
|
const passengerPieces = this.getGlassPieces(damageLocationsSelected.PASSENGER);
|
||||||
|
|
||||||
|
return !!passengerPieces?.length;
|
||||||
|
},
|
||||||
|
hasRearDamage() {
|
||||||
|
const rearPieces = this.getGlassPieces(damageLocationsSelected.REAR);
|
||||||
|
|
||||||
|
return !!rearPieces?.length;
|
||||||
|
},
|
||||||
|
windshieldCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.WINDSHIELD);
|
||||||
|
|
||||||
|
if (this.hasWindshieldDamage) {
|
||||||
|
return [answerContent?.Text];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
driverSideCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.DRIVER);
|
||||||
|
const damageAnswers = this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
|
const driverSideItems = this.getGlassPieces(damageLocationsSelected.DRIVER);
|
||||||
|
const damageAnswersOnOrder = damageAnswers?.filter((answer) =>
|
||||||
|
driverSideItems?.some((glassPiece) => answer.Name === glassPiece.glassName));
|
||||||
|
|
||||||
|
if (this.hasDriverSideDamage) {
|
||||||
|
return [
|
||||||
|
answerContent?.Text,
|
||||||
|
this.generateBulletedListFromAnswers(damageAnswersOnOrder)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
passengerSideCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.PASSENGER);
|
||||||
|
const damageAnswers = this.getAnswersNullSafe(answerContent?.SubWidgetName);
|
||||||
|
const passengerSideItems = this.getGlassPieces(damageLocationsSelected.PASSENGER);
|
||||||
|
const damageAnswersOnOrder = damageAnswers?.filter((answer) =>
|
||||||
|
passengerSideItems?.some((glassPiece) => answer.Name === glassPiece.glassName));
|
||||||
|
|
||||||
|
if (this.hasPassengerSideDamage) {
|
||||||
|
return [
|
||||||
|
answerContent?.Text,
|
||||||
|
this.generateBulletedListFromAnswers(damageAnswersOnOrder)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
rearCopy() {
|
||||||
|
const answerContent = this.getLocationAnswer(damageLocationsSelected.REAR);
|
||||||
|
|
||||||
|
if (this.hasRearDamage) {
|
||||||
|
return [answerContent?.Text];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
locationAnswers() {
|
||||||
|
return this.getAnswersNullSafe(this.damageLocationsWidgetName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editClicked() {
|
||||||
|
this.$emit('edit-clicked');
|
||||||
|
},
|
||||||
|
getAnswersNullSafe(widgetName) {
|
||||||
|
const rawAnswers = this.getCmsContent(widgetName, 'Answers');
|
||||||
|
|
||||||
|
return rawAnswers || [];
|
||||||
|
},
|
||||||
|
getLocationAnswer(damageLocation) {
|
||||||
|
return this.locationAnswers?.find((answer) => answer.Name === damageLocation);
|
||||||
|
},
|
||||||
|
getGlassPieces(damageLocation) {
|
||||||
|
return this.damage?.glassToReplace?.filter((item) => item.glassLocation === damageLocation);
|
||||||
|
},
|
||||||
|
generateBulletedListFromAnswers(answers) {
|
||||||
|
let list = '<ul>';
|
||||||
|
|
||||||
|
answers.forEach((answer) => {
|
||||||
|
list += `<li>${answer.Text}</li>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
list += '</ul>';
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<reviewBlock
|
||||||
|
editScreenReaderTextCmsWidgetName="EditAppointmentScreenReader"
|
||||||
|
:customHeaderText="headerText"
|
||||||
|
:content="displayContent"
|
||||||
|
@editClicked="editClicked" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import reviewBlock from '@/layouts/review-page/review-block/review-block.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'schedule-review',
|
||||||
|
components: {
|
||||||
|
reviewBlock
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
appointmentType: String
|
||||||
|
},
|
||||||
|
emits: ['edit-clicked'],
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
displayContent() {
|
||||||
|
return [
|
||||||
|
this.getCmsContent(this.cmsWidgetName, 'BodyText'),
|
||||||
|
this.getCmsContent(this.cmsWidgetName, 'BodyText2')
|
||||||
|
];
|
||||||
|
},
|
||||||
|
headerText() {
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, 'HeaderText');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editClicked() {
|
||||||
|
this.$emit('edit-clicked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
// Components
|
||||||
|
import serviceLocationReview from '@/layouts/review-page/review-sections/service-location-review/service-location-review.vue';
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||||
|
|
||||||
|
const cmsContent = {
|
||||||
|
ServiceLocationTitleWidget: {
|
||||||
|
Text: 'Title Text'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockMixin = {
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn((widgetName, cmsFieldName) => cmsContent?.[widgetName]?.[cmsFieldName] ?? '')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function generateDefaultProps() {
|
||||||
|
return {
|
||||||
|
cmsWidgetName: 'ServiceLocationTitleWidget',
|
||||||
|
serviceLocation: {
|
||||||
|
address: 'Mobile Address 1',
|
||||||
|
address2: 'Mobile Address 2',
|
||||||
|
city: 'Mobile City',
|
||||||
|
state: 'MO',
|
||||||
|
zipCode: '11111',
|
||||||
|
zipCodeCtu: '',
|
||||||
|
appointmentType: AppointmentTypeStrings.MOBILE,
|
||||||
|
isVehicleProtected: false,
|
||||||
|
provider: {
|
||||||
|
providerNumber: '',
|
||||||
|
address: {
|
||||||
|
streetAddress: 'Service Location Address',
|
||||||
|
city: 'Service Location City',
|
||||||
|
state: 'SL',
|
||||||
|
zipCode: '22222',
|
||||||
|
zipCodeCtu: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
methodToRun();
|
||||||
|
|
||||||
|
mountOptions.data = () => (
|
||||||
|
initialData
|
||||||
|
);
|
||||||
|
|
||||||
|
mountOptions.mixins = [mockMixin];
|
||||||
|
|
||||||
|
const wrapper = shallowMount(serviceLocationReview, mountOptions);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Service Location Review Block', () => {
|
||||||
|
test('Should render mobile address if mobile appointment', async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual([
|
||||||
|
'Mobile Address 1, Mobile Address 2, Mobile City, MO 11111'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should render service location address if inshop appointment.', async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
props.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP;
|
||||||
|
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual([
|
||||||
|
'Service Location Address, Service Location City, SL 22222'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should render service location address if drop-off appointment', async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
props.serviceLocation.appointmentType = AppointmentTypeStrings.DROP_OFF;
|
||||||
|
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual([
|
||||||
|
'Service Location Address, Service Location City, SL 22222'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Should not add comma or any text if address2 is null', async () => {
|
||||||
|
// Arrange
|
||||||
|
const props = generateDefaultProps();
|
||||||
|
props.serviceLocation.address2 = null;
|
||||||
|
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
...props
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toEqual(['Mobile Address 1, Mobile City, MO 11111']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
<template>
|
||||||
|
<reviewBlock
|
||||||
|
editScreenReaderTextCmsWidgetName="EditLocationScreenReader"
|
||||||
|
:headerCmsWidgetName="cmsWidgetName"
|
||||||
|
:content="displayContent"
|
||||||
|
@editClicked="editClicked" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||||
|
import reviewBlock from '@/layouts/review-page/review-block/review-block.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'service-location-review',
|
||||||
|
components: {
|
||||||
|
reviewBlock
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
serviceLocation: Object
|
||||||
|
},
|
||||||
|
emits: ['edit-clicked'],
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
displayContent() {
|
||||||
|
return [
|
||||||
|
`${this.addressInfo.address}${this.addressInfo.address2 ? ', ' : ''}${
|
||||||
|
this.addressInfo.address2
|
||||||
|
}, ${this.addressInfo.city}, ${this.addressInfo.state} ${this.addressInfo.zipCode}`
|
||||||
|
];
|
||||||
|
},
|
||||||
|
addressInfo() {
|
||||||
|
if (this.serviceLocation?.appointmentType === AppointmentTypeStrings.MOBILE) {
|
||||||
|
return {
|
||||||
|
address: this.serviceLocation?.address,
|
||||||
|
address2: this.serviceLocation?.address2 ?? '',
|
||||||
|
city: this.serviceLocation?.city,
|
||||||
|
state: this.serviceLocation?.state,
|
||||||
|
zipCode: this.serviceLocation?.zipCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
address: this.serviceLocation?.provider?.address?.streetAddress,
|
||||||
|
address2: '',
|
||||||
|
city: this.serviceLocation?.provider?.address?.city,
|
||||||
|
state: this.serviceLocation?.provider?.address?.state,
|
||||||
|
zipCode: this.serviceLocation?.provider?.address?.zipCode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editClicked() {
|
||||||
|
this.$emit('edit-clicked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,969 @@
|
||||||
|
// Components
|
||||||
|
import servicePackageReview from '@/layouts/review-page/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';
|
||||||
|
|
||||||
|
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 defense 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 DEFENSE',
|
||||||
|
description: null,
|
||||||
|
partType: 'RAIN DEFENSE',
|
||||||
|
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(wrapper) {
|
||||||
|
wrapper.vm.initializeComponent({
|
||||||
|
wipers: [testConstants.parts.frontWiperPart],
|
||||||
|
rainDefense: 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(wrapper);
|
||||||
|
|
||||||
|
// 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(wrapper);
|
||||||
|
|
||||||
|
// 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(wrapper);
|
||||||
|
|
||||||
|
// 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(wrapper);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
});
|
||||||
|
|
||||||
|
wrapper.vm.initializeComponent({
|
||||||
|
wipers: scenario.params.wiperResponse,
|
||||||
|
rainDefense: scenario.params.rainDefenseResponse
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.packageNameWidget).toEqual(iteration.expected.packageNameWidget);
|
||||||
|
expect(wrapper.vm.displayContent).toEqual(iteration.expected.displayContent);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
<template>
|
||||||
|
<reviewBlock
|
||||||
|
editScreenReaderTextCmsWidgetName="EditServiceTypeScreenReader"
|
||||||
|
:headerCmsWidgetName="packageNameWidget"
|
||||||
|
:content="displayContent"
|
||||||
|
@editClicked="editClicked" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import settleAllPromises from '@/helpers/layout-helper';
|
||||||
|
// import baseMixin from '@/mixins/base-mixin.js';
|
||||||
|
// import store from '@/store';
|
||||||
|
import reviewBlock from '@/layouts/review-page/review-block/review-block.vue';
|
||||||
|
import {
|
||||||
|
getHighestFullySatisfiedTier,
|
||||||
|
containsLineItemWithPartType
|
||||||
|
} from '@/helpers/service-package-helper.js';
|
||||||
|
// import { storeActions } from '@/constants/store-actions.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 ?? []),
|
||||||
|
...this.availableVaps
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
loadInitialData() {
|
||||||
|
/* const wipersPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
storeActions.GET_WIPERS,
|
||||||
|
{
|
||||||
|
serviceZipCode: store.getters.order.serviceLocation.zipCode,
|
||||||
|
carId: store.getters.vehicle.carId
|
||||||
|
},
|
||||||
|
'review'
|
||||||
|
);
|
||||||
|
const rainDefensePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
storeActions.GET_RAIN_DEFENSE,
|
||||||
|
null,
|
||||||
|
'review'
|
||||||
|
);
|
||||||
|
|
||||||
|
const promiseResultMap = [
|
||||||
|
{
|
||||||
|
resultKey: 'wipers',
|
||||||
|
promise: wipersPromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'rainDefense',
|
||||||
|
promise: rainDefensePromise
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return settleAllPromises(promiseResultMap); */
|
||||||
|
},
|
||||||
|
initializeComponent(apiResponses) {
|
||||||
|
const vapsFromApi = [...apiResponses.wipers, apiResponses.rainDefense];
|
||||||
|
|
||||||
|
this.availableVaps = vapsFromApi;
|
||||||
|
},
|
||||||
|
editClicked() {
|
||||||
|
this.$emit('edit-clicked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// Components
|
||||||
|
import vehicleReview from '@/layouts/review-page/review-sections/vehicle-review/vehicle-review.vue';
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
|
|
||||||
|
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||||
|
fetchCmsContentForPage: () => Promise.resolve('content')
|
||||||
|
}));
|
||||||
|
|
||||||
|
function getShallowMountedComponent(initialData = {}, methodToRun = () => {}) {
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
methodToRun();
|
||||||
|
|
||||||
|
mountOptions.data = () => (
|
||||||
|
initialData
|
||||||
|
);
|
||||||
|
|
||||||
|
const wrapper = shallowMount(vehicleReview, mountOptions);
|
||||||
|
wrapper.vm.setCmsContent = jest.fn();
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('Vehicle Review Block', () => {
|
||||||
|
test('Correctly assembles vehicle info into a display string', async () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper } = getShallowMountedComponent({
|
||||||
|
vehicle: {
|
||||||
|
year: '2019',
|
||||||
|
make: 'Honda',
|
||||||
|
model: 'Odyssey'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.displayContent).toStrictEqual(['2019 Honda Odyssey']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
<template>
|
||||||
|
<reviewBlock
|
||||||
|
editScreenReaderTextCmsWidgetName="EditVehicleScreenReader"
|
||||||
|
:headerCmsWidgetName="cmsWidgetName"
|
||||||
|
:content="displayContent"
|
||||||
|
@editClicked="editClicked" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import reviewBlock from '@/layouts/review-page/review-block/review-block.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'vehicle-review',
|
||||||
|
components: {
|
||||||
|
reviewBlock
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
vehicle: Object
|
||||||
|
},
|
||||||
|
emits: ['edit-clicked'],
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
displayContent() {
|
||||||
|
return [`${this.vehicle.year} ${this.vehicle.make} ${this.vehicle.model}`];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
editClicked() {
|
||||||
|
this.$emit('edit-clicked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -1,72 +1,8 @@
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
|
||||||
export async function getAlertReasons(ctu) {
|
export default async function getAlertReasons(ctu) {
|
||||||
const store = useMainStore();
|
const store = useMainStore();
|
||||||
const alertReasons = await store.getAlertReasonsByCtu(ctu);
|
const alertReasons = await store.getAlertReasonsByCtu(ctu);
|
||||||
|
|
||||||
return Promise.resolve(alertReasons);
|
return Promise.resolve(alertReasons);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calcDaysBetweenDates(dateString1, dateString2) {
|
|
||||||
const date1 = new Date(dateString1);
|
|
||||||
const date2 = new Date(dateString2);
|
|
||||||
const timeDifference = Math.abs(date2 - date1); // Calculate the time difference in milliseconds
|
|
||||||
return Math.ceil(timeDifference / (1000 * 60 * 60 * 24)); // Convert milliseconds to days
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertDateToDateString(date) {
|
|
||||||
// returns YYYY-MM-DD format
|
|
||||||
if (date instanceof Date !== true) return null;
|
|
||||||
return (
|
|
||||||
`${date.getFullYear()
|
|
||||||
}-${
|
|
||||||
(`0${date.getMonth() + 1}`).slice(-2)
|
|
||||||
}-${
|
|
||||||
(`0${date.getDate()}`).slice(-2)}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function convertDateStringToDate(dateString) {
|
|
||||||
// dateString must be YYYY-MM-DD format
|
|
||||||
if (typeof dateString !== 'string') return null;
|
|
||||||
const dateParts = dateString.split('-');
|
|
||||||
return new Date(dateParts[0], parseInt(dateParts[1], 10) - 1, dateParts[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function sumDateString(dateString, daysToAdd) {
|
|
||||||
// dateString must be YYYY-MM-DD format
|
|
||||||
if (typeof dateString !== 'string') return null;
|
|
||||||
const date = convertDateStringToDate(dateString);
|
|
||||||
date.setDate(date.getDate() + daysToAdd);
|
|
||||||
return convertDateToDateString(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function militaryToTwelveHourTime(timeString) {
|
|
||||||
// Expected input: "HH:MM"
|
|
||||||
if (typeof timeString !== 'string') return null;
|
|
||||||
let hours = parseInt(timeString.split(':')[0], 10);
|
|
||||||
const minutes = timeString.split(':')[1];
|
|
||||||
const meridianNotation = hours > 11 ? 'PM' : 'AM';
|
|
||||||
|
|
||||||
if (hours > 12) {
|
|
||||||
hours -= 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${hours}:${minutes} ${meridianNotation}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDisplayTextForDurationLength(durationMinimum, durationMaximum) {
|
|
||||||
const isLongAppointment = durationMaximum >= 120;
|
|
||||||
const isDurationRange = durationMinimum !== durationMaximum;
|
|
||||||
|
|
||||||
const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum;
|
|
||||||
const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum;
|
|
||||||
|
|
||||||
const durationText = isDurationRange
|
|
||||||
? `${adjustedMinimum} - ${adjustedMaximum}`
|
|
||||||
: adjustedMinimum;
|
|
||||||
|
|
||||||
const unitText = isLongAppointment ? 'hours' : 'minutes';
|
|
||||||
|
|
||||||
return `${durationText} ${unitText}`;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
import { getAlertReasons } from '@/layouts/schedule-page/helpers/schedule-helper';
|
import getAlertReasons from '@/layouts/schedule-page/helpers/schedule-helper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'location-alerts',
|
name: 'location-alerts',
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,6 @@ import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||||
import textBlock from '@/digital-components/text-block/text-block.vue';
|
import textBlock from '@/digital-components/text-block/text-block.vue';
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
import {
|
|
||||||
calcDaysBetweenDates,
|
|
||||||
convertDateStringToDate,
|
|
||||||
sumDateString
|
|
||||||
} from '@/layouts/schedule-page/helpers/schedule-helper';
|
|
||||||
import {
|
import {
|
||||||
AppointmentTypeStrings,
|
AppointmentTypeStrings,
|
||||||
GET_MOBILE_TIME_SLOTS,
|
GET_MOBILE_TIME_SLOTS,
|
||||||
|
|
@ -82,6 +77,7 @@ import {
|
||||||
PREMIUM_FEE_PART_TYPE
|
PREMIUM_FEE_PART_TYPE
|
||||||
} from '@/constants/schedule-constants.js';
|
} from '@/constants/schedule-constants.js';
|
||||||
import { fetchCmsContentForPage, splitCopyOnCMSPlaceHolder } from '@/helpers/cms-content-helper';
|
import { fetchCmsContentForPage, splitCopyOnCMSPlaceHolder } from '@/helpers/cms-content-helper';
|
||||||
|
import { calcDaysBetweenDates, convertDateStringToDate, sumDateString } from '@/helpers/date-helper';
|
||||||
import settleAllPromises from '@/helpers/layout-helper';
|
import settleAllPromises from '@/helpers/layout-helper';
|
||||||
import { Form, defineRule } from 'vee-validate';
|
import { Form, defineRule } from 'vee-validate';
|
||||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,7 @@ import {
|
||||||
PREMIUM_TIME_SLOT_ID_FLAG,
|
PREMIUM_TIME_SLOT_ID_FLAG,
|
||||||
PREMIUM_FEE_PART_TYPE
|
PREMIUM_FEE_PART_TYPE
|
||||||
} from '@/constants/schedule-constants';
|
} from '@/constants/schedule-constants';
|
||||||
import {
|
import { convertDateStringToDate, getDisplayTextForDurationLength, militaryToTwelveHourTime } from '@/helpers/date-helper';
|
||||||
convertDateStringToDate,
|
|
||||||
militaryToTwelveHourTime,
|
|
||||||
getDisplayTextForDurationLength
|
|
||||||
} from '@/layouts/schedule-page/helpers/schedule-helper';
|
|
||||||
import timeSlotModalListButton from './time-slot-modal-list-button/time-slot-modal-list-button.vue';
|
import timeSlotModalListButton from './time-slot-modal-list-button/time-slot-modal-list-button.vue';
|
||||||
|
|
||||||
const cmsWidgetFieldMappings = {
|
const cmsWidgetFieldMappings = {
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-qu
|
||||||
import textBlock from '@/digital-components/text-block/text-block.vue';
|
import textBlock from '@/digital-components/text-block/text-block.vue';
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
import { fetchCmsContentForPage, fetchGlobalCmsContent, updateCmsSiteHeader } from '@/helpers/cms-content-helper';
|
||||||
import settleAllPromises from '@/helpers/layout-helper';
|
import settleAllPromises from '@/helpers/layout-helper';
|
||||||
import { required, regex } from '@/helpers/validation-rules';
|
import { required, regex } from '@/helpers/validation-rules';
|
||||||
import errorMessages from '@/constants/error-messages';
|
import errorMessages from '@/constants/error-messages';
|
||||||
|
|
@ -226,19 +226,24 @@ export default {
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
// Call APIs
|
// Call APIs
|
||||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||||
|
const cmsGlobalSiteHeaderContentPromise = fetchGlobalCmsContent('iss-siteheader');
|
||||||
|
|
||||||
// Settle promises and get results
|
// Settle promises and get results
|
||||||
const promiseResultMap = [
|
const promiseResultMap = [
|
||||||
{
|
{
|
||||||
resultKey: 'cmsContent',
|
resultKey: 'cmsContent',
|
||||||
promise: cmsContentPromise
|
promise: cmsContentPromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'globalSiteHeaderCmsContent',
|
||||||
|
promise: cmsGlobalSiteHeaderContentPromise
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// use resultMap to populate layout content.
|
// use resultMap to populate layout content.
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
|
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
|
updateCmsSiteHeader(resultMap.globalSiteHeaderCmsContent);
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -317,7 +322,6 @@ export default {
|
||||||
this.navigateForward();
|
this.navigateForward();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
navigateForward() {
|
navigateForward() {
|
||||||
if (this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false) {
|
if (this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false) {
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
|
|
@ -354,7 +358,6 @@ export default {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getWelcomePageModelFromStore() {
|
getWelcomePageModelFromStore() {
|
||||||
return {
|
return {
|
||||||
policyNumber: this.mainStore.order.policy.policyNumber,
|
policyNumber: this.mainStore.order.policy.policyNumber,
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,6 @@ function navigate(
|
||||||
optionalParams = {},
|
optionalParams = {},
|
||||||
optionalPageData = {}
|
optionalPageData = {}
|
||||||
) {
|
) {
|
||||||
/*eslint-disable-line*/
|
|
||||||
if (!scenario) {
|
if (!scenario) {
|
||||||
window.console.error('No scenario provided. Please review the routing table.');
|
window.console.error('No scenario provided. Please review the routing table.');
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,14 @@ const navigationScenarios = Object.freeze({
|
||||||
CLICKED_FORWARD_WITH_TPA_DISABLED: 'CLICKED_FORWARD_WITH_TPA_DISABLED',
|
CLICKED_FORWARD_WITH_TPA_DISABLED: 'CLICKED_FORWARD_WITH_TPA_DISABLED',
|
||||||
CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: 'CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES',
|
CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES: 'CLICKED_FORWARD_WITH_POLICY_AND_VEHICLES',
|
||||||
|
|
||||||
|
// Review Page
|
||||||
|
CLICKED_CUSTOMER_EDIT: 'CLICKED_CUSTOMER_EDIT',
|
||||||
|
CLICKED_DAMAGE_EDIT: 'CLICKED_DAMAGE_EDIT',
|
||||||
|
CLICKED_SCHEDULE_EDIT: 'CLICKED_SCHEDULE_EDIT',
|
||||||
|
CLICKED_SERVICE_LOCATION_EDIT: 'CLICKED_SERVICE_LOCATION_EDIT',
|
||||||
|
CLICKED_SERVICE_PACKAGE_EDIT: 'CLICKED_SERVICE_PACKAGE_EDIT',
|
||||||
|
CLICKED_VEHICLE_EDIT: 'CLICKED_VEHICLE_EDIT',
|
||||||
|
|
||||||
// Bailout
|
// Bailout
|
||||||
CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT'
|
CLICKED_FORWARD_WITH_BAILOUT: 'CLICKED_FORWARD_WITH_BAILOUT'
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -609,6 +609,30 @@ const routingTable = () => [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD,
|
scenario: navigationScenarios.CLICKED_FORWARD,
|
||||||
destinationIssPageValue: issPageValues.PAYMENT_PAGE
|
destinationIssPageValue: issPageValues.PAYMENT_PAGE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_CUSTOMER_EDIT,
|
||||||
|
destinationIssPageValue: issPageValues.CONTACT_DETAILS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_DAMAGE_EDIT,
|
||||||
|
destinationIssPageValue: issPageValues.VEHICLE_DAMAGE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_SCHEDULE_EDIT,
|
||||||
|
destinationIssPageValue: issPageValues.SCHEDULE_PAGE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_SERVICE_LOCATION_EDIT,
|
||||||
|
destinationIssPageValue: issPageValues.SERVICE_LOCATION
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_SERVICE_PACKAGE_EDIT,
|
||||||
|
destinationIssPageValue: issPageValues.SERVICE_PACKAGES
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_VEHICLE_EDIT,
|
||||||
|
destinationIssPageValue: issPageValues.VEHICLE_SELECTION
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,28 @@ import applicationConfig from '@/constants/application-config';
|
||||||
import issPageValues from '@/router/router-constants/issPage-values';
|
import issPageValues from '@/router/router-constants/issPage-values';
|
||||||
import damageLocationsSelected from '@/constants/damage-locations-selected';
|
import damageLocationsSelected from '@/constants/damage-locations-selected';
|
||||||
import coverageStatuses from '@/constants/coverage-statuses';
|
import coverageStatuses from '@/constants/coverage-statuses';
|
||||||
import { deepEqual } from '@/helpers/object-helper';
|
|
||||||
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants';
|
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants';
|
||||||
import getDateDifferenceInDays from '@/helpers/date-helper';
|
import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper';
|
||||||
import endorsementOptions from '@/constants/endorsement-options';
|
// import endorsementOptions from '@/constants/endorsement-options';
|
||||||
|
|
||||||
const storeId = 'main';
|
const storeId = 'main';
|
||||||
|
|
||||||
|
function getDisplayTextForDurationLength(durationMinimum, durationMaximum) {
|
||||||
|
const isLongAppointment = durationMaximum >= 120;
|
||||||
|
const isDurationRange = durationMinimum !== durationMaximum;
|
||||||
|
|
||||||
|
const adjustedMinimum = isLongAppointment ? durationMinimum / 60 : durationMinimum;
|
||||||
|
const adjustedMaximum = isLongAppointment ? durationMaximum / 60 : durationMaximum;
|
||||||
|
|
||||||
|
const durationText = isDurationRange
|
||||||
|
? `${adjustedMinimum} - ${adjustedMaximum}`
|
||||||
|
: adjustedMinimum;
|
||||||
|
|
||||||
|
const unitText = isLongAppointment ? 'hours' : 'minutes';
|
||||||
|
|
||||||
|
return `${durationText} ${unitText}`;
|
||||||
|
}
|
||||||
|
|
||||||
function getTimeSlotsAdditionalEventData(
|
function getTimeSlotsAdditionalEventData(
|
||||||
provisionalTriggers,
|
provisionalTriggers,
|
||||||
zipCode,
|
zipCode,
|
||||||
|
|
@ -175,6 +190,7 @@ const getDefaultState = () => ({
|
||||||
issConfig: {
|
issConfig: {
|
||||||
clientName: 'Generic Insurance', // this is the default and will be overriden by the client's name
|
clientName: 'Generic Insurance', // this is the default and will be overriden by the client's name
|
||||||
clientDisplayName: 'Generic Insurance', // this is the default and will be overridden by the client's name or client display name.
|
clientDisplayName: 'Generic Insurance', // this is the default and will be overridden by the client's name or client display name.
|
||||||
|
clientHeader: {},
|
||||||
styleSheet: '', // Stylesheet used by the client.
|
styleSheet: '', // Stylesheet used by the client.
|
||||||
parentAccountNumber: 0, // Parent account number used by the client.
|
parentAccountNumber: 0, // Parent account number used by the client.
|
||||||
isCoverageEnabled: false, // Indicates if we should be calling coverage on this flow.
|
isCoverageEnabled: false, // Indicates if we should be calling coverage on this flow.
|
||||||
|
|
@ -202,7 +218,7 @@ export const useMainStore = defineStore({
|
||||||
lineItems: (state) => state.order.lineItems,
|
lineItems: (state) => state.order.lineItems,
|
||||||
payment: (state) => state.order.payment,
|
payment: (state) => state.order.payment,
|
||||||
policy: (state) => state.order.policy,
|
policy: (state) => state.order.policy,
|
||||||
hasAnyNonWindshieldGlassParts: (state) => !state.order.policy.isDamageGlassOnly,
|
hasAnyNonWindshieldGlassParts: (s) => !s.order.policy.isDamageGlassOnly,
|
||||||
isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
||||||
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
|
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
|
||||||
isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF,
|
isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF,
|
||||||
|
|
@ -251,6 +267,30 @@ export const useMainStore = defineStore({
|
||||||
requestTextUpdates: s.order.contactInfo.requestTextUpdates ?? false,
|
requestTextUpdates: s.order.contactInfo.requestTextUpdates ?? false,
|
||||||
notesForTechnician: s.order.contactInfo.notesForTechnician
|
notesForTechnician: s.order.contactInfo.notesForTechnician
|
||||||
}),
|
}),
|
||||||
|
scheduleDisplayText: (s) => {
|
||||||
|
const dateModel = convertDateStringToDate(s.order.schedule.date);
|
||||||
|
const readableDate = dateModel?.toLocaleDateString('en-us', {
|
||||||
|
weekday: 'long',
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric'
|
||||||
|
});
|
||||||
|
|
||||||
|
const readableStartTime = militaryToTwelveHourTime(s.order.schedule.startTime);
|
||||||
|
const readableEndTime = militaryToTwelveHourTime(s.order.schedule.endTime);
|
||||||
|
|
||||||
|
const readableDuration = getDisplayTextForDurationLength(
|
||||||
|
s.order.schedule.jobMinMinutes,
|
||||||
|
s.order.schedule.jobMaxMinutes
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
date: readableDate,
|
||||||
|
startTime: readableStartTime,
|
||||||
|
endTime: readableEndTime,
|
||||||
|
duration: readableDuration
|
||||||
|
};
|
||||||
|
},
|
||||||
experimentOrder: (state) => ({
|
experimentOrder: (state) => ({
|
||||||
issVehicleYear: state.order.vehicle.year,
|
issVehicleYear: state.order.vehicle.year,
|
||||||
issVehicleMake: state.order.vehicle.make,
|
issVehicleMake: state.order.vehicle.make,
|
||||||
|
|
@ -546,6 +586,7 @@ export const useMainStore = defineStore({
|
||||||
manualGlassNames: manualGlassNamesArray,
|
manualGlassNames: manualGlassNamesArray,
|
||||||
policyState: this.order.customer.address.state,
|
policyState: this.order.customer.address.state,
|
||||||
status: this.order.policy.status,
|
status: this.order.policy.status,
|
||||||
|
originalDeductible: this.order.originalDeductible,
|
||||||
currentDeductible: this.order.currentDeductible,
|
currentDeductible: this.order.currentDeductible,
|
||||||
noCoverage: this.order.policy.noCoverage,
|
noCoverage: this.order.policy.noCoverage,
|
||||||
isRepair: this.order.damage.isRepair,
|
isRepair: this.order.damage.isRepair,
|
||||||
|
|
@ -899,8 +940,7 @@ export const useMainStore = defineStore({
|
||||||
}
|
}
|
||||||
const ctuToUse = this.order.serviceLocation.zipCodeCtu;
|
const ctuToUse = this.order.serviceLocation.zipCodeCtu;
|
||||||
const availableLineItemsFormattedForRequest = getLineItemQueryStringForPricing(availableLineItems);
|
const availableLineItemsFormattedForRequest = getLineItemQueryStringForPricing(availableLineItems);
|
||||||
const { policy } = this.order;
|
const deductibleToUse = this.order.currentDeductible;
|
||||||
const deductibleToUse = this.damage.isRepair ? policy.deductible.repair : policy.deductible.replace;
|
|
||||||
|
|
||||||
let queryString =
|
let queryString =
|
||||||
`ParentAccountNumber=${this.order.accountNumber}`
|
`ParentAccountNumber=${this.order.accountNumber}`
|
||||||
|
|
@ -920,7 +960,7 @@ export const useMainStore = defineStore({
|
||||||
endpoint: `${endpoints.GetInsurancePriceOrderItems.url}?${queryString}`
|
endpoint: `${endpoints.GetInsurancePriceOrderItems.url}?${queryString}`
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return [];
|
throw error;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.data?.lineItems) {
|
if (response.data?.lineItems) {
|
||||||
|
|
@ -1400,8 +1440,8 @@ export const useMainStore = defineStore({
|
||||||
this.order.policy.endorsements = vehicle?.endorsements;
|
this.order.policy.endorsements = vehicle?.endorsements;
|
||||||
|
|
||||||
// TODO logic should be more complicated later on
|
// TODO logic should be more complicated later on
|
||||||
this.order.originalDeductible = parseFloat(vehicle.deductible);
|
this.order.originalDeductible = vehicle.deductible;
|
||||||
this.order.currentDeductible = parseFloat(vehicle.deductible);
|
this.order.currentDeductible = vehicle.deductible;
|
||||||
|
|
||||||
this.resetSupportingItemsState();
|
this.resetSupportingItemsState();
|
||||||
this.resetVapsState();
|
this.resetVapsState();
|
||||||
|
|
@ -1467,6 +1507,7 @@ export const useMainStore = defineStore({
|
||||||
resetISSConfigState() {
|
resetISSConfigState() {
|
||||||
this.issConfig.clientName = 'Generic Insurance';
|
this.issConfig.clientName = 'Generic Insurance';
|
||||||
this.issConfig.clientDisplayName = 'Generic Insurance';
|
this.issConfig.clientDisplayName = 'Generic Insurance';
|
||||||
|
this.issConfig.clientHeader = {};
|
||||||
this.issConfig.parentAccountNumber = 0;
|
this.issConfig.parentAccountNumber = 0;
|
||||||
this.issConfig.styleSheet = '';
|
this.issConfig.styleSheet = '';
|
||||||
this.issConfig.isCoverageEnabled = false;
|
this.issConfig.isCoverageEnabled = false;
|
||||||
|
|
@ -1592,11 +1633,9 @@ export const useMainStore = defineStore({
|
||||||
updateIsSafeliteProvider(isSafelite) {
|
updateIsSafeliteProvider(isSafelite) {
|
||||||
this.order.serviceLocation.IsSafeliteProvider = isSafelite;
|
this.order.serviceLocation.IsSafeliteProvider = isSafelite;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateDeductible(finalDeductible) {
|
updateDeductible(finalDeductible) {
|
||||||
this.order.currentDeductible = finalDeductible;
|
this.order.currentDeductible = finalDeductible;
|
||||||
},
|
},
|
||||||
|
|
||||||
savePartQuestionAnswers(partQuestionAnswersArray) {
|
savePartQuestionAnswers(partQuestionAnswersArray) {
|
||||||
// if part question answers have changed, reset subsequent question answers
|
// if part question answers have changed, reset subsequent question answers
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.partQuestionAnswers, 'result');
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.partQuestionAnswers, 'result');
|
||||||
|
|
@ -1639,7 +1678,6 @@ export const useMainStore = defineStore({
|
||||||
// Save new values
|
// Save new values
|
||||||
this.updateMoldingQuestionAnswers(moldingQuestionAnswersArray);
|
this.updateMoldingQuestionAnswers(moldingQuestionAnswersArray);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveCapabilityQuestionAnswers(capabilityQuestionAnswersArray) {
|
saveCapabilityQuestionAnswers(capabilityQuestionAnswersArray) {
|
||||||
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.capabilityQuestionAnswers, 'result');
|
const sortedPreviousResultsArray = sortArrayOfObjectsByPropertyValue(this.order.damage.capabilityQuestionAnswers, 'result');
|
||||||
const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswersArray, 'result');
|
const sortedCapabilityQuestionAnswersArray = sortArrayOfObjectsByPropertyValue(capabilityQuestionAnswersArray, 'result');
|
||||||
|
|
@ -1657,16 +1695,9 @@ export const useMainStore = defineStore({
|
||||||
this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray);
|
this.updateCapabilityQuestionAnswers(capabilityQuestionAnswersArray);
|
||||||
},
|
},
|
||||||
saveGlassParts(glassParts) {
|
saveGlassParts(glassParts) {
|
||||||
if (!deepEqual(glassParts, this.order.lineItems.glassParts)) {
|
|
||||||
this.resetServiceLocationAndDependencies();
|
|
||||||
}
|
|
||||||
this.order.lineItems.glassParts = glassParts;
|
this.order.lineItems.glassParts = glassParts;
|
||||||
},
|
},
|
||||||
saveSupportingItems(supportingItems) {
|
saveSupportingItems(supportingItems) {
|
||||||
if (!deepEqual(supportingItems, this.order.lineItems.supportingItems)) {
|
|
||||||
this.resetServiceLocationAndDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.order.lineItems.supportingItems = supportingItems;
|
this.order.lineItems.supportingItems = supportingItems;
|
||||||
},
|
},
|
||||||
saveSupportingItemsSuppressingStateResetting(supportingItems) {
|
saveSupportingItemsSuppressingStateResetting(supportingItems) {
|
||||||
|
|
|
||||||
|
|
@ -1758,6 +1758,7 @@ describe('Store', () => {
|
||||||
const policyState = getRandomString(2, 2);
|
const policyState = getRandomString(2, 2);
|
||||||
const status = getRandomString(6, 8);
|
const status = getRandomString(6, 8);
|
||||||
const currentDeductible = getRandomInt(0, 5000);
|
const currentDeductible = getRandomInt(0, 5000);
|
||||||
|
const originalDeductible = getRandomInt(0, 5000);
|
||||||
const noCoverage = getRandomBoolean();
|
const noCoverage = getRandomBoolean();
|
||||||
const isRepair = getRandomBoolean();
|
const isRepair = getRandomBoolean();
|
||||||
const policyNumber = getRandomString(10, 20);
|
const policyNumber = getRandomString(10, 20);
|
||||||
|
|
@ -1772,6 +1773,7 @@ describe('Store', () => {
|
||||||
store.order.referralCorrelationId = referralCorrelationId;
|
store.order.referralCorrelationId = referralCorrelationId;
|
||||||
store.issConfig.parentAccountNumber = accountNumber;
|
store.issConfig.parentAccountNumber = accountNumber;
|
||||||
store.order.currentDeductible = currentDeductible;
|
store.order.currentDeductible = currentDeductible;
|
||||||
|
store.order.originalDeductible = originalDeductible;
|
||||||
store.order.policy.noCoverage = noCoverage;
|
store.order.policy.noCoverage = noCoverage;
|
||||||
store.order.policy.status = status;
|
store.order.policy.status = status;
|
||||||
store.order.customer.address.state = policyState;
|
store.order.customer.address.state = policyState;
|
||||||
|
|
@ -1803,6 +1805,7 @@ describe('Store', () => {
|
||||||
policyState,
|
policyState,
|
||||||
status,
|
status,
|
||||||
currentDeductible,
|
currentDeductible,
|
||||||
|
originalDeductible,
|
||||||
noCoverage,
|
noCoverage,
|
||||||
isRepair,
|
isRepair,
|
||||||
policyNumber,
|
policyNumber,
|
||||||
|
|
@ -1837,6 +1840,7 @@ describe('Store', () => {
|
||||||
const policyState = getRandomString(2, 2);
|
const policyState = getRandomString(2, 2);
|
||||||
const status = getRandomString(6, 8);
|
const status = getRandomString(6, 8);
|
||||||
const currentDeductible = getRandomInt(0, 5000);
|
const currentDeductible = getRandomInt(0, 5000);
|
||||||
|
const originalDeductible = getRandomInt(0, 5000);
|
||||||
const noCoverage = getRandomBoolean();
|
const noCoverage = getRandomBoolean();
|
||||||
const isRepair = getRandomBoolean();
|
const isRepair = getRandomBoolean();
|
||||||
const endorsementAnswers = [
|
const endorsementAnswers = [
|
||||||
|
|
@ -1871,6 +1875,7 @@ describe('Store', () => {
|
||||||
store.order.referralCorrelationId = referralCorrelationId;
|
store.order.referralCorrelationId = referralCorrelationId;
|
||||||
store.issConfig.parentAccountNumber = accountNumber;
|
store.issConfig.parentAccountNumber = accountNumber;
|
||||||
store.order.currentDeductible = currentDeductible;
|
store.order.currentDeductible = currentDeductible;
|
||||||
|
store.order.originalDeductible = originalDeductible;
|
||||||
store.order.policy.noCoverage = noCoverage;
|
store.order.policy.noCoverage = noCoverage;
|
||||||
store.order.policy.status = status;
|
store.order.policy.status = status;
|
||||||
store.order.customer.address.state = policyState;
|
store.order.customer.address.state = policyState;
|
||||||
|
|
@ -1904,6 +1909,7 @@ describe('Store', () => {
|
||||||
policyState,
|
policyState,
|
||||||
status,
|
status,
|
||||||
currentDeductible,
|
currentDeductible,
|
||||||
|
originalDeductible,
|
||||||
noCoverage,
|
noCoverage,
|
||||||
isRepair,
|
isRepair,
|
||||||
policyNumber,
|
policyNumber,
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,12 @@ $limu-button-color: #A9E3E9;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
&.btn-override[aria-disabled="false"]{
|
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
|
||||||
&.btn-primary {
|
&.btn-primary {
|
||||||
background: $limu-button-color !important;
|
background: $limu-button-color !important;
|
||||||
color: $limu-button-text-color !important;
|
color: $limu-button-text-color !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
background: $limu-button-color !important;
|
background: $limu-button-color !important;
|
||||||
color: $limu-button-text-color !important;
|
color: $limu-button-text-color !important;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue