CSR-2323 save vaps to store when promo added. This should allow an update to the package name in the review dropdown
1267 lines
45 KiB
Vue
1267 lines
45 KiB
Vue
<template>
|
|
<div class="cart">
|
|
<div class="px-0">
|
|
<div
|
|
class="row vin-toggle flex align-items-center pt-4"
|
|
:class="[isExpanded ? 'expanded' : '']"
|
|
@click="toggleIsExpanded()">
|
|
<a
|
|
aria-label="expand cart"
|
|
href="javascript:void(0)"
|
|
class="col d-flex justify-content-between py-0">
|
|
<span class="label">{{ amountDueText }}</span>
|
|
<span class="label amount-due">{{
|
|
getLineItemAmount(amountDue, showCoverageAsPending)
|
|
}}</span>
|
|
</a>
|
|
</div>
|
|
<div class="cart-panel">
|
|
<div class="price-table">
|
|
<!-- Deductible, if applicable -->
|
|
<div v-if="deductibleLineItem" class="deductible">
|
|
<textBlock cmsWidgetName="DeductibleTextWidget" />
|
|
<span>
|
|
{{
|
|
getLineItemAmount(
|
|
deductibleLineItem.subTotal,
|
|
showCoverageAsPending
|
|
)
|
|
}}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Service Type -->
|
|
<div class="service-type">
|
|
<textBlock :cmsWidgetName="servicePackageTitleWidget" />
|
|
<span>
|
|
{{ getLineItemAmount(packagePrice) }}
|
|
</span>
|
|
<span
|
|
v-if="packagePriceWithoutDiscount > packagePrice"
|
|
class="struck-out-price">
|
|
{{ getLineItemAmount(packagePriceWithoutDiscount) }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- Packaged Cart Items -->
|
|
<div
|
|
v-for="(cartItem, i) in packageCartItems"
|
|
:key="i"
|
|
class="packaged-cart-item">
|
|
<span
|
|
><span :class="cartItem.category === 'promos' ? 'promo' : ''">{{
|
|
cartItem.name
|
|
}}</span></span
|
|
>
|
|
<textLink
|
|
v-if="allowItemRemoval"
|
|
ref="removeLink"
|
|
linkType="text"
|
|
:text="removeLinkText"
|
|
href="javascript:void(0)"
|
|
@click-event="removeItem(cartItem.cartItemType, cartItem.category)">
|
|
<template v-slot:after-text>
|
|
<span class="sr-only">{{ cartItem.name }}</span>
|
|
</template>
|
|
</textLink>
|
|
</div>
|
|
|
|
<!-- Nonpackaged Cart Items -->
|
|
<div
|
|
v-for="(cartItem, i) in nonpackageCartItems"
|
|
:key="i"
|
|
class="non-packaged-cart-item"
|
|
:class="[
|
|
i % 2 == 0 ? 'even' : 'odd',
|
|
cartItem.isRemovable ? 'removable-cart-item' : '',
|
|
]">
|
|
<span v-if="cartItem != recycleFeeCartItem">{{ cartItem.name }}</span>
|
|
<textLink
|
|
v-if="allowItemRemoval && cartItem.isRemovable"
|
|
ref="removeLink"
|
|
linkType="text"
|
|
:text="removeLinkText"
|
|
href="javascript:void(0)"
|
|
@click-event="removeItem(cartItem.cartItemType, cartItem.category)" />
|
|
<textLink
|
|
v-else-if="
|
|
cartItem == recycleFeeCartItem && recyclingModalCmsWidgetName
|
|
"
|
|
linkType="text"
|
|
:text="recycleFeeCartItem.name"
|
|
href="javascript:void(0)"
|
|
@click-event="openModal(recyclingModalCmsWidgetName)" />
|
|
<span v-else-if="cartItem == recycleFeeCartItem">
|
|
{{ recycleFeeCartItem.name }}
|
|
</span>
|
|
<span
|
|
v-if="
|
|
!showCoverageAsVerified ||
|
|
(showCoverageAsVerified && !cartItem.isCoveredByInsurance)
|
|
"
|
|
>{{
|
|
getLineItemAmount(cartItem.subTotal, null, cartItem.category)
|
|
}}</span
|
|
>
|
|
</div>
|
|
|
|
<!-- Sub total, sales tax, total columns -->
|
|
<div class="sub-total">
|
|
<span>{{ subtotalText }}</span>
|
|
<span>{{ getLineItemAmount(subTotal, showCoverageAsPending) }}</span>
|
|
</div>
|
|
<div class="sales-tax" v-show="showSalesTax">
|
|
<span>{{ salesTaxText }}</span>
|
|
<span>{{ getLineItemAmount(salesTax) }}</span>
|
|
</div>
|
|
<div v-if="showAsPaid" class="amount-paid">
|
|
<span>{{ amountPaidText }}</span>
|
|
<span>{{ getLineItemAmount(amountPaid) }}</span>
|
|
</div>
|
|
<div class="amount-due">
|
|
<span>{{ amountDueText }}</span>
|
|
<span>{{ getLineItemAmount(amountDue, showCoverageAsPending) }}</span>
|
|
</div>
|
|
</div>
|
|
<div
|
|
v-if="insuranceCompanyName && (showCoverageAsVerified || showCoverageAsPending)"
|
|
class="insurance-company-name caption">
|
|
{{ insuranceCompanyName }}
|
|
</div>
|
|
<promoModalQuestion
|
|
ref="promoModalQuestion"
|
|
class="small mt-4"
|
|
v-model="lineItems"
|
|
:addableVaps="availableVaps"
|
|
:pageName="pageName"
|
|
modalWidgetName="PromoModalWidget"
|
|
@promoAdded="saveVaps" />
|
|
</div>
|
|
</div>
|
|
<div
|
|
class="my-2 lh-1 applied-promo-tag"
|
|
v-for="(promoCode, i) in getPromoCodeList"
|
|
:key="i">
|
|
<span class="caption"
|
|
>Promo code <span class="promo-code">{{ promoCode }}</span> applied
|
|
</span>
|
|
</div>
|
|
<contentGroupModal ref="RecycleModal" cmsWidgetName="RecycleModal">
|
|
<textBlock cmsWidgetName="RecycleTextBlock" />
|
|
</contentGroupModal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
// Components
|
|
import textLink from "@/ux-components/text-link/text-link";
|
|
import textBlock from "@/digital-components/text-block/text-block";
|
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
|
|
import promoModalQuestion from "@/fmg-components/promo-modal-question/promo-modal-question";
|
|
|
|
// Mixins
|
|
import baseMixin from "@/mixins/base-mixin.js";
|
|
|
|
// Helpers
|
|
import { deepClone } from "@/helpers/object-helper";
|
|
import { getHighestFullySatisfiedTier, getPackageContents } from "@/helpers/service-package-helper";
|
|
import { getPromoCodeWithoutBundleIdentifier } from "@/helpers/promotions-helper";
|
|
import { storeActions } from "@/constants/store-actions";
|
|
|
|
// Constants
|
|
import { partTypeStrings } from "@/constants/part-type-strings";
|
|
import { cartItemCategories } from "@/constants/cart-item-categories";
|
|
import { cartItemTypes } from "@/constants/cart-item-types";
|
|
import { coverageStatus, cartItemTypesCoveredByInsurance } from "@/constants/insurance";
|
|
|
|
export default {
|
|
name: "cart",
|
|
props: {
|
|
modelValue: Object,
|
|
damage: Object,
|
|
servicePackageOptionsCmsName: String,
|
|
availableVaps: Object,
|
|
pageName: String,
|
|
allowItemRemoval: Boolean,
|
|
recyclingModalCmsWidgetName: String,
|
|
showAsPaid: Boolean,
|
|
isInsurance: Boolean,
|
|
insuranceDeductible: Number,
|
|
insuranceCompanyName: String,
|
|
showInsuranceCoverageAs: String,
|
|
shouldHideRecalibration: Boolean,
|
|
isItac: Boolean,
|
|
isNoComp: Boolean,
|
|
},
|
|
data() {
|
|
return {
|
|
isExpanded: true, // set default to true so cart is open on page load. This may be temporary.
|
|
currencyFormatter: new Intl.NumberFormat("en-US", {
|
|
style: "currency",
|
|
currency: "USD",
|
|
}),
|
|
};
|
|
},
|
|
methods: {
|
|
openModal(modalName) {
|
|
this.$refs[modalName].openModal();
|
|
},
|
|
toggleIsExpanded() {
|
|
this.isExpanded = !this.isExpanded;
|
|
},
|
|
getVapsPrice(packageName) {
|
|
const vapsItems = this.getVapsCartItemsForSelectedPackage(packageName);
|
|
|
|
let subTotal = 0;
|
|
|
|
vapsItems.forEach((item) => {
|
|
subTotal += item.subTotal;
|
|
});
|
|
|
|
return subTotal;
|
|
},
|
|
getPromoDiscounts() {
|
|
const promoItems = this.promoCartItems;
|
|
|
|
let subTotal = 0;
|
|
|
|
promoItems?.forEach((item) => {
|
|
subTotal += item.subTotal;
|
|
});
|
|
|
|
return subTotal;
|
|
},
|
|
getServicePackageDiscount() {
|
|
const servicePackageDiscountLineItems = this.servicePackageDiscountCartItem;
|
|
let subTotal = 0;
|
|
|
|
subTotal += servicePackageDiscountLineItems?.subTotal ?? 0;
|
|
return subTotal;
|
|
},
|
|
getVapsCartItemsForSelectedPackage(packageName) {
|
|
const packageContentTypes = getPackageContents(
|
|
this.glassToReplace,
|
|
this.availableLineItems,
|
|
this.isRepair,
|
|
packageName
|
|
);
|
|
|
|
let vapsCartItemsForSelectedPackage = [];
|
|
|
|
this.cartItems.forEach((cartItem) => {
|
|
packageContentTypes.forEach((vapType) => {
|
|
if (cartItem.cartItemType.includes(vapType)) {
|
|
vapsCartItemsForSelectedPackage.push(cartItem);
|
|
}
|
|
});
|
|
});
|
|
|
|
if (this.promoCartItems) {
|
|
this.promoCartItems.forEach((promoCartItem) => {
|
|
vapsCartItemsForSelectedPackage.push(promoCartItem);
|
|
});
|
|
}
|
|
|
|
return vapsCartItemsForSelectedPackage;
|
|
},
|
|
getCmsContentForVapsType(vapsType) {
|
|
const vapsItemDescriptions = this.getCmsContent("VapsItemDescriptions", "Answers");
|
|
|
|
if (!vapsItemDescriptions) {
|
|
return "";
|
|
}
|
|
|
|
const vapsTypeName = vapsItemDescriptions.find((entry) => entry.Name === vapsType);
|
|
|
|
return vapsTypeName.Text;
|
|
},
|
|
|
|
getLineItemAmount(amount, useVerifyingText, category) {
|
|
if (useVerifyingText) return this.verifyingCoverageText;
|
|
return category == "promos" || category == "servicePackageDiscount"
|
|
? "(" + this.currencyFormatter.format(amount * -1) + ")"
|
|
: this.currencyFormatter.format(amount);
|
|
},
|
|
|
|
async removeItem(cartItemType, category) {
|
|
this.lineItems[category] = this.lineItems[category].filter(
|
|
(lineItemsToKeep) => lineItemsToKeep.cartItemType != cartItemType
|
|
);
|
|
|
|
await this.dispatchStoreAction(storeActions.SAVE_VAPS, this.lineItems.vaps, false);
|
|
},
|
|
|
|
async saveVaps(vaps) {
|
|
this.lineItems.vaps = [...vaps];
|
|
await this.dispatchStoreAction(storeActions.SAVE_VAPS, this.lineItems.vaps, false);
|
|
},
|
|
|
|
getPromoCodeList() {
|
|
if (this.$refs["promoModalQuestion"]) {
|
|
return this.$refs["promoModalQuestion"].getPromoCodeList();
|
|
}
|
|
return [];
|
|
},
|
|
},
|
|
computed: {
|
|
lineItems: {
|
|
get: function () {
|
|
return this.modelValue;
|
|
},
|
|
set: function (newValue) {
|
|
this.$emit("update:modelValue", newValue);
|
|
},
|
|
},
|
|
lineItemsWithoutRecal() {
|
|
if (!this.lineItems || this.lineItems.length < 1) return;
|
|
|
|
const lineItemsCopy = deepClone(this.lineItems);
|
|
lineItemsCopy.glassParts = lineItemsCopy.glassParts
|
|
? baseMixin.methods.filterOutRecalibration(lineItemsCopy?.glassParts)
|
|
: [];
|
|
return lineItemsCopy;
|
|
},
|
|
showCoverageAsPending() {
|
|
return this.showInsuranceCoverageAs === coverageStatus.PENDING;
|
|
},
|
|
showCoverageAsVerified() {
|
|
return this.showInsuranceCoverageAs === coverageStatus.VERIFIED;
|
|
},
|
|
showSalesTax() {
|
|
const tax = parseFloat(this.salesTax).toFixed(2);
|
|
return tax > 0;
|
|
},
|
|
currentDeductible() {
|
|
const deductible = this.insuranceDeductible;
|
|
if (!(deductible === 0 || deductible > 0)) {
|
|
global.$logger.logError("Error: currentDeductible should not be null");
|
|
}
|
|
return deductible;
|
|
},
|
|
screenReaderTotalAmountDueText() {
|
|
return this.getCmsContent("ScreenReaderTotalAmountDueWidget", "Text");
|
|
},
|
|
screenReaderPackagePriceText() {
|
|
return this.getCmsContent("ScreenReaderPackagePriceTextWidget", "Text");
|
|
},
|
|
screenReaderRemoveVapsText() {
|
|
return this.getCmsContent("ScreenReaderRemoveVapsWidget", "Text");
|
|
},
|
|
screenReaderRecycleFeeText() {
|
|
return this.getCmsContent("ScreenReaderRecycleFeeWidget", "Text");
|
|
},
|
|
screenReaderSubTotalText() {
|
|
return this.getCmsContent("ScreenReaderSubTotalWidget", "Text");
|
|
},
|
|
screenReaderAmountPaidText() {
|
|
return this.getCmsContent("ScreenReaderAmountPaidWidget", "Text");
|
|
},
|
|
screenReaderSalesTaxText() {
|
|
return this.getCmsContent("ScreenReaderSalesTaxWidget", "Text");
|
|
},
|
|
availableLineItems() {
|
|
if (!this.lineItems || this.lineItems.length < 1) {
|
|
return [];
|
|
}
|
|
return [
|
|
...(this.lineItems.glassParts ?? []),
|
|
...(this.lineItems.supportingItems ?? []),
|
|
...(this.availableVaps ?? []),
|
|
];
|
|
},
|
|
cartItems: {
|
|
get: function () {
|
|
let cartItems = [];
|
|
|
|
if (this.frontWipersCartItem) {
|
|
cartItems.push(this.frontWipersCartItem);
|
|
}
|
|
|
|
if (this.rearWipersCartItem) {
|
|
cartItems.push(this.rearWipersCartItem);
|
|
}
|
|
|
|
if (this.rainDefenseCartItem) {
|
|
cartItems.push(this.rainDefenseCartItem);
|
|
}
|
|
|
|
if (this.glassPartCartItems) {
|
|
this.glassPartCartItems.forEach((glassPartCartItem) => {
|
|
cartItems.push(glassPartCartItem);
|
|
});
|
|
}
|
|
|
|
if (this.otherSupportingItemsCartItem) {
|
|
cartItems.push(this.otherSupportingItemsCartItem);
|
|
}
|
|
|
|
if (this.recycleFeeCartItem) {
|
|
cartItems.push(this.recycleFeeCartItem);
|
|
}
|
|
|
|
if (this.suppliesRepairCartItem) {
|
|
cartItems.push(this.suppliesRepairCartItem);
|
|
}
|
|
|
|
if (this.mobileFeeCartItem) {
|
|
cartItems.push(this.mobileFeeCartItem);
|
|
}
|
|
|
|
if (this.servicePackageDiscountCartItem) {
|
|
cartItems.push(this.servicePackageDiscountCartItem);
|
|
}
|
|
|
|
if (this.premiumAppointmentDiscountCartItem) {
|
|
cartItems.push(this.premiumAppointmentDiscountCartItem);
|
|
}
|
|
|
|
if (this.promoCartItems) {
|
|
this.promoCartItems.forEach((promoCartItem) => {
|
|
cartItems.push(promoCartItem);
|
|
});
|
|
}
|
|
|
|
return cartItems;
|
|
},
|
|
},
|
|
servicePackageTitleWidget() {
|
|
const servicePackageNames = this.getCmsContent(
|
|
this.servicePackageOptionsCmsName,
|
|
"Answers"
|
|
);
|
|
|
|
if (!servicePackageNames) {
|
|
return "";
|
|
}
|
|
|
|
const currentPackage = servicePackageNames.find(
|
|
(entry) => entry.Name === this.packageLevel
|
|
);
|
|
|
|
return currentPackage.SubWidgetName;
|
|
},
|
|
packageLevel() {
|
|
const tier = getHighestFullySatisfiedTier(
|
|
this.glassToReplace,
|
|
this.availableLineItems,
|
|
this.isRepair,
|
|
this.vaps
|
|
);
|
|
|
|
return tier;
|
|
},
|
|
packagePrice() {
|
|
let packagePrice = 0;
|
|
|
|
if (!this.isInsurance && this.shouldHideRecalibration) {
|
|
// Update packagePrice if Cash only && is part of RemoveRecal experiment
|
|
packagePrice = baseMixin.methods.getTierOnePackagePrice(
|
|
baseMixin.methods.filterOutFees(
|
|
baseMixin.methods.filterOutRecalibration(this.availableLineItems) // Strip out recal before filtering out fees
|
|
)
|
|
);
|
|
} else if (!this.showCoverageAsVerified && !this.showCoverageAsPending) {
|
|
// Update packagePrice if is verified insurance OR if Cash && not part of RemoveRecal experiment
|
|
packagePrice = baseMixin.methods.getTierOnePackagePrice(
|
|
baseMixin.methods.filterOutFees(this.availableLineItems)
|
|
);
|
|
}
|
|
|
|
packagePrice += this.getVapsPrice(this.packageLevel);
|
|
if (this.servicePackageDiscountCartItem) {
|
|
packagePrice -= this.getServicePackageDiscount();
|
|
}
|
|
|
|
return packagePrice;
|
|
},
|
|
packagePriceWithoutDiscount() {
|
|
let fullPrice = this.packagePrice;
|
|
let discount = this.getPromoDiscounts();
|
|
fullPrice += Math.abs(discount);
|
|
return fullPrice;
|
|
},
|
|
isRepair() {
|
|
if (!this.damage) {
|
|
return;
|
|
}
|
|
|
|
return this.damage.isRepair;
|
|
},
|
|
glassToReplace() {
|
|
if (!this.damage) {
|
|
return;
|
|
}
|
|
|
|
return this.damage.glassToReplace;
|
|
},
|
|
glassParts() {
|
|
const glassParts = this.lineItems?.glassParts;
|
|
return glassParts?.length > 0 ? glassParts : [];
|
|
},
|
|
vaps() {
|
|
const vaps = this.lineItems?.vaps;
|
|
return vaps?.length > 0 ? vaps : [];
|
|
},
|
|
supportingItems() {
|
|
const supportingItems = this.lineItems?.supportingItems;
|
|
return supportingItems?.length > 0 ? supportingItems : [];
|
|
},
|
|
promos() {
|
|
const promos = this.lineItems?.promos;
|
|
return promos?.length > 0 ? promos : [];
|
|
},
|
|
deductibleLineItemName() {
|
|
return this.getCmsContent("DeductibleTextWidget", "Text");
|
|
},
|
|
deductibleLineItem() {
|
|
let lineItem = null;
|
|
|
|
if (this.showCoverageAsVerified || this.showCoverageAsPending) {
|
|
lineItem = {
|
|
name: this.deductibleLineItemName,
|
|
subTotal: this.currentDeductible,
|
|
};
|
|
}
|
|
|
|
return lineItem;
|
|
},
|
|
verifyingCoverageText() {
|
|
return this.getCmsContent("VerifyingCoverageTextWidget", "Text");
|
|
},
|
|
// Cart Item Groupings
|
|
packageCartItems() {
|
|
return this.getVapsCartItemsForSelectedPackage(this.packageLevel);
|
|
},
|
|
nonpackageCartItems() {
|
|
const nonpackageCartItems = [];
|
|
|
|
this.cartItems.forEach((cartItem) => {
|
|
if (!this.packageCartItems.find((packageCartItem) => packageCartItem == cartItem)) {
|
|
if (cartItem.isDisplayed) {
|
|
nonpackageCartItems.push(cartItem);
|
|
}
|
|
}
|
|
});
|
|
return nonpackageCartItems;
|
|
},
|
|
// Individual Cart Items
|
|
frontWiperCartItemName() {
|
|
return this.getCmsContentForVapsType(partTypeStrings.FRONT_WIPER);
|
|
},
|
|
frontWipersCartItem() {
|
|
let cartItem = null;
|
|
|
|
const frontWiperLineItems = this.vaps.filter(
|
|
(vapsLineItem) => vapsLineItem.partType == partTypeStrings.FRONT_WIPER
|
|
);
|
|
|
|
if (frontWiperLineItems.length > 0) {
|
|
cartItem = {
|
|
name: this.frontWiperCartItemName,
|
|
category: cartItemCategories.VAPS,
|
|
cartItemType: cartItemTypes.FRONT_WIPERS,
|
|
isDisplayed: true,
|
|
isRemovable: true,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.FRONT_WIPERS
|
|
),
|
|
};
|
|
|
|
frontWiperLineItems.forEach((lineItem) => {
|
|
lineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(lineItem);
|
|
|
|
cartItem.subTotal +=
|
|
(lineItem.kitPrice ?? 0) +
|
|
(lineItem.laborAmount ?? 0) +
|
|
(lineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax += lineItem.salesTax ?? 0;
|
|
});
|
|
}
|
|
|
|
return cartItem;
|
|
},
|
|
rearWiperCartItemName() {
|
|
return this.getCmsContentForVapsType(partTypeStrings.REAR_WIPER);
|
|
},
|
|
rearWipersCartItem() {
|
|
let cartItem = null;
|
|
|
|
const rearWiperLineItems = this.vaps.filter(
|
|
(vapsLineItem) => vapsLineItem.partType == partTypeStrings.REAR_WIPER
|
|
);
|
|
|
|
if (rearWiperLineItems.length > 0) {
|
|
cartItem = {
|
|
name: this.rearWiperCartItemName,
|
|
category: cartItemCategories.VAPS,
|
|
cartItemType: cartItemTypes.REAR_WIPERS,
|
|
isDisplayed: true,
|
|
isRemovable: true,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.REAR_WIPERS
|
|
),
|
|
};
|
|
|
|
rearWiperLineItems.forEach((lineItem) => {
|
|
lineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(lineItem);
|
|
|
|
cartItem.subTotal +=
|
|
(lineItem.kitPrice ?? 0) +
|
|
(lineItem.laborAmount ?? 0) +
|
|
(lineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax += lineItem.salesTax ?? 0;
|
|
});
|
|
}
|
|
|
|
return cartItem;
|
|
},
|
|
rainDefenseCartItemName() {
|
|
return this.getCmsContentForVapsType(partTypeStrings.RAIN_DEFENSE);
|
|
},
|
|
rainDefenseCartItem() {
|
|
let cartItem = null;
|
|
|
|
const rainDefenseLineItem = this.vaps.find(
|
|
(vapsLineItem) => vapsLineItem.partType == partTypeStrings.RAIN_DEFENSE
|
|
);
|
|
|
|
if (rainDefenseLineItem) {
|
|
cartItem = {
|
|
name: this.getCmsContentForVapsType(partTypeStrings.RAIN_DEFENSE),
|
|
category: cartItemCategories.VAPS,
|
|
cartItemType: cartItemTypes.RAIN_DEFENSE,
|
|
isDisplayed: true,
|
|
isRemovable: true,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.RAIN_DEFENSE
|
|
),
|
|
};
|
|
|
|
rainDefenseLineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(rainDefenseLineItem);
|
|
|
|
cartItem.subTotal +=
|
|
(rainDefenseLineItem.kitPrice ?? 0) +
|
|
(rainDefenseLineItem.laborAmount ?? 0) +
|
|
(rainDefenseLineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax += rainDefenseLineItem.salesTax ?? 0;
|
|
}
|
|
|
|
return cartItem;
|
|
},
|
|
glassPartCartItems() {
|
|
const glassPartCartItems = [];
|
|
|
|
if (this.glassParts.length > 0) {
|
|
this.glassParts.forEach((lineItem) => {
|
|
let cartItem = {
|
|
name: null,
|
|
category: cartItemCategories.GLASS_PARTS,
|
|
cartItemType: cartItemTypes.GLASS_PARTS,
|
|
isDisplayed: false,
|
|
isRemovable: false,
|
|
subTotal:
|
|
(lineItem.kitPrice ?? 0) +
|
|
(lineItem.laborAmount ?? 0) +
|
|
(lineItem.sellingPrice ?? 0),
|
|
salesTax: lineItem.salesTax ?? 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.GLASS_PARTS
|
|
),
|
|
};
|
|
|
|
if (lineItem.childParts?.length > 0) {
|
|
lineItem.childParts.forEach((childPartLineItem) => {
|
|
cartItem.subTotal +=
|
|
(childPartLineItem.kitPrice ?? 0) +
|
|
(childPartLineItem.laborAmount ?? 0) +
|
|
(childPartLineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax += childPartLineItem.salesTax;
|
|
});
|
|
}
|
|
|
|
glassPartCartItems.push(cartItem);
|
|
});
|
|
}
|
|
|
|
return glassPartCartItems;
|
|
},
|
|
recycleFeeCartItemName() {
|
|
return this.getCmsContent("RecycleFeeTextWidget", "Text");
|
|
},
|
|
requiresRecycleFeeCartItem() {
|
|
return !this.isRepair;
|
|
},
|
|
recycleFeeCartItem() {
|
|
let cartItem = null;
|
|
|
|
let recycleFeeLineItem = this.supportingItems.find(
|
|
(supportingItem) => supportingItem.partType == partTypeStrings.REPLACE_FEE
|
|
);
|
|
|
|
if (!recycleFeeLineItem && this.requiresRecycleFeeCartItem) {
|
|
recycleFeeLineItem = {
|
|
partNumber: partTypeStrings.RECYCLE_FEE,
|
|
partType: partTypeStrings.REPLACE_FEE,
|
|
laborAmount: 0,
|
|
kitPrice: 0,
|
|
sellingPrice: 0,
|
|
salesTax: 0,
|
|
};
|
|
}
|
|
|
|
if (recycleFeeLineItem) {
|
|
cartItem = {
|
|
name: this.recycleFeeCartItemName,
|
|
category: cartItemCategories.SUPPORTING_ITEMS,
|
|
cartItemType: cartItemTypes.REPLACE_FEE,
|
|
isDisplayed: true,
|
|
isRemovable: false,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.REPLACE_FEE
|
|
),
|
|
};
|
|
|
|
recycleFeeLineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(recycleFeeLineItem);
|
|
|
|
cartItem.subTotal +=
|
|
(recycleFeeLineItem.kitPrice ?? 0) +
|
|
(recycleFeeLineItem.laborAmount ?? 0) +
|
|
(recycleFeeLineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax = recycleFeeLineItem.salesTax ?? 0;
|
|
}
|
|
|
|
return cartItem;
|
|
},
|
|
suppliesRepairCartItemName() {
|
|
return this.getCmsContent("SuppliesRepairTextWidget", "Text");
|
|
},
|
|
suppliesRepairCartItem() {
|
|
let cartItem = null;
|
|
|
|
const suppliesRepairLineItem = this.supportingItems.find(
|
|
(supportingItem) =>
|
|
supportingItem.partType == partTypeStrings.REPAIR_FEE &&
|
|
supportingItem.partNumber != "WSREPAIR"
|
|
);
|
|
|
|
if (suppliesRepairLineItem) {
|
|
cartItem = {
|
|
name: this.suppliesRepairCartItemName,
|
|
category: cartItemCategories.SUPPORTING_ITEMS,
|
|
cartItemType: cartItemTypes.SUPPLIES_REPAIR,
|
|
isDisplayed: true,
|
|
isRemovable: false,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.SUPPLIES_REPAIR
|
|
),
|
|
};
|
|
|
|
suppliesRepairLineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(suppliesRepairLineItem);
|
|
|
|
cartItem.subTotal +=
|
|
(suppliesRepairLineItem.kitPrice ?? 0) +
|
|
(suppliesRepairLineItem.laborAmount ?? 0) +
|
|
(suppliesRepairLineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax = suppliesRepairLineItem.salesTax ?? 0;
|
|
}
|
|
|
|
return cartItem;
|
|
},
|
|
mobileFeeCartItemName() {
|
|
return this.getCmsContent("MobileServiceTextWidget", "Text");
|
|
},
|
|
mobileFeeCartItem() {
|
|
let cartItem = null;
|
|
const mobileFeeLineItem = this.supportingItems.find(
|
|
(lineItem) => lineItem.partType == partTypeStrings.MOBILE_FEE
|
|
);
|
|
|
|
var mobileTotal =
|
|
(mobileFeeLineItem?.kitPrice ?? 0) +
|
|
(mobileFeeLineItem?.laborAmount ?? 0) +
|
|
(mobileFeeLineItem?.sellingPrice ?? 0);
|
|
|
|
if (mobileFeeLineItem && mobileTotal > 0) {
|
|
cartItem = {
|
|
name: this.mobileFeeCartItemName,
|
|
category: cartItemCategories.SUPPORTING_ITEMS,
|
|
cartItemType: cartItemTypes.MOBILE_FEE,
|
|
isDisplayed: true,
|
|
isRemovable: false,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.MOBILE_FEE
|
|
),
|
|
};
|
|
mobileFeeLineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(mobileFeeLineItem);
|
|
cartItem.subTotal += mobileTotal;
|
|
cartItem.salesTax += mobileFeeLineItem.salesTax ?? 0;
|
|
}
|
|
return cartItem;
|
|
},
|
|
servicePackageDiscountCartItemName() {
|
|
return this.getCmsContent("ServicePackageDiscountTextWidget", "Text");
|
|
},
|
|
servicePackageDiscountCartItem() {
|
|
let cartItem = null;
|
|
|
|
const servicePackageDiscountLineItem = this.supportingItems.find(
|
|
(lineItem) => lineItem.partType == partTypeStrings.SERVICE_PACKAGE_DISCOUNT
|
|
);
|
|
|
|
if (servicePackageDiscountLineItem) {
|
|
cartItem = {
|
|
name:
|
|
this.servicePackageDiscountCartItemName +
|
|
Math.abs(
|
|
baseMixin.methods.getTotalLineItemPrice(servicePackageDiscountLineItem)
|
|
),
|
|
category: cartItemCategories.SERVICE_PACKAGE_DISCOUNT,
|
|
cartItemType: cartItemTypes.SERVICE_PACKAGE_DISCOUNT,
|
|
isDisplayed: true,
|
|
isRemovable: false,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: false,
|
|
};
|
|
|
|
servicePackageDiscountLineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(servicePackageDiscountLineItem);
|
|
|
|
cartItem.subTotal +=
|
|
(servicePackageDiscountLineItem.kitPrice ?? 0) +
|
|
(servicePackageDiscountLineItem.laborAmount ?? 0) +
|
|
(servicePackageDiscountLineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax += servicePackageDiscountLineItem.salesTax ?? 0;
|
|
}
|
|
|
|
return cartItem;
|
|
},
|
|
otherSupportingItemsCartItem() {
|
|
let cartItem = null;
|
|
|
|
const otherSupportingItems = this.supportingItems.filter((item) => {
|
|
return item.partType != partTypeStrings.SERVICE_PACKAGE_DISCOUNT;
|
|
});
|
|
// Don't include fees they are part of the package total
|
|
let otherSupportingItemsLineItems =
|
|
baseMixin.methods.filterOutFees(otherSupportingItems);
|
|
|
|
if (otherSupportingItemsLineItems.length > 0) {
|
|
cartItem = {
|
|
name: null,
|
|
category: cartItemCategories.SUPPORTING_ITEMS,
|
|
cartItemType: cartItemTypes.SUPPORTING_ITEMS,
|
|
isDisplayed: false,
|
|
isRemovable: false,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.SUPPORTING_ITEMS
|
|
),
|
|
};
|
|
|
|
otherSupportingItemsLineItems.forEach((lineItem) => {
|
|
lineItem.cartItemType = cartItem.cartItemType;
|
|
cartItem.lineItems.push(lineItem);
|
|
|
|
cartItem.subTotal +=
|
|
(lineItem.kitPrice ?? 0) +
|
|
(lineItem.laborAmount ?? 0) +
|
|
(lineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax += lineItem.salesTax ?? 0;
|
|
});
|
|
}
|
|
|
|
return cartItem;
|
|
},
|
|
premiumAppointmentDiscountCartItemName() {
|
|
return this.getCmsContent("PremiumAppointmentTextWidget", "Text");
|
|
},
|
|
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,
|
|
isRemovable: true,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(
|
|
cartItemTypes.EARLY_BIRD
|
|
),
|
|
};
|
|
|
|
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;
|
|
},
|
|
promoCartItems() {
|
|
const promoCartItems = [];
|
|
|
|
// get unique promo codes
|
|
const uniquePromoCodes = [
|
|
...new Set(
|
|
this.promos.map((promo) => getPromoCodeWithoutBundleIdentifier(promo.promoCode))
|
|
),
|
|
];
|
|
|
|
uniquePromoCodes.forEach((promoCode) => {
|
|
// get the codes with the prefix from the promo array
|
|
const promoLineItems = this.promos.filter(
|
|
(promo) => getPromoCodeWithoutBundleIdentifier(promo.promoCode) == promoCode
|
|
);
|
|
|
|
// Create a cart item for each promo
|
|
let cartItem = null;
|
|
|
|
cartItem = {
|
|
name: promoCode,
|
|
category: cartItemCategories.PROMOS,
|
|
cartItemType: promoCode,
|
|
isDisplayed: true,
|
|
isRemovable: true,
|
|
subTotal: 0,
|
|
salesTax: 0,
|
|
lineItems: [],
|
|
isCoveredByInsurance: cartItemTypesCoveredByInsurance.includes(promoCode),
|
|
};
|
|
|
|
promoLineItems.forEach((promoLineItem) => {
|
|
promoLineItem.cartItemType = cartItem.cartItemType;
|
|
|
|
cartItem.subTotal +=
|
|
(promoLineItem.kitPrice ?? 0) +
|
|
(promoLineItem.laborAmount ?? 0) +
|
|
(promoLineItem.sellingPrice ?? 0);
|
|
|
|
cartItem.salesTax += promoLineItem.salesTax ?? 0;
|
|
|
|
cartItem.lineItems.push(promoLineItem);
|
|
});
|
|
|
|
promoCartItems.push(cartItem);
|
|
});
|
|
|
|
return promoCartItems;
|
|
},
|
|
removeLinkText() {
|
|
return this.getCmsContent("RemoveCartItemTextWidget", "Text");
|
|
},
|
|
recycleFeeText() {
|
|
return this.getCmsContent("RecycleFeeTextWidget", "Text");
|
|
},
|
|
salesTaxText() {
|
|
return this.getCmsContent("SalesTaxTextWidget", "Text");
|
|
},
|
|
amountDueText() {
|
|
return this.getCmsContent("AmountDueTextWidget", "Text");
|
|
},
|
|
amountPaidText() {
|
|
return this.getCmsContent("AmountPaidTextWidget", "Text");
|
|
},
|
|
subtotalText() {
|
|
return this.getCmsContent("SubtotalTextWidget", "Text");
|
|
},
|
|
subTotal() {
|
|
if (!this.lineItems || this.lineItems.length < 1) return;
|
|
return this.isInsurance || !this.shouldHideRecalibration
|
|
? baseMixin.methods.getSubTotal(this.lineItems) // calculate with recal (if on order)
|
|
: baseMixin.methods.getSubTotal(this.lineItemsWithoutRecal); // calculate without recal
|
|
},
|
|
salesTax() {
|
|
if (!this.lineItems || this.lineItems.length < 1) return;
|
|
|
|
if (
|
|
this.isInsurance &&
|
|
!this.showCoverageAsVerified &&
|
|
!this.isItac &&
|
|
!this.isNoComp
|
|
) {
|
|
return 0;
|
|
}
|
|
|
|
return this.isInsurance || !this.shouldHideRecalibration
|
|
? baseMixin.methods.getSalesTax(this.lineItems) // calculate with recal (if on order)
|
|
: baseMixin.methods.getSalesTax(this.lineItemsWithoutRecal); // calculated without recal
|
|
},
|
|
amountDue() {
|
|
if (!this.lineItems || this.lineItems.length < 1) return;
|
|
if (this.showAsPaid) return 0;
|
|
return this.isInsurance || !this.shouldHideRecalibration
|
|
? baseMixin.methods.getAmountDue(this.lineItems) // calculate with recal (if on order)
|
|
: baseMixin.methods.getAmountDue(this.lineItemsWithoutRecal); // calculated without recal
|
|
},
|
|
amountPaid() {
|
|
if (!this.showAsPaid) {
|
|
return 0;
|
|
}
|
|
|
|
// unary plus operator to convert string amount to numeric so we can add them together
|
|
var amtPaid = +this.subTotal + +this.salesTax;
|
|
return amtPaid;
|
|
},
|
|
},
|
|
components: {
|
|
textBlock,
|
|
textLink,
|
|
contentGroupModal,
|
|
promoModalQuestion,
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.cart {
|
|
margin-bottom: 1rem;
|
|
|
|
h5 {
|
|
border-bottom: 1px solid $gray-500;
|
|
color: $black;
|
|
}
|
|
.modal-body {
|
|
h5 {
|
|
text-align: center;
|
|
border-bottom: none;
|
|
}
|
|
}
|
|
.border-bottom {
|
|
color: $gray;
|
|
}
|
|
.label {
|
|
color: $black;
|
|
font-weight: 500;
|
|
line-height: 1.625;
|
|
}
|
|
.amount-due {
|
|
color: $green;
|
|
}
|
|
.cart-panel {
|
|
max-height: 0;
|
|
transition: all 350ms ease-in;
|
|
overflow: hidden;
|
|
visibility: hidden;
|
|
color: $gray-600;
|
|
}
|
|
.price-table {
|
|
div {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 0.5rem 1.5rem;
|
|
&:nth-last-child(-n + 3) {
|
|
background-color: $green-100;
|
|
}
|
|
&:last-child {
|
|
background-color: $green;
|
|
color: #ffffff;
|
|
}
|
|
}
|
|
.deductible {
|
|
background-color: $gray-100;
|
|
}
|
|
.service-type {
|
|
background-color: $gray-100;
|
|
}
|
|
.deductible ~ .service-type {
|
|
background: $white;
|
|
}
|
|
.service-type ~ .packaged-cart-item {
|
|
background-color: $gray-100;
|
|
}
|
|
.deductible ~ .packaged-cart-item {
|
|
background: $white;
|
|
}
|
|
.struck-out-price {
|
|
text-decoration: line-through;
|
|
padding-left: 0.5rem;
|
|
}
|
|
.packaged-cart-item {
|
|
padding-left: 2.5rem;
|
|
align-items: center;
|
|
span {
|
|
display: flex;
|
|
font-size: 0.875rem;
|
|
&:nth-child(2) {
|
|
justify-content: flex-end;
|
|
}
|
|
&:last-child {
|
|
justify-content: flex-end;
|
|
}
|
|
&.promo {
|
|
text-transform: uppercase;
|
|
}
|
|
}
|
|
a {
|
|
font-size: 0.875rem;
|
|
text-decoration: none;
|
|
line-height: 1.75;
|
|
}
|
|
}
|
|
.non-packaged-cart-item {
|
|
&.odd {
|
|
background: $gray-100;
|
|
}
|
|
}
|
|
.deductible ~ .non-packaged-cart-item {
|
|
&.odd {
|
|
background: $white;
|
|
}
|
|
}
|
|
.non-packaged-cart-item {
|
|
&.even {
|
|
background-color: $white;
|
|
}
|
|
a {
|
|
line-height: 1.625;
|
|
}
|
|
}
|
|
.deductible ~ .non-packaged-cart-item {
|
|
&.even {
|
|
background-color: $gray-100;
|
|
}
|
|
}
|
|
// Custom order/wrap for removable nonpackaged Cart Items
|
|
.removable-cart-item {
|
|
flex-wrap: wrap;
|
|
span {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
a {
|
|
order: 3;
|
|
margin-right: 100%;
|
|
text-decoration: none;
|
|
}
|
|
}
|
|
.package-type,
|
|
.service-type,
|
|
.deductible {
|
|
align-items: center;
|
|
}
|
|
.sub-total,
|
|
.sales-tax,
|
|
.amount-due,
|
|
.amount-paid {
|
|
font-weight: 500;
|
|
color: $black;
|
|
}
|
|
.sub-total {
|
|
border-top: 1px solid $green;
|
|
}
|
|
.service-type,
|
|
.deductible {
|
|
.text-block {
|
|
background: transparent;
|
|
margin-top: 0;
|
|
padding: 0;
|
|
width: 50%;
|
|
}
|
|
}
|
|
}
|
|
.insurance-company-name {
|
|
margin-top: 0.5rem;
|
|
}
|
|
.vin-toggle {
|
|
&:after {
|
|
content: "";
|
|
transition: all 0.5s ease;
|
|
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.9' xml:space='preserve'%3e%3cpath d='M8 8.9c-.2 0-.5-.1-.6-.3L.3 1.5C.1 1.4 0 1.1 0 .9 0 .7.1.4.3.3.4.1.7 0 .9 0c.2 0 .5.1.6.3L8 6.7 14.5.2c.1-.1.4-.2.6-.2.2 0 .5.1.6.3s.3.4.3.6c0 .2-.1.5-.3.6L8.6 8.6c-.1.2-.4.3-.6.3z' fill='%231474a2'/%3e%3c/svg%3e");
|
|
background-repeat: no-repeat;
|
|
background-position: right center;
|
|
width: 16px;
|
|
height: 9px;
|
|
display: inline-flex;
|
|
position: relative;
|
|
right: 0.75rem;
|
|
margin: 0.5rem 0 0.5rem 1rem;
|
|
cursor: pointer;
|
|
}
|
|
&.expanded:after {
|
|
transform: rotate(180deg);
|
|
}
|
|
&.expanded + .cart-panel {
|
|
max-height: 650px;
|
|
transition: all 150ms ease-in;
|
|
overflow: hidden;
|
|
padding: 1rem 0 0.5rem;
|
|
visibility: visible;
|
|
}
|
|
a {
|
|
text-decoration: none;
|
|
}
|
|
}
|
|
.applied-promo-tag {
|
|
span {
|
|
color: $green-700;
|
|
font-weight: 500;
|
|
padding: 2px 8px;
|
|
background-color: $green-100;
|
|
border-radius: 12px;
|
|
|
|
&.promo-code {
|
|
text-transform: uppercase;
|
|
padding: 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.payment-method-question {
|
|
.question-text {
|
|
margin: 1rem 0 0.5rem 0;
|
|
}
|
|
span {
|
|
line-height: 24px;
|
|
}
|
|
}
|
|
</style>
|