Merge branch 'develop' into feature/CASH-1947
This commit is contained in:
commit
ca4f6323c2
31 changed files with 676 additions and 2945 deletions
|
|
@ -32,11 +32,7 @@ module.exports = {
|
||||||
"!src/layouts/payment-pia-return/*.vue", // Temp test exclusion while in development
|
"!src/layouts/payment-pia-return/*.vue", // Temp test exclusion while in development
|
||||||
"!src/layouts/insurance/*.vue", // Temp test exclusion while in development
|
"!src/layouts/insurance/*.vue", // Temp test exclusion while in development
|
||||||
"!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development
|
"!src/layouts/insurance-company/*.vue", // Temp test exclusion while in development
|
||||||
"!src/layouts/schedule/**/*.vue", // Temp test exclusion while in development
|
|
||||||
"!src/digital-components/date-picker/**/*.vue", // Temp test exclusion while in development
|
"!src/digital-components/date-picker/**/*.vue", // Temp test exclusion while in development
|
||||||
|
|
||||||
"!src/**/*-june-2025.vue", // Exclude these temporary files for CASH-845 project
|
|
||||||
|
|
||||||
"!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development
|
"!src/layouts/insurance-company/insurance-company-question/*.vue", // Temp test exclusion while in development
|
||||||
"!src/experiment-components/*.vue",
|
"!src/experiment-components/*.vue",
|
||||||
// END
|
// END
|
||||||
|
|
@ -44,7 +40,7 @@ module.exports = {
|
||||||
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
statements: 64,
|
statements: 68,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en-US">
|
<html lang="en-US">
|
||||||
<head>
|
<head>
|
||||||
|
<meta name="robots" content="noindex" />
|
||||||
<script>
|
<script>
|
||||||
window.dataLayer = [{}];
|
window.dataLayer = [{}];
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,10 @@ export const pageProgressMapper = {
|
||||||
percent: 30,
|
percent: 30,
|
||||||
step: 1,
|
step: 1,
|
||||||
},
|
},
|
||||||
|
"policy-info": {
|
||||||
|
percent: 55,
|
||||||
|
step: 2,
|
||||||
|
},
|
||||||
quote: {
|
quote: {
|
||||||
percent: 60,
|
percent: 60,
|
||||||
step: 2,
|
step: 2,
|
||||||
|
|
|
||||||
|
|
@ -173,4 +173,29 @@ export const quotePageDiscountTable = [
|
||||||
packageLevel: packageNames.TIER_THREE,
|
packageLevel: packageNames.TIER_THREE,
|
||||||
isInsurance: true,
|
isInsurance: true,
|
||||||
},
|
},
|
||||||
|
// Replace - Curve Tempered
|
||||||
|
{
|
||||||
|
name: "Curve Tempered Glass Only",
|
||||||
|
experimentCode: "Show_GlassOnly_Replace_CT_Discount",
|
||||||
|
partNumber: "GL CT CSH PKG",
|
||||||
|
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
|
||||||
|
description: "GLASS CT GEOTARGET DISC",
|
||||||
|
packageLevel: packageNames.TIER_ONE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Curve Tempered Standard",
|
||||||
|
experimentCode: "Show_Standard_Replace_CT_Discount",
|
||||||
|
partNumber: "STD CT CSH PKG",
|
||||||
|
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
|
||||||
|
description: "STD CT GEOTARGET DISC",
|
||||||
|
packageLevel: packageNames.TIER_TWO,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Curve Tempered Premium",
|
||||||
|
experimentCode: "Show_Premium_Replace_CT_Discount",
|
||||||
|
partNumber: "PRM CT CSH PKG",
|
||||||
|
partType: partTypeStrings.QUOTE_PAGE_DISCOUNT,
|
||||||
|
description: "PREM CT GEOTARGET DISC",
|
||||||
|
packageLevel: packageNames.TIER_THREE,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,7 @@ const storeMutations = {
|
||||||
UPDATE_EXTERNAL_PARAMETER_SERVICE_PACKAGE: "updateExternalParameterServicePackage",
|
UPDATE_EXTERNAL_PARAMETER_SERVICE_PACKAGE: "updateExternalParameterServicePackage",
|
||||||
UPDATE_EXTERNAL_PARAMETER_SOURCE: "updateExternalParameterSource",
|
UPDATE_EXTERNAL_PARAMETER_SOURCE: "updateExternalParameterSource",
|
||||||
UPDATE_EXTERNAL_PARAMETER_PHONE_NUMBER: "updateExternalParameterPhoneNumber",
|
UPDATE_EXTERNAL_PARAMETER_PHONE_NUMBER: "updateExternalParameterPhoneNumber",
|
||||||
|
UPDATE_EXTERNAL_PARAMETER_QS_STASH: "updateExternalParameterQsStash",
|
||||||
|
|
||||||
//RESET EXTERNAL_PARAMETER MUTATIONS
|
//RESET EXTERNAL_PARAMETER MUTATIONS
|
||||||
RESET_EXTERNAL_PARAMETER_VEHICLE_STATE: "resetExternalParameterVehicleState",
|
RESET_EXTERNAL_PARAMETER_VEHICLE_STATE: "resetExternalParameterVehicleState",
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,17 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="date-picker text-center"
|
class="date-picker text-center"
|
||||||
:class="`${calendarViewDirection} calendar-2025 ${showPricingByDayClass}`">
|
:class="`${calendarViewDirection} calendar-2025 ${showPricingByDayClass} ${loadingStatus === 'reinitial' ? 'loading-reinitial' : ''}`">
|
||||||
<fieldset id="date-picker-fieldset" ref="datePickerFieldset">
|
<fieldset id="date-picker-fieldset" ref="datePickerFieldset">
|
||||||
<legend class="sr-only">Select a day and time</legend>
|
<legend class="sr-only">Select a day and time</legend>
|
||||||
<div
|
<div
|
||||||
v-for="month in months"
|
v-for="(month, i) in months"
|
||||||
:key="`${month.monthLabel}-${month.yearNum?.toString()}`"
|
:key="`${month.monthLabel}-${month.yearNum?.toString()}`"
|
||||||
:id="`${month.monthLabel}-${month.yearNum?.toString()}`"
|
:id="`${month.monthLabel}-${month.yearNum?.toString()}`"
|
||||||
class="calendar-grid-container"
|
class="calendar-grid-container month"
|
||||||
:class="[
|
:class="[
|
||||||
hideSomeDaysForInitialView ? 'partial-month-initial-view' : '',
|
hideSomeDaysForInitialView ? 'partial-month-initial-view' : '',
|
||||||
month.monthClass,
|
month.monthClass,
|
||||||
|
i === 0 ? 'first-month-shown' : '',
|
||||||
]">
|
]">
|
||||||
<div class="month-year body-small d-flex align-items-center">
|
<div class="month-year body-small d-flex align-items-center">
|
||||||
{{ month.monthLabel }} {{ month.yearNum?.toString() }}
|
{{ month.monthLabel }} {{ month.yearNum?.toString() }}
|
||||||
|
|
@ -114,7 +115,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<loader
|
<loader
|
||||||
:class="[!isLoading ? 'date-picker-hidden' : '']"
|
class="date-picker-loader"
|
||||||
|
:class="[loadingStatus !== 'none' ? 'show-loader' : '']"
|
||||||
loaderColor="blue"
|
loaderColor="blue"
|
||||||
loaderPosition="center" />
|
loaderPosition="center" />
|
||||||
<div class="row form-test-error" id="date-of-month-error">
|
<div class="row form-test-error" id="date-of-month-error">
|
||||||
|
|
@ -125,7 +127,7 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-link view-more-dates"
|
class="btn btn-link view-more-dates"
|
||||||
id="viewMoreDates"
|
id="viewMoreDates"
|
||||||
:disabled="isLoading"
|
:disabled="loadingStatus !== 'none'"
|
||||||
@click="showAnotherMonth">
|
@click="showAnotherMonth">
|
||||||
View more dates
|
View more dates
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -160,7 +162,6 @@ export default {
|
||||||
name: "datePicker",
|
name: "datePicker",
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoading: true,
|
|
||||||
months: null,
|
months: null,
|
||||||
disableViewMoreDatesButton: false,
|
disableViewMoreDatesButton: false,
|
||||||
hideSomeDaysForInitialView: null,
|
hideSomeDaysForInitialView: null,
|
||||||
|
|
@ -169,7 +170,10 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
customComponentId: String,
|
customComponentId: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
selectableDatesSetting: {
|
selectableDatesSetting: {
|
||||||
type: String,
|
type: String,
|
||||||
validator(value) {
|
validator(value) {
|
||||||
|
|
@ -200,6 +204,10 @@ export default {
|
||||||
pricingByDayUpcharge: Number,
|
pricingByDayUpcharge: Number,
|
||||||
isPricingByDayExperiment: Boolean,
|
isPricingByDayExperiment: Boolean,
|
||||||
isMobileSelected: Boolean,
|
isMobileSelected: Boolean,
|
||||||
|
loadingStatus: {
|
||||||
|
type: String,
|
||||||
|
default: "none",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const uuid = uuidv4();
|
const uuid = uuidv4();
|
||||||
|
|
@ -324,9 +332,9 @@ export default {
|
||||||
let preSelectedDateMonthEnd = this.getMonthEnd(
|
let preSelectedDateMonthEnd = this.getMonthEnd(
|
||||||
preSelectedDate.replace("-mobile", "")
|
preSelectedDate.replace("-mobile", "")
|
||||||
);
|
);
|
||||||
let weekIncludesPreSelectedMonthEnd = false;
|
let monthEndsByThisWeek = false;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (!weekIncludesPreSelectedMonthEnd) {
|
while (!monthEndsByThisWeek && i < 52) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
weekStartDate = this.getNextWeekSunday(weekEndDate);
|
weekStartDate = this.getNextWeekSunday(weekEndDate);
|
||||||
weekEndDate = this.getWeekEndDate(weekStartDate);
|
weekEndDate = this.getWeekEndDate(weekStartDate);
|
||||||
|
|
@ -338,7 +346,12 @@ export default {
|
||||||
preSelectedDateMonthEnd === weekEndDate
|
preSelectedDateMonthEnd === weekEndDate
|
||||||
) {
|
) {
|
||||||
weekEndDate = preSelectedDateMonthEnd;
|
weekEndDate = preSelectedDateMonthEnd;
|
||||||
weekIncludesPreSelectedMonthEnd = true;
|
monthEndsByThisWeek = true;
|
||||||
|
} else if (preSelectedDateMonthEnd < weekEndDate) {
|
||||||
|
// Additional case: if month ends before this week (but not necessarily during it),
|
||||||
|
// still cut the loop here, but don't truncate the week.
|
||||||
|
|
||||||
|
monthEndsByThisWeek = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
weeks.push({
|
weeks.push({
|
||||||
|
|
@ -489,7 +502,6 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async setCalendarData(config = {}) {
|
async setCalendarData(config = {}) {
|
||||||
this.isLoading = true;
|
|
||||||
this.selectableDatesInshop = [];
|
this.selectableDatesInshop = [];
|
||||||
this.selectableDatesMobile = [];
|
this.selectableDatesMobile = [];
|
||||||
this.months = [];
|
this.months = [];
|
||||||
|
|
@ -541,7 +553,6 @@ export default {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
this.months = months;
|
this.months = months;
|
||||||
this.isLoading = false;
|
|
||||||
|
|
||||||
if (config.preSelectedDate) {
|
if (config.preSelectedDate) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
|
@ -729,7 +740,6 @@ export default {
|
||||||
},
|
},
|
||||||
async showAnotherMonth() {
|
async showAnotherMonth() {
|
||||||
if (!this.months) return;
|
if (!this.months) return;
|
||||||
this.isLoading = true;
|
|
||||||
let monthToShow;
|
let monthToShow;
|
||||||
let monthStartDate;
|
let monthStartDate;
|
||||||
|
|
||||||
|
|
@ -774,7 +784,6 @@ export default {
|
||||||
monthToShowDates[monthToShowDates.length - 1].inputValue
|
monthToShowDates[monthToShowDates.length - 1].inputValue
|
||||||
);
|
);
|
||||||
|
|
||||||
this.isLoading = false;
|
|
||||||
this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days
|
this.hideSomeDaysForInitialView = false; // if hid days on initial partial view, this will reveal those days
|
||||||
monthToShow.monthClass = monthToShow.monthClass.replace(" month-hidden", "");
|
monthToShow.monthClass = monthToShow.monthClass.replace(" month-hidden", "");
|
||||||
this.scrollToElement(monthToShow.monthString);
|
this.scrollToElement(monthToShow.monthString);
|
||||||
|
|
@ -787,7 +796,6 @@ export default {
|
||||||
},
|
},
|
||||||
async updateSelectableDates(monthStart, monthEnd) {
|
async updateSelectableDates(monthStart, monthEnd) {
|
||||||
const moreSelectableDates = await this.getMoreDatesCallback(monthStart, monthEnd);
|
const moreSelectableDates = await this.getMoreDatesCallback(monthStart, monthEnd);
|
||||||
|
|
||||||
moreSelectableDates.inshopTimeSlotsData.days.forEach((selectableDate) => {
|
moreSelectableDates.inshopTimeSlotsData.days.forEach((selectableDate) => {
|
||||||
const index = this.selectableDatesInshop.findIndex(
|
const index = this.selectableDatesInshop.findIndex(
|
||||||
(dateObj) => dateObj.date === selectableDate.date
|
(dateObj) => dateObj.date === selectableDate.date
|
||||||
|
|
@ -846,12 +854,6 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
isLoading(newValue) {
|
|
||||||
// if done loading dates, then set to first available date
|
|
||||||
if (newValue === false && this.firstAvailableSelectableDate) {
|
|
||||||
this.selectedDate = this.firstAvailableSelectableDate;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modelValue(newValue) {
|
modelValue(newValue) {
|
||||||
this.resetField({
|
this.resetField({
|
||||||
value: newValue,
|
value: newValue,
|
||||||
|
|
@ -872,9 +874,14 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.date-picker-hidden {
|
.date-picker-loader {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
|
|
||||||
|
&.show-loader {
|
||||||
|
opacity: 1;
|
||||||
|
max-height: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.date-picker {
|
.date-picker {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
@ -903,12 +910,12 @@ export default {
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.calendar-grid-container {
|
.month {
|
||||||
margin: 0 auto 1rem auto;
|
margin: 0 auto 1rem auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition:
|
transition:
|
||||||
height ease 2s,
|
height ease 1s,
|
||||||
opacity ease 2s;
|
max-height ease 1s;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(7, 1fr);
|
grid-template-columns: repeat(7, 1fr);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
@ -1157,7 +1164,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.past {
|
.past {
|
||||||
.calendar-grid-container {
|
.month {
|
||||||
.month-year {
|
.month-year {
|
||||||
grid-area: 1 / 1 / 2 / 6;
|
grid-area: 1 / 1 / 2 / 6;
|
||||||
}
|
}
|
||||||
|
|
@ -1214,7 +1221,7 @@ export default {
|
||||||
}
|
}
|
||||||
// new calendar styling overrides
|
// new calendar styling overrides
|
||||||
&.calendar-2025 {
|
&.calendar-2025 {
|
||||||
.calendar-grid-container .grid-item {
|
.month .grid-item {
|
||||||
margin: 0 0 0.15rem 0;
|
margin: 0 0 0.15rem 0;
|
||||||
}
|
}
|
||||||
.month-year {
|
.month-year {
|
||||||
|
|
@ -1316,6 +1323,33 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.loading-reinitial {
|
||||||
|
.month {
|
||||||
|
opacity: 0;
|
||||||
|
max-height: 0;
|
||||||
|
}
|
||||||
|
.month.first-month-shown {
|
||||||
|
opacity: 1;
|
||||||
|
max-height: none;
|
||||||
|
|
||||||
|
.grid-item.radio-wrapper.selectable-day {
|
||||||
|
input[type="radio"]:checked + label,
|
||||||
|
label {
|
||||||
|
background-color: $white;
|
||||||
|
border: none;
|
||||||
|
color: initial;
|
||||||
|
cursor: default;
|
||||||
|
&:hover {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
font-family: UrbanistRegular;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
:deep(.timeslots .button-inner-wrapper) {
|
:deep(.timeslots .button-inner-wrapper) {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,6 @@ export default {
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
// Clean up event listeners and observers
|
// Clean up event listeners and observers
|
||||||
window.removeEventListener("sierra-chat-transfer", this._handleSierraToSalesforceTransfer);
|
window.removeEventListener("sierra-chat-transfer", this._handleSierraToSalesforceTransfer);
|
||||||
if (this._salesforceChatOpenObserver) {
|
|
||||||
this._salesforceChatOpenObserver.disconnect();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initializeSalesforceWebchat() {
|
initializeSalesforceWebchat() {
|
||||||
|
|
@ -133,6 +130,9 @@ export default {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
.embedded-messaging > .embeddedMessagingFrame[class~="isMaximized"] {
|
||||||
|
z-index: 9999 !important;
|
||||||
|
}
|
||||||
.dockableContainer {
|
.dockableContainer {
|
||||||
&.showDockableContainer {
|
&.showDockableContainer {
|
||||||
color: $gray-600;
|
color: $gray-600;
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,6 @@ describe("sierraWebchat.vue", () => {
|
||||||
expect(window.sierraChat.closeChatModal).toHaveBeenCalled();
|
expect(window.sierraChat.closeChatModal).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("dispatches sierra-chat-closed on handleSierraOnClose", () => {
|
|
||||||
const eventSpy = jest.spyOn(window, "dispatchEvent");
|
|
||||||
wrapper.vm.createSierraConfig().onClose();
|
|
||||||
expect(eventSpy).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({ type: "sierra-chat-closed" })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("dispatches sierra-chat-transfer on handleSierraOnTransfer", () => {
|
it("dispatches sierra-chat-transfer on handleSierraOnTransfer", () => {
|
||||||
const eventSpy = jest.spyOn(window, "dispatchEvent");
|
const eventSpy = jest.spyOn(window, "dispatchEvent");
|
||||||
const transfer = {
|
const transfer = {
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,20 @@ import analyticsMixin from "@/mixins/analytics-mixin";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { routeData } from "@/router/constants/routes";
|
import { routeData } from "@/router/constants/routes";
|
||||||
import { deepClone } from "@/helpers/object-helper";
|
import { deepClone } from "@/helpers/object-helper";
|
||||||
|
import { webchatHelper } from "@/helpers/webchat-helper";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "sierraWebchat",
|
name: "sierraWebchat",
|
||||||
mixins: [analyticsMixin],
|
mixins: [analyticsMixin],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
transferInProgress: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const { webchatGlobalNonpersistedState, launchWebchat } = webchatHelper();
|
||||||
|
return { webchatGlobalNonpersistedState, launchWebchat };
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openSierraChatModal() {
|
openSierraChatModal() {
|
||||||
const sierra = window.sierraChat || window.sierra || window.SierraChat;
|
const sierra = window.sierraChat || window.sierra || window.SierraChat;
|
||||||
|
|
@ -35,11 +45,18 @@ export default {
|
||||||
display: "corner",
|
display: "corner",
|
||||||
onLoad: () => this.openSierraChatModal(),
|
onLoad: () => this.openSierraChatModal(),
|
||||||
onOpen: () => {},
|
onOpen: () => {},
|
||||||
onClose: () => window.dispatchEvent(new CustomEvent("sierra-chat-closed")),
|
onClose: () => {
|
||||||
onTransfer: (transfer) =>
|
if (!this.transferInProgress) {
|
||||||
|
this.webchatGlobalNonpersistedState.showWebchatButton = true;
|
||||||
|
this.transferInProgress = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTransfer: (transfer) => {
|
||||||
|
this.transferInProgress = true;
|
||||||
window.dispatchEvent(
|
window.dispatchEvent(
|
||||||
new CustomEvent("sierra-chat-transfer", { detail: transfer })
|
new CustomEvent("sierra-chat-transfer", { detail: transfer })
|
||||||
),
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getSierraContext() {
|
getSierraContext() {
|
||||||
|
|
@ -138,10 +155,7 @@ export default {
|
||||||
}
|
}
|
||||||
// Pass data to Salesforce chat if available
|
// Pass data to Salesforce chat if available
|
||||||
const transfer = event.detail;
|
const transfer = event.detail;
|
||||||
if (
|
if (window.embeddedservice_bootstrap && window.embeddedservice_bootstrap.prechatAPI) {
|
||||||
window.embeddedservice_bootstrap &&
|
|
||||||
typeof window.embeddedservice_bootstrap.bootstrapEmbeddedService === "function"
|
|
||||||
) {
|
|
||||||
if (
|
if (
|
||||||
transfer &&
|
transfer &&
|
||||||
transfer.data &&
|
transfer.data &&
|
||||||
|
|
@ -155,37 +169,16 @@ export default {
|
||||||
LastName: transfer.data.last_name,
|
LastName: transfer.data.last_name,
|
||||||
Email: transfer.data.email,
|
Email: transfer.data.email,
|
||||||
});
|
});
|
||||||
if (
|
|
||||||
window.embeddedservice_bootstrap.utilAPI &&
|
|
||||||
typeof window.embeddedservice_bootstrap.utilAPI.launchChat === "function"
|
|
||||||
) {
|
|
||||||
window.embeddedservice_bootstrap.utilAPI.launchChat();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
window.embeddedservice_bootstrap.utilAPI.launchChat();
|
this.webchatGlobalNonpersistedState.shouldLaunchSierra = false;
|
||||||
|
this.launchWebchat();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.addEventListener("sierra-chat-transfer", this._handleSierraTransfer);
|
window.addEventListener("sierra-chat-transfer", this._handleSierraTransfer);
|
||||||
|
|
||||||
// Notify funnel-header about Sierra chat open/close state
|
|
||||||
this._sierraChatContainerObserver = new MutationObserver(() => {
|
|
||||||
const isOpen = !!document.querySelector("[data-sierra-chat-container]");
|
|
||||||
window.dispatchEvent(
|
|
||||||
new CustomEvent("sierra-chat-visibility", { detail: { open: isOpen } })
|
|
||||||
);
|
|
||||||
});
|
|
||||||
this._sierraChatContainerObserver.observe(document.body, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
window.removeEventListener("launch-sierra-webchat", this.triggerSierraChat);
|
window.removeEventListener("launch-sierra-webchat", this.triggerSierraChat);
|
||||||
window.removeEventListener("sierra-chat-transfer", this._handleSierraTransfer);
|
window.removeEventListener("sierra-chat-transfer", this._handleSierraTransfer);
|
||||||
if (this._sierraChatContainerObserver) {
|
|
||||||
this._sierraChatContainerObserver.disconnect();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -79,16 +79,7 @@ export default {
|
||||||
return this.getCmsContent(this.cmsWidgetName, "LogoImage");
|
return this.getCmsContent(this.cmsWidgetName, "LogoImage");
|
||||||
},
|
},
|
||||||
shouldShowWebchatButton() {
|
shouldShowWebchatButton() {
|
||||||
// Hide the chat icon if Sierra chat is open
|
return this.webchatGlobalNonpersistedState.showWebchatButton;
|
||||||
if (this.sierraChatOpen) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Show if either Sierra is enabled or Salesforce button is available and not hidden by page
|
|
||||||
return (
|
|
||||||
(this.webchatGlobalNonpersistedState.shouldLaunchSierra ||
|
|
||||||
this.webchatGlobalNonpersistedState.showWebchatButton) &&
|
|
||||||
!this.shouldHideWebchatButtonOnPage
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -116,10 +107,6 @@ export default {
|
||||||
webchatClicked(event) {
|
webchatClicked(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.launchWebchat();
|
this.launchWebchat();
|
||||||
// Only set sierraChatOpen if Sierra experiment is active
|
|
||||||
if (this.webchatGlobalNonpersistedState.shouldLaunchSierra) {
|
|
||||||
this.sierraChatOpen = true;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
syncSierraExperimentFlag() {
|
syncSierraExperimentFlag() {
|
||||||
const experiments = store.getters.applicationUser.experiments;
|
const experiments = store.getters.applicationUser.experiments;
|
||||||
|
|
@ -159,11 +146,6 @@ export default {
|
||||||
unknownAlertEvent.displayAlert = true;
|
unknownAlertEvent.displayAlert = true;
|
||||||
this.globalAlertMessages.push(unknownAlertEvent);
|
this.globalAlertMessages.push(unknownAlertEvent);
|
||||||
}
|
}
|
||||||
// Listen for Sierra chat open/close events from sierra-webchat
|
|
||||||
this._handleSierraChatVisibility = (event) => {
|
|
||||||
this.sierraChatOpen = !!(event.detail && event.detail.open);
|
|
||||||
};
|
|
||||||
window.addEventListener("sierra-chat-visibility", this._handleSierraChatVisibility);
|
|
||||||
|
|
||||||
// Add scroll listener for header shadow effect
|
// Add scroll listener for header shadow effect
|
||||||
this._handleScroll = () => {
|
this._handleScroll = () => {
|
||||||
|
|
@ -172,8 +154,6 @@ export default {
|
||||||
window.addEventListener("scroll", this._handleScroll);
|
window.addEventListener("scroll", this._handleScroll);
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
window.removeEventListener("sierra-chat-closed", this._handleSierraChatClosed);
|
|
||||||
window.removeEventListener("sierra-chat-visibility", this._handleSierraChatVisibility);
|
|
||||||
window.removeEventListener("sierra-chat-transfer", this._handleSierraToSalesforceTransfer);
|
window.removeEventListener("sierra-chat-transfer", this._handleSierraToSalesforceTransfer);
|
||||||
window.removeEventListener("scroll", this._handleScroll);
|
window.removeEventListener("scroll", this._handleScroll);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
|
||||||
defineRule(
|
defineRule(
|
||||||
"email-address-format",
|
"email-address-format",
|
||||||
regex(
|
regex(
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
|
/^([a-zA-Z0-9_.+]+)@([a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*\.)+([a-zA-Z]{2,})$/,
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
errorMessages.EMAIL_ADDRESS_FORMAT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ const webchatGlobalNonpersistedState = reactive({
|
||||||
|
|
||||||
export const webchatHelper = () => {
|
export const webchatHelper = () => {
|
||||||
function launchWebchat() {
|
function launchWebchat() {
|
||||||
|
webchatGlobalNonpersistedState.showWebchatButton = false;
|
||||||
if (webchatGlobalNonpersistedState.shouldLaunchSierra) {
|
if (webchatGlobalNonpersistedState.shouldLaunchSierra) {
|
||||||
window.dispatchEvent(new CustomEvent("launch-sierra-webchat")); // launches the sierra chat
|
window.dispatchEvent(new CustomEvent("launch-sierra-webchat")); // launches the sierra chat
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
|
||||||
defineRule(
|
defineRule(
|
||||||
"email-address-format",
|
"email-address-format",
|
||||||
regex(
|
regex(
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
|
/^([a-zA-Z0-9_.+]+)@([a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*\.)+([a-zA-Z]{2,})$/,
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
errorMessages.EMAIL_ADDRESS_FORMAT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIR
|
||||||
defineRule(
|
defineRule(
|
||||||
"email-address-format",
|
"email-address-format",
|
||||||
regex(
|
regex(
|
||||||
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
|
/^([a-zA-Z0-9_.+]+)@([a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*\.)+([a-zA-Z]{2,})$/,
|
||||||
errorMessages.EMAIL_ADDRESS_FORMAT
|
errorMessages.EMAIL_ADDRESS_FORMAT
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ export default {
|
||||||
console.log(`Price = ${this.amountDue}`);
|
console.log(`Price = ${this.amountDue}`);
|
||||||
console.log(`Adyen Price = ${this.adyenPriceTotal}`);
|
console.log(`Adyen Price = ${this.adyenPriceTotal}`);
|
||||||
|
|
||||||
const requestBody = this.adyenInitRequestInfo;
|
const requestBody = this.getAdyenInitRequestInfo();
|
||||||
|
|
||||||
console.log(`Calling with:`);
|
console.log(`Calling with:`);
|
||||||
console.log(requestBody);
|
console.log(requestBody);
|
||||||
|
|
@ -294,6 +294,15 @@ export default {
|
||||||
|
|
||||||
console.log(checkout);
|
console.log(checkout);
|
||||||
|
|
||||||
|
const expiryTime = new Date(checkout.options.expiresAt);
|
||||||
|
const expiryInterval = expiryTime.getTime() - new Date().getTime();
|
||||||
|
|
||||||
|
const handleTimeout = () => {
|
||||||
|
this.resetAdyenDropin();
|
||||||
|
};
|
||||||
|
|
||||||
|
const timeout = setTimeout(handleTimeout, expiryInterval);
|
||||||
|
|
||||||
const configuration = {
|
const configuration = {
|
||||||
paymentMethodsConfiguration: {
|
paymentMethodsConfiguration: {
|
||||||
ideal: {
|
ideal: {
|
||||||
|
|
@ -505,14 +514,26 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
async resetAdyenDropin() {
|
||||||
piaType() {
|
this?.dropinComponent?.unmount();
|
||||||
return this.$store.getters.order.payment.piaType;
|
await this.initializeAdyen();
|
||||||
},
|
},
|
||||||
|
|
||||||
adyenInitRequestInfo() {
|
// Now a Method so it is always freshly called and not cached.
|
||||||
|
getIdempotencyKey() {
|
||||||
|
const currentDateTime = new Date();
|
||||||
|
const currentHour = currentDateTime.getUTCHours();
|
||||||
|
const currentDate = currentDateTime.getUTCDate();
|
||||||
|
const id = this?.$store?.getters?.order?.referralCorrelationId;
|
||||||
|
const system = this.sourceSystem;
|
||||||
|
const total = this.adyenPriceTotal;
|
||||||
|
|
||||||
|
return `${id}-${system}-${currentDate}-${currentHour}-${total}`;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Now a Method so it is always freshly called and not cached.
|
||||||
|
getAdyenInitRequestInfo() {
|
||||||
return {
|
return {
|
||||||
sourceSystem: this.sourceSystem,
|
sourceSystem: this.sourceSystem,
|
||||||
referralSequenceNumber: this.$store.getters.order.referralSequenceNumber,
|
referralSequenceNumber: this.$store.getters.order.referralSequenceNumber,
|
||||||
|
|
@ -529,9 +550,15 @@ export default {
|
||||||
IP: "127.0.0.1", // TODO
|
IP: "127.0.0.1", // TODO
|
||||||
firstName: this.$store.getters.order.customer.firstName,
|
firstName: this.$store.getters.order.customer.firstName,
|
||||||
lastName: this.$store.getters.order.customer.lastName,
|
lastName: this.$store.getters.order.customer.lastName,
|
||||||
idempotencyKey: this.idempotencyKey,
|
idempotencyKey: this.getIdempotencyKey(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
piaType() {
|
||||||
|
return this.$store.getters.order.payment.piaType;
|
||||||
|
},
|
||||||
|
|
||||||
workOrderNumberLastSixDigits() {
|
workOrderNumberLastSixDigits() {
|
||||||
const workOrderNumber = this.$store.getters.order.workOrderNumber ?? "";
|
const workOrderNumber = this.$store.getters.order.workOrderNumber ?? "";
|
||||||
|
|
@ -588,10 +615,6 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
idempotencyKey() {
|
|
||||||
return `${this.$store.getters.order.referralCorrelationId}-${this.sourceSystem}`;
|
|
||||||
},
|
|
||||||
|
|
||||||
sourceSystem() {
|
sourceSystem() {
|
||||||
return "FMG-2.0";
|
return "FMG-2.0";
|
||||||
},
|
},
|
||||||
|
|
@ -601,7 +624,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
adyenPriceTotal() {
|
adyenPriceTotal() {
|
||||||
return this.amountDue * 100;
|
return Math.round(this.amountDue * 100);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Cart info
|
// Cart info
|
||||||
|
|
|
||||||
|
|
@ -745,10 +745,16 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updatePaymentMethod(paymentMethod) {
|
updatePaymentMethod(paymentMethod) {
|
||||||
// if the payment method is not set yet, then set it based on what HOP sends us
|
debugLog(
|
||||||
|
`updatePaymentMethod(${paymentMethod}) and existing store.getters.order.payment.piaType = ${store?.getters?.order?.payment?.piaType}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// if the payment method is not set yet, then set it based on what HOP sends
|
||||||
|
// or if its not already set to AfterPay, always set it based on what HOP sends
|
||||||
if (
|
if (
|
||||||
store.getters.order.payment.piaType == paymentMethods.PAY_NOW ||
|
store.getters.order.payment.piaType == paymentMethods.PAY_NOW ||
|
||||||
store.getters.order.payment.piaType == paymentMethods.NONE
|
store.getters.order.payment.piaType == paymentMethods.NONE ||
|
||||||
|
store.getters.order.payment.piaType != paymentMethods.AFTERPAY
|
||||||
) {
|
) {
|
||||||
console.log(new Date() + " UPDATE PaymentMethod from HOP:" + paymentMethod);
|
console.log(new Date() + " UPDATE PaymentMethod from HOP:" + paymentMethod);
|
||||||
this.dispatchStoreAction(
|
this.dispatchStoreAction(
|
||||||
|
|
|
||||||
70
src/layouts/policy-info/policy-info.spec.js
Normal file
70
src/layouts/policy-info/policy-info.spec.js
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import policyInfo from "@/layouts/policy-info/policy-info.vue";
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
|
||||||
|
// Mock our module for promises.
|
||||||
|
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||||
|
settleAllPromises: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Mock fetchCmsContentForPage
|
||||||
|
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||||
|
fetchCmsContentForPage: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("policy-info.vue", () => {
|
||||||
|
describe("component rendering", () => {
|
||||||
|
test("renders funnelHeader component", () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
expect(wrapper.findComponent({ name: "funnelHeader" }).exists()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders funnelSubHeader component", () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
expect(wrapper.findComponent({ name: "funnelSubHeader" }).exists()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders navbar component", () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
expect(wrapper.findComponent({ name: "navbar" }).exists()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders Form component", () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
expect(wrapper.findComponent({ name: "Form" }).exists()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("methods", () => {
|
||||||
|
test("arePagePrerequisitesValid returns true", () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
expect(wrapper.vm.arePagePrerequisitesValid()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocks() {
|
||||||
|
const mockCmsContent = {
|
||||||
|
FunnelHeaderWidget: { Text: "Header" },
|
||||||
|
FunnelSubHeaderWidget: { Text: "Subheader" },
|
||||||
|
FunnelFooterWidget: { Text: "Footer" },
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchCmsContentForPage.mockResolvedValue(mockCmsContent);
|
||||||
|
settleAllPromises.mockResolvedValue({ cmsContent: mockCmsContent });
|
||||||
|
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
route: { name: "policy-info", query: {}, params: {} },
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn(),
|
||||||
|
navigateWithSaving: jest.fn(),
|
||||||
|
navigateWithoutSaving: jest.fn(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const wrapper = shallowMount(policyInfo, mountOptions);
|
||||||
|
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
72
src/layouts/policy-info/policy-info.vue
Normal file
72
src/layouts/policy-info/policy-info.vue
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
<template>
|
||||||
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||||
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
|
||||||
|
<funnelSubHeader class="pb-4" cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
|
<!--
|
||||||
|
... Page code goes here.
|
||||||
|
-->
|
||||||
|
<navbar
|
||||||
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
ref="navbar"
|
||||||
|
:isForwardActionDisabled="!meta.valid"
|
||||||
|
@back-clicked="backButtonAction"
|
||||||
|
@ForwardClicked="forwardButtonAction" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
||||||
|
import navbar from "@/fmg-components/nav-bar/nav-bar";
|
||||||
|
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
|
||||||
|
import { Form } from "vee-validate";
|
||||||
|
|
||||||
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "policy-info",
|
||||||
|
mixins: [],
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
Form,
|
||||||
|
funnelHeader,
|
||||||
|
navbar,
|
||||||
|
funnelSubHeader,
|
||||||
|
},
|
||||||
|
// Ensure CMS content is fetched during route navigation without depending on `to`/`from`
|
||||||
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
const pageName = to.name;
|
||||||
|
const cmsContentPromise = fetchCmsContentForPage(pageName);
|
||||||
|
const promiseResultMap = [
|
||||||
|
{
|
||||||
|
resultKey: "cmsContent",
|
||||||
|
promise: cmsContentPromise,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
|
next((vm) => {
|
||||||
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async backButtonAction() {
|
||||||
|
// Stub, for navigating back via nav-bar.
|
||||||
|
},
|
||||||
|
async forwardButtonAction() {
|
||||||
|
// Stub, for navigating forward via nav-bar
|
||||||
|
},
|
||||||
|
arePagePrerequisitesValid() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
@ -72,10 +72,10 @@ export function isDropOffRouteCode(routeCode) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTodayDate(routeCode) {
|
export function getTodayDate() {
|
||||||
return new Date();
|
return new Date();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTodayDateString(routeCode) {
|
export function getTodayDateString() {
|
||||||
return convertDateToDateString(getTodayDate());
|
return convertDateToDateString(getTodayDate());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
183
src/layouts/schedule/schedule.spec.js
Normal file
183
src/layouts/schedule/schedule.spec.js
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
// Components
|
||||||
|
import schedule from "@/layouts/schedule/schedule.vue";
|
||||||
|
|
||||||
|
// Supporting Files
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { routeData } from "@/router/constants/routes";
|
||||||
|
import store from "@/store";
|
||||||
|
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||||
|
|
||||||
|
const storeMocked = {
|
||||||
|
getters: {
|
||||||
|
payment: { isInsurance: false },
|
||||||
|
order: {
|
||||||
|
payment: { isInsurance: false, insuranceCoverage: { isVerified: false } },
|
||||||
|
referralNumber: "",
|
||||||
|
serviceLocation: {
|
||||||
|
address: "",
|
||||||
|
address2: "",
|
||||||
|
city: "",
|
||||||
|
state: "",
|
||||||
|
zipCode: "00000",
|
||||||
|
zipCodeCtu: "000",
|
||||||
|
appointmentType: null,
|
||||||
|
provider: {},
|
||||||
|
isVehicleProtected: false,
|
||||||
|
},
|
||||||
|
schedule: {
|
||||||
|
date: "",
|
||||||
|
routeCode: "",
|
||||||
|
startTime: "",
|
||||||
|
endTime: "",
|
||||||
|
jobMinMinutes: null,
|
||||||
|
jobMaxMinutes: null,
|
||||||
|
},
|
||||||
|
policy: {
|
||||||
|
isItac: false,
|
||||||
|
isNoComp: false,
|
||||||
|
},
|
||||||
|
damage: { isRepair: false },
|
||||||
|
lineItems: { glassParts: [] },
|
||||||
|
},
|
||||||
|
vehicle: {
|
||||||
|
cardId: "",
|
||||||
|
},
|
||||||
|
lineItems: {
|
||||||
|
supportingItems: [],
|
||||||
|
},
|
||||||
|
applicationUser: {
|
||||||
|
experiments: [],
|
||||||
|
},
|
||||||
|
isMobileAppointment: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||||
|
navigateToHeritageFunnel: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("schedule.vue", () => {
|
||||||
|
describe("navigation", () => {
|
||||||
|
test("backButtonAction => non-insurance: navigateWithoutSaving called", () => {
|
||||||
|
// Arrange
|
||||||
|
const { wrapper, mocks } = setupMocks();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
wrapper.vm.backButtonAction();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.vm.$router.navigateWithoutSaving).toHaveBeenCalledWith(
|
||||||
|
mocks.navigationScenarios.CLICKED_BACK,
|
||||||
|
routeData.SCHEDULE.name
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("backButtonAction => insurance verified: navigateToHeritageFunnel called", () => {
|
||||||
|
// Arrange
|
||||||
|
store.getters.order.payment.isInsurance = true;
|
||||||
|
store.getters.order.payment.insuranceCoverage = { isVerified: true };
|
||||||
|
store.getters.order.referralNumber = "";
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
wrapper.vm.backButtonAction();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(navigateToHeritageFunnel).toHaveBeenCalledWith({
|
||||||
|
shouldSaveSession: false,
|
||||||
|
pageNameToLog: "schedule",
|
||||||
|
navType: "back",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("computed: isForwardActionDisabled", () => {
|
||||||
|
test("should be true when routeCode missing or appointmentType not set", async () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
await wrapper.setData({
|
||||||
|
selectedTimeSlotInfo: { timeSlot: { routeCode: null } },
|
||||||
|
appointmentType: null,
|
||||||
|
});
|
||||||
|
expect(wrapper.vm.isForwardActionDisabled).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should be false when routeCode present and appointmentType set", async () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
await wrapper.setData({
|
||||||
|
selectedTimeSlotInfo: { timeSlot: { routeCode: "RC123" } },
|
||||||
|
appointmentType: "SomeType",
|
||||||
|
});
|
||||||
|
expect(wrapper.vm.isForwardActionDisabled).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("computed: selectedRouteCodeData", () => {
|
||||||
|
test("should return null when routeCode not set", async () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
await wrapper.setData({
|
||||||
|
selectedTimeSlotInfo: { timeSlot: { routeCode: null } },
|
||||||
|
});
|
||||||
|
expect(wrapper.vm.selectedRouteCodeData).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should return routeCode and premium flag when set", async () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
await wrapper.setData({
|
||||||
|
selectedTimeSlotInfo: {
|
||||||
|
timeSlot: { routeCode: "RC999" },
|
||||||
|
isPremiumAppointment: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(wrapper.vm.selectedRouteCodeData).toEqual({
|
||||||
|
routeCode: "RC999",
|
||||||
|
isPremiumAppointment: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("forwardButtonAction (early exit path)", () => {
|
||||||
|
test("shows recal acknowledgement popup and does not navigate when required", async () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
// Force the recal-ack modal path
|
||||||
|
wrapper.vm.showRecalAcknowledgementModal = jest.fn(() => true);
|
||||||
|
await wrapper.setData({ isRecalAcknowledgedForScheduling: null });
|
||||||
|
|
||||||
|
await wrapper.vm.forwardButtonAction();
|
||||||
|
|
||||||
|
expect(wrapper.vm.showRecalAcknowledgementPopup).toBe(true);
|
||||||
|
expect(wrapper.vm.$router.navigateWithSaving).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function setupMocks(mountOptionsMockData = {}) {
|
||||||
|
const route = { name: "schedule" };
|
||||||
|
const defaultMountOptions = {
|
||||||
|
route: route,
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn(),
|
||||||
|
navigateWithSaving: jest.fn(),
|
||||||
|
navigateWithoutSaving: jest.fn(),
|
||||||
|
},
|
||||||
|
store: { ...storeMocked },
|
||||||
|
};
|
||||||
|
const mockBaseMixin = {
|
||||||
|
methods: {
|
||||||
|
getTierOnePackagePrice: jest.fn(),
|
||||||
|
filterOutFees: jest.fn(),
|
||||||
|
getCmsContent: jest.fn(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const baseMountOptions = getMountOptions({
|
||||||
|
...defaultMountOptions,
|
||||||
|
...mountOptionsMockData,
|
||||||
|
});
|
||||||
|
|
||||||
|
baseMountOptions.global.mixins = [mockBaseMixin];
|
||||||
|
baseMountOptions.global.mocks.pageName = route.name;
|
||||||
|
const wrapper = shallowMount(schedule, baseMountOptions);
|
||||||
|
wrapper.getCmsContent = jest.fn();
|
||||||
|
|
||||||
|
return { wrapper, mocks: baseMountOptions.global?.mocks || {} };
|
||||||
|
}
|
||||||
|
|
@ -98,15 +98,11 @@
|
||||||
linkWidgetName="ServiceZipLinkWidget"
|
linkWidgetName="ServiceZipLinkWidget"
|
||||||
modalWidgetName="ServiceZipModalWidget" />
|
modalWidgetName="ServiceZipModalWidget" />
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="row your-shop-location" v-if="showShopLocationComponent">
|
||||||
class="row your-shop-location"
|
|
||||||
v-if="appointmentType && appointmentType !== appointmentTypeStrings.MOBILE">
|
|
||||||
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
|
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
|
||||||
<div>
|
<div>
|
||||||
<shopLocation
|
<shopLocation
|
||||||
v-if="
|
v-if="showShopLocationComponent"
|
||||||
appointmentType && appointmentType !== appointmentTypeStrings.MOBILE
|
|
||||||
"
|
|
||||||
:selectedShop="selectedShopAnswer"
|
:selectedShop="selectedShopAnswer"
|
||||||
:selectedProviderNumberFromParent="selectedProvider?.providerNumber"
|
:selectedProviderNumberFromParent="selectedProvider?.providerNumber"
|
||||||
:shopProviderDataFromParent="shopProviderData"
|
:shopProviderDataFromParent="shopProviderData"
|
||||||
|
|
@ -153,7 +149,8 @@
|
||||||
:pricingByDayBasePrice="pricingByDayBasePrice"
|
:pricingByDayBasePrice="pricingByDayBasePrice"
|
||||||
:pricingByDayUpcharge="pricingByDayUpcharge"
|
:pricingByDayUpcharge="pricingByDayUpcharge"
|
||||||
:showPricingByDay="showPricingByDay"
|
:showPricingByDay="showPricingByDay"
|
||||||
:isPricingByDayExperiment="isPricingByDayExperiment" />
|
:isPricingByDayExperiment="isPricingByDayExperiment"
|
||||||
|
:loadingStatus="calendarLoadingStatus" />
|
||||||
<timeSlotQuestion
|
<timeSlotQuestion
|
||||||
ref="timeSlotModalQuestion"
|
ref="timeSlotModalQuestion"
|
||||||
v-if="showTimeSlotQuestion"
|
v-if="showTimeSlotQuestion"
|
||||||
|
|
@ -172,7 +169,8 @@
|
||||||
:timeSlotsForSelectedDate="timeSlotsForSelectedDate"
|
:timeSlotsForSelectedDate="timeSlotsForSelectedDate"
|
||||||
:isSameDay="isSameDay"
|
:isSameDay="isSameDay"
|
||||||
:selectedRouteCodeData="selectedRouteCodeData"
|
:selectedRouteCodeData="selectedRouteCodeData"
|
||||||
@waitListRequested="handleWaitListRequested" />
|
@waitListRequested="handleWaitListRequested"
|
||||||
|
:lazyLoadAmountToLoad="10" />
|
||||||
<navbar
|
<navbar
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
ref="navbar"
|
ref="navbar"
|
||||||
|
|
@ -445,15 +443,14 @@ export default {
|
||||||
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
|
selectedTimeSlotInfo: this.getSelectedTimeSlotInfo(),
|
||||||
mobilePremiumAppointmentFee: null,
|
mobilePremiumAppointmentFee: null,
|
||||||
waitListRequested: null,
|
waitListRequested: null,
|
||||||
displayWaitList: null,
|
|
||||||
pricingByDayUpchargeLineItem: null,
|
pricingByDayUpchargeLineItem: null,
|
||||||
includePricingByDayUpcharge: null,
|
includePricingByDayUpcharge: null,
|
||||||
isPricingByDayExperiment: null,
|
isPricingByDayExperiment: null,
|
||||||
pricingByDayBasePrice: null,
|
pricingByDayBasePrice: null,
|
||||||
pricingByDayUpcharge: null,
|
pricingByDayUpcharge: null,
|
||||||
showPricingByDay: null,
|
showPricingByDay: null,
|
||||||
selectableDatesInshop: [],
|
selectableDatesInshop: {},
|
||||||
selectableDatesMobile: [],
|
selectableDatesMobile: {},
|
||||||
preSelectedDate: null,
|
preSelectedDate: null,
|
||||||
streetAddress: this.getServiceAddressFromStore(),
|
streetAddress: this.getServiceAddressFromStore(),
|
||||||
apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(),
|
apartmentNumberOrBusinessName: this.getServiceAddress2FromStore(),
|
||||||
|
|
@ -486,6 +483,7 @@ export default {
|
||||||
experimentSettings.SHOW_MOBILE_FIRST_APPT,
|
experimentSettings.SHOW_MOBILE_FIRST_APPT,
|
||||||
"true"
|
"true"
|
||||||
),
|
),
|
||||||
|
calendarLoadingStatus: "none",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
|
@ -596,6 +594,8 @@ export default {
|
||||||
|
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
|
vm.showLoadingModal();
|
||||||
|
vm.calendarLoadingStatus = "initial";
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
|
vm.$refs.locationAlerts.initializeComponent(resultMap.alertReasons);
|
||||||
vm.mobilePremiumAppointmentFee = pricedPremiumFee;
|
vm.mobilePremiumAppointmentFee = pricedPremiumFee;
|
||||||
|
|
@ -616,6 +616,9 @@ export default {
|
||||||
);
|
);
|
||||||
vm.initializeDatePicker().then(() => {
|
vm.initializeDatePicker().then(() => {
|
||||||
vm.showMobileFirstModal();
|
vm.showMobileFirstModal();
|
||||||
|
vm.hideLoadingModal();
|
||||||
|
vm.calendarLoadingStatus = "none";
|
||||||
|
if (!vm.preSelectedDate) vm.setSelectedDateToFirstAvailable();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -632,6 +635,20 @@ export default {
|
||||||
this.handleZipCodeChange(newValue);
|
this.handleZipCodeChange(newValue);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
showShopLocationComponent() {
|
||||||
|
// If we get no inshop or mobile data, then show the shoplocation component so the user is not
|
||||||
|
// looking at a half blank screen with no way to try another zip/location.
|
||||||
|
if (
|
||||||
|
(this.selectableDatesInshop === undefined &&
|
||||||
|
this.selectableDatesMobile === undefined) ||
|
||||||
|
(this.selectableDatesInshop?.days?.length === 0 &&
|
||||||
|
this.selectableDatesMobile?.days?.length === 0) ||
|
||||||
|
(this.appointmentType && this.appointmentType !== AppointmentTypeStrings.MOBILE)
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
isMobileSelected() {
|
isMobileSelected() {
|
||||||
return (
|
return (
|
||||||
this.appointmentType == AppointmentTypeStrings.MOBILE ||
|
this.appointmentType == AppointmentTypeStrings.MOBILE ||
|
||||||
|
|
@ -887,6 +904,53 @@ export default {
|
||||||
? this.$refs.mobileFirstModal?.getIsModalOpen()
|
? this.$refs.mobileFirstModal?.getIsModalOpen()
|
||||||
: false;
|
: false;
|
||||||
},
|
},
|
||||||
|
displayWaitList() {
|
||||||
|
if (!this.appointmentType) return false;
|
||||||
|
const firstMobileDateString =
|
||||||
|
Array.isArray(this.selectableDatesMobile.days) &&
|
||||||
|
this.selectableDatesMobile.days.length > 0
|
||||||
|
? this.selectableDatesMobile.days[0].date
|
||||||
|
: null;
|
||||||
|
const firstInshopDateString =
|
||||||
|
Array.isArray(this.selectableDatesInshop.days) &&
|
||||||
|
this.selectableDatesInshop.days.length > 0
|
||||||
|
? this.selectableDatesInshop.days[0].date
|
||||||
|
: null;
|
||||||
|
const dateString =
|
||||||
|
this.isMobileSelected && firstMobileDateString
|
||||||
|
? firstMobileDateString
|
||||||
|
: firstInshopDateString;
|
||||||
|
|
||||||
|
if (
|
||||||
|
experimentMixin.methods.hasSettingEqualTo(
|
||||||
|
experimentSettings.DISPLAY_WAITLIST,
|
||||||
|
"true"
|
||||||
|
) &&
|
||||||
|
dateString
|
||||||
|
) {
|
||||||
|
const [year, month, day] = dateString.split("-").map(Number);
|
||||||
|
const targetDate = new Date(year, month - 1, day);
|
||||||
|
const currentDate = getTodayDate();
|
||||||
|
const futureDate = new Date(currentDate);
|
||||||
|
const experimentThresholdDays = experimentMixin.methods.hasSetting(
|
||||||
|
experimentSettings.WAITLIST_THRESHOLD_DAYS
|
||||||
|
)
|
||||||
|
? parseInt(
|
||||||
|
experimentMixin.methods.getSettingValue(
|
||||||
|
experimentSettings.WAITLIST_THRESHOLD_DAYS
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: 0;
|
||||||
|
futureDate.setDate(currentDate.getDate() + experimentThresholdDays);
|
||||||
|
|
||||||
|
if (targetDate >= futureDate) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
hasSelectableDatesLoaded() {
|
hasSelectableDatesLoaded() {
|
||||||
if (this.isMobileSelected) {
|
if (this.isMobileSelected) {
|
||||||
return this.selectableDatesMobile?.days?.length > 0;
|
return this.selectableDatesMobile?.days?.length > 0;
|
||||||
|
|
@ -1155,9 +1219,10 @@ export default {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async onShopSelected(shopQuestionPopUpData) {
|
onShopSelected(shopQuestionPopUpData) {
|
||||||
this.resetWaitlist();
|
this.resetWaitlist();
|
||||||
this.preSelectedDate = null;
|
this.preSelectedDate = null;
|
||||||
|
this.calendarLoadingStatus = "reinitial";
|
||||||
this.shopProviderData = shopQuestionPopUpData.shopProviderData;
|
this.shopProviderData = shopQuestionPopUpData.shopProviderData;
|
||||||
const oldProvider = this.selectedProvider;
|
const oldProvider = this.selectedProvider;
|
||||||
const selectedProvider = this.shopProviderData.shopProviders.find((shopProvider) => {
|
const selectedProvider = this.shopProviderData.shopProviders.find((shopProvider) => {
|
||||||
|
|
@ -1177,11 +1242,16 @@ export default {
|
||||||
this.updateSelectedProvider(selectedProvider);
|
this.updateSelectedProvider(selectedProvider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.initializeDatePicker();
|
this.initializeDatePicker().then(() => {
|
||||||
this.setSelectedDateToFirstAvailable();
|
this.showMobileFirstModal();
|
||||||
|
this.hideLoadingModal();
|
||||||
|
this.calendarLoadingStatus = "none";
|
||||||
|
this.setSelectedDateToFirstAvailable();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
async getMoreScheduleData(startDate, endDate) {
|
async getMoreScheduleData(startDate, endDate) {
|
||||||
// called only when "View more dates" is clicked; not on initial page load
|
// called only when "View more dates" is clicked; not on initial page load
|
||||||
|
this.calendarLoadingStatus = "more";
|
||||||
const moreShopTimeSlots = await getScheduleApiResponse({
|
const moreShopTimeSlots = await getScheduleApiResponse({
|
||||||
startDateString: startDate,
|
startDateString: startDate,
|
||||||
endDateString: endDate,
|
endDateString: endDate,
|
||||||
|
|
@ -1193,6 +1263,7 @@ export default {
|
||||||
includeMobileTimeSlots: this.isServiceableMobile,
|
includeMobileTimeSlots: this.isServiceableMobile,
|
||||||
includeInshopTimeSlots: this.isServiceableInshop || this.isServiceableDropoff,
|
includeInshopTimeSlots: this.isServiceableInshop || this.isServiceableDropoff,
|
||||||
});
|
});
|
||||||
|
this.calendarLoadingStatus = "none";
|
||||||
|
|
||||||
// ADD API CALL RESULTS TO EXISTING DATE DATA
|
// ADD API CALL RESULTS TO EXISTING DATE DATA
|
||||||
this.selectableDatesInshop.days = this.selectableDatesInshop.days.concat(
|
this.selectableDatesInshop.days = this.selectableDatesInshop.days.concat(
|
||||||
|
|
@ -1231,7 +1302,6 @@ export default {
|
||||||
await datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData;
|
await datePickerInitialData.initialShopTimeSlotsResponse.inshopTimeSlotsData;
|
||||||
this.selectableDatesMobile =
|
this.selectableDatesMobile =
|
||||||
await datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData;
|
await datePickerInitialData.initialShopTimeSlotsResponse.mobileTimeSlotsData;
|
||||||
this.setDisplayWaitList();
|
|
||||||
|
|
||||||
if (this.preSelectedDate) {
|
if (this.preSelectedDate) {
|
||||||
this.selectedDate = this.preSelectedDate;
|
this.selectedDate = this.preSelectedDate;
|
||||||
|
|
@ -1243,11 +1313,8 @@ export default {
|
||||||
) {
|
) {
|
||||||
await this.$nextTick();
|
await this.$nextTick();
|
||||||
await this.$refs.datePicker.showAnotherMonth();
|
await this.$refs.datePicker.showAnotherMonth();
|
||||||
this.setDisplayWaitList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isShowMobileFirstAppt && this.hideLoadingModal();
|
|
||||||
},
|
},
|
||||||
getIsRecalAcknowledgedForSchedulingFromStore() {
|
getIsRecalAcknowledgedForSchedulingFromStore() {
|
||||||
return store.getters.order.isRecalAcknowledgedForScheduling;
|
return store.getters.order.isRecalAcknowledgedForScheduling;
|
||||||
|
|
@ -1261,8 +1328,8 @@ export default {
|
||||||
if (isMobileSelected === undefined) {
|
if (isMobileSelected === undefined) {
|
||||||
isMobileSelected = this.appointmentType === AppointmentTypeStrings.MOBILE;
|
isMobileSelected = this.appointmentType === AppointmentTypeStrings.MOBILE;
|
||||||
}
|
}
|
||||||
let storedDate = store.getters.order.schedule.date;
|
let storedDate = store.getters.order.schedule?.date;
|
||||||
if (isMobileSelected) storedDate += "-mobile";
|
if (isMobileSelected && storedDate) storedDate += "-mobile";
|
||||||
return storedDate;
|
return storedDate;
|
||||||
},
|
},
|
||||||
getSelectedTimeSlotInfo() {
|
getSelectedTimeSlotInfo() {
|
||||||
|
|
@ -1517,39 +1584,6 @@ export default {
|
||||||
}
|
}
|
||||||
this.showLoadingModal();
|
this.showLoadingModal();
|
||||||
},
|
},
|
||||||
setDisplayWaitList() {
|
|
||||||
const dateString = this.isMobileSelected
|
|
||||||
? this.selectableDatesMobile?.days[0]?.date
|
|
||||||
: this.selectableDatesInshop?.days[0]?.date;
|
|
||||||
if (
|
|
||||||
experimentMixin.methods.hasSettingEqualTo(
|
|
||||||
experimentSettings.DISPLAY_WAITLIST,
|
|
||||||
"true"
|
|
||||||
) &&
|
|
||||||
dateString
|
|
||||||
) {
|
|
||||||
const [year, month, day] = dateString.split("-").map(Number);
|
|
||||||
const targetDate = new Date(year, month - 1, day);
|
|
||||||
const currentDate = getTodayDate();
|
|
||||||
const futureDate = new Date(currentDate);
|
|
||||||
const experimentThresholdDays = experimentMixin.methods.hasSetting(
|
|
||||||
experimentSettings.WAITLIST_THRESHOLD_DAYS
|
|
||||||
)
|
|
||||||
? parseInt(
|
|
||||||
experimentMixin.methods.getSettingValue(
|
|
||||||
experimentSettings.WAITLIST_THRESHOLD_DAYS
|
|
||||||
)
|
|
||||||
)
|
|
||||||
: 0;
|
|
||||||
futureDate.setDate(currentDate.getDate() + experimentThresholdDays);
|
|
||||||
|
|
||||||
if (targetDate >= futureDate) {
|
|
||||||
this.displayWaitList = true;
|
|
||||||
} else {
|
|
||||||
this.displayWaitList = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateSupportingItems() {
|
updateSupportingItems() {
|
||||||
const supportingItems = this.getSupportingItems();
|
const supportingItems = this.getSupportingItems();
|
||||||
|
|
||||||
|
|
@ -1758,6 +1792,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resetMobileLocation();
|
this.resetMobileLocation();
|
||||||
|
this.calendarLoadingStatus = "initial";
|
||||||
|
|
||||||
getShopProviderData(newZipCode.zipCode, this.pageName).then((result) => {
|
getShopProviderData(newZipCode.zipCode, this.pageName).then((result) => {
|
||||||
this.shopProviderData = result.data;
|
this.shopProviderData = result.data;
|
||||||
|
|
@ -1768,6 +1803,9 @@ export default {
|
||||||
this.selectedDate = null;
|
this.selectedDate = null;
|
||||||
this.initializeDatePicker().then(() => {
|
this.initializeDatePicker().then(() => {
|
||||||
this.showMobileFirstModal();
|
this.showMobileFirstModal();
|
||||||
|
this.hideLoadingModal();
|
||||||
|
this.calendarLoadingStatus = "none";
|
||||||
|
this.setSelectedDateToFirstAvailable();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -1820,7 +1858,6 @@ export default {
|
||||||
this.appointmentType = null;
|
this.appointmentType = null;
|
||||||
}
|
}
|
||||||
this.setSelectedDateToFirstAvailable(); // v-if on appointmentTypeQuestion ensures dates have been loaded by now
|
this.setSelectedDateToFirstAvailable(); // v-if on appointmentTypeQuestion ensures dates have been loaded by now
|
||||||
this.setDisplayWaitList(); // v-if on appointmentTypeQuestion ensures dates have been loaded by now
|
|
||||||
},
|
},
|
||||||
setSelectedDateToFirstAvailable() {
|
setSelectedDateToFirstAvailable() {
|
||||||
this.selectedDate = this.getFirstAvailableDate();
|
this.selectedDate = this.getFirstAvailableDate();
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,10 @@
|
||||||
isInshopOrDropOffAppointment ? 'is-inshop-or-drop-off-appointment' : '',
|
isInshopOrDropOffAppointment ? 'is-inshop-or-drop-off-appointment' : '',
|
||||||
]"
|
]"
|
||||||
:answers="availableTimeSlots"
|
:answers="availableTimeSlots"
|
||||||
:lazyLoad="{ isLazyLoad: !isMobileAppointment, amountToLoad: 10 }"
|
:lazyLoad="{
|
||||||
|
isLazyLoad: isLazyLoad,
|
||||||
|
amountToLoad: lazyLoadAmountToLoad || 10,
|
||||||
|
}"
|
||||||
groupName="chooseTimeSlot"
|
groupName="chooseTimeSlot"
|
||||||
textPosition="text-center"
|
textPosition="text-center"
|
||||||
questionText="Available times:"
|
questionText="Available times:"
|
||||||
|
|
@ -134,6 +137,7 @@ export default {
|
||||||
isSameDay: Boolean,
|
isSameDay: Boolean,
|
||||||
displayWaitList: Boolean,
|
displayWaitList: Boolean,
|
||||||
selectedRouteCodeData: Object,
|
selectedRouteCodeData: Object,
|
||||||
|
lazyLoadAmountToLoad: Number,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -396,6 +400,26 @@ export default {
|
||||||
!this.isDropOffAppointmentAvailable
|
!this.isDropOffAppointmentAvailable
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
isLazyLoad() {
|
||||||
|
if (this.availableTimeSlots?.length < this.lazyLoadAmountToLoad + 1) return false;
|
||||||
|
if (this.isMobileAppointment) return false;
|
||||||
|
if (this.selectedAnswerForTimeSlots && !this.isSelectedInshopTimeSlotShowing)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
availableTimeSlotsForInshop() {
|
||||||
|
return this.getAvailableTimeSlotsForInshop(this.timeSlotsForSelectedDate?.timeSlots);
|
||||||
|
},
|
||||||
|
isSelectedInshopTimeSlotShowing() {
|
||||||
|
if (!this.selectedAnswerForTimeSlots) return false;
|
||||||
|
const idx = this.availableTimeSlotsForInshop?.findIndex((timeSlot) => {
|
||||||
|
return timeSlot.value === this.selectedAnswerForTimeSlots;
|
||||||
|
});
|
||||||
|
if (idx > -1 && idx < this.lazyLoadAmountToLoad) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateDropoffAndTimeSlotAnswersFromSelectedRouteCodeData(selectedRouteCodeData) {
|
updateDropoffAndTimeSlotAnswersFromSelectedRouteCodeData(selectedRouteCodeData) {
|
||||||
|
|
@ -453,6 +477,7 @@ export default {
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
getAvailableTimeSlotsForInshop(timeSlotsForSelectedDate) {
|
getAvailableTimeSlotsForInshop(timeSlotsForSelectedDate) {
|
||||||
|
if (!timeSlotsForSelectedDate) return;
|
||||||
return timeSlotsForSelectedDate
|
return timeSlotsForSelectedDate
|
||||||
.filter((timeSlot) => {
|
.filter((timeSlot) => {
|
||||||
return !isDropOffRouteCode(timeSlot.id);
|
return !isDropOffRouteCode(timeSlot.id);
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ import { errorMessages } from "@/constants/error-messages";
|
||||||
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
||||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
||||||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
|
import { debugLog } from "@/helpers/debug-log-helper";
|
||||||
|
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import baseMixin from "@/mixins/base-mixin";
|
import baseMixin from "@/mixins/base-mixin";
|
||||||
|
|
@ -144,6 +145,7 @@ export default {
|
||||||
if (store.getters.externalParameterState?.isExternalParameter) {
|
if (store.getters.externalParameterState?.isExternalParameter) {
|
||||||
await nextTick();
|
await nextTick();
|
||||||
const isValid = await baseMixin.methods.isFormValid(vm.$refs.theForm);
|
const isValid = await baseMixin.methods.isFormValid(vm.$refs.theForm);
|
||||||
|
debugLog(`**** vehicle-damage is form valid: ${isValid} ****`);
|
||||||
if (
|
if (
|
||||||
store.getters.vehicle?.vehicleSubType === "MOTOR HOME" &&
|
store.getters.vehicle?.vehicleSubType === "MOTOR HOME" &&
|
||||||
store.getters.externalParameterDamage.damageType?.toUpperCase() ===
|
store.getters.externalParameterDamage.damageType?.toUpperCase() ===
|
||||||
|
|
@ -183,7 +185,10 @@ export default {
|
||||||
const selectedGlassToReplace =
|
const selectedGlassToReplace =
|
||||||
resultMap.damageOptions.windshieldOptions.availableReplacementOptions;
|
resultMap.damageOptions.windshieldOptions.availableReplacementOptions;
|
||||||
|
|
||||||
if (selectedGlassToReplace == damageLocationsSelected.SINGLE) {
|
if (
|
||||||
|
selectedGlassToReplace == damageLocationsSelected.SINGLE &&
|
||||||
|
store.getters.externalParameterDamage.damageType
|
||||||
|
) {
|
||||||
vm.selectedWindshieldOptions.selectedWindshieldReplaceOptions.push(
|
vm.selectedWindshieldOptions.selectedWindshieldReplaceOptions.push(
|
||||||
damageLocationsSelected.SINGLE
|
damageLocationsSelected.SINGLE
|
||||||
);
|
);
|
||||||
|
|
@ -251,6 +256,8 @@ export default {
|
||||||
if (store.getters.vehicle.carId) {
|
if (store.getters.vehicle.carId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
debugLog("**** Vehicle Page Prereq invalid ****");
|
||||||
|
debugLog("store.getters.vehicle.carId:", store.getters.vehicle?.carId, true);
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
attachCustomEvents() {
|
attachCustomEvents() {
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ import { applicationConfig } from "../constants/application-config";
|
||||||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||||
import { routeData } from "@/router/constants/routes";
|
import { routeData } from "@/router/constants/routes";
|
||||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
import { Variables } from "../constants/analytics";
|
|
||||||
import { containsRecalParts, getRecalPartNumbers } from "@/helpers/recal-helper";
|
import { containsRecalParts, getRecalPartNumbers } from "@/helpers/recal-helper";
|
||||||
import { getAmountDue, getSubTotal, getSalesTax } from "@/helpers/pricing-helper.js";
|
import { getAmountDue, getSubTotal, getSalesTax } from "@/helpers/pricing-helper.js";
|
||||||
import { partTypeStrings } from "@/constants/part-type-strings";
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
|
|
@ -248,9 +247,25 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
var appointment = `${order?.schedule?.date ?? ""} ${order?.schedule?.startTime ?? ""}`;
|
var appointment = `${order?.schedule?.date ?? ""} ${order?.schedule?.startTime ?? ""}`;
|
||||||
|
var currentPageName = getPageNameFromRouter();
|
||||||
|
|
||||||
|
// add query strings to the page name for debugging. on the vehicle page, if from an external link, pull it from the stash
|
||||||
|
if (currentPageName === "vehicle") {
|
||||||
|
if (!window.location.search) {
|
||||||
|
if (store.getters.externalParameterState?.qsStash) {
|
||||||
|
currentPageName += `${store.getters.externalParameterState.qsStash}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentPageName += `${window.location.search}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (window.location.search) {
|
||||||
|
currentPageName += `${window.location.search}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var sessionData = {};
|
var sessionData = {};
|
||||||
sessionData.currentPage = getPageNameFromRouter();
|
sessionData.currentPage = currentPageName;
|
||||||
sessionData.sid = getSessionIdValue();
|
sessionData.sid = getSessionIdValue();
|
||||||
sessionData.deviceId = getDeviceIdValue();
|
sessionData.deviceId = getDeviceIdValue();
|
||||||
sessionData.fmgSessionId = applicationUser?.savedSessionId;
|
sessionData.fmgSessionId = applicationUser?.savedSessionId;
|
||||||
|
|
@ -952,9 +967,6 @@ export default {
|
||||||
ValueToLogTypes() {
|
ValueToLogTypes() {
|
||||||
return ValueToLogTypes;
|
return ValueToLogTypes;
|
||||||
},
|
},
|
||||||
Variables() {
|
|
||||||
return Variables;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,10 @@ export const routeData = {
|
||||||
name: "quote",
|
name: "quote",
|
||||||
path: "/quote",
|
path: "/quote",
|
||||||
},
|
},
|
||||||
|
POLICY_INFO: {
|
||||||
|
name: "policy-info",
|
||||||
|
path: "/policy-info",
|
||||||
|
},
|
||||||
INSURANCE_COMPANY: {
|
INSURANCE_COMPANY: {
|
||||||
name: "insurance-company",
|
name: "insurance-company",
|
||||||
path: "/insurance-company",
|
path: "/insurance-company",
|
||||||
|
|
|
||||||
|
|
@ -429,6 +429,10 @@ const routingTable = function () {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pageName: routeData.POLICY_INFO.name,
|
||||||
|
maps: [],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pageName: routeData.INSURANCE_COMPANY.name,
|
pageName: routeData.INSURANCE_COMPANY.name,
|
||||||
maps: [
|
maps: [
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { storeActions } from "@/constants/store-actions";
|
||||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||||
import { queryStrings } from "@/constants/query-strings";
|
import { queryStrings } from "@/constants/query-strings";
|
||||||
import { externalParameterStatus } from "@/constants/external-parameters";
|
import { externalParameterStatus } from "@/constants/external-parameters";
|
||||||
|
import { debugLog } from "@/helpers/debug-log-helper";
|
||||||
|
|
||||||
export async function initializeFromQueryStrings() {
|
export async function initializeFromQueryStrings() {
|
||||||
// Get advertiser info
|
// Get advertiser info
|
||||||
|
|
@ -26,12 +27,13 @@ function setupAdvertisersAndAffiliates() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateExternalParameterState() {
|
function updateExternalParameterState() {
|
||||||
|
debugLog("--- updateExternalParameterState ---");
|
||||||
const externalParameterYear = getQuerystringParameter(queryStrings.VEHICLE_YEAR);
|
const externalParameterYear = getQuerystringParameter(queryStrings.VEHICLE_YEAR);
|
||||||
const externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE);
|
const externalParameterMake = getQuerystringParameter(queryStrings.VEHICLE_MAKE);
|
||||||
const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL);
|
const externalParameterModel = getQuerystringParameter(queryStrings.VEHICLE_MODEL);
|
||||||
const externalParameterStyle = getQuerystringParameter(queryStrings.VEHICLE_STYLE);
|
const externalParameterStyle = getQuerystringParameter(queryStrings.VEHICLE_STYLE);
|
||||||
const externalParameterDamage = getQuerystringParameter(queryStrings.VEHICLE_DAMAGE);
|
const externalParameterDamage = getQuerystringParameter(queryStrings.VEHICLE_DAMAGE);
|
||||||
const externalParameterZipCode = getQuerystringParameter(queryStrings.SERVICE_ZIP);
|
let externalParameterZipCode = getQuerystringParameter(queryStrings.SERVICE_ZIP);
|
||||||
const externalParameterEmail = getQuerystringParameter(queryStrings.EMAIL);
|
const externalParameterEmail = getQuerystringParameter(queryStrings.EMAIL);
|
||||||
const externalParameterIsInsurance = getQuerystringParameter(queryStrings.IS_INSURANCE);
|
const externalParameterIsInsurance = getQuerystringParameter(queryStrings.IS_INSURANCE);
|
||||||
const externalParameterVinSelection = getQuerystringParameter(queryStrings.VIN_SELECTION);
|
const externalParameterVinSelection = getQuerystringParameter(queryStrings.VIN_SELECTION);
|
||||||
|
|
@ -39,6 +41,27 @@ function updateExternalParameterState() {
|
||||||
const externalParameterNumberOfChips = getQuerystringParameter(queryStrings.NUMBER_OF_CHIPS);
|
const externalParameterNumberOfChips = getQuerystringParameter(queryStrings.NUMBER_OF_CHIPS);
|
||||||
const externalParameterSource = getQuerystringParameter(queryStrings.EXPERIMENTS);
|
const externalParameterSource = getQuerystringParameter(queryStrings.EXPERIMENTS);
|
||||||
const externalParameterPhoneNumber = getQuerystringParameter(queryStrings.PHONE_NUMBER);
|
const externalParameterPhoneNumber = getQuerystringParameter(queryStrings.PHONE_NUMBER);
|
||||||
|
|
||||||
|
if (!externalParameterZipCode) {
|
||||||
|
externalParameterZipCode = getQuerystringParameter(queryStrings.ZIP_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (externalParameterYear || externalParameterZipCode) {
|
||||||
|
debugLog("externalParameterYear:", externalParameterYear);
|
||||||
|
debugLog("externalParameterMake:", externalParameterMake);
|
||||||
|
debugLog("externalParameterModel:", externalParameterModel);
|
||||||
|
debugLog("externalParameterStyle:", externalParameterStyle);
|
||||||
|
debugLog("externalParameterDamage:", externalParameterDamage);
|
||||||
|
debugLog("externalParameterZipCode:", externalParameterZipCode);
|
||||||
|
debugLog("externalParameterEmail:", externalParameterEmail);
|
||||||
|
debugLog("externalParameterIsInsurance:", externalParameterIsInsurance);
|
||||||
|
debugLog("externalParameterVinSelection:", externalParameterVinSelection);
|
||||||
|
debugLog("externalParameterServicePackage:", externalParameterServicePackage);
|
||||||
|
debugLog("externalParameterNumberOfChips:", externalParameterNumberOfChips);
|
||||||
|
debugLog("externalParameterSource:", externalParameterSource);
|
||||||
|
debugLog("externalPhoneNumber:", externalParameterPhoneNumber);
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
externalParameterYear &&
|
externalParameterYear &&
|
||||||
externalParameterMake &&
|
externalParameterMake &&
|
||||||
|
|
@ -51,6 +74,7 @@ function updateExternalParameterState() {
|
||||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMake);
|
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MAKE, externalParameterMake);
|
||||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MODEL, externalParameterModel);
|
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_MODEL, externalParameterModel);
|
||||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_STYLE, externalParameterStyle);
|
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_STYLE, externalParameterStyle);
|
||||||
|
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_QS_STASH, window.location.search);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
externalParameterDamage &&
|
externalParameterDamage &&
|
||||||
|
|
@ -100,6 +124,7 @@ function updateExternalParameterState() {
|
||||||
externalParameterPhoneNumber
|
externalParameterPhoneNumber
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
debugLog("--- updateExternalParameterState END ---");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is an existing external parameter state then they have already been through from an external source(LeadGen) and
|
// if there is an existing external parameter state then they have already been through from an external source(LeadGen) and
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ export const routes = [
|
||||||
createRoute(routeData.CONFIRMATION),
|
createRoute(routeData.CONFIRMATION),
|
||||||
createRoute(routeData.RETURN_USER),
|
createRoute(routeData.RETURN_USER),
|
||||||
createRoute(routeData.MOBILE_DETAILS),
|
createRoute(routeData.MOBILE_DETAILS),
|
||||||
|
createRoute(routeData.POLICY_INFO),
|
||||||
|
|
||||||
// Virtual pages (resolve to a non-virtual page.)
|
// Virtual pages (resolve to a non-virtual page.)
|
||||||
createVirtualRoute(routeData.LANDING, landingBeforeEnter),
|
createVirtualRoute(routeData.LANDING, landingBeforeEnter),
|
||||||
|
|
|
||||||
|
|
@ -516,6 +516,10 @@ export const mutations = {
|
||||||
externalParameterState.vehicle.style = style;
|
externalParameterState.vehicle.style = style;
|
||||||
saveExternalParameterState(externalParameterState);
|
saveExternalParameterState(externalParameterState);
|
||||||
},
|
},
|
||||||
|
updateExternalParameterQsStash(state, qsStash) {
|
||||||
|
externalParameterState.qsStash = qsStash;
|
||||||
|
saveExternalParameterState(externalParameterState);
|
||||||
|
},
|
||||||
updateExternalParameterIsRepair(state, isRepair) {
|
updateExternalParameterIsRepair(state, isRepair) {
|
||||||
externalParameterState.vehicleDamage.isRepair = isRepair;
|
externalParameterState.vehicleDamage.isRepair = isRepair;
|
||||||
saveExternalParameterState(externalParameterState);
|
saveExternalParameterState(externalParameterState);
|
||||||
|
|
@ -4142,6 +4146,7 @@ function createExternalParameterDefaultState() {
|
||||||
// create default externalParameter state
|
// create default externalParameter state
|
||||||
const externalParameterDefaultState = {
|
const externalParameterDefaultState = {
|
||||||
isExternalParameter: externalParameterStatus.NOT_SET,
|
isExternalParameter: externalParameterStatus.NOT_SET,
|
||||||
|
qsStash: null,
|
||||||
vehicle: {
|
vehicle: {
|
||||||
year: null,
|
year: null,
|
||||||
make: null,
|
make: null,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue