Merge branch 'develop' into feature/CSR-1392
This commit is contained in:
commit
b3fc0c7315
23 changed files with 255 additions and 66 deletions
|
|
@ -7,6 +7,7 @@ const cartItemTypes = {
|
||||||
RECYCLE_FEE: "RECYCLE FEE",
|
RECYCLE_FEE: "RECYCLE FEE",
|
||||||
MOBILE_FEE: "MOBILE FEE",
|
MOBILE_FEE: "MOBILE FEE",
|
||||||
PROMOS: "PROMOS",
|
PROMOS: "PROMOS",
|
||||||
|
EARLY_BIRD: "EARLY BIRD",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { cartItemTypes };
|
export { cartItemTypes };
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ const partTypeStrings = {
|
||||||
RECALIBRATION: "RECALIBRATION",
|
RECALIBRATION: "RECALIBRATION",
|
||||||
RECYCLE_FEE: "RECYCLE FEE",
|
RECYCLE_FEE: "RECYCLE FEE",
|
||||||
MOBILE_FEE: "MOBILE FEE",
|
MOBILE_FEE: "MOBILE FEE",
|
||||||
|
REPAIR_FEE: "REPAIR FEE",
|
||||||
|
EARLY_BIRD: "EARLY BIRD",
|
||||||
};
|
};
|
||||||
|
|
||||||
export { partTypeStrings };
|
export { partTypeStrings };
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ describe("cart.vue", () => {
|
||||||
kitPrice: 0,
|
kitPrice: 0,
|
||||||
laborAmount: 34.98,
|
laborAmount: 34.98,
|
||||||
partNumber: "MOBILE FEE",
|
partNumber: "MOBILE FEE",
|
||||||
partType: "REPLACE FEE",
|
partType: "MOBILE FEE",
|
||||||
salesTax: 2.62,
|
salesTax: 2.62,
|
||||||
sellingPrice: 0,
|
sellingPrice: 0,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="cart">
|
<div class="cart mb-4">
|
||||||
<div class="px-0">
|
<div class="px-0">
|
||||||
<div
|
<div
|
||||||
class="row vin-toggle flex align-items-center"
|
class="row vin-toggle flex align-items-center"
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
:class="[this.packageCartItems ? 'vaps' : '']">
|
:class="[this.packageCartItems ? 'vaps' : '']">
|
||||||
<span>{{ cartItem.name }}</span>
|
<span>{{ cartItem.name }}</span>
|
||||||
<textLink
|
<textLink
|
||||||
|
v-if="allowItemRemoval"
|
||||||
ref="removeLink"
|
ref="removeLink"
|
||||||
linkType="text"
|
linkType="text"
|
||||||
:text="removeLinkText"
|
:text="removeLinkText"
|
||||||
|
|
@ -33,9 +34,13 @@
|
||||||
|
|
||||||
<!-- Nonpackaged Cart Items -->
|
<!-- Nonpackaged Cart Items -->
|
||||||
<hr style="background: red" />
|
<hr style="background: red" />
|
||||||
<div v-for="(cartItem, i) in nonpackageCartItems" :key="i">
|
<div
|
||||||
|
class="premium-appt-cart-item"
|
||||||
|
v-for="(cartItem, i) in nonpackageCartItems"
|
||||||
|
:key="i">
|
||||||
<span>{{ cartItem.name }}</span>
|
<span>{{ cartItem.name }}</span>
|
||||||
<textLink
|
<textLink
|
||||||
|
v-if="allowItemRemoval"
|
||||||
ref="removeLink"
|
ref="removeLink"
|
||||||
linkType="text"
|
linkType="text"
|
||||||
:text="removeLinkText"
|
:text="removeLinkText"
|
||||||
|
|
@ -46,14 +51,38 @@
|
||||||
|
|
||||||
<!-- Fees -->
|
<!-- Fees -->
|
||||||
<div v-if="recycleFeeCartItem">
|
<div v-if="recycleFeeCartItem">
|
||||||
<span>{{ recycleFeeCartItem.name }}</span
|
<textLink
|
||||||
><span>{{ currencyFormatter.format(recycleFeeCartItem.subTotal) }}</span>
|
linkType="text"
|
||||||
|
:text="recycleFeeCartItem.name"
|
||||||
|
href="#!"
|
||||||
|
@click-event="openModal(recyclingModalCmsWidgetName)" />
|
||||||
|
<span>{{ currencyFormatter.format(recycleFeeCartItem.subTotal) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="mobileFeeCartItem">
|
<div v-if="mobileFeeCartItem">
|
||||||
<span>{{ mobileFeeCartItem.name }}</span
|
<span>{{ mobileFeeCartItem.name }}</span
|
||||||
><span>{{ currencyFormatter.format(mobileFeeCartItem.subTotal) }}</span>
|
><span>{{ currencyFormatter.format(mobileFeeCartItem.subTotal) }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="premiumAppointmentDiscountCartItem" class="premium-appt-cart-item">
|
||||||
|
<span>{{ premiumAppointmentDiscountCartItem.name }}</span>
|
||||||
|
<textLink
|
||||||
|
v-if="allowItemRemoval"
|
||||||
|
ref="removeLink"
|
||||||
|
linkType="text"
|
||||||
|
:text="removeLinkText"
|
||||||
|
href="#!"
|
||||||
|
@click-event="
|
||||||
|
removeItem(
|
||||||
|
premiumAppointmentDiscountCartItem.cartItemType,
|
||||||
|
'supportingItems'
|
||||||
|
)
|
||||||
|
" />
|
||||||
|
<span>{{
|
||||||
|
currencyFormatter.format(premiumAppointmentDiscountCartItem.subTotal)
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
<!-- promos here -->
|
||||||
|
|
||||||
<!-- Sub total, sales tax, total columns -->
|
<!-- Sub total, sales tax, total columns -->
|
||||||
<div class="sub-total">
|
<div class="sub-total">
|
||||||
<span>{{ subtotalText }}</span
|
<span>{{ subtotalText }}</span
|
||||||
|
|
@ -69,6 +98,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<contentGroupModal ref="RecycleModal" cmsWidgetName="RecycleModal">
|
||||||
|
<textBlock cmsWidgetName="RecycleTextBlock" />
|
||||||
|
</contentGroupModal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -76,6 +108,7 @@
|
||||||
// Components
|
// Components
|
||||||
import textLink from "@/ux-components/text-link/text-link";
|
import textLink from "@/ux-components/text-link/text-link";
|
||||||
import textBlock from "@/digital-components/text-block/text-block";
|
import textBlock from "@/digital-components/text-block/text-block";
|
||||||
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
||||||
|
|
||||||
// Mixins
|
// Mixins
|
||||||
import baseMixin from "@/mixins/base-mixin.js";
|
import baseMixin from "@/mixins/base-mixin.js";
|
||||||
|
|
@ -96,6 +129,8 @@ export default {
|
||||||
damage: Object,
|
damage: Object,
|
||||||
servicePackageOptionsCmsName: String,
|
servicePackageOptionsCmsName: String,
|
||||||
availableLineItems: Object,
|
availableLineItems: Object,
|
||||||
|
allowItemRemoval: Boolean,
|
||||||
|
recyclingModalCmsWidgetName: String,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -109,6 +144,9 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
openModal(modalName) {
|
||||||
|
this.$refs[modalName].openModal();
|
||||||
|
},
|
||||||
toggleClass: function (event) {
|
toggleClass: function (event) {
|
||||||
this.isActive = !this.isActive;
|
this.isActive = !this.isActive;
|
||||||
},
|
},
|
||||||
|
|
@ -216,6 +254,10 @@ export default {
|
||||||
cartItems.push(cartItem);
|
cartItems.push(cartItem);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.premiumAppointmentDiscountCartItem) {
|
||||||
|
cartItems.push(this.premiumAppointmentDiscountCartItem);
|
||||||
|
}
|
||||||
|
|
||||||
return cartItems;
|
return cartItems;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -294,7 +336,11 @@ export default {
|
||||||
const nonpackageCartItems = [];
|
const nonpackageCartItems = [];
|
||||||
|
|
||||||
this.cartItems.forEach((cartItem) => {
|
this.cartItems.forEach((cartItem) => {
|
||||||
if (cartItem == this.recycleFeeCartItem || cartItem == this.mobileFeeCartItem) {
|
if (
|
||||||
|
cartItem == this.recycleFeeCartItem ||
|
||||||
|
cartItem == this.mobileFeeCartItem ||
|
||||||
|
cartItem == this.premiumAppointmentDiscountCartItem
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,8 +516,8 @@ export default {
|
||||||
lineItems: [],
|
lineItems: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
//recycleFeeLineItem.cartItemType = cartItem.cartItemType;
|
recycleFeeLineItem.cartItemType = cartItem.cartItemType;
|
||||||
//cartItem.lineItems.push(recycleFeeLineItem);
|
cartItem.lineItems.push(recycleFeeLineItem);
|
||||||
|
|
||||||
cartItem.subTotal +=
|
cartItem.subTotal +=
|
||||||
(recycleFeeLineItem.kitPrice ?? 0) +
|
(recycleFeeLineItem.kitPrice ?? 0) +
|
||||||
|
|
@ -490,7 +536,7 @@ export default {
|
||||||
let cartItem = null;
|
let cartItem = null;
|
||||||
|
|
||||||
const mobileFeeLineItem = this.supportingItems.find(
|
const mobileFeeLineItem = this.supportingItems.find(
|
||||||
(lineItem) => lineItem.partNumber == partTypeStrings.MOBILE_FEE
|
(lineItem) => lineItem.partType == partTypeStrings.MOBILE_FEE
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mobileFeeLineItem) {
|
if (mobileFeeLineItem) {
|
||||||
|
|
@ -520,10 +566,11 @@ export default {
|
||||||
otherSupportingItemsCartItem() {
|
otherSupportingItemsCartItem() {
|
||||||
let cartItem = null;
|
let cartItem = null;
|
||||||
|
|
||||||
const otherSupportingItemsLineItems = this.supportingItems.filter(
|
let otherSupportingItemsLineItems = baseMixin.methods.filterOutFees(
|
||||||
(lineItem) =>
|
this.supportingItems
|
||||||
lineItem.partNumber != partTypeStrings.MOBILE_FEE &&
|
);
|
||||||
lineItem.partNumber != partTypeStrings.RECYCLE_FEE
|
otherSupportingItemsLineItems = otherSupportingItemsLineItems.filter(
|
||||||
|
(lineItem) => lineItem.partType != partTypeStrings.EARLY_BIRD
|
||||||
);
|
);
|
||||||
|
|
||||||
if (otherSupportingItemsLineItems.length > 0) {
|
if (otherSupportingItemsLineItems.length > 0) {
|
||||||
|
|
@ -552,6 +599,40 @@ export default {
|
||||||
|
|
||||||
return cartItem;
|
return cartItem;
|
||||||
},
|
},
|
||||||
|
premiumAppointmentDiscountCartItemName() {
|
||||||
|
return "Early bird appointment"; // TODO: get from CMS
|
||||||
|
},
|
||||||
|
premiumAppointmentDiscountCartItem() {
|
||||||
|
let cartItem = null;
|
||||||
|
|
||||||
|
const premiumAppointmentDiscountLineItem = this.supportingItems.find(
|
||||||
|
(lineItem) => lineItem.partType == partTypeStrings.EARLY_BIRD
|
||||||
|
);
|
||||||
|
|
||||||
|
if (premiumAppointmentDiscountLineItem) {
|
||||||
|
cartItem = {
|
||||||
|
name: this.premiumAppointmentDiscountCartItemName,
|
||||||
|
category: cartItemCategories.SUPPORTING_ITEMS,
|
||||||
|
cartItemType: cartItemTypes.EARLY_BIRD,
|
||||||
|
isDisplayed: true,
|
||||||
|
subTotal: 0,
|
||||||
|
salesTax: 0,
|
||||||
|
lineItems: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
premiumAppointmentDiscountLineItem.cartItemType = cartItem.cartItemType;
|
||||||
|
cartItem.lineItems.push(premiumAppointmentDiscountLineItem);
|
||||||
|
|
||||||
|
cartItem.subTotal +=
|
||||||
|
(premiumAppointmentDiscountLineItem.kitPrice ?? 0) +
|
||||||
|
(premiumAppointmentDiscountLineItem.laborAmount ?? 0) +
|
||||||
|
(premiumAppointmentDiscountLineItem.sellingPrice ?? 0);
|
||||||
|
|
||||||
|
cartItem.salesTax += premiumAppointmentDiscountLineItem.salesTax ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cartItem;
|
||||||
|
},
|
||||||
removeLinkText() {
|
removeLinkText() {
|
||||||
return this.getCmsContent("RemoveCartItemTextWidget", "Text");
|
return this.getCmsContent("RemoveCartItemTextWidget", "Text");
|
||||||
},
|
},
|
||||||
|
|
@ -599,6 +680,7 @@ export default {
|
||||||
components: {
|
components: {
|
||||||
textBlock,
|
textBlock,
|
||||||
textLink,
|
textLink,
|
||||||
|
contentGroupModal,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -609,6 +691,12 @@ export default {
|
||||||
border-bottom: 1px solid $gray-500;
|
border-bottom: 1px solid $gray-500;
|
||||||
color: $black;
|
color: $black;
|
||||||
}
|
}
|
||||||
|
.modal-body {
|
||||||
|
h5 {
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
.border-bottom {
|
.border-bottom {
|
||||||
color: $gray;
|
color: $gray;
|
||||||
}
|
}
|
||||||
|
|
@ -643,7 +731,7 @@ export default {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
span {
|
span {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 33.33333%;
|
font-size: 0.875rem;
|
||||||
&:nth-child(2) {
|
&:nth-child(2) {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
@ -651,6 +739,9 @@ export default {
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.package-type,
|
.package-type,
|
||||||
.service-type {
|
.service-type {
|
||||||
|
|
@ -673,6 +764,18 @@ export default {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Custom order/wrap for nonpackaged Cart Items
|
||||||
|
.premium-appt-cart-item {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
span {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
order: 3;
|
||||||
|
margin-right: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.vin-toggle {
|
.vin-toggle {
|
||||||
&:after {
|
&:after {
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,18 @@
|
||||||
<img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" />
|
<img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" />
|
||||||
<menuModal />
|
<menuModal />
|
||||||
</div>
|
</div>
|
||||||
<alert
|
|
||||||
v-if="displayGlobalAlert"
|
<transition name="fade" mode="out-in">
|
||||||
class="rounded-0 w-100 border-0 shadow-sm"
|
<alert
|
||||||
cmsWidgetName="GlobalAlert"
|
v-if="displayGlobalAlert"
|
||||||
:manualHeadline="globalAlertMessage.messageHeadline"
|
class="rounded-0 w-100 border-0 shadow-sm"
|
||||||
:manualCopy="globalAlertMessage.messageCopy"
|
cmsWidgetName="GlobalAlert"
|
||||||
:alertClass="globalAlertMessage.type"
|
:manualHeadline="globalAlertMessage.messageHeadline"
|
||||||
v-bind:isDismissible="globalAlertMessage.isDismissible" />
|
:manualCopy="globalAlertMessage.messageCopy"
|
||||||
|
:alertClass="globalAlertMessage.type"
|
||||||
|
:onAlertCloseCallback="onAlertClose"
|
||||||
|
v-bind:isDismissible="globalAlertMessage.isDismissible" />
|
||||||
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -21,6 +25,9 @@ import eventBus from "@/helpers/event-bus/event-bus";
|
||||||
import { globalEvents } from "@/constants/events";
|
import { globalEvents } from "@/constants/events";
|
||||||
import menuModal from "@/fmg-components/funnel-header/menu-modal/menu-modal";
|
import menuModal from "@/fmg-components/funnel-header/menu-modal/menu-modal";
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const ALERT_DURATION = 3000; // millisecond time to display alert before dismissal
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "funnel-header",
|
name: "funnel-header",
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -32,6 +39,7 @@ export default {
|
||||||
messageHeadline: "",
|
messageHeadline: "",
|
||||||
type: "",
|
type: "",
|
||||||
},
|
},
|
||||||
|
countdownTimer: () => {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -42,6 +50,21 @@ export default {
|
||||||
return this.getCmsContent(this.cmsWidgetName, "LogoImage");
|
return this.getCmsContent(this.cmsWidgetName, "LogoImage");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
triggerGlobalAlert(alertEvent, isAutoDismissing) {
|
||||||
|
clearTimeout(this.countdownTimer);
|
||||||
|
this.displayGlobalAlert = true;
|
||||||
|
this.globalAlertMessage = alertEvent;
|
||||||
|
if (isAutoDismissing) {
|
||||||
|
this.countdownTimer = setTimeout(() => {
|
||||||
|
this.displayGlobalAlert = false;
|
||||||
|
}, ALERT_DURATION);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onAlertClose() {
|
||||||
|
this.displayGlobalAlert = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
components: {
|
components: {
|
||||||
alert,
|
alert,
|
||||||
menuModal,
|
menuModal,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
||||||
<div class="page-container-grouped-styles position-relative">
|
<div class="page-container-grouped-styles position-relative">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
<div>
|
<div>
|
||||||
<div class="container-fluid pb-2">
|
<div class="container-fluid pb-2">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ import { partTypeStrings } from "@/constants/part-type-strings";
|
||||||
import { defineRule } from "vee-validate";
|
import { defineRule } from "vee-validate";
|
||||||
import { required } from "@/helpers/validation-rules";
|
import { required } from "@/helpers/validation-rules";
|
||||||
import { errorMessages } from "@/constants/error-messages";
|
import { errorMessages } from "@/constants/error-messages";
|
||||||
|
import { processIfStatements } from "@/helpers/cms-content-helper";
|
||||||
|
|
||||||
// DEFINE VALIDATION RULES
|
// DEFINE VALIDATION RULES
|
||||||
defineRule("checkbox-required", required(errorMessages.OPTION_REQUIRED));
|
defineRule("checkbox-required", required(errorMessages.OPTION_REQUIRED));
|
||||||
|
|
@ -87,20 +88,23 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
processIfStatements,
|
||||||
openModal(modalName) {
|
openModal(modalName) {
|
||||||
|
this.selectedWipers = this.getSelectedWipers(); // reset selectedWipers to null upon modal open
|
||||||
this.$refs[modalName].openModal();
|
this.$refs[modalName].openModal();
|
||||||
},
|
},
|
||||||
closeModal(modalName) {
|
closeModal(modalName) {
|
||||||
this.$refs[modalName].closeModal();
|
this.$refs[modalName].closeModal();
|
||||||
},
|
},
|
||||||
addRainDefenseToCart(modalName, part) {
|
addRainDefenseToCart(modalName, part) {
|
||||||
const alreadyInCart = this.currentCartItems.vaps.some((item) => {
|
this.currentCartItems.vaps.push(part);
|
||||||
return item.partType === part.partType;
|
|
||||||
});
|
|
||||||
if (!alreadyInCart) {
|
|
||||||
this.currentCartItems.vaps.push(part);
|
|
||||||
}
|
|
||||||
this.closeModal(modalName);
|
this.closeModal(modalName);
|
||||||
|
const message = this.getRainDefenseAddedMessage();
|
||||||
|
this.$emit("added-to-cart", {
|
||||||
|
messageHeadline: message,
|
||||||
|
type: "alert-success",
|
||||||
|
isDismissible: true,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
addWipersToCart(modalName, part) {
|
addWipersToCart(modalName, part) {
|
||||||
const itemsForCart = [];
|
const itemsForCart = [];
|
||||||
|
|
@ -122,9 +126,11 @@ export default {
|
||||||
this.wipersOffered === wipersOfferedStrings.FRONT
|
this.wipersOffered === wipersOfferedStrings.FRONT
|
||||||
) {
|
) {
|
||||||
itemsForCart.push(wipersOfferedStrings.FRONT);
|
itemsForCart.push(wipersOfferedStrings.FRONT);
|
||||||
|
this.selectedWipers = ["FRONT"];
|
||||||
}
|
}
|
||||||
if (!rearWipersAlreadyInCart && this.wipersOffered === wipersOfferedStrings.REAR) {
|
if (!rearWipersAlreadyInCart && this.wipersOffered === wipersOfferedStrings.REAR) {
|
||||||
itemsForCart.push(wipersOfferedStrings.REAR);
|
itemsForCart.push(wipersOfferedStrings.REAR);
|
||||||
|
this.selectedWipers = ["REAR"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,7 +148,13 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.closeModal(modalName);
|
this.closeModal(modalName);
|
||||||
this.selectedWipers;
|
|
||||||
|
const message = this.getWipersAddedMessage();
|
||||||
|
this.$emit("added-to-cart", {
|
||||||
|
messageHeadline: message,
|
||||||
|
type: "alert-success",
|
||||||
|
isDismissible: true,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
updateWipersOffered(value) {
|
updateWipersOffered(value) {
|
||||||
this.wipersOffered = value;
|
this.wipersOffered = value;
|
||||||
|
|
@ -150,6 +162,34 @@ export default {
|
||||||
getSelectedWipers() {
|
getSelectedWipers() {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
getRainDefenseAddedMessage() {
|
||||||
|
return this.AddRainDefenseSuccessMessageFromCms;
|
||||||
|
},
|
||||||
|
getWipersAddedMessage() {
|
||||||
|
return this.processIfStatements(
|
||||||
|
this.AddWipersSuccessMessageFromCms,
|
||||||
|
"custom",
|
||||||
|
this.getCustomValueFromString
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getCustomValueFromString(str) {
|
||||||
|
switch (str) {
|
||||||
|
case "vapsAddedIsFrontWipers":
|
||||||
|
return (
|
||||||
|
this.selectedWipers?.length === 1 &&
|
||||||
|
this.selectedWipers[0] === wipersOfferedStrings.FRONT
|
||||||
|
);
|
||||||
|
case "vapsAddedIsRearWipers":
|
||||||
|
return (
|
||||||
|
this.selectedWipers?.length === 1 &&
|
||||||
|
this.selectedWipers[0] === wipersOfferedStrings.REAR
|
||||||
|
);
|
||||||
|
case "vapsAddedIsBothWipers":
|
||||||
|
return this.selectedWipers?.length > 1;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
currentCartItems() {
|
currentCartItems() {
|
||||||
|
|
@ -301,6 +341,12 @@ export default {
|
||||||
|
|
||||||
return wipersOptions;
|
return wipersOptions;
|
||||||
},
|
},
|
||||||
|
AddRainDefenseSuccessMessageFromCms() {
|
||||||
|
return this.getCmsContent("AddRainDefenseSuccessMessageWidget", "Text");
|
||||||
|
},
|
||||||
|
AddWipersSuccessMessageFromCms() {
|
||||||
|
return this.getCmsContent("AddWipersSuccessMessageWidget", "Text");
|
||||||
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
buttonQuestion,
|
buttonQuestion,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||||
<loadingModal notFullScreen ref="loadingModal" />
|
<loadingModal notFullScreen ref="loadingModal" />
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
@ -13,10 +13,7 @@
|
||||||
cmsWidgetName="VehicleBannerWidget"
|
cmsWidgetName="VehicleBannerWidget"
|
||||||
:displayGenericVehicleImage="false" />
|
:displayGenericVehicleImage="false" />
|
||||||
|
|
||||||
<funnelSubHeader
|
<funnelSubHeader class="mb-5 mt-4" cmsWidgetName="FunnelSubHeaderWidget" />
|
||||||
class="mb-5 mt-4"
|
|
||||||
cmsWidgetName="FunnelSubHeaderWidget"
|
|
||||||
leftAlignHeader />
|
|
||||||
|
|
||||||
<p v-if="isPiaDisabled" class="fw-normal no-pia-disclaimer">
|
<p v-if="isPiaDisabled" class="fw-normal no-pia-disclaimer">
|
||||||
<span>{{ noPiaDisclaimer }}</span>
|
<span>{{ noPiaDisclaimer }}</span>
|
||||||
|
|
@ -27,9 +24,13 @@
|
||||||
<cart
|
<cart
|
||||||
:damage="damageInfo"
|
:damage="damageInfo"
|
||||||
:availableLineItems="availableLineItems"
|
:availableLineItems="availableLineItems"
|
||||||
|
:allowItemRemoval="true"
|
||||||
v-model="lineItems"
|
v-model="lineItems"
|
||||||
servicePackageOptionsCmsName="ServicePackageTitle"
|
servicePackageOptionsCmsName="ServicePackageTitle"
|
||||||
@cart-remove="cartRemove" />
|
@cart-remove="cartRemove"
|
||||||
|
recyclingModalCmsWidgetName="RecycleModal" />
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<alert
|
<alert
|
||||||
|
|
@ -44,7 +45,8 @@
|
||||||
<add-vaps-modal-buttons
|
<add-vaps-modal-buttons
|
||||||
v-model="lineItems"
|
v-model="lineItems"
|
||||||
:availableLineItems="availableLineItems"
|
:availableLineItems="availableLineItems"
|
||||||
vapsTilesCmsName="VapsProductTiles" />
|
vapsTilesCmsName="VapsProductTiles"
|
||||||
|
@added-to-cart="showAlert" />
|
||||||
|
|
||||||
<paymentMethodQuestion
|
<paymentMethodQuestion
|
||||||
v-if="!isPiaDisabled"
|
v-if="!isPiaDisabled"
|
||||||
|
|
@ -371,6 +373,9 @@ export default {
|
||||||
this.$route
|
this.$route
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
showAlert(alert) {
|
||||||
|
this.$refs.funnelHeader.triggerGlobalAlert(alert, true);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
damageInfo() {
|
damageInfo() {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles vehicle-damage">
|
<div class="container-fluid page-container-grouped-styles vehicle-damage">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="container-fluid page-container-grouped-styles">
|
<div class="container-fluid page-container-grouped-styles">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,19 @@
|
||||||
<div
|
<div
|
||||||
class="alert fade show text-center mb-0 py-2 px-4 border-0"
|
class="alert fade show text-center mb-0 py-2 px-4 border-0"
|
||||||
role="alert"
|
role="alert"
|
||||||
|
v-on="{ 'close.bs.alert': onAlertClose }"
|
||||||
:class="[
|
:class="[
|
||||||
isDismissible ? 'alert-dismissible' : '',
|
isDismissible ? 'alert-dismissible' : '',
|
||||||
this.alertClass,
|
this.alertClass,
|
||||||
this.cssClassNameForCmsWidget,
|
this.cssClassNameForCmsWidget,
|
||||||
]">
|
]">
|
||||||
<p class="m-0 fw-bold alert-heading">{{ alertHeadline }}</p>
|
<p class="mx-6 my-0 fw-bold alert-heading">{{ alertHeadline }}</p>
|
||||||
<template v-for="paragraph in splitAlertCopyForParagraphTag" :key="paragraph">
|
<template v-for="paragraph in splitAlertCopyForParagraphTag" :key="paragraph">
|
||||||
<p
|
<p
|
||||||
class="m-0 text-body small"
|
class="mx-4 mt-1 mb-0 text-body small"
|
||||||
v-if="!doesCopyContainRouterLink(paragraph) && !doesCopyContainTextLink(paragraph)"
|
v-if="!doesCopyContainRouterLink(paragraph) && !doesCopyContainTextLink(paragraph)"
|
||||||
v-html="paragraph"></p>
|
v-html="paragraph"></p>
|
||||||
<p class="m-0 text-body small" v-else>
|
<p class="mx-4 mt-1 mb-0 text-body small" v-else>
|
||||||
<template v-if="doesCopyContainRouterLink(paragraph)">
|
<template v-if="doesCopyContainRouterLink(paragraph)">
|
||||||
<textBlock :customText="paragraph" class="mb-1" marginTopSizeOverride="0" />
|
<textBlock :customText="paragraph" class="mb-1" marginTopSizeOverride="0" />
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -32,7 +33,7 @@
|
||||||
</template>
|
</template>
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
<button type="button" class="btn-close p-2" data-bs-dismiss="alert" aria-label="Close">
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.7 23.7" xml:space="preserve">
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 23.7 23.7" xml:space="preserve">
|
||||||
<path
|
<path
|
||||||
d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z" />
|
d="m23.24 2.7-9.15 9.15L23.24 21a1.581 1.581 0 0 1-1.12 2.7c-.42 0-.82-.16-1.12-.46l-9.15-9.15-9.15 9.15c-.3.3-.7.46-1.12.46A1.581 1.581 0 0 1 .46 21l8.47-8.47.68-.68L.46 2.7c-.62-.62-.62-1.62 0-2.24.62-.62 1.62-.62 2.24 0l8.47 8.47.68.68L21 .46a1.57 1.57 0 0 1 2.23 0c.63.62.63 1.62.01 2.24z" />
|
||||||
|
|
@ -58,14 +59,14 @@ export default {
|
||||||
name: "alert",
|
name: "alert",
|
||||||
props: {
|
props: {
|
||||||
isDismissible: Boolean,
|
isDismissible: Boolean,
|
||||||
/*
|
|
||||||
alertClass class names:
|
|
||||||
alert-success (green)
|
|
||||||
alert-danger (red)
|
|
||||||
alert-warning (yellow)
|
|
||||||
alert-info (blue)
|
|
||||||
*/
|
|
||||||
alertClass: String,
|
alertClass: String,
|
||||||
|
/*
|
||||||
|
alertClass class names:
|
||||||
|
alert-success (green)
|
||||||
|
alert-danger (red)
|
||||||
|
alert-warning (yellow)
|
||||||
|
alert-info (blue)
|
||||||
|
*/
|
||||||
cmsWidgetName: {
|
cmsWidgetName: {
|
||||||
type: String,
|
type: String,
|
||||||
default(rawProps) {
|
default(rawProps) {
|
||||||
|
|
@ -81,6 +82,9 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
onAlertCloseCallback: {
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
pageQueryString() {
|
pageQueryString() {
|
||||||
|
|
@ -124,6 +128,9 @@ export default {
|
||||||
document.documentElement.clientHeight - footerHeight)
|
document.documentElement.clientHeight - footerHeight)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
onAlertClose() {
|
||||||
|
this.onAlertCloseCallback?.();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.ensureAlertIsInViewPort();
|
this.ensureAlertIsInViewPort();
|
||||||
|
|
@ -137,6 +144,8 @@ export default {
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.alert {
|
.alert {
|
||||||
|
padding: 0.675rem 0;
|
||||||
|
|
||||||
button {
|
button {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -145,12 +154,13 @@ export default {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
width: 0.75rem;
|
width: 0.75rem;
|
||||||
height: 0.75rem;
|
height: 0.75rem;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
&.alert-dismissible {
|
&.alert-dismissible {
|
||||||
button {
|
button {
|
||||||
display: flex;
|
display: flex;
|
||||||
top: 2px;
|
top: 0.875rem;
|
||||||
right: 2px;
|
right: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.alert-info {
|
&.alert-info {
|
||||||
|
|
@ -199,7 +209,6 @@ export default {
|
||||||
}
|
}
|
||||||
& p {
|
& p {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
margin-bottom: 0.25rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue