Just a draft update
This commit is contained in:
parent
279076b547
commit
d15798ce89
28 changed files with 1161 additions and 124 deletions
|
|
@ -14,5 +14,5 @@
|
||||||
@import "@/styles/common-error-styles.scss";
|
@import "@/styles/common-error-styles.scss";
|
||||||
@import "@/styles/common-animations.scss";
|
@import "@/styles/common-animations.scss";
|
||||||
@import "@/styles/shared-input-button-styles.scss";
|
@import "@/styles/shared-input-button-styles.scss";
|
||||||
@import "@/styles/client-customizations.scss"
|
@import "@/styles/client-customizations.scss";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
const damageCustomLabels = Object.freeze({
|
const damageCustomLabels = Object.freeze({
|
||||||
MATCH: 'match',
|
MATCH: 'match',
|
||||||
REAR_WINDOW: 'rear window',
|
REAR_WINDOW: 'rear window',
|
||||||
SIDE_WINDOW: 'side window',
|
SIDE_WINDOW: 'side window',
|
||||||
WINDSHIELD: 'windshield',
|
WINDSHIELD: 'windshield'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default damageCustomLabels;
|
export default damageCustomLabels;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
const damageLocationsCms = {
|
const damageLocationsCms = {
|
||||||
WINDSHIELD: "WINDSHIELD",
|
WINDSHIELD: "WINDSHIELD",
|
||||||
SIDEDOOR: "SIDEDOOR",
|
SIDEDOOR: "SIDEDOOR",
|
||||||
REARWINDOW: "REARWINDOW",
|
REARWINDOW: "REARWINDOW",
|
||||||
DRIVERSIDE: "DRIVERSIDE",
|
DRIVERSIDE: "DRIVERSIDE",
|
||||||
PASSENGERSIDE: "PASSENGERSIDE",
|
PASSENGERSIDE: "PASSENGERSIDE"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { damageLocationsCms };
|
export { damageLocationsCms };
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,21 @@
|
||||||
const damageLocationsSelected = {
|
const damageLocationsSelected = {
|
||||||
WINDSHIELD: "Windshield",
|
WINDSHIELD: "Windshield",
|
||||||
SIDEDOOR: "SideDoor",
|
SIDEDOOR: "SideDoor",
|
||||||
REARWINDOW: "RearWindow",
|
REARWINDOW: "RearWindow",
|
||||||
REPAIR: "Repair",
|
REPAIR: "Repair",
|
||||||
REPLACE: "Replace",
|
REPLACE: "Replace",
|
||||||
DRIVER: "Driver",
|
DRIVER: "Driver",
|
||||||
PASSENGER: "Passenger",
|
PASSENGER: "Passenger",
|
||||||
FRONT: "Front",
|
FRONT: "Front",
|
||||||
REAR: "Rear",
|
REAR: "Rear",
|
||||||
BACK: "Back",
|
BACK: "Back",
|
||||||
QUARTER: "Quarter",
|
QUARTER: "Quarter",
|
||||||
VENT: "Vent",
|
VENT: "Vent",
|
||||||
SINGLE: "Single",
|
SINGLE: "Single",
|
||||||
DRIVERSIDE: "DriverSide",
|
DRIVERSIDE: "DriverSide",
|
||||||
PASSENGERSIDE: "PassengerSide",
|
PASSENGERSIDE: "PassengerSide",
|
||||||
STATIONARY: "Stationary",
|
STATIONARY: "Stationary",
|
||||||
SLIDER: "Slider",
|
SLIDER: "Slider"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { damageLocationsSelected };
|
export { damageLocationsSelected };
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
const dynamicStrings = {
|
const dynamicStrings = {
|
||||||
GLOBAL_STATE: "globalState",
|
GLOBAL_STATE: "globalState",
|
||||||
CUSTOM: "custom",
|
CUSTOM: "custom",
|
||||||
ROUTER_LINK: "routerLink:",
|
ROUTER_LINK: "routerLink:",
|
||||||
MODAL_LINK: "modalLink"
|
MODAL_LINK: "modalLink"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { dynamicStrings };
|
export { dynamicStrings };
|
||||||
|
|
@ -18,8 +18,8 @@ const customMappings = {
|
||||||
{ key: "Passenger Back", transformedValue: "passenger side back door" },
|
{ key: "Passenger Back", transformedValue: "passenger side back door" },
|
||||||
{ key: "Passenger Vent", transformedValue: "passenger side vent glass" },
|
{ key: "Passenger Vent", transformedValue: "passenger side vent glass" },
|
||||||
{ key: "Passenger Quarter", transformedValue: "passenger side quarter panel" },
|
{ key: "Passenger Quarter", transformedValue: "passenger side quarter panel" },
|
||||||
{ key: "Passenger SlideDoor", transformedValue: "passenger side sliding door" },
|
{ key: "Passenger SlideDoor", transformedValue: "passenger side sliding door" }
|
||||||
],
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Gets an instance of a string where the dynamic portion of the text {custom:KeyName}
|
// Gets an instance of a string where the dynamic portion of the text {custom:KeyName}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,19 @@ const endpoints = {
|
||||||
GetPartFromCapabilityAnswer: {
|
GetPartFromCapabilityAnswer: {
|
||||||
url: "/parts/api/v1/parts/part-from-capability-answer",
|
url: "/parts/api/v1/parts/part-from-capability-answer",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
|
GetWipers: {
|
||||||
|
url: '/parts/api/v1/parts/wipers',
|
||||||
|
method: 'GET'
|
||||||
|
},
|
||||||
|
GetRainDefense: {
|
||||||
|
url: '/parts/api/v1/parts/rain-defense',
|
||||||
|
method: 'GET'
|
||||||
|
},
|
||||||
|
GetSupportingItems: {
|
||||||
|
url: '/parts/api/v1/parts/supporting-items',
|
||||||
|
method: 'POST'
|
||||||
|
},
|
||||||
GetVehicle: {
|
GetVehicle: {
|
||||||
url: "/vehicle/api/v1/vehicle/lookup",
|
url: "/vehicle/api/v1/vehicle/lookup",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
@ -64,20 +76,20 @@ const endpoints = {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
LookupVehicleByVin: {
|
LookupVehicleByVin: {
|
||||||
url: "/vehicle/api/v1/vehicle/lookup",
|
url: "/vehicle/api/v1/vehicle/lookup",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
LookupVinByAddress: {
|
LookupVinByAddress: {
|
||||||
url: "/vehicle/api/v1/vehicle/lookup-vin-by-address",
|
url: "/vehicle/api/v1/vehicle/lookup-vin-by-address",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
LookupVinByPlate: {
|
LookupVinByPlate: {
|
||||||
url: "/vehicle/api/v1/vehicle/lookup-vin-by-plate",
|
url: "/vehicle/api/v1/vehicle/lookup-vin-by-plate",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
InitializeSession: {
|
InitializeSession: {
|
||||||
url: "/analytics/api/v1/analytics/initialize",
|
url: "/analytics/api/v1/analytics/initialize",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
GetExperimentsByUser: {
|
GetExperimentsByUser: {
|
||||||
url: "/analytics/api/v1/analytics/get-experiments",
|
url: "/analytics/api/v1/analytics/get-experiments",
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ const errorMessages = {
|
||||||
DAMAGE_OPTION_REQUIRED: "Please select an option",
|
DAMAGE_OPTION_REQUIRED: "Please select an option",
|
||||||
|
|
||||||
POLICYHOLDER_FIRST_NAME_REQUIRED: "Please enter the policyholder first name",
|
POLICYHOLDER_FIRST_NAME_REQUIRED: "Please enter the policyholder first name",
|
||||||
POLICYHOLDER_LAST_NAME_REQUIRED: "Please enter the policyholder last name",
|
POLICYHOLDER_LAST_NAME_REQUIRED: "Please enter the policyholder last name"
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
const globalEvents = {
|
const globalEvents = {
|
||||||
Categories: {
|
Categories: {
|
||||||
GLOBAL_ALERT: "GLOBAL_ALERT",
|
GLOBAL_ALERT: "GLOBAL_ALERT"
|
||||||
},
|
},
|
||||||
SubCategories: {
|
SubCategories: {
|
||||||
PAGE_NOT_FOUND: "PAGE_NOT_FOUND",
|
PAGE_NOT_FOUND: "PAGE_NOT_FOUND"
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const globalEventTypes = {
|
const globalEventTypes = {
|
||||||
Success: "alert-success",
|
Success: "alert-success",
|
||||||
Warning: "alert-warning",
|
Warning: "alert-warning",
|
||||||
Info: "alert-info",
|
Info: "alert-info",
|
||||||
Danger: "alert-danger",
|
Danger: "alert-danger"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { globalEvents, globalEventTypes };
|
export { globalEvents, globalEventTypes };
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
const experimentUniverses = {
|
const experimentUniverses = {
|
||||||
ISS_FUNNEL: "ISSFunnel",
|
ISS_FUNNEL: "ISSFunnel"
|
||||||
};
|
};
|
||||||
|
|
||||||
const experimentSettings = {
|
const experimentSettings = {
|
||||||
GOOGLE_CUSTOM_DIMENSION_INDEX: "Google Custom Dimension Index",
|
GOOGLE_CUSTOM_DIMENSION_INDEX: "Google Custom Dimension Index"
|
||||||
};
|
};
|
||||||
|
|
||||||
const experimentTriggers = {
|
const experimentTriggers = {
|
||||||
SITE_ENTRY: "SiteEntry",
|
SITE_ENTRY: "SiteEntry",
|
||||||
PAGE_ENTRY: "PageEntry",
|
PAGE_ENTRY: "PageEntry"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { experimentUniverses, experimentSettings, experimentTriggers };
|
export { experimentUniverses, experimentSettings, experimentTriggers };
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export const headerKeys = {
|
export const headerKeys = {
|
||||||
EXPERIMENT: "X-Experiment-Data",
|
EXPERIMENT: "X-Experiment-Data"
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
const endpoints = {
|
const endpoints = {
|
||||||
GetRouteInfo: {
|
GetRouteInfo: {
|
||||||
url: "https://mockey.qa.sagaws.net/service/ISS/Content/RouteInfo",
|
url: "https://mockey.qa.sagaws.net/service/ISS/Content/RouteInfo",
|
||||||
method: "GET",
|
method: "GET"
|
||||||
},
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
8
src/constants/part-type-strings.js
Normal file
8
src/constants/part-type-strings.js
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
const partTypeStrings = {
|
||||||
|
FRONT_WIPER: 'FRONT WIPER',
|
||||||
|
REAR_WIPER: 'REAR WIPER',
|
||||||
|
RAIN_DEFENSE: 'RAIN DEFENSE',
|
||||||
|
RECALIBRATION: 'RECALIBRATION'
|
||||||
|
};
|
||||||
|
|
||||||
|
export { partTypeStrings };
|
||||||
|
|
@ -49,5 +49,5 @@ export const states = {
|
||||||
WA: "Washington",
|
WA: "Washington",
|
||||||
WV: "West Virginia",
|
WV: "West Virginia",
|
||||||
WI: "Wisconsin",
|
WI: "Wisconsin",
|
||||||
WY: "Wyoming",
|
WY: "Wyoming"
|
||||||
};
|
};
|
||||||
|
|
@ -34,7 +34,7 @@ const tintMap = {
|
||||||
{ name: "gray tint privacy", src: "Glass-NoShade-GrayTint.svg" },
|
{ name: "gray tint privacy", src: "Glass-NoShade-GrayTint.svg" },
|
||||||
|
|
||||||
// No shade or tint
|
// No shade or tint
|
||||||
{ name: "clear", src: "Glass-NoShade-NoTint.svg" },
|
{ name: "clear", src: "Glass-NoShade-NoTint.svg" }
|
||||||
],
|
],
|
||||||
|
|
||||||
windshield: [
|
windshield: [
|
||||||
|
|
@ -69,8 +69,8 @@ const tintMap = {
|
||||||
{ name: "gray tint privacy", src: "Windshield-NoShade-GrayTint.svg" },
|
{ name: "gray tint privacy", src: "Windshield-NoShade-GrayTint.svg" },
|
||||||
|
|
||||||
// No shade or tint
|
// No shade or tint
|
||||||
{ name: "clear", src: "Windshield-NoShade-NoTint.svg" },
|
{ name: "clear", src: "Windshield-NoShade-NoTint.svg" }
|
||||||
],
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Gets the tint image source string given the glass location, and the tint description (like 'Green Tint')
|
// Gets the tint image source string given the glass location, and the tint description (like 'Green Tint')
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ const vehicleCategories = {
|
||||||
COMMERCIALVAN: "COMMERCIAL VAN",
|
COMMERCIALVAN: "COMMERCIAL VAN",
|
||||||
SUV: "SUV",
|
SUV: "SUV",
|
||||||
MOTORHOME: "MOTOR HOME",
|
MOTORHOME: "MOTOR HOME",
|
||||||
SEMI: "SEMI",
|
SEMI: "SEMI"
|
||||||
};
|
};
|
||||||
|
|
||||||
export { vehicleCategories };
|
export { vehicleCategories };
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const vinLookupMethodSelections = Object.freeze({
|
const vinLookupMethodSelections = Object.freeze({
|
||||||
MANUALVIN: 'ManualVin',
|
MANUALVIN: 'ManualVin',
|
||||||
LICENSEPLATE: 'LicensePlate',
|
LICENSEPLATE: 'LicensePlate',
|
||||||
HOMEADDRESS: 'HomeAddress',
|
HOMEADDRESS: 'HomeAddress'
|
||||||
});
|
});
|
||||||
|
|
||||||
export {vinLookupMethodSelections};
|
export {vinLookupMethodSelections};
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
:buttonLabel="answer.buttonLabel"
|
:buttonLabel="answer.buttonLabel"
|
||||||
:buttonLabelSubCopy="answer.buttonLabelSubCopy"
|
:buttonLabelSubCopy="answer.buttonLabelSubCopy"
|
||||||
:buttonBodyCopy="answer.buttonBodyCopy"
|
:buttonBodyCopy="answer.buttonBodyCopy"
|
||||||
:buttonAuxillaryCopy="answer.buttonAuxillaryCopy"
|
:buttonAuxiliaryCopy="answer.buttonAuxiliaryCopy"
|
||||||
:buttonFooterCopy="answer.buttonFooterCopy"
|
:buttonFooterCopy="answer.buttonFooterCopy"
|
||||||
:buttonImage="answer.buttonImage"
|
:buttonImage="answer.buttonImage"
|
||||||
:buttonImageId="answer.buttonImageId"
|
:buttonImageId="answer.buttonImageId"
|
||||||
|
|
@ -195,7 +195,7 @@ export default {
|
||||||
altText: answer.altText ?? (answer.Name ? answer.Name : answer),
|
altText: answer.altText ?? (answer.Name ? answer.Name : answer),
|
||||||
buttonLabelSubCopy: answer.buttonLabelSubCopy ?? answer.SubText,
|
buttonLabelSubCopy: answer.buttonLabelSubCopy ?? answer.SubText,
|
||||||
buttonBodyCopy: answer.buttonBodyCopy ?? answer.buttonBodyCopy,
|
buttonBodyCopy: answer.buttonBodyCopy ?? answer.buttonBodyCopy,
|
||||||
buttonAuxillaryCopy: answer.buttonAuxillaryCopy ?? answer.buttonAuxillaryCopy,
|
buttonAuxiliaryCopy: answer.buttonAuxiliaryCopy ?? answer.buttonAuxiliaryCopy,
|
||||||
buttonFooterCopy: answer.buttonFooterCopy ?? answer.buttonFooterCopy,
|
buttonFooterCopy: answer.buttonFooterCopy ?? answer.buttonFooterCopy,
|
||||||
buttonImage: answer.buttonImage ?? answer.AnswerImageUrl,
|
buttonImage: answer.buttonImage ?? answer.AnswerImageUrl,
|
||||||
buttonImageId: answer.buttonImageId ?? answer.ImageId,
|
buttonImageId: answer.buttonImageId ?? answer.ImageId,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { dynamicStrings } from "@/constants/dynamic-strings";
|
import { dynamicStrings } from '@/constants/dynamic-strings';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
|
||||||
export function fetchCmsContentForPage(issPage) {
|
export function fetchCmsContentForPage(issPage) {
|
||||||
const store = useMainStore()
|
const store = useMainStore()
|
||||||
const clientName = store.issConfig.clientName;
|
const clientName = store.issConfig.clientName;
|
||||||
const accountNumber = store.issConfig.accountNumber;
|
const accountNumber = store.issConfig.accountNumber;
|
||||||
const clientOverride = (clientName.length > 0 && accountNumber > 0);
|
const clientOverride = (clientName.length > 0 && accountNumber > 0);
|
||||||
|
|
||||||
return store.getPageData(issPage)
|
return store.getPageData(issPage)
|
||||||
|
|
@ -18,7 +18,7 @@ export function fetchCmsContentForPage(issPage) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Else get the client override page.
|
// Else get the client override page.
|
||||||
const pageName = issPage + "_" + clientName.toLowerCase().replace(/ /g, "");
|
const pageName = issPage + '_' + clientName.toLowerCase().replace(/ /g, '');
|
||||||
|
|
||||||
return store.getPageData(pageName)
|
return store.getPageData(pageName)
|
||||||
.then(
|
.then(
|
||||||
|
|
@ -140,7 +140,12 @@ function findAndReplaceGlobalStateValues(widgetModel, widgetName) {
|
||||||
// This is a recursive function, it will call itself until it runs out of items to iterate on given the object.
|
// This is a recursive function, it will call itself until it runs out of items to iterate on given the object.
|
||||||
function processWidgetItemForReplacement(widgetModel, key) {
|
function processWidgetItemForReplacement(widgetModel, key) {
|
||||||
// If we have a string, and it needs to be replaced.
|
// If we have a string, and it needs to be replaced.
|
||||||
if (typeof widgetModel[key] === "string") {
|
if (typeof widgetModel[key] === 'string') {
|
||||||
|
widgetModel[key] = processIfStatements(
|
||||||
|
widgetModel[key],
|
||||||
|
dynamicStrings.GLOBAL_STATE,
|
||||||
|
getStoreValueFromString
|
||||||
|
);
|
||||||
if (widgetModel[key].includes(dynamicStrings.GLOBAL_STATE)) {
|
if (widgetModel[key].includes(dynamicStrings.GLOBAL_STATE)) {
|
||||||
widgetModel[key] = mapStringToState(widgetModel[key]);
|
widgetModel[key] = mapStringToState(widgetModel[key]);
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +157,7 @@ function processWidgetItemForReplacement(widgetModel, key) {
|
||||||
|
|
||||||
// If we have an object. array, etc
|
// If we have an object. array, etc
|
||||||
if (
|
if (
|
||||||
typeof widgetModel[key] === "object" &&
|
typeof widgetModel[key] === 'object' &&
|
||||||
Object.keys(widgetModel[key]).length
|
Object.keys(widgetModel[key]).length
|
||||||
) {
|
) {
|
||||||
Object.keys(widgetModel[key]).forEach((item) => {
|
Object.keys(widgetModel[key]).forEach((item) => {
|
||||||
|
|
@ -167,13 +172,13 @@ function processWidgetItemForReplacement(widgetModel, key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapStringToModal(str) {
|
function mapStringToModal(str) {
|
||||||
let startIndex = str.indexOf("{" + dynamicStrings.MODAL_LINK);
|
let startIndex = str.indexOf('{' + dynamicStrings.MODAL_LINK);
|
||||||
let linkToReplace = str.substring(startIndex, str.length);
|
let linkToReplace = str.substring(startIndex, str.length);
|
||||||
linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf("}") + 1);
|
linkToReplace = linkToReplace.substring(0, linkToReplace.indexOf('}') + 1);
|
||||||
|
|
||||||
let params = linkToReplace.substring((dynamicStrings.MODAL_LINK).length + 2, linkToReplace.length -1)
|
let params = linkToReplace.substring((dynamicStrings.MODAL_LINK).length + 2, linkToReplace.length -1)
|
||||||
let splitParams = params.split(",");
|
let splitParams = params.split(',');
|
||||||
let bodyText = '<a href="#!" data-bs-toggle="modal" data-bs-target="#' + splitParams[0] + '" aria-label="Modal window">' + splitParams[1] +'</a>'
|
let bodyText = '<a href="#!" data-bs-toggle="modal" data-bs-target="#' + splitParams[0] + '" aria-label="Modal window">' + splitParams[1] + '</a>';
|
||||||
|
|
||||||
return str.replace(linkToReplace, bodyText);
|
return str.replace(linkToReplace, bodyText);
|
||||||
}
|
}
|
||||||
|
|
@ -181,28 +186,22 @@ function mapStringToModal(str) {
|
||||||
// Function to convert a string, into a matching global state item.
|
// Function to convert a string, into a matching global state item.
|
||||||
function mapStringToState(str) {
|
function mapStringToState(str) {
|
||||||
// Pull all matches out of the string.
|
// Pull all matches out of the string.
|
||||||
const regexExp = new RegExp("{(.*?):(.*?)}", "g");
|
const regexExp = new RegExp('{(.*?):(.*?)}', 'g');
|
||||||
const regexMatches = [...str.matchAll(regexExp)];
|
const regexMatches = [...str.matchAll(regexExp)];
|
||||||
const globalStateMatches = regexMatches.filter(match => {
|
const globalStateMatches = regexMatches.filter(match => {
|
||||||
return match[1] === dynamicStrings.GLOBAL_STATE;
|
return match[1] === dynamicStrings.GLOBAL_STATE;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Our final string value that will be built from the matches.
|
// Our final string value that will be built from the matches.
|
||||||
let stringBuilder = "";
|
let stringBuilder = '';
|
||||||
|
|
||||||
for (const match of globalStateMatches) {
|
for (const match of globalStateMatches) {
|
||||||
// Reset store state for each match.
|
// Reset store state for each match.
|
||||||
let storeState = useMainStore();
|
const valueFromStore = getStoreValueFromString(match[2]);
|
||||||
|
if (!valueFromStore) {
|
||||||
for (const s of match[2].split(".")) {
|
return '';
|
||||||
if (storeState[s] != undefined) {
|
|
||||||
storeState = storeState[s];
|
|
||||||
} else {
|
|
||||||
return ""; // if we can't map our string to state data, return an empty string.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
const stringWithReplacement = str.replace(match[0], valueFromStore);
|
||||||
const stringWithReplacement = str.replace(match[0], storeState);
|
|
||||||
|
|
||||||
// If we still have values we need to substitute, call this function again.
|
// If we still have values we need to substitute, call this function again.
|
||||||
if (stringWithReplacement.includes(dynamicStrings.GLOBAL_STATE)) {
|
if (stringWithReplacement.includes(dynamicStrings.GLOBAL_STATE)) {
|
||||||
|
|
@ -216,6 +215,186 @@ function mapStringToState(str) {
|
||||||
return stringBuilder.trimStart();
|
return stringBuilder.trimStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStoreValueFromString(str) {
|
||||||
|
let storeOrStateObject = useMainStore();
|
||||||
|
for (const s of str.split('.')) {
|
||||||
|
if (s === 'getters') continue;
|
||||||
|
if (storeOrStateObject[s] != undefined) {
|
||||||
|
storeOrStateObject = storeOrStateObject[s];
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return storeOrStateObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////
|
||||||
|
// If Statement Processing Logic //
|
||||||
|
///////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive function - replaces all instances of if statements from the CMS that utilize the specified ifConditionKeyword
|
||||||
|
* @param {*} str string - Input string to be processed
|
||||||
|
* @param {*} ifConditionKeyword string - Defines which if statements to process ex: 'globalState'
|
||||||
|
* @param {*} replacePlaceholderCallback function - Callback to replace CMS placeholder values
|
||||||
|
* @returns The processed string
|
||||||
|
*/
|
||||||
|
export function processIfStatements(str, ifConditionKeyword, replacePlaceholderCallback) {
|
||||||
|
const containsRelevantIfStatement = new RegExp('{if:' + ifConditionKeyword + ':.+?}', 'g').test(
|
||||||
|
str
|
||||||
|
);
|
||||||
|
if (!containsRelevantIfStatement) {
|
||||||
|
return str;
|
||||||
|
} else {
|
||||||
|
const ifStatementRegexExpression = getIfStatementRegexExpression();
|
||||||
|
const ifStatementRegexMatches = [...str.matchAll(ifStatementRegexExpression)];
|
||||||
|
const completeIfStatementArray = getAndFlagFirstNonNestedIfStatementWithKeyword(
|
||||||
|
ifStatementRegexMatches,
|
||||||
|
ifConditionKeyword
|
||||||
|
);
|
||||||
|
executeIfStatementAndSetProcessedStrings(
|
||||||
|
completeIfStatementArray,
|
||||||
|
replacePlaceholderCallback
|
||||||
|
);
|
||||||
|
const reconstructedPostProcessedString = joinProcessedRegexArray(ifStatementRegexMatches);
|
||||||
|
return processIfStatements(
|
||||||
|
reconstructedPostProcessedString,
|
||||||
|
ifConditionKeyword,
|
||||||
|
replacePlaceholderCallback
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAndFlagFirstNonNestedIfStatementWithKeyword(matches, ifConditionKeyword) {
|
||||||
|
let index = 0;
|
||||||
|
for (const match of matches) {
|
||||||
|
if (match.groups.isIfStatement && match.groups.ifConditionType === ifConditionKeyword) {
|
||||||
|
let interiorIndex = 0;
|
||||||
|
let nestedLevel = 0;
|
||||||
|
let elseStatementIndex = null;
|
||||||
|
for (const interiorMatch of matches.slice(index + 1)) {
|
||||||
|
if (interiorMatch.groups.isIfStatement) {
|
||||||
|
if (interiorMatch.groups.ifConditionType === ifConditionKeyword) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
nestedLevel++;
|
||||||
|
}
|
||||||
|
} else if (interiorMatch.groups.isElseStatement) {
|
||||||
|
if (!nestedLevel) {
|
||||||
|
elseStatementIndex = interiorIndex + 1;
|
||||||
|
}
|
||||||
|
} else if (interiorMatch.groups.isEndStatement) {
|
||||||
|
if (nestedLevel) {
|
||||||
|
nestedLevel--;
|
||||||
|
} else {
|
||||||
|
const ifStatementArray = matches.slice(index, index + interiorIndex + 2);
|
||||||
|
flagMatchesForProcessing(ifStatementArray, elseStatementIndex);
|
||||||
|
return ifStatementArray;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interiorIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function flagMatchesForProcessing(matches, elseStatementIndex) {
|
||||||
|
matches[0].isFlaggedForProcessing = true;
|
||||||
|
matches[matches.length - 1].isFlaggedForProcessing = true;
|
||||||
|
if (elseStatementIndex) {
|
||||||
|
matches[elseStatementIndex].isFlaggedForProcessing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinProcessedRegexArray(regexMatches) {
|
||||||
|
let processedString = '';
|
||||||
|
regexMatches.forEach((match) => {
|
||||||
|
const rawString = match[0];
|
||||||
|
processedString += match.groups.processedString ?? rawString;
|
||||||
|
});
|
||||||
|
return processedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeIfStatementAndSetProcessedStrings(ifStatementArray, replacePlaceholderCallback) {
|
||||||
|
const ifCondition = replacePlaceholderCallback(ifStatementArray[0].groups.ifCondition);
|
||||||
|
let isInsideDesiredBlock = ifCondition;
|
||||||
|
|
||||||
|
ifStatementArray.forEach((entry) => {
|
||||||
|
if (entry.groups.isElseStatement && entry.isFlaggedForProcessing) {
|
||||||
|
isInsideDesiredBlock = !ifCondition;
|
||||||
|
} else if (entry.groups.isEndStatement && entry.isFlaggedForProcessing) {
|
||||||
|
isInsideDesiredBlock = true;
|
||||||
|
}
|
||||||
|
setProcessedStringOnEntry(entry, isInsideDesiredBlock);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setProcessedStringOnEntry(entry, isInsideDesiredBlock) {
|
||||||
|
if (!isInsideDesiredBlock) {
|
||||||
|
entry.groups.processedString = '';
|
||||||
|
} else {
|
||||||
|
if (entry.groups.isIfStatement) {
|
||||||
|
entry.groups.processedString = entry.isFlaggedForProcessing
|
||||||
|
? entry.groups.ifTrailingString
|
||||||
|
: entry[0];
|
||||||
|
} else if (entry.groups.isElseStatement) {
|
||||||
|
entry.groups.processedString = entry.isFlaggedForProcessing
|
||||||
|
? entry.groups.elseTrailingString
|
||||||
|
: entry[0];
|
||||||
|
} else {
|
||||||
|
entry.groups.processedString = entry.isFlaggedForProcessing
|
||||||
|
? entry.groups.endTrailingString
|
||||||
|
: entry[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIfStatementRegexExpression() {
|
||||||
|
// Matches but does not capture:
|
||||||
|
// {if:...} or {else} or {end}
|
||||||
|
const anyLogicOperatorNonCapture = '(?:{(?:end|else|if:.*?)})';
|
||||||
|
// NOTE: ?<variableName> syntax stores the captured match like so: match.groups.variableName
|
||||||
|
const matchStartOfString =
|
||||||
|
'(?<processedString>^.+?)' + // Match and Capture all characters (lazy), cannot be empty
|
||||||
|
'(?=(?:{if))'; // Looks ahead but does not capture {if
|
||||||
|
const matchIfOperator =
|
||||||
|
'(?<isIfStatement>{if:)' + // Match & Capture {if:
|
||||||
|
'(?<ifConditionType>.*?):' + // Match all chars up to and including next ':' - Capture all chars up to ':'
|
||||||
|
'(?<ifCondition>.*?)}' + // Match all chars up to and including next '}' - Capture all chars up to '}'
|
||||||
|
'(?<ifTrailingString>.*?)' + // Match and Capture all characters (lazy), can be empty
|
||||||
|
'(?=' +
|
||||||
|
anyLogicOperatorNonCapture +
|
||||||
|
')'; // Looks ahead but does not capture the next logic operator
|
||||||
|
const matchElseOperator =
|
||||||
|
'(?<isElseStatement>{else})' + // Match & Capture {else}
|
||||||
|
'(?<elseTrailingString>.*?)' + // Match & Capture all characters (lazy), can be empty
|
||||||
|
'(?=' +
|
||||||
|
anyLogicOperatorNonCapture +
|
||||||
|
')'; // Looks ahead but does not capture the next logic operator
|
||||||
|
const matchEndOperator =
|
||||||
|
'(?<isEndStatement>{end})' + // Match & Capture {end}
|
||||||
|
'(?<endTrailingString>.*?)' + // Match & Capture all chracters (lazy), can be empty
|
||||||
|
'(?=' +
|
||||||
|
anyLogicOperatorNonCapture +
|
||||||
|
'|$)'; // Looks ahead but does not capture the next logic operator
|
||||||
|
// Combine all matching patterns, separated by 'or' pipes
|
||||||
|
return new RegExp(
|
||||||
|
matchStartOfString +
|
||||||
|
'|' +
|
||||||
|
matchIfOperator +
|
||||||
|
'|' +
|
||||||
|
matchElseOperator +
|
||||||
|
'|' +
|
||||||
|
matchEndOperator,
|
||||||
|
'g'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////
|
||||||
|
// End of If Statement Processing Logic //
|
||||||
|
//////////////////////////////////////////
|
||||||
|
|
||||||
export function doesCopyContainRouterLink(copy) {
|
export function doesCopyContainRouterLink(copy) {
|
||||||
return copy.includes(this.dynamicStrings.ROUTER_LINK);
|
return copy.includes(this.dynamicStrings.ROUTER_LINK);
|
||||||
}
|
}
|
||||||
|
|
@ -229,14 +408,14 @@ export function getRouterLinkRouteFromCopy(copy) {
|
||||||
// sample input: {routerLink:estimate,provide your VIN}
|
// sample input: {routerLink:estimate,provide your VIN}
|
||||||
// first split would return 'estimate,provide your VIN'
|
// first split would return 'estimate,provide your VIN'
|
||||||
// second split would return 'estimate'
|
// second split would return 'estimate'
|
||||||
return copy.split(":")[1].split(",")[0];
|
return copy.split(':')[1].split(',')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRouterLinkDisplayTextFromCopy(copy) {
|
export function getRouterLinkDisplayTextFromCopy(copy) {
|
||||||
// sample input: {routerLink:estimate,provide your VIN}
|
// sample input: {routerLink:estimate,provide your VIN}
|
||||||
// first split would return 'estimate,provide your VIN'
|
// first split would return 'estimate,provide your VIN'
|
||||||
// second split would return 'provide your VIN'
|
// second split would return 'provide your VIN'
|
||||||
return copy.split(":")[1].split(",")[1];
|
return copy.split(':')[1].split(',')[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returned from the CMS that has newlines will return blocks wrapped in
|
// Copy returned from the CMS that has newlines will return blocks wrapped in
|
||||||
|
|
@ -245,5 +424,5 @@ export function getRouterLinkDisplayTextFromCopy(copy) {
|
||||||
// attributes present
|
// attributes present
|
||||||
export function splitCMSCopyOnParagraphTag(copy) {
|
export function splitCMSCopyOnParagraphTag(copy) {
|
||||||
// filter removes empty strings that are a result of string.split with regex
|
// filter removes empty strings that are a result of string.split with regex
|
||||||
return copy.split(/(?:<p(?:.*?)>)|(?:<\/p>)/g).filter((paragraph) => paragraph !== "");
|
return copy.split(/(?:<p(?:.*?)>)|(?:<\/p>)/g).filter((paragraph) => paragraph !== '');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,13 @@ export default({
|
||||||
isDismissible: false,
|
isDismissible: false,
|
||||||
messageCopy: "",
|
messageCopy: "",
|
||||||
messageHeadline: "",
|
messageHeadline: "",
|
||||||
type: "",
|
type: ""
|
||||||
},
|
},
|
||||||
headerAnswers: null
|
headerAnswers: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
cmsWidgetName: String,
|
cmsWidgetName: String
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
imageSrc()
|
imageSrc()
|
||||||
|
|
@ -51,7 +51,7 @@ export default({
|
||||||
return {
|
return {
|
||||||
"background-color": this.headerAnswers ? this.headerAnswers.HexCode : "#FFFFFF"
|
"background-color": this.headerAnswers ? this.headerAnswers.HexCode : "#FFFFFF"
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
const answers = this.getCmsContent(this.cmsWidgetName, "Answers");
|
const answers = this.getCmsContent(this.cmsWidgetName, "Answers");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,361 @@
|
||||||
|
<template>
|
||||||
|
<buttonQuestion ref="buttonQuestion"
|
||||||
|
:answers="servicePackageAnswers"
|
||||||
|
:groupName="groupName"
|
||||||
|
buttonTypeString="servicePackageRadio"
|
||||||
|
:buttonTypeObject="servicePackageRadio"
|
||||||
|
v-model="selectedPackageName"
|
||||||
|
:validationRules="validationRules"
|
||||||
|
:isRequired="isRequired" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import buttonQuestion from '@/digital-components/button-question/button-question';
|
||||||
|
import baseMixin from '@/mixins/base-mixin.js';
|
||||||
|
import { processIfStatements } from '@/helpers/cms-content-helper';
|
||||||
|
import { damageLocationsSelected as glassLocations } from '@/constants/damage-locations-selected';
|
||||||
|
import servicePackageRadio from './service-package-radio/service-package-radio';
|
||||||
|
import { partTypeStrings } from '@/constants/part-type-strings';
|
||||||
|
const packageNames = {
|
||||||
|
TIER_ONE: 'TierOne',
|
||||||
|
TIER_TWO: 'TierTwo',
|
||||||
|
TIER_THREE: 'TierThree'
|
||||||
|
};
|
||||||
|
export default {
|
||||||
|
name: 'servicePackageQuestion',
|
||||||
|
props: {
|
||||||
|
cmsWidgetName: String,
|
||||||
|
groupName: String,
|
||||||
|
validationRules: String,
|
||||||
|
isRequired: Boolean,
|
||||||
|
availableLineItems: []
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
servicePackageRadio: servicePackageRadio,
|
||||||
|
selectedPackageName: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
availableLineItems() {
|
||||||
|
if (this.allGlassPartsAndSupportingItemsHavePrices(this.$store.lineItems)) {
|
||||||
|
this.selectDefaultPackage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedPackageName(newValue) {
|
||||||
|
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);
|
||||||
|
this.$emit('vapsItemsSelected', VapsProductsInSelectedPackage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
nullSafeAvailableLineItems() {
|
||||||
|
return this.availableLineItems ?? [];
|
||||||
|
},
|
||||||
|
servicePackageAnswers() {
|
||||||
|
if (!this.cmsWidgetName) return {};
|
||||||
|
const cmsAnswersContent = [
|
||||||
|
{
|
||||||
|
Name: 'EconomyServicePackage',
|
||||||
|
cmsWidgetName: 'EconomyServicePackage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'StandardServicePackage',
|
||||||
|
cmsWidgetName: 'StandardServicePackage'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: 'PremiumServicePackage',
|
||||||
|
cmsWidgetName: 'PremiumServicePackage'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
//This isn't mainly about header text, header text is just the canary in the coal mine
|
||||||
|
//Vue will often hit this code twice during a pageload. The first time without
|
||||||
|
//having yet loaded cms content- and so this just skips that first time
|
||||||
|
if (this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText') == '') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
console.log(this.getCmsContent(this.cmsWidgetName, 'HeaderText'));
|
||||||
|
|
||||||
|
const modifiedAnswers = [{
|
||||||
|
Answers: {
|
||||||
|
value: answer.Name,
|
||||||
|
buttonLabel: this.getHeaderTextFromCms(this.cmsWidgetName),
|
||||||
|
buttonLabelSubCopy: this.getSubheaderTextFromCms(this.cmsWidgetName),
|
||||||
|
buttonBodyCopy: this.getBodyTextFromCms(this.cmsWidgetName),
|
||||||
|
buttonAuxiliaryCopy: 'Aux Copy', //his.getPackagePriceString(answer.Name),
|
||||||
|
buttonFooterCopy: this.getFooterTextFromCms(this.cmsWidgetName),
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
return modifiedAnswers;
|
||||||
|
},
|
||||||
|
frontWipersApplicableForTierTwo() {
|
||||||
|
const frontWipersAreAvailable = this.lineItemsContainsPartType(
|
||||||
|
partTypeStrings.FRONT_WIPER
|
||||||
|
);
|
||||||
|
const isRepair = this.$store.order.damage.isRepair;
|
||||||
|
const glassToReplaceContainsWindshield = this.glassToReplaceContainsGlassLocation(
|
||||||
|
glassLocations.WINDSHIELD
|
||||||
|
);
|
||||||
|
if (frontWipersAreAvailable) {
|
||||||
|
if (isRepair) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (glassToReplaceContainsWindshield) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rearWiperApplicableForTierTwo() {
|
||||||
|
const rearWiperIsAvailable = this.lineItemsContainsPartType(partTypeStrings.REAR_WIPER);
|
||||||
|
return (
|
||||||
|
this.glassToReplaceContainsGlassLocation(glassLocations.REAR) &&
|
||||||
|
rearWiperIsAvailable
|
||||||
|
);
|
||||||
|
},
|
||||||
|
frontWipersApplicableForTierThree() {
|
||||||
|
const frontWipersAreAvailable = this.lineItemsContainsPartType(
|
||||||
|
partTypeStrings.FRONT_WIPER
|
||||||
|
);
|
||||||
|
return frontWipersAreAvailable;
|
||||||
|
},
|
||||||
|
rearWiperApplicableForTierThree() {
|
||||||
|
const rearWiperIsAvailable = this.lineItemsContainsPartType(partTypeStrings.REAR_WIPER);
|
||||||
|
const frontWipersAreAvailable = this.lineItemsContainsPartType(
|
||||||
|
partTypeStrings.FRONT_WIPER
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
rearWiperIsAvailable &&
|
||||||
|
(this.glassToReplaceContainsGlassLocation(glassLocations.REAR) ||
|
||||||
|
!frontWipersAreAvailable)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
rainDefenseApplicableForTierThree() {
|
||||||
|
if (
|
||||||
|
this.rearWiperApplicableForTierTwo &&
|
||||||
|
!this.frontWipersApplicableForTierTwo &&
|
||||||
|
this.frontWipersApplicableForTierThree
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
shouldDisplayTierTwoPackage() {
|
||||||
|
return this.frontWipersApplicableForTierTwo || this.rearWiperApplicableForTierTwo;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
processIfStatements,
|
||||||
|
getHeaderTextFromCms(cmsWidgetName) {
|
||||||
|
return this.getCmsContent(cmsWidgetName, 'HeaderText');
|
||||||
|
},
|
||||||
|
getSubheaderTextFromCms(cmsWidgetName) {
|
||||||
|
return this.getCmsContent(cmsWidgetName, 'SubheaderText');
|
||||||
|
},
|
||||||
|
getBodyTextFromCms(cmsWidgetName) {
|
||||||
|
const bodyText = this.getCmsContent(cmsWidgetName, "BodyText");
|
||||||
|
return this.processIfStatements(bodyText, "custom", this.getCustomValueFromString);
|
||||||
|
},
|
||||||
|
getFooterTextFromCms(cmsWidgetName) {
|
||||||
|
const footerText = this.getCmsContent(cmsWidgetName, "FooterText");
|
||||||
|
return this.processIfStatements(footerText, "custom", this.getCustomValueFromString);
|
||||||
|
},
|
||||||
|
getPackagePriceString(packageName) {
|
||||||
|
const formattedPriceFloat = parseFloat(this.getPackagePrice(packageName)).toFixed(2);
|
||||||
|
return 'As little as $' + formattedPriceFloat;
|
||||||
|
},
|
||||||
|
getPackagePrice(packageName) {
|
||||||
|
let priceFloat = this.isInsuranceSelected
|
||||||
|
? 0
|
||||||
|
: baseMixin.methods.getTierOnePackagePrice(
|
||||||
|
baseMixin.methods.filterOutFees(this.nullSafeAvailableLineItems)
|
||||||
|
);
|
||||||
|
if (packageName === packageNames.TIER_TWO) {
|
||||||
|
priceFloat += this.getTierTwoPackageVapsPrice();
|
||||||
|
} else if (packageName === packageNames.TIER_THREE) {
|
||||||
|
priceFloat += this.getTierThreePackageVapsPrice();
|
||||||
|
}
|
||||||
|
return priceFloat;
|
||||||
|
},
|
||||||
|
getTierTwoPackageVapsPrice() {
|
||||||
|
let vapsPrice = 0;
|
||||||
|
const priceFrontWipers = this.frontWipersApplicableForTierTwo;
|
||||||
|
const priceRearWipers = this.rearWiperApplicableForTierTwo;
|
||||||
|
this.nullSafeAvailableLineItems.forEach((item) => {
|
||||||
|
if (
|
||||||
|
(priceFrontWipers &&
|
||||||
|
item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER) ||
|
||||||
|
(priceRearWipers && item.partType.toUpperCase() === partTypeStrings.REAR_WIPER)
|
||||||
|
) {
|
||||||
|
vapsPrice += baseMixin.methods.getTotalLineItemPrice(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return vapsPrice;
|
||||||
|
},
|
||||||
|
getTierThreePackageVapsPrice() {
|
||||||
|
let vapsPrice = 0;
|
||||||
|
const priceFrontWipers = this.frontWipersApplicableForTierThree;
|
||||||
|
const priceRearWipers = this.rearWiperApplicableForTierThree;
|
||||||
|
const priceRainDefense = this.rainDefenseApplicableForTierThree;
|
||||||
|
this.nullSafeAvailableLineItems.forEach((item) => {
|
||||||
|
if (
|
||||||
|
(priceFrontWipers &&
|
||||||
|
item.partType.toUpperCase() === partTypeStrings.FRONT_WIPER) ||
|
||||||
|
(priceRearWipers &&
|
||||||
|
item.partType.toUpperCase() === partTypeStrings.REAR_WIPER) ||
|
||||||
|
(priceRainDefense &&
|
||||||
|
item.partType.toUpperCase() === partTypeStrings.RAIN_DEFENSE)
|
||||||
|
) {
|
||||||
|
vapsPrice += baseMixin.methods.getTotalLineItemPrice(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return vapsPrice;
|
||||||
|
},
|
||||||
|
selectDefaultPackage() {
|
||||||
|
const vapsFromStore = this.$store.lineItems.vaps;
|
||||||
|
let lowestTierForPackage = packageNames.TIER_ONE;
|
||||||
|
if (vapsFromStore?.length > 0) {
|
||||||
|
vapsFromStore.every((vapsItem) => {
|
||||||
|
let lowestTierForThisItem = this.getLowestTierForThisItem(vapsItem);
|
||||||
|
if (lowestTierForThisItem === packageNames.TIER_THREE) {
|
||||||
|
lowestTierForPackage = packageNames.TIER_THREE;
|
||||||
|
return false;
|
||||||
|
} else if (lowestTierForThisItem === packageNames.TIER_TWO) {
|
||||||
|
lowestTierForPackage = packageNames.TIER_TWO;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.selectedPackageName = lowestTierForPackage;
|
||||||
|
},
|
||||||
|
allGlassPartsAndSupportingItemsHavePrices(lineItems) {
|
||||||
|
if (lineItems?.glassParts) {
|
||||||
|
for (let i = 0; i < lineItems.glassParts.length; i++) {
|
||||||
|
if (this.priceIsNullOrZero(lineItems.glassParts[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lineItems?.supportingItems) {
|
||||||
|
for (let i = 0; i < lineItems.supportingItems.length; i++) {
|
||||||
|
if (this.priceIsNullOrZero(lineItems.supportingItems[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
priceIsNullOrZero(lineItem) {
|
||||||
|
return (
|
||||||
|
(lineItem.kitPrice == null || lineItem.kitPrice == 0) &&
|
||||||
|
(lineItem.laborAmount == null || lineItem.laborAmount == 0) &&
|
||||||
|
(lineItem.sellingPrice == null || lineItem.sellingPrice == 0)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getLowestTierForThisItem(vapsItem) {
|
||||||
|
let lowestTierForThisItem = null;
|
||||||
|
switch (vapsItem.partType) {
|
||||||
|
case partTypeStrings.FRONT_WIPER:
|
||||||
|
if (this.frontWipersApplicableForTierThree) {
|
||||||
|
lowestTierForThisItem = packageNames.TIER_THREE;
|
||||||
|
}
|
||||||
|
if (this.frontWipersApplicableForTierTwo) {
|
||||||
|
lowestTierForThisItem = packageNames.TIER_TWO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case partTypeStrings.REAR_WIPER:
|
||||||
|
if (this.rearWiperApplicableForTierThree) {
|
||||||
|
lowestTierForThisItem = packageNames.TIER_THREE;
|
||||||
|
}
|
||||||
|
if (this.rearWiperApplicableForTierTwo) {
|
||||||
|
lowestTierForThisItem = packageNames.TIER_TWO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case partTypeStrings.RAIN_DEFENSE:
|
||||||
|
if (this.rainDefenseApplicableForTierThree) {
|
||||||
|
lowestTierForThisItem = packageNames.TIER_THREE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return lowestTierForThisItem;
|
||||||
|
},
|
||||||
|
getVapsLineItemsForSelectedPackage(packageName) {
|
||||||
|
const vapsLineItemsForSelectedPackage = [];
|
||||||
|
if (packageName === packageNames.TIER_TWO) {
|
||||||
|
if (this.frontWipersApplicableForTierTwo) {
|
||||||
|
vapsLineItemsForSelectedPackage.push(
|
||||||
|
...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.rearWiperApplicableForTierTwo) {
|
||||||
|
vapsLineItemsForSelectedPackage.push(
|
||||||
|
...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (packageName === packageNames.TIER_THREE) {
|
||||||
|
if (this.frontWipersApplicableForTierThree) {
|
||||||
|
vapsLineItemsForSelectedPackage.push(
|
||||||
|
...this.getLineItemsContainingPartType(partTypeStrings.FRONT_WIPER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.rearWiperApplicableForTierThree) {
|
||||||
|
vapsLineItemsForSelectedPackage.push(
|
||||||
|
...this.getLineItemsContainingPartType(partTypeStrings.REAR_WIPER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (this.rainDefenseApplicableForTierThree) {
|
||||||
|
vapsLineItemsForSelectedPackage.push(
|
||||||
|
...this.getLineItemsContainingPartType(partTypeStrings.RAIN_DEFENSE)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vapsLineItemsForSelectedPackage;
|
||||||
|
},
|
||||||
|
getCustomValueFromString(str) {
|
||||||
|
switch (str) {
|
||||||
|
case 'isRecalibrationOnOrder':
|
||||||
|
return this.isRecalibrationOnOrder;
|
||||||
|
case 'frontWipersApplicableForTierTwo':
|
||||||
|
return this.frontWipersApplicableForTierTwo;
|
||||||
|
case 'rearWiperApplicableForTierTwo':
|
||||||
|
return this.rearWiperApplicableForTierTwo;
|
||||||
|
case 'frontWipersApplicableForTierThree':
|
||||||
|
return this.frontWipersApplicableForTierThree;
|
||||||
|
case 'rearWiperApplicableForTierThree':
|
||||||
|
return this.rearWiperApplicableForTierThree;
|
||||||
|
case 'rainDefenseApplicableForTierThree':
|
||||||
|
return this.rainDefenseApplicableForTierThree;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getLineItemsContainingPartType(partType) {
|
||||||
|
const partTypeMatches = this.nullSafeAvailableLineItems.filter(
|
||||||
|
(lineItem) => lineItem.partType.toUpperCase() === partType
|
||||||
|
);
|
||||||
|
return partTypeMatches;
|
||||||
|
},
|
||||||
|
lineItemsContainsPartType(partType) {
|
||||||
|
const partTypeMatches = this.getLineItemsContainingPartType(partType);
|
||||||
|
return !!partTypeMatches.length;
|
||||||
|
},
|
||||||
|
glassToReplaceContainsGlassLocation(glassLocation) {
|
||||||
|
const glassLocationMatches =
|
||||||
|
this.$store.order.damage.glassToReplace?.filter(
|
||||||
|
(glassToReplace) => glassToReplace.glassLocation === glassLocation
|
||||||
|
) ?? [];
|
||||||
|
return !!glassLocationMatches.length;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
buttonQuestion
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,267 @@
|
||||||
|
<template>
|
||||||
|
<baseInputButton v-bind="$props" @buttonClicked="handleAnswerChange" v-model="selectedValue">
|
||||||
|
<div class="package-label"
|
||||||
|
:class="[this.buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||||
|
for="testradio">
|
||||||
|
<div class="package-specs" style="max-height:1000px;">
|
||||||
|
<p class="m-0">
|
||||||
|
<span v-html="this.buttonLabel"></span>
|
||||||
|
<span class="pricing-info" v-html="this.buttonAuxiliaryCopy"></span>
|
||||||
|
</p>
|
||||||
|
<p class="sub-label m-0"
|
||||||
|
v-if="this.buttonLabelSubCopy"
|
||||||
|
v-html="this.buttonLabelSubCopy"></p>
|
||||||
|
<div class="hide-when-closed" style="display: block;">
|
||||||
|
<!-- Parse the body text containing <ul> with logic -->
|
||||||
|
<ul>
|
||||||
|
<li v-for="listItem in this.arrayOfListItemsFromBodyText" :key="listItem">
|
||||||
|
<!-- no textLink -->
|
||||||
|
<span v-if="!doesCopyContainTextLink(listItem)"
|
||||||
|
v-html="listItem"></span>
|
||||||
|
<!-- with textLink -->
|
||||||
|
<template v-else
|
||||||
|
v-for="copy in splitCopyOnCMSPlaceHolder(listItem)"
|
||||||
|
:key="copy">
|
||||||
|
<span v-if="!doesCopyContainTextLink(copy)" v-html="copy"></span>
|
||||||
|
<span v-else>
|
||||||
|
<textLink linkType="text"
|
||||||
|
:text="getRouterLinkDisplayTextFromCopy(copy)"
|
||||||
|
href="#!"
|
||||||
|
@click-event="
|
||||||
|
$emit('buttonEvent', {
|
||||||
|
eventName: 'openModal',
|
||||||
|
args: getRouterLinkRouteFromCopy(copy),
|
||||||
|
})
|
||||||
|
"
|
||||||
|
:data-bs-target="'#' + getRouterLinkRouteFromCopy(copy)"
|
||||||
|
aria-label="Modal window" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<!-- End of body text parsing -->
|
||||||
|
<div class="package-footer fw-bold caption ms-n6"
|
||||||
|
v-if="this.buttonFooterCopy"
|
||||||
|
v-html="this.buttonFooterCopy"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</baseInputButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import baseInputButton from '@/digital-components/base-input-button/base-input-button';
|
||||||
|
import textLink from '@/ux-components/text-link/text-link';
|
||||||
|
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin';
|
||||||
|
import {
|
||||||
|
getRouterLinkDisplayTextFromCopy,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
splitCopyOnCMSPlaceHolder,
|
||||||
|
doesCopyContainTextLink,
|
||||||
|
} from '@/helpers/cms-content-helper';
|
||||||
|
export default {
|
||||||
|
name: 'servicePackageRadio',
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
components: {
|
||||||
|
baseInputButton,
|
||||||
|
textLink
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
arrayOfListItemsFromBodyText() {
|
||||||
|
return this.getArrayOfListItemsFromRawCmsCopy(this.buttonBodyCopy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getRouterLinkDisplayTextFromCopy,
|
||||||
|
getRouterLinkRouteFromCopy,
|
||||||
|
splitCopyOnCMSPlaceHolder,
|
||||||
|
doesCopyContainTextLink,
|
||||||
|
stripUlTagFromCopy(copy) {
|
||||||
|
if (copy) {
|
||||||
|
const regex = /(?:<ul(?:.*?)>)|(?:<\/ul>)/g;
|
||||||
|
return copy.replace(regex, '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getArrayOfListItemsFromRawCmsCopy(copy) {
|
||||||
|
if (copy) {
|
||||||
|
const withoutUlTags = this.stripUlTagFromCopy(copy);
|
||||||
|
return withoutUlTags
|
||||||
|
.split(/(?:<li(?:.*?)>)|(?:<\/li>)/g)
|
||||||
|
.filter((lineItem) => lineItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.package-main {
|
||||||
|
.package-wrapper {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="radio"] {
|
||||||
|
opacity: 0;
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
|
||||||
|
+ .package-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
border: 1px solid $gray-300;
|
||||||
|
box-shadow: 0px 4px 8px -4px rgba(0, 0, 0, 0.15), 0px 4px 24px -8px rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
overflow: hidden;
|
||||||
|
min-height: 60px;
|
||||||
|
|
||||||
|
&.has-subheader {
|
||||||
|
min-height: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: relative;
|
||||||
|
top: 5px;
|
||||||
|
margin-right: 1rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid $gray-500;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
min-width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 19px;
|
||||||
|
top: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
min-width: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
+ .package-label {
|
||||||
|
&:before {
|
||||||
|
border: 1px solid #8e9292;
|
||||||
|
box-shadow: 0px 0px 0px 4px #9fcee6, 0px 1px 4px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:checked {
|
||||||
|
+ .package-label {
|
||||||
|
.package-specs {
|
||||||
|
max-height: 1000px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .package-label {
|
||||||
|
.package-specs {
|
||||||
|
.hide-when-closed {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .package-label {
|
||||||
|
background-color: $blue-100;
|
||||||
|
border: 1px solid $blue;
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .package-label {
|
||||||
|
&:before {
|
||||||
|
box-shadow: 0px 0px 0px 1px $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .package-label {
|
||||||
|
&:after {
|
||||||
|
background: $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
+ .package-label {
|
||||||
|
&:before {
|
||||||
|
border: 2px solid $blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.package-footer {
|
||||||
|
color: $red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.package-specs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
max-height: 0;
|
||||||
|
transition: all 0.5s ease;
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-weight: 500;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
span {
|
||||||
|
&.pricing-info {
|
||||||
|
color: $green;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.sub-label {
|
||||||
|
color: $green;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
margin: 1rem 0 0 -15px;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.714;
|
||||||
|
|
||||||
|
a {
|
||||||
|
line-height: 1.714;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideaway {
|
||||||
|
from {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(40px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-when-closed {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
151
src/layouts/service-packages/service-packages.vue
Normal file
151
src/layouts/service-packages/service-packages.vue
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
<template>
|
||||||
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||||
|
<div class="page-container-grouped-styles">
|
||||||
|
<loadingModal ref="loadingModal" />
|
||||||
|
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||||
|
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
|
||||||
|
<div class="fade-on-route-transition sub-container make-tall">
|
||||||
|
<servicePackageQuestion ref="servicePackage"
|
||||||
|
cmsWidgetName="ServicePackage"
|
||||||
|
groupName="ServicePackageQuestion"
|
||||||
|
:availableLineItems="availableLineItems"
|
||||||
|
@vapsItemsSelected="vapsItemsSelectedAction"
|
||||||
|
v-on="{ 'buttonEvent.openModal': openModalAction }"
|
||||||
|
validationRules="option-required"
|
||||||
|
isRequired />
|
||||||
|
<textBlock cmsWidgetName="PriceDisclaimerWidget"
|
||||||
|
justifyText="left"
|
||||||
|
typeStyle="caption"
|
||||||
|
class="mt-4" />
|
||||||
|
<!--<contentGroupModal ref="RainDefenseModal" cmsWidgetName="RainDefenseModal" />
|
||||||
|
<contentGroupModal ref="FrontWiperModal" cmsWidgetName="FrontWiperModal" />
|
||||||
|
<contentGroupModal ref="RearWiperModal" cmsWidgetName="RearWiperModal" />
|
||||||
|
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />-->
|
||||||
|
<siteFooter cmsWidgetName="SiteFooterWidget"
|
||||||
|
:isForwardActionDisabled="!meta.valid"
|
||||||
|
:isBackButtonHidden="shouldHideBackButton"
|
||||||
|
@back-clicked="backButtonAction"
|
||||||
|
@ForwardClicked="forwardButtonAction" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Components
|
||||||
|
import siteHeader from '@/iss-components/site-header/site-header';
|
||||||
|
import siteFooter from '@/iss-components/site-footer/site-footer';
|
||||||
|
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header';
|
||||||
|
import servicePackageQuestion from './service-package-question/service-package-question';
|
||||||
|
import textBlock from '@/digital-components/text-block/text-block';
|
||||||
|
//import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal';
|
||||||
|
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
|
||||||
|
//import vehicleQuestionsMixin from '../../mixins/vehicle-questions-mixin';
|
||||||
|
import { settleAllPromises } from '@/helpers/layout-helper';
|
||||||
|
import { useMainStore } from "@/store";
|
||||||
|
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||||
|
import { required } from '@/helpers/validation-rules';
|
||||||
|
import { errorMessages } from '@/constants/error-messages';
|
||||||
|
import { Form, defineRule } from 'vee-validate';
|
||||||
|
//import { navigateToHeritageFunnel } from '@/helpers/heritage-integration/navigation-helper';
|
||||||
|
//import { applicationConfig } from '@/constants/application-config';
|
||||||
|
defineRule('option-required', required(errorMessages.OPTION_REQUIRED));
|
||||||
|
export default {
|
||||||
|
name: 'service-packages',
|
||||||
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
const store = useMainStore();
|
||||||
|
|
||||||
|
// Call APIs
|
||||||
|
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||||
|
|
||||||
|
const carId = store.order.vehicle.carId;
|
||||||
|
const serviceZipCode = store.order.serviceLocation.zipCode;
|
||||||
|
const wipersPromise = store.getWipers(carId, serviceZipCode);
|
||||||
|
const rainDefensePromise = store.getRainDefense();
|
||||||
|
const supportingItemsPromise = store.getSupportingItems();
|
||||||
|
const promiseResultMap = [
|
||||||
|
{
|
||||||
|
resultKey: 'cmsContent',
|
||||||
|
promise: cmsContentPromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'wipers',
|
||||||
|
promise: wipersPromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'rainDefense',
|
||||||
|
promise: rainDefensePromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'supportingItems',
|
||||||
|
promise: supportingItemsPromise
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
|
const clonedGlassParts = store.order.lineItems.glassParts
|
||||||
|
? JSON.parse(JSON.stringify(store.order.lineItems.glassParts))
|
||||||
|
: [];
|
||||||
|
const availableLineItems = [
|
||||||
|
resultMap.rainDefense,
|
||||||
|
...resultMap.supportingItems,
|
||||||
|
...resultMap.wipers,
|
||||||
|
...clonedGlassParts
|
||||||
|
];
|
||||||
|
const pricingResults = await baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
|
||||||
|
{
|
||||||
|
availableLineItems: availableLineItems
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
// Call the "next" function to complete the transition to this page.
|
||||||
|
next((vm) => {
|
||||||
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
vm.pricedGlassParts = clonedGlassParts;
|
||||||
|
vm.supportingItems = resultMap.supportingItems;
|
||||||
|
vm.availableLineItems = pricingResults;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selectedVaps: null,
|
||||||
|
availableLineItems: null,
|
||||||
|
supportingItems: null,
|
||||||
|
pricedGlassParts: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
openModalAction(modalName) {
|
||||||
|
this.$refs[modalName].openModal();
|
||||||
|
},
|
||||||
|
arePagePrerequisitesValid() {
|
||||||
|
return (
|
||||||
|
store.getters.order.serviceLocation.zipCode &&
|
||||||
|
store.getters.order.serviceLocation.zipCodeCtu &&
|
||||||
|
(store.getters.order.damage.isRepair ||
|
||||||
|
(store.getters.order.lineItems?.glassParts != null &&
|
||||||
|
store.getters.order.lineItems.glassParts.length > 0)) &&
|
||||||
|
store.getters.order.referralNumber?.length !== 6
|
||||||
|
);
|
||||||
|
},
|
||||||
|
vapsItemsSelectedAction(vapsItemsSelected) {
|
||||||
|
this.selectedVaps = vapsItemsSelected;
|
||||||
|
},
|
||||||
|
backButtonAction() {
|
||||||
|
this.$router.navigate(
|
||||||
|
this.navigationScenarios.CLICKED_BACK,
|
||||||
|
this.$route
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
siteHeader,
|
||||||
|
siteFooter,
|
||||||
|
siteSubHeader,
|
||||||
|
Form,
|
||||||
|
textBlock,
|
||||||
|
servicePackageQuestion,
|
||||||
|
loadingModal
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -22,6 +22,12 @@ const vueApp = createApp(App);
|
||||||
*/
|
*/
|
||||||
vueApp.config.unwrapInjectedRef = true;
|
vueApp.config.unwrapInjectedRef = true;
|
||||||
|
|
||||||
|
vueApp.config.compilerOptions.isCustomElement = (tag) => {
|
||||||
|
return (tag === 'siteSubHeader' ||
|
||||||
|
tag === 'ServicePackages' ||
|
||||||
|
tag === 'servicePackageQuestion');
|
||||||
|
}
|
||||||
|
|
||||||
// Pinia
|
// Pinia
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
vueApp.use(pinia);
|
vueApp.use(pinia);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ export default {
|
||||||
buttonLabel: [Number, String],
|
buttonLabel: [Number, String],
|
||||||
buttonLabelSubCopy: String,
|
buttonLabelSubCopy: String,
|
||||||
buttonBodyCopy: String,
|
buttonBodyCopy: String,
|
||||||
buttonAuxillaryCopy: String,
|
buttonAuxiliaryCopy: String,
|
||||||
buttonFooterCopy: String,
|
buttonFooterCopy: String,
|
||||||
buttonImage: String,
|
buttonImage: String,
|
||||||
buttonImageId: String,
|
buttonImageId: String,
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ const routes = [
|
||||||
router.addRoute({
|
router.addRoute({
|
||||||
path: routeData[0].path, // Always the same path, because we control it with query strings.
|
path: routeData[0].path, // Always the same path, because we control it with query strings.
|
||||||
name: routeData[0].name,
|
name: routeData[0].name,
|
||||||
|
query: to.query,
|
||||||
component: routeData[0].component,
|
component: routeData[0].component,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -68,15 +69,16 @@ const routes = [
|
||||||
console.log(error);
|
console.log(error);
|
||||||
GoToStartOn404(next);
|
GoToStartOn404(next);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: createWebHistory("/"),
|
history: createWebHistory("/"),
|
||||||
routes,
|
routes
|
||||||
});
|
});
|
||||||
|
|
||||||
router.afterEach((to, from) => {
|
router.afterEach((to, from) => { /*eslint-disable-line*/
|
||||||
|
|
||||||
const store = useMainStore();
|
const store = useMainStore();
|
||||||
// Update lastPageVisited in the store
|
// Update lastPageVisited in the store
|
||||||
|
|
@ -106,12 +108,12 @@ async function GetRouteInfoFromPageName(pageName) {
|
||||||
routeData.push({
|
routeData.push({
|
||||||
path: "/",
|
path: "/",
|
||||||
name: `${key}`,
|
name: `${key}`,
|
||||||
component: lazyLoadComponent(jsonFromResponse[key].LayoutName),
|
component: lazyLoadComponent(jsonFromResponse[key].LayoutName)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return routeData;
|
return routeData;
|
||||||
};
|
}
|
||||||
|
|
||||||
//Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example.
|
//Use this navigation when you need to call next() explicitly. beforeRouteEnter is a good example.
|
||||||
router.overrideNavigation = (
|
router.overrideNavigation = (
|
||||||
|
|
@ -141,7 +143,7 @@ router.navigate = (scenario, currentRoute, optionalQuery = {}, optionalParams =
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigate to the next route, depending on the scenario.
|
// Navigate to the next route, depending on the scenario.
|
||||||
function navigate (scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {}) {
|
function navigate (scenario, currentRoute, optionalQuery = {}, optionalParams = {}, optionalPageData = {}) { /*eslint-disable-line*/
|
||||||
if (!scenario) {
|
if (!scenario) {
|
||||||
console.error("No scenario provided. Please review the routing table.");
|
console.error("No scenario provided. Please review the routing table.");
|
||||||
return;
|
return;
|
||||||
|
|
@ -170,7 +172,7 @@ function navigate (scenario, currentRoute, optionalQuery = {}, optionalParams =
|
||||||
router.push({
|
router.push({
|
||||||
name: "root",
|
name: "root",
|
||||||
query: Object.assign(optionalQuery, {
|
query: Object.assign(optionalQuery, {
|
||||||
issPage: matchingScenarioMap.destinationIssPageValue,
|
issPage: matchingScenarioMap.destinationIssPageValue
|
||||||
}),
|
}),
|
||||||
params: optionalParams
|
params: optionalParams
|
||||||
});
|
});
|
||||||
|
|
@ -182,7 +184,7 @@ function navigate (scenario, currentRoute, optionalQuery = {}, optionalParams =
|
||||||
// Navigate to an external url.
|
// Navigate to an external url.
|
||||||
function navigateToUrl(url, optionalQuery = {}) {
|
function navigateToUrl(url, optionalQuery = {}) {
|
||||||
// possibly show some loading screen in the future here.
|
// possibly show some loading screen in the future here.
|
||||||
let externalUrl = new URL(url);
|
const externalUrl = new URL(url);
|
||||||
|
|
||||||
for (const queryKey in optionalQuery) {
|
for (const queryKey in optionalQuery) {
|
||||||
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
|
externalUrl.searchParams.append(queryKey, optionalQuery[queryKey]);
|
||||||
|
|
@ -219,7 +221,7 @@ function GoToStartOn404(next) {
|
||||||
router.addRoute({
|
router.addRoute({
|
||||||
path: "/",
|
path: "/",
|
||||||
name: errorPageName,
|
name: errorPageName,
|
||||||
component: lazyLoadComponent(errorPageName),
|
component: lazyLoadComponent(errorPageName)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Put item on the bus
|
// Put item on the bus
|
||||||
|
|
@ -230,13 +232,13 @@ function GoToStartOn404(next) {
|
||||||
isDismissible: true,
|
isDismissible: true,
|
||||||
messageCopy: "You can get a quote by starting on this page.",
|
messageCopy: "You can get a quote by starting on this page.",
|
||||||
messageHeadline: "We're sorry, something went wrong.",
|
messageHeadline: "We're sorry, something went wrong.",
|
||||||
type: globalEventTypes.Danger,
|
type: globalEventTypes.Danger
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
next({
|
next({
|
||||||
name: errorPageName,
|
name: errorPageName,
|
||||||
query: {issPage: errorPageName },
|
query: {issPage: errorPageName }
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
@ -249,14 +251,14 @@ async function runExperiments(nextPage) {
|
||||||
await store.runExperimentsForTrigger({
|
await store.runExperimentsForTrigger({
|
||||||
userId: getDeviceIdValue(),
|
userId: getDeviceIdValue(),
|
||||||
triggerEvent: experimentTriggers.SITE_ENTRY,
|
triggerEvent: experimentTriggers.SITE_ENTRY,
|
||||||
triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE,
|
triggerValue: applicationConfig.SITE_ENTRY_TRIGGER_VALUE
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await store.runExperimentsForTrigger({
|
await store.runExperimentsForTrigger({
|
||||||
userId: getDeviceIdValue(),
|
userId: getDeviceIdValue(),
|
||||||
triggerEvent: experimentTriggers.PAGE_ENTRY,
|
triggerEvent: experimentTriggers.PAGE_ENTRY,
|
||||||
triggerValue: nextPage,
|
triggerValue: nextPage
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,27 @@
|
||||||
export const issPageValues = {
|
export const issPageValues = {
|
||||||
ENTRY_PAGE: "entry-page",
|
ENTRY_PAGE: 'entry-page',
|
||||||
WELCOME_PAGE: "welcome-page",
|
WELCOME_PAGE: 'welcome-page',
|
||||||
POLICY_HOLDER_DETAILS: "policy-holder-details",
|
POLICY_HOLDER_DETAILS: 'policy-holder-details',
|
||||||
VEHICLE_MAKE: "vehicle-make",
|
VEHICLE_MAKE: 'vehicle-make',
|
||||||
VEHICLE_YEAR: "vehicle-year",
|
VEHICLE_YEAR: 'vehicle-year',
|
||||||
VEHICLE_MODEL: "vehicle-model",
|
VEHICLE_MODEL: 'vehicle-model',
|
||||||
VEHICLE_STYLE: "vehicle-style",
|
VEHICLE_STYLE: 'vehicle-style',
|
||||||
VEHICLE_DAMAGE: "vehicle-damage",
|
VEHICLE_DAMAGE: 'vehicle-damage',
|
||||||
VEHICLE_LOOKUP: "vehicle-lookup",
|
VEHICLE_LOOKUP: 'vehicle-lookup',
|
||||||
ADDRESS_LOOKUP: "address-lookup",
|
ADDRESS_LOOKUP: 'address-lookup',
|
||||||
ADDRESS_VEHICLES: "address-vehicles",
|
ADDRESS_VEHICLES: 'address-vehicles',
|
||||||
LICENSE_PLATE_LOOKUP: "license-plate-lookup",
|
LICENSE_PLATE_LOOKUP: 'license-plate-lookup',
|
||||||
VIN_LOOKUP: "vin-lookup",
|
VIN_LOOKUP: 'vin-lookup',
|
||||||
VEHICLE_PARTS: "vehicle-parts",
|
VEHICLE_PARTS: 'vehicle-parts',
|
||||||
PART_QUESTIONS: "part-questions",
|
PART_QUESTIONS: 'part-questions',
|
||||||
MOLDING_QUESTIONS: "molding-questions",
|
MOLDING_QUESTIONS: 'molding-questions',
|
||||||
CAPABILITY_QUESTIONS: "capability-questions",
|
CAPABILITY_QUESTIONS: 'capability-questions',
|
||||||
COVERAGE_STATEMENT: "coverage-statement",
|
COVERAGE_STATEMENT: 'coverage-statement',
|
||||||
PROVIDER_PREFERENCE: "provider-preference",
|
PROVIDER_PREFERENCE: 'provider-preference',
|
||||||
SERVICE_LOCATION: "service-location",
|
SERVICE_LOCATION: 'service-location',
|
||||||
REVEAL: "reveal",
|
REVEAL: 'reveal',
|
||||||
ESTIMATE: "estimate",
|
ESTIMATE: 'estimate',
|
||||||
ADDRESS_VEHICLES: "address-vehicles",
|
ADDRESS_VEHICLES: 'address-vehicles',
|
||||||
QUOTE: "quote",
|
SERVICE_PACKAGE: 'service-package',
|
||||||
HERITAGE: "heritage",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -118,6 +118,7 @@ export const useMainStore = defineStore({
|
||||||
vehicle: (state) => state.order.vehicle,
|
vehicle: (state) => state.order.vehicle,
|
||||||
damage: (state) => state.order.damage,
|
damage: (state) => state.order.damage,
|
||||||
lineItems: (state) => state.order.lineItems,
|
lineItems: (state) => state.order.lineItems,
|
||||||
|
hasAnyNonWindshieldGlassParts: (state) => !state.order.policy.isDamageGlassOnly,
|
||||||
eventBusItem: (state) => ( eventCategory, eventSubCategory) => {
|
eventBusItem: (state) => ( eventCategory, eventSubCategory) => {
|
||||||
|
|
||||||
const matchedEvent = state.applicationUser.eventBus.find(
|
const matchedEvent = state.applicationUser.eventBus.find(
|
||||||
|
|
@ -433,7 +434,58 @@ export const useMainStore = defineStore({
|
||||||
capabilityAnswerResults: capabilityQuestionAnswersForPart,
|
capabilityAnswerResults: capabilityQuestionAnswersForPart,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
getWipers() {
|
||||||
|
const carId = this.order.vehicle.carId;
|
||||||
|
///WARNING WARNING DANGER WILL ROBINSON
|
||||||
|
///TODO: this is temp test code until serviceLocation is complete.
|
||||||
|
//const serviceZipCode = this.order.serviceLocation.zipCode;
|
||||||
|
const serviceZipCode = '44902';
|
||||||
|
return globalMethods
|
||||||
|
.callHttpClient({
|
||||||
|
method: endpoints.GetWipers.method,
|
||||||
|
endpoint: `${endpoints.GetWipers.url}/${carId}/${serviceZipCode}`
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
// The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
|
||||||
|
console.error(error);
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getRainDefense() {
|
||||||
|
return globalMethods
|
||||||
|
.callHttpClient({
|
||||||
|
method: endpoints.GetRainDefense.method,
|
||||||
|
endpoint: `${endpoints.GetRainDefense.url}`
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
// The wiper service sometimes returns 500s on legitimate carId/zipCode combination - return empty array instead of breaking flow
|
||||||
|
console.error(error);
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getSupportingItems() {
|
||||||
|
const glassPartsArray = this.order.lineItems.glassParts ?? [];
|
||||||
|
const carId = this.order.vehicle.carId;
|
||||||
|
const isRepair = this.order.damage.isRepair;
|
||||||
|
const numberOfChips = this.order.damage.numberOfChips;
|
||||||
|
return globalMethods
|
||||||
|
.callHttpClient({
|
||||||
|
method: endpoints.GetSupportingItems.method,
|
||||||
|
endpoint: endpoints.GetSupportingItems.url,
|
||||||
|
payload: {
|
||||||
|
carId: carId,
|
||||||
|
serviceType: isRepair ? 'Repair' : 'Replace',
|
||||||
|
parentAccountNumber: 0,
|
||||||
|
parts: glassPartsArray,
|
||||||
|
numberOfRepairChips: isRepair ? numberOfChips : 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
lookupVehicleByVin(vin) {
|
lookupVehicleByVin(vin) {
|
||||||
return globalMethods.callHttpClient({
|
return globalMethods.callHttpClient({
|
||||||
method: endpoints.LookupVehicleByVin.method,
|
method: endpoints.LookupVehicleByVin.method,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue