Merge remote-tracking branch 'origin/develop' into feature/CSR-1971

This commit is contained in:
Scott Kiener 2024-03-01 10:58:48 -05:00
commit 8f2fda3995
34 changed files with 736 additions and 121 deletions

View file

@ -24,12 +24,13 @@ module.exports = {
"!src/layouts/review/*.vue", // Temp test exclusion while in development
"!src/layouts/payment/*.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
// END
], // ! means exclude from coverage.
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],
coverageThreshold: {
global: {
statements: 78,
statements: 77,
},
},
// Uncomment this to avoid the massive amount of warnings we are getting for onSubmit and onInvalidSubmit

View file

@ -11,6 +11,7 @@ const applicationConfig = {
PAGE_QUERYSTRING: "fmgPage",
SITE_ENTRY_TRIGGER_VALUE: "FixMyGlass",
CASH_PARENT_ACCOUNT_NUMBER: 167132,
CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER: "87291",
MY_ACCOUNT: process.env.VUE_APP_MY_ACCOUNT,
PIA_RESPONSE_URL:
location.protocol +

View file

@ -0,0 +1,18 @@
const coverageStatus = {
PENDING: "Pending",
NOCOMP: "NoComp",
VERIFIED: "Verified",
};
export function coverageStatusValue(intCoverageStatus) {
switch (intCoverageStatus) {
case 0:
return coverageStatus.PENDING;
case 1:
return coverageStatus.NOCOMP;
case 2:
return coverageStatus.VERIFIED;
default:
return null;
}
}

View file

@ -21,6 +21,7 @@ const queryStrings = {
TRANS_REFERENCE_NUMBER: "auth_trans_ref_no",
LAST_FOUR: "last_four",
DISPLAY_PIA_ALERT: "displayPiaAlert",
PAGE_ERROR: "pageerror",
};
export { queryStrings };

View file

@ -80,6 +80,7 @@ const storeActions = {
SAVE_PAYMENT_TYPE: "savePaymentType",
SAVE_PAYMENT_METHOD_CHOICE: "savePaymentMethodChoice",
SAVE_PARENT_ACCOUNT_NUMBER: "saveParentAccountNumber",
SAVE_BILL_TO_ACCOUNT_NUMBER: "saveBillToAccountNumber",
SAVE_SUPPORTING_ITEMS: "saveSupportingItems",
SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING:
"saveSupportingItemsSuppressingStateResetting",

View file

@ -46,6 +46,7 @@ const storeMutations = {
UPDATE_REFERRAL_DATE: "updateReferralDate",
UPDATE_REFERRAL_CORRELATION_ID: "updateReferralCorrelationId",
UPDATE_PARENT_ACCT_NUMBER: "updateParentAcctNumber",
UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber",
UPDATE_EON: "updateEON",
UPDATE_IS_INSURANCE: "updateIsInsurance",
UPDATE_SAVED_SESSION_ID: "updateSavedSessionId",

View file

@ -46,7 +46,11 @@
:maxlength="maxLength ? maxLength : '999'"
@focus="$emit('focus', $event.target.value)"
@keydown="keyDownHandler" />
<button v-if="includeSearchIcon" type="submit" aria-label="Search button" />
<button
v-if="includeSearchIcon"
type="submit"
aria-label="Search button"
@click="focusSearchInput" />
<template v-if="includeImageQuestion">
<template v-if="!isDisabled">
<label class="camera-icon-input" v-show="!isImageProcessing">
@ -169,6 +173,11 @@ export default {
};
},
methods: {
focusSearchInput() {
//Focus cursor in input when search icon is clicked
const field = document.querySelector("input");
field.focus();
},
async imageChanged(e) {
let file = e.target.files[0];

View file

@ -103,7 +103,7 @@
ref="promoModalQuestion"
class="small mt-4"
v-model="lineItems"
@addedPromo="handleAddedPromo"
emitToGrandparent="true"
:availableVaps="availableVaps"
modalWidgetName="PromoModalWidget" />
</div>
@ -245,10 +245,6 @@ export default {
}
return [];
},
handleAddedPromo(lineItems) {
// NOTE: these lineItems are passed from promo-modal-question
this.$emit("update:modelValue", lineItems);
},
},
computed: {
screenReaderTotalAmountDueText() {

View file

@ -120,7 +120,7 @@ export default {
<style lang="scss" scoped>
.menu-modal-container {
position: absolute;
padding: 1.47rem 1rem 1.47rem 1.47rem;
padding: 1.47rem 0 1.47rem 1.47rem;
right: 0;
button {
border: none;
@ -186,7 +186,7 @@ export default {
}
.menu-modal-container {
position: absolute;
padding: 1.47rem 1rem 1.47rem 1.47rem;
padding: 1.47rem 0 1.47rem 1.47rem;
right: 0;
top: -5rem;
button {

View file

@ -106,6 +106,11 @@ export default {
required: false,
default: true,
},
emitToGrandparent: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
promoLinkText() {
@ -175,6 +180,7 @@ export default {
},
onModalClosed() {
this.resetAlerts();
if (this.emitToGrandparent) this.$parent.$emit("update:modelValue", this.lineItems);
this.$emit("update:modelValue", this.lineItems);
this.promoCode = "";
this.modal.resetForm();
@ -261,7 +267,6 @@ export default {
this.availableVaps,
this.pageName
);
if (promoCodeData.isValid) {
if (this.taxPromos) {
const pricedLineItemsToTax = [];
@ -305,7 +310,6 @@ export default {
this.lineItems.vaps?.push(...getVaps);
}
this.lineItems?.promos.push(...promoCodeData.promoCode);
this.$emit("added-promo", this.lineItems);
this.closeModal();
} else {
this.getErrorMessage(promoCodeData.errorCode, promoCodeData.additionalInfo);

View file

@ -61,7 +61,11 @@ export default {
);
}
//router.navigateError();
// do not route to error logic when no wipers found or no promo found (404s)
if (error.response.status != "404") {
router.navigateError();
}
return reject(error.response);
}
);

View file

@ -1,6 +1,7 @@
import globalMethods from "@/global-methods";
import axios from "axios";
import analyticsMixIn from "@/mixins/analytics-mixin";
import router from "@/router";
//Mock external dependencies
jest.mock("axios");
@ -29,6 +30,7 @@ it("Global Methods - Call Http Client - Should Reject Promise", () => {
isError: true,
});
analyticsMixIn.methods.pushEventToGA = jest.fn();
router.navigateError = jest.fn();
//Act
globalMethods.callHttpClient(httpArgs).catch((err) => {

View file

@ -18,7 +18,7 @@ export function updateOrCreateFunnelCookie() {
ReferralNumber: store.getters.order.referralNumber,
ReferralDate: store.getters.order.referralDate,
ReferralCorrelationId: store.getters.order.referralCorrelationId,
ReferralParentAccountNumber: store.getters.order.accountNumber,
ReferralParentAccountNumber: store.getters.order.payment.parentAccountNumber,
HasDelayedClaimRegistration: wasClaimRegistrationDelayed,
SuppressConceptFunnel: shouldSuppressConceptFunnel,
SavedSessionId: store.getters.applicationUser.savedSessionId,

View file

@ -18,6 +18,16 @@ import router from "@/router";
the user has an existing order and they come back in from the Safelite.com CTA.
*/
export async function getPageToRouteExistingOrderTo(toRoute = {}) {
const fmgPage = getQuerystringParameter(queryStrings.FMG_PAGE.toLowerCase());
if (fmgPage && fmgPage === fmgPageValues.SERVICE_LOCATION) {
const serviceLocationComponent = await getLazyLoadedComponent(
fmgPageValues.SERVICE_LOCATION
);
if (serviceLocationComponent.methods.arePagePrerequisitesValid()) {
return fmgPageValues.SERVICE_LOCATION;
}
}
// If the user is coming in via the Safelite.Com CTA
if (toRoute.query[queryStrings.START_TYPE] === "fmg") {
const latestPageRoute = await getLatestPageForRedirection();
@ -26,12 +36,7 @@ export async function getPageToRouteExistingOrderTo(toRoute = {}) {
// If navigating to a specific page, and that page is not part of the vin pages.
// Return that page, so that it can navigate like normal.
if (
toRoute.query[queryStrings.FMG_PAGE] !== undefined &&
toRoute.query[queryStrings.FMG_PAGE] !== fmgPageValues.SERVICE_LOCATION &&
toRoute.query[queryStrings.FMG_PAGE] !== fmgPageValues.SCHEDULE &&
!isVinRelatedPage(toRoute)
) {
if (toRoute.query[queryStrings.FMG_PAGE] !== undefined && !isVinRelatedPage(toRoute)) {
return overrideYmmsDirectionIfNeeded(toRoute);
}

View file

@ -0,0 +1,48 @@
// Components
import bailout from "@/layouts/bailout/bailout.vue";
// Supporting Files
import { shallowMount } from "@vue/test-utils";
import { getMountOptions } from "@/helpers/unit-test-helper.js";
// 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("bailout.vue", () => {
test("arePagePrerequisitesValid should be true ", async () => {
//Arrange
const { wrapper } = setupMocks();
//Act
let arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
//Assert
expect(arePagePrerequisitesValid).toBe(true);
});
});
function setupMocks() {
const mountOptions = getMountOptions({});
//Mock props
const mockMixin = {
methods: {
getCmsContent: jest.fn(),
},
};
mountOptions.mixins = [mockMixin];
const wrapper = shallowMount(bailout, mountOptions);
wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.backButtonAction = jest.fn();
return { wrapper };
}

View file

@ -0,0 +1,79 @@
<template>
<Form>
<loadingModal ref="loadingModal" />
<div class="container-fluid page-container-grouped-styles">
<div class="row justify-content-center">
<div class="col-md-6">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" />
<navbar
cmsWidgetName="FunnelFooterWidget"
isForwardActionDisabled="true"
isSubmitHidden="true"
@back-clicked="backButtonAction" />
</div>
</div>
</div>
</Form>
</template>
<script>
// Components
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
export default {
name: "bailout",
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
methods: {
arePagePrerequisitesValid() {
return true;
},
backButtonAction() {
this.$router.go(-1);
},
},
components: {
funnelHeader,
navbar,
vehicleBanner,
funnelSubHeader,
loadingModal,
},
};
</script>

View file

@ -0,0 +1,3 @@
describe("insurance", () => {
it.todo("Should render a normal string");
});

View file

@ -0,0 +1,326 @@
<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<loadingModal ref="loadingModal" />
<div class="container-fluid page-container-grouped-styles">
<div class="row justify-content-center">
<div class="col-md-6">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-4" />
<textboxQuestion
class="mb-2 mt-5"
cmsWidgetName="InsuranceCoQuestionWidget"
includeSearchIcon
cornerStyle="rounded" />
<navbar
cmsWidgetName="FunnelFooterWidget"
ref="navbar"
:isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</Form>
</template>
<script>
// Components
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 textboxQuestion from "@/digital-components/textbox-question/textbox-question";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
// Supporting files
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import { storeActions } from "@/constants/store-actions";
import { errorMessages } from "@/constants/error-messages";
import {
getDamageString,
getIsWindshieldOnly,
isGlassAvailableForCarId,
} from "@/helpers/damage-helper";
import { required, regex } from "@/helpers/validation-rules";
import { Form, defineRule } from "vee-validate";
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
import { routerParams } from "@/router/router-constants/router-params";
import store from "@/store";
import vinPagesMixin from "@/mixins/vin-pages-mixin";
// DEFINE VALIDATION RULES
defineRule("zip-required", required(errorMessages.SERVICE_ZIP_REQUIRED));
defineRule("zip-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.SERVICE_ZIP_FORMAT));
defineRule("email-address-required", required(errorMessages.EMAIL_ADDRESS_REQUIRED));
defineRule(
"email-address-format",
regex(
/^([a-zA-Z0-9_\-.+]+)@([a-zA-Z0-9-]+)\.([a-zA-Z]{2,})$/,
errorMessages.EMAIL_ADDRESS_FORMAT
)
);
defineRule("vin-required", required(errorMessages.VIN_REQUIRED));
defineRule("vin-format", regex(/^[a-hA-Hj-nJ-NpPr-zR-Z0-9]{17}$/, errorMessages.VIN_FORMAT));
export default {
name: "insurance",
mixins: [vinPagesMixin],
async beforeRouteEnter(to, from, next) {
// Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// Call the "next" function to complete the transition to this page.
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
});
},
data() {
return {
vin: this.getVinFromStore(),
serviceZipCode: this.getZipFromStore() ?? this.$route.query.zipcode,
emailAddress: this.getEmailFromStore(),
isCarIdDifferent: false,
customAlertData: {},
previouslyEnteredCarId: "",
vinPopulatedOnPageLoad: this.getVinFromStore()?.length > 0,
isSelectedGlassAvailableForVehicle: true,
displayInvalidZipAlert: false,
displayNonServiceableZipAlert: false,
displayVinNotFoundAlert: false,
displayMatchedDifferentVehicleAlert: false,
displayVinScanFailedAlert: false,
};
},
methods: {
arePagePrerequisitesValid() {
return store.getters.vehicle.carId !== null;
},
getEmailFromStore() {
return this.$store.getters.order.customer.emailAddress;
},
getVinFromStore() {
return this.$store.getters.vehicle.vin;
},
getZipFromStore() {
return this.$store.getters.order.serviceLocation.zipCode;
},
attachCustomEvents() {
this.prependActionToMethod(this, this.forwardButtonAction, () => {
this.pushEventToGA(
this.$route.query[this.queryStrings.FMG_PAGE],
this.GaActions.SUBMITTED,
this.GaLabels.VIN_LOOKUP,
true
);
});
},
backButtonAction() {
// route to move backwards
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
},
async forwardButtonAction() {
this.resetAlerts();
// If this is a new VIN Lookup, do both a Vehicle Lookup and a Zip Validation
if (!this.vinPopulatedOnPageLoad) {
const vehicleLookupResponse = this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VEHICLE_BY_VIN,
{ vin: this.vin },
"vin-lookup"
);
// Settle promises and get results
const promiseResultMap = [
{
resultKey: "vehicleLookupResponse",
promise: vehicleLookupResponse,
},
{
resultKey: "zipCodeData",
promise: this.getZipCodeData(this.serviceZipCode),
},
];
const resultMap = await settleAllPromises(promiseResultMap);
// If a Service Zip is entered and it is an invalid zip code (ex. 11111) then show an alert
const isZipValid = resultMap.zipCodeData.isValid;
if (this.serviceZipCode && !isZipValid) {
this.displayInvalidZipAlert = true;
return this.$refs.navbar.removeLoader();
}
this.displayInvalidZipAlert = false;
// If either lookup fails, remove the loader and stop processing the page.
if (!resultMap.vehicleLookupResponse || !resultMap.zipCodeData.isServiceable) {
// If the vehicle result is undefined, the vin entered was invalid.
if (!resultMap.vehicleLookupResponse) {
this.displayVinNotFoundAlert = true;
}
// Check if Service Zip entered is serviceable, if not display an alert
if (!resultMap.zipCodeData.isServiceable) {
this.displayNonServiceableZipAlert = true;
}
// Remove loader and stop processing the page.
return this.$refs.navbar.removeLoader();
}
// Check if the CarId is different from the lookup vs what is in state currently.
this.isCarIdDifferent =
resultMap.vehicleLookupResponse.carId !== this.$store.getters.vehicle.carId;
if (
this.isCarIdDifferent &&
resultMap.vehicleLookupResponse.carId !== this.previouslyEnteredCarId
) {
this.previouslyEnteredCarId = resultMap.vehicleLookupResponse.carId;
this.customAlertData.vehicleInfo = resultMap.vehicleLookupResponse;
this.displayMatchedDifferentVehicleAlert = true;
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(
resultMap.vehicleLookupResponse.carId,
"vin-lookup"
);
// Update button "Continue with..."
this.$refs.navbar.updateButtonText(
`Continue with ${resultMap.vehicleLookupResponse.year} ${resultMap.vehicleLookupResponse.make} ${resultMap.vehicleLookupResponse.model}`
);
return this.$refs.navbar.removeLoader();
}
// Save vin, vehicle, customer and service information
await this.dispatchStoreAction(
storeActions.SAVE_VIN_LOOKUP,
{
isSelectedGlassAvailableForVehicle: this.isSelectedGlassAvailableForVehicle,
vehicleInfo: Object.assign(resultMap.vehicleLookupResponse, {
vin: this.vin,
}),
},
false
);
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
await this.dispatchStoreAction(
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
{
state: resultMap.zipCodeData.state,
zipCode: this.serviceZipCode,
zipCodeCtu: resultMap.zipCodeData.zipCodeCtu,
},
false
);
return await this.navigateForward();
}
// If a VIN has already been found. Validate the Service Zip (in case of changes)
const zipCodeData = await this.getZipCodeData(this.serviceZipCode);
// Check if Service Zip entered is serviceable then save the ZIP info
if (zipCodeData.isServiceable) {
//Only save the zipCode, state, and zipCodeCtu if the zip changed or we lack zipCodeCtu
if (
this.$store.getters.order.serviceLocation.zipCode != this.serviceZipCode ||
!this.$store.getters.order.serviceLocation.zipCodeCtu
) {
await this.dispatchStoreAction(
storeActions.SAVE_SERVICE_ZIP_CODE_INFO,
{
state: zipCodeData.state,
zipCode: this.serviceZipCode,
zipCodeCtu: zipCodeData.zipCodeCtu,
},
false
);
}
await this.dispatchStoreAction(storeActions.SAVE_EMAIL, this.emailAddress, false);
return await this.navigateForward();
}
// If the Service Zip is NOT serviceable then show an alert
if (zipCodeData.isValid) {
this.displayNonServiceableZipAlert = true;
} else {
this.displayInvalidZipAlert = true;
}
return this.$refs.navbar.removeLoader();
},
async navigateForward() {
if (this.isCarIdDifferent && !this.isSelectedGlassAvailableForVehicle) {
this.$router.navigateWithSaving(
this.navigationScenarios.SELECTED_VIN_WITH_MISMATCHED_GLASS,
this.$route,
{},
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true }
);
} else {
await this.navigateForwardWithSingleCarMatch();
}
},
displayVinScanAlert() {
this.displayVinScanFailedAlert = true;
},
getVinFromImage(image) {
return new Promise((resolve, reject) => {
this.dispatchStoreActionWithLogging(
storeActions.LOOKUP_VIN_BY_IMAGE,
image,
"vin-lookup"
)
.then((response) => {
if (response.data.length > 0) {
resolve(response.data[0]);
} else {
reject("No VINs detected.");
}
})
.catch(() => {
reject("An error occurred during the lookup.");
});
});
},
resetAlerts() {
this.displayMatchedDifferentVehicleAlert = false;
this.displayNonServiceableZipAlert = false;
this.displayInvalidZipAlert = false;
this.displayVinNotFoundAlert = false;
this.displayVinScanFailedAlert = false;
},
},
mounted() {
this.attachCustomEvents();
},
components: {
funnelHeader,
navbar,
funnelSubHeader,
textboxQuestion,
Form,
loadingModal,
},
};
</script>

View file

@ -237,7 +237,7 @@ export default {
const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
billToAccountNumber: "87291",
billToAccountNumber: store.getters.payment.billToAccountNumber,
providerNumber: store.getters.order.serviceLocation.provider.providerNumber,
appointmentType: store.getters.order.serviceLocation.appointmentType,
serviceLocationCity: store.getters.order.serviceLocation.city,
@ -307,9 +307,6 @@ export default {
},
methods: {
arePagePrerequisitesValid() {
// Line Items
const packageReqs = !!store.getters.order.lineItems.supportingItems;
// Service Location
const serviceLocation = store.getters.order.serviceLocation;
const mobileReqs = !!(
@ -354,9 +351,7 @@ export default {
customer.emailAddress
);
return (
packageReqs && serviceLocationReqs && isInsuranceSet && scheduleReqs && customerReqs
);
return serviceLocationReqs && isInsuranceSet && scheduleReqs && customerReqs;
},
getPaymentMethodFromStore() {
const piaType = store.getters.order.payment.piaType;
@ -398,7 +393,7 @@ export default {
await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
billToAccountNumber: "87291",
billToAccountNumber: store.getters.payment.billToAccountNumber,
providerNumber:
this.$store.getters.order.serviceLocation.provider.providerNumber,
appointmentType: this.$store.getters.order.serviceLocation.appointmentType,

View file

@ -512,7 +512,7 @@ describe("payment.vue", () => {
});
});
describe("handleIFrameContentWindwMessage", () => {
describe("handleIFrameContentWindowMessage", () => {
test("Navigates back if afterpay is closed", () => {
// Arrange
const event = {
@ -524,7 +524,7 @@ describe("payment.vue", () => {
wrapper.vm.backButtonAction = jest.fn();
// Act
wrapper.vm.handleIFrameContentWindwMessage(event);
wrapper.vm.handleIFrameContentWindowMessage(event);
// Assert
expect(wrapper.vm.backButtonAction).toBeCalled();
@ -539,7 +539,7 @@ describe("payment.vue", () => {
const wrapper = setupMocks({});
// Act
wrapper.vm.handleIFrameContentWindwMessage(event);
wrapper.vm.handleIFrameContentWindowMessage(event);
// Assert
expect(wrapper.vm.shouldBlockInteraction).toBe(true);

View file

@ -356,7 +356,7 @@ export default {
const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
{
billToAccountNumber: "87291",
billToAccountNumber: store.getters.payment.billToAccountNumber,
providerNumber: store.getters.order.serviceLocation.provider.providerNumber,
appointmentType: store.getters.order.serviceLocation.appointmentType,
serviceLocationCity: store.getters.order.serviceLocation.city,
@ -440,9 +440,6 @@ export default {
},
methods: {
arePagePrerequisitesValid() {
// Line Items
const packageReqs = !!store.getters.order.lineItems.supportingItems;
// Service Location
const serviceLocation = store.getters.order.serviceLocation;
const mobileReqs = !!(
@ -492,7 +489,6 @@ export default {
(store.getters.order.payment.isPia || !!store.getters.order.payment.piaType);
return (
packageReqs &&
serviceLocationReqs &&
isInsuranceSet &&
scheduleReqs &&
@ -647,17 +643,19 @@ export default {
this.submitHopForm();
},
handleIFrameContentWindwMessage(event) {
if (event.data.indexOf("afterpayClosed") > -1) {
this.backButtonAction();
}
if (event.data.indexOf("creditCardSubmit") > -1) {
this.setUIBlock(true);
handleIFrameContentWindowMessage(event) {
if (typeof event.data === "string") {
if (event.data.indexOf("afterpayClosed") > -1) {
this.backButtonAction();
}
if (event.data.indexOf("creditCardSubmit") > -1) {
this.setUIBlock(true);
}
}
},
setIFrameListener() {
window.addEventListener("message", (event) =>
this.handleIFrameContentWindwMessage(event)
this.handleIFrameContentWindowMessage(event)
);
},
setUIBlock(val) {

View file

@ -140,42 +140,6 @@ describe("quote.vue", () => {
expect(wrapper.vm.$router.navigateWithSaving).toHaveBeenCalled();
});
test("IsInsurance true should navigateToHeritageFunnel", async () => {
//Arrange
store.getters = {
payment: {
insuranceCoverage: {},
isInsurance: true,
},
order: {
lineItems: [],
payment: {
parentAccountNumber: null,
},
},
};
const { wrapper } = setupMocks({
customMountOptions: {
router: {
navigateWithSaving: jest.fn(),
},
route: { quote },
mixins: [mockMixin],
},
});
wrapper.vm.dispatchStoreAction = jest.fn(() => {
return {
data: [],
};
});
//Act
await wrapper.vm.forwardButtonAction();
//Assert
expect(navigateToHeritage.navigateToHeritageFunnel).toHaveBeenCalled();
});
test("should pass arePagePrerequisitesValid with a repair order", () => {
//Arrange
store.getters = {

View file

@ -293,6 +293,11 @@ export default {
applicationConfig.CASH_PARENT_ACCOUNT_NUMBER,
false
);
this.dispatchStoreAction(
this.storeActions.SAVE_BILL_TO_ACCOUNT_NUMBER,
applicationConfig.CASH_DEFAULT_BILL_TO_ACCOUNT_NUMBER,
false
);
}
if (
@ -327,6 +332,10 @@ export default {
pageNameToLog: "quote",
loadingModal: this.$refs.loadingModal,
});
// this.$router.navigateWithSaving(
// this.navigationScenarios.CLICKED_FORWARD_WITH_INSURANCE,
// this.$route
// );
} else {
this.$router.navigateWithSaving(
this.navigationScenarios.CLICKED_FORWARD_WITH_CASH,

View file

@ -64,7 +64,7 @@ export default {
}
},
activePromos() {
this.selectDefaultPackage();
if (this.activePromos?.length) this.selectDefaultPackage();
},
selectedPackageName(newValue) {
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);

View file

@ -314,14 +314,13 @@ export default {
serviceLocation.provider.providerNumber);
const paymentInfo = store.getters.payment.isInsurance !== null;
const supportingItems = store.getters.lineItems.supportingItems !== null;
const damageInfo =
store.getters.order.damage.isRepair ||
(store.getters.order.lineItems?.glassParts != null &&
store.getters.order.lineItems.glassParts.length > 0);
return serviceLocationPreReqs && paymentInfo && supportingItems && damageInfo;
return serviceLocationPreReqs && paymentInfo && damageInfo;
},
async getAvailableDatesMethod(startDate, endDate) {
const newShopTimeSlots = await getAvailableDates(
@ -348,9 +347,14 @@ export default {
},
getSelectedTimeSlotInfo() {
const supportingItems = this.getSupportingItems();
const isPremiumAppointment =
!!supportingItems.filter((lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE)
.length > 0;
var isPremiumAppointment = false;
if (supportingItems) {
isPremiumAppointment =
!!supportingItems.filter(
(lineItem) => lineItem.partType === PREMIUM_FEE_PART_TYPE
).length > 0;
}
const selectedTimeSlotInfo = {
timeSlot: store.getters.order.schedule,
@ -461,6 +465,10 @@ export default {
false
);
} else {
if (!supportingItems) {
return;
}
// if it's not a mobile and/or premium early bird, then make sure we remove any that may have been added
const removePremiumFeeIndex = supportingItems.findIndex(
(item) => item.partType == PREMIUM_FEE_PART_TYPE

View file

@ -16,6 +16,14 @@ export async function getPricedMobileFeePart(serviceZipCode, pageNameToLog) {
false
);
if (
mobileFeePart.data === null ||
mobileFeePart.data === undefined ||
mobileFeePart.data === ""
) {
return null;
}
// Get the Mobile Fee Part Price
const pricingResults = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.PRICE_ORDER_ITEMS_AND_SAVE_SERVER_DATA,

View file

@ -138,6 +138,7 @@ import {
getServiceabilityDetails,
getShopProviderData,
} from "@/layouts/service-location/helpers/service-location-helper/service-location-helper";
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
import { Provider } from "@/layouts/service-location/classes/provider";
@ -348,11 +349,19 @@ export default {
},
methods: {
arePagePrerequisitesValid() {
return (
store.getters.lineItems.supportingItems !== null &&
store.getters.order.serviceLocation.zipCode !== null &&
store.getters.payment.isInsurance !== null
);
// insurance drops the recycle fee on replace orders so it won't be in supportingItems
if (store.getters.payment.isInsurance && !store.getters.order.damage.isRepair) {
return (
store.getters.order.serviceLocation.zipCode !== null &&
store.getters.payment.isInsurance !== null
);
} else {
return (
store.getters.lineItems.supportingItems !== null &&
store.getters.order.serviceLocation.zipCode !== null &&
store.getters.payment.isInsurance !== null
);
}
},
setData(zipCodeData, serviceabilityDetails, mobileFeePart, shopProviderData) {
if (zipCodeData) {
@ -438,7 +447,14 @@ export default {
this.recalibrationInformationModal.openModal();
},
backButtonAction() {
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
if (store.getters.order.payment.isInsurance) {
navigateToHeritageFunnel({ shouldSaveSession: false });
} else {
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_BACK,
this.$route
);
}
},
updateAndSaveSupportingItems() {
const supportingItems = store.getters.lineItems.supportingItems;
@ -453,7 +469,7 @@ export default {
supportingItems[mobileFeeIndex].sellingPrice = this.mobileFeePart.sellingPrice;
supportingItems[mobileFeeIndex].kitPrice = this.mobileFeePart.kitPrice;
} else {
supportingItems.push(this.mobileFeePart);
if (this.mobileFeePart !== null) supportingItems.push(this.mobileFeePart);
}
this.dispatchStoreAction(
@ -463,7 +479,7 @@ export default {
);
} else {
// if it's not a mobile, then make sure we remove any that may have been added
const removeMobileFeeIndex = supportingItems.findIndex(
const removeMobileFeeIndex = supportingItems?.findIndex(
(item) => item.partType == MOBILE_FEE_PART_TYPE
);

View file

@ -95,19 +95,14 @@ export default {
},
tintSelectionOptions() {
let tintOptions = [];
Object.keys(this.featureListData).forEach((tintOption) => {
tintOptions.push({
const tintOptions = Object.keys(this.featureListData).map((tintOption) => {
const buttonImage = this.getTintSourceImage(this.glassLocation, tintOption);
return {
value: tintOption,
buttonLabel: tintOption,
buttonImage: require(`@/assets/img/tints/${this.getTintSourceImage(
this.glassLocation,
tintOption
)}`),
});
buttonImage: buttonImage ? require(`@/assets/img/tints/${buttonImage}`) : null,
};
});
return tintOptions;
},

View file

@ -32,8 +32,14 @@ import analyticsMixin from "@/mixins/analytics-mixin";
import { experimentTriggers } from "../constants/experiments";
import { applicationConfig } from "../constants/application-config";
import { shouldStripPromoQueryString } from "@/helpers/promotions-helper";
import bailout from "@/layouts/bailout/bailout";
const routes = [
{
path: "/bailout",
name: "bailout",
component: bailout,
},
{
path: "/",
name: "root",
@ -103,6 +109,7 @@ const routes = [
}
if (!arePagePrerequisitesValid(component)) {
console.log("Page prereq error: " + component.default.name);
GoToFunnelStartOn404(next);
}
@ -110,6 +117,7 @@ const routes = [
}
if (!isExistingFmgPageName(to.query.fmgPage)) {
console.log("Not an existing fmg page name:" + to.query.fmgPage);
GoToFunnelStartOn404(next);
}
@ -131,6 +139,9 @@ const routes = [
.components.default();
if (!arePagePrerequisitesValid(nextComponent)) {
console.log(
"Page Prereqs not valid for next component: " + nextComponent.default.name
);
GoToFunnelStartOn404(next);
}
@ -324,6 +335,7 @@ async function navigate(
const hasZip = getQuerystringParameter(queryStrings.ZIP_CODE);
const zip = getQuerystringParameter(queryStrings.ZIP_CODE);
const promo = getQuerystringParameter(queryStrings.PROMO);
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
if (
hasZip &&
@ -339,6 +351,10 @@ async function navigate(
queryStringsObject[queryStrings.PROMO] = promo;
}
if (pageError) {
queryStringsObject[queryStrings.PAGE_ERROR] = pageError;
}
router.push({
name: "root",
query: Object.assign(optionalQuery, queryStringsObject),
@ -431,7 +447,38 @@ async function DisplayPageError() {
);
baseMixin.methods.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
location.reload();
const pageError = getQuerystringParameter(queryStrings.PAGE_ERROR);
// we use the pageError querystring as a counter to how many times a user has experienced an error and been routed here.
// once they receive more than 1 pageerrors, we'll reset their state to hopefully correct any issues they may be having.
var navPage = fmgPageValues.VEHICLE;
if (store.getters.payment.insuranceCoverage.isVerified) {
navPage = fmgPageValues.VEHICLE_DAMAGE;
}
if (pageError) {
var errorCount = Number(pageError);
if (errorCount > 1) {
deleteFunnelCookie();
await baseMixin.methods.dispatchStoreAction(storeActions.RESET_STATE);
router.push({
path: "/",
query: { fmgPage: navPage },
});
} else {
errorCount++;
router.push({
path: "/",
query: { fmgPage: navPage, pageError: errorCount },
});
}
} else {
router.push({
path: "/",
query: { fmgPage: navPage, pageError: "1" },
});
}
}
function isExistingFmgPageName(pageName) {

View file

@ -11,6 +11,7 @@ const fmgPageValues = {
ESTIMATE: "estimate",
ADDRESS_VEHICLES: "address-vehicles",
QUOTE: "quote",
INSURANCE: "insurance",
SERVICE_LOCATION: "service-location",
HERITAGE: "heritage",
SCHEDULE: "schedule",

View file

@ -11,6 +11,7 @@ const navigationScenarios = {
CLICKED_BACK: "CLICKED_BACK",
CLICKED_FORWARD: "CLICKED_FORWARD",
CLICKED_FORWARD_WITH_CASH: "CLICKED_FORWARD_WITH_CASH",
CLICKED_FORWARD_WITH_INSURANCE: "CLICKED_FORWARD_WITH_INSURANCE",
// Vin selection
CLICKED_BACK_WITH_VIN: "CLICKED_BACK_WITH_VIN",

View file

@ -389,6 +389,23 @@ const routingTable = function (store) {
scenario: navigationScenarios.CLICKED_FORWARD_WITH_CASH,
destinationFmgPageValue: fmgPageValues.SERVICE_LOCATION,
},
{
scenario: navigationScenarios.CLICKED_FORWARD_WITH_INSURANCE,
destinationFmgPageValue: fmgPageValues.INSURANCE,
},
],
},
{
fmgPageValue: fmgPageValues.INSURANCE,
maps: [
{
scenario: navigationScenarios.CLICKED_BACK,
destinationFmgPageValue: fmgPageValues.QUOTE,
},
{
scenario: navigationScenarios.CLICKED_FORWARD,
destinationFmgPageValue: fmgPageValues.SCHEDULE,
},
],
},
{

View file

@ -29,6 +29,7 @@ import {
} from "@/helpers/promotions-helper";
import { getDateDifferenceInDays } from "@/helpers/date-helper";
import sharedMutations from "./vuex-shared-mutations/vuexSharedMutations";
import { coverageStatusValue } from "@/constants/coverage-status";
// Export State
const getDefaultState = () => {
return {
@ -83,6 +84,8 @@ const getDefaultState = () => {
partQuestionAnswers: null,
moldingQuestionAnswers: null,
capabilityQuestionAnswers: null,
dateOfLoss: null,
damageCause: null,
},
lineItems: {
glassParts: null,
@ -99,6 +102,7 @@ const getDefaultState = () => {
coverageVerificationType: null,
},
parentAccountNumber: 0,
billToAccountNumber: null,
isPia: null,
piaType: null,
inactivePromos: null,
@ -118,6 +122,14 @@ const getDefaultState = () => {
lastFour: null,
},
},
policy: {
currentDeductible: 0,
policyNumber: null,
isItac: false,
additionalAuthFlag: null,
isNoComp: false,
insuranceCompanyName: null,
},
schedule: {
date: null,
startTime: null,
@ -240,6 +252,9 @@ export const mutations = {
updateParentAcctNumber(state, parentAcctNumber) {
state.order.payment.parentAccountNumber = parentAcctNumber;
},
updateBillToAcctNumber(state, billToAcctNumber) {
state.order.payment.billToAccountNumber = billToAcctNumber;
},
updateEON(state, eon) {
state.order.eon = eon;
},
@ -499,6 +514,8 @@ export const mutations = {
state.order.damage.glassToReplace = sessionInformation.order.damage.glassToReplace;
state.order.damage.isRepair = sessionInformation.order.damage.isRepair;
state.order.damage.numberOfChips = sessionInformation.order.damage.numberOfChips;
state.order.damage.dateOfLoss = sessionInformation.order.damage?.dateOfLoss;
state.order.damage.damageCause = sessionInformation.order.damage?.damageCause;
state.order.damage.partQuestionAnswers =
sessionInformation.order.damage.partQuestionAnswers;
@ -515,6 +532,8 @@ export const mutations = {
state.order.payment.parentAccountNumber =
sessionInformation.order.payment.parentAccountNumber;
state.order.payment.billToAccountNumber =
sessionInformation.order.payment.billToAccountNumber;
state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos;
state.order.serviceLocation.address =
@ -549,8 +568,9 @@ export const mutations = {
state.order.payment.isInsurance = sessionInformation.order.payment.isInsurance;
state.order.payment.insuranceCoverage.isVerified =
sessionInformation?.order.payment.insuranceCoverage.isVerified;
state.order.payment.insuranceCoverage.coverageStatus =
sessionInformation?.order.payment.insuranceCoverage.coverageStatus;
state.order.payment.insuranceCoverage.coverageStatus = coverageStatusValue(
sessionInformation?.order.payment.insuranceCoverage.coverageStatus
);
state.order.payment.insuranceCoverage.coverageVerificationType =
sessionInformation?.order.payment.insuranceCoverage.coverageVerificationType;
@ -565,12 +585,25 @@ export const mutations = {
state.applicationUser.pageData = sessionInformation.applicationUser.pageData;
state.applicationUser.lastPage = sessionInformation.applicationUser.lastPage;
if (sessionInformation.applicationUser.savedSessionId) {
state.applicationUser.savedSessionId =
sessionInformation.applicationUser.savedSessionId;
}
state.order.schedule.date = sessionInformation.order.schedule?.date;
state.order.schedule.startTime = sessionInformation.order.schedule?.startTime;
state.order.schedule.endTime = sessionInformation.order.schedule?.endTime;
state.order.schedule.routeCode = sessionInformation.order.schedule?.routeCode;
state.order.schedule.jobMaxMinutes = sessionInformation.order.schedule?.jobMaxMinutes;
state.order.schedule.jobMinMinutes = sessionInformation.order.schedule?.jobMinMinutes;
state.order.policy.currentDeductible = sessionInformation.order.policy?.currentDeductible;
state.order.policy.additionalAuthFlag = sessionInformation.order.policy?.additionalAuthFlag;
state.order.policy.isItac = sessionInformation.order.policy?.isItac;
state.order.policy.policyNumber = sessionInformation.order.policy?.policyNumber;
state.order.policy.insuranceCompanyName =
sessionInformation.order.policy?.insuranceCompanyName;
state.order.policy.isNoComp = sessionInformation.order.policy?.noComprehensive;
},
updateExperiments(state, experiments) {
state.applicationUser.experiments = experiments;
@ -656,6 +689,7 @@ export const getters = {
applicationUser: (state) => state.applicationUser,
order: (state) => state.order,
payment: (state) => state.order.payment,
policy: (state) => state.order.policy,
experimentOrder: (state) => {
return {
funnelVehicleYear: state.order.vehicle.year,
@ -1334,7 +1368,7 @@ export const actions = {
getMobileFeePart(context, { pageNameToLog }) {
const damageType = context.getters.damage.isRepair ? "Repair" : "Replace";
const parentAccountNumber = context.getters.payment.parentAccountNumber;
const billToAccountNumber = 87291; // TODO: MAKE THIS REAL
const billToAccountNumber = context.getters.payment.billToAccountNumber;
return globalMethods.callHttpClient({
method: endpoints.GetMobileFeePart.method,
@ -1345,15 +1379,19 @@ export const actions = {
},
getServiceabilityDetails(context, { payload: { serviceZipCode }, pageNameToLog }) {
const lineItemsWithOnlyPartNumbers = context.getters.order.lineItems.supportingItems.map(
const lineItemsWithOnlyPartNumbers = context.getters.order.lineItems.supportingItems?.map(
(lineItem) => ({
partNumber: lineItem.partNumber,
})
);
const lineItems = buildQueryStringParameterFromArrayOfComplexObjects(
lineItemsWithOnlyPartNumbers,
"lineItems"
);
var lineItems = null;
if (lineItemsWithOnlyPartNumbers) {
lineItems = buildQueryStringParameterFromArrayOfComplexObjects(
lineItemsWithOnlyPartNumbers,
"lineItems"
);
}
const vehicle = context.getters.vehicle;
const carId = vehicle.carId;
@ -1365,9 +1403,18 @@ export const actions = {
"glassPieces"
);
var endPoint = `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}`;
if (lineItems) {
endPoint += `&${lineItems}`;
}
if (glassPieces) {
endPoint += `&${glassPieces}`;
}
return globalMethods.callHttpClient({
method: endpoints.GetServiceabilityDetails.method,
endpoint: `${endpoints.GetServiceabilityDetails.url}?zip=${serviceZipCode}&carId=${carId}&${lineItems}&${glassPieces}`,
endpoint: endPoint,
logApiCall: true,
pageNameToLog: pageNameToLog,
});
@ -1444,7 +1491,7 @@ export const actions = {
) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
const payment = context.state.order.payment;
let lineItems = [
...(order.lineItems.supportingItems ?? []),
...(order.lineItems.vaps ?? []),
@ -1466,15 +1513,16 @@ export const actions = {
endDate: endDate,
shopAppointmentType: shopAppointmentType,
applicationName: applicationConfig.APPLICATION_NAME,
parentAccountNumber: context.getters.payment.parentAccountNumber,
parentAccountNumber: payment.parentAccountNumber,
carId: vehicle.carId,
lineItems: lineItems,
glassPieces: glassPieces,
eon: order.eon,
billToAccountNumber: context.getters.payment.billToAccountNumber,
coverage: {
status: "",
deductible: 0,
additionalAuthFlag: "",
status: payment.insuranceCoverage.coverageStatus,
deductible: order.policy.currentDeductible,
additionalAuthFlag: order.policy.additionalAuthFlag,
},
partSelection: {
hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
@ -1512,6 +1560,7 @@ export const actions = {
getMobileTimeSlots(context, { payload: { startDate, endDate }, pageNameToLog }) {
const order = context.state.order;
const vehicle = context.state.order.vehicle;
const payment = context.state.order.payment;
let lineItems = [
...(order.lineItems.supportingItems ?? []),
...(order.lineItems.vaps ?? []),
@ -1530,15 +1579,16 @@ export const actions = {
startDate: startDate,
endDate: endDate,
applicationName: applicationConfig.APPLICATION_NAME,
parentAccountNumber: context.getters.payment.parentAccountNumber,
parentAccountNumber: payment.parentAccountNumber,
carId: vehicle.carId,
lineItems: lineItems,
glassPieces: glassPieces,
eon: order.eon,
billToAccountNumber: context.getters.payment.billToAccountNumber,
coverage: {
status: "",
deductible: 0,
additionalAuthFlag: "",
status: payment.insuranceCoverage.coverageStatus,
deductible: order.policy.currentDeductible,
additionalAuthFlag: order.policy.additionalAuthFlag,
},
partSelection: {
hasAnsweredPartQuestions: !!order.damage.partQuestionAnswers?.length,
@ -1557,6 +1607,7 @@ export const actions = {
},
zipCode: order.serviceLocation.zipCode,
};
return globalMethods.callHttpClient({
method: endpoints.GetMobileTimeSlots.method,
endpoint: endpoints.GetMobileTimeSlots.url,
@ -1691,6 +1742,7 @@ export const actions = {
lastFour: order.payment.ccToken.lastFour,
},
},
policy: {},
serviceLocation: {
streetAddress: order.serviceLocation.address,
streetAddress2: order.serviceLocation.address2,
@ -2107,6 +2159,9 @@ export const actions = {
saveParentAccountNumber(context, parentAccountNumber) {
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
},
saveBillToAccountNumber(context, billToAccountNumber) {
context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber);
},
saveSupportingItems(context, supportingItems) {
if (!deepEqual(supportingItems, context.state.order.lineItems.supportingItems)) {
@ -2200,6 +2255,7 @@ export const actions = {
const vehicle = context.getters.order.vehicle;
// TODO: Insurance pricing...`ParentAccountNumber=${context.getters.order.payment.parentAccountNumber}`
let queryString =
`ParentAccountNumber=${applicationConfig.CASH_PARENT_ACCOUNT_NUMBER}` +
`&CTU=${ctuToUse}` +

View file

@ -10,6 +10,7 @@
class="d-flex w-100 align-items-center px-2 h-100 list-card-content button-content rounded-3"
:class="labelClasses">
<img
v-if="buttonImage"
:id="buttonImageId"
:class="!isWide ? 'order-1' : 'ms-auto order-3'"
:src="buttonImage"