DigitalConsumer.FixMyGlass/src/layouts/quote/service-package-question/service-package-question.vue

442 lines
17 KiB
Vue

<template>
<buttonQuestion
ref="buttonQuestion"
:answers="servicePackageAnswers"
:groupName="groupName"
buttonTypeString="servicePackageRadio"
:buttonTypeObject="getButtonTypeObject()"
v-model="selectedPackageName"
:validationRules="validationRules"
:isRequired="isRequired"
:logDisplayedValuesEvent="true"
:isInsuranceSelected="isInsuranceSelected" />
</template>
<script>
import buttonQuestion from "@/digital-components/button-question/button-question";
import baseMixin from "@/mixins/base-mixin.js";
import { processIfStatements } from "@/helpers/cms-content-helper";
import servicePackageRadio from "./service-package-radio/service-package-radio";
import servicePackageRadioExperiment from "@/experiment-components/service-package-radio";
import servicePackageRadioAfterpayExperiment from "@/experiment-components/service-package-radio-for-afterpay";
import { partTypeStrings } from "@/constants/part-type-strings";
import { packageNames } from "@/constants/package-names";
import store from "@/store";
import { storeMutations } from "@/constants/store-mutations";
import {
shouldFrontWipersBeAvailable,
shouldRearWipersBeAvailable,
shouldRainDefenseBeAvailable,
getAvailablePackages,
getHighestRequiredTier,
getPackageContents,
containsLineItemWithPartType,
findLineItemsWithPartType,
getPackageNameByType,
getDiscountedPackageName,
} from "@/helpers/service-package-helper";
import {
getPromosThatMatchLineItemsOnOrder,
removeVapsPromosFromPromoArray,
getPromosWithAddableVaps,
getLineItemsThatMatchPromos,
} from "@/helpers/promotions-helper";
import { containsRecalParts, getItemsWithoutRecalParts } from "@/helpers/recal-helper";
import experimentMixin from "@/mixins/experiment-mixin.js";
import { experimentSettings } from "@/constants/experiments";
export default {
name: "servicePackageQuestion",
props: {
groupName: String,
cashCmsWidgetName: String,
insuranceCmsWidgetName: String,
validationRules: String,
isRequired: Boolean,
isInsuranceSelected: Boolean,
availableLineItems: null,
activePromos: null,
servicePackage: null,
isRecalibrationOnOrder: Boolean,
shouldHideRecalibration: Boolean,
},
data() {
return {
servicePackageRadio: servicePackageRadio,
servicePackageRadioExperiment: servicePackageRadioExperiment,
servicePackageRadioAfterpayExperiment: servicePackageRadioAfterpayExperiment,
selectedPackageName: null,
};
},
watch: {
availableLineItems() {
if (
this.$store.getters.payment.isInsurance != null ||
getPromosWithAddableVaps(this.activePromos).length ||
this.servicePackage != null
) {
this.selectDefaultPackage();
}
},
activePromos() {
if (this.activePromos?.length) this.selectDefaultPackage();
},
selectedPackageName(newValue) {
const VapsProductsInSelectedPackage = this.getVapsLineItemsForSelectedPackage(newValue);
this.$emit("vapsItemsSelected", VapsProductsInSelectedPackage);
const servicePackageDiscountPartInSelectedPackage =
this.getServicePackageDiscountPartForSelectedPackage(newValue);
let supportingItems = this.supportingLineItems;
if (
containsLineItemWithPartType(
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
supportingItems
)
) {
supportingItems = supportingItems.filter(
(item) => item.partType !== partTypeStrings.SERVICE_PACKAGE_DISCOUNT
);
}
if (
servicePackageDiscountPartInSelectedPackage?.length > 0 &&
supportingItems != null
) {
supportingItems.push(servicePackageDiscountPartInSelectedPackage[0]);
}
this.$emit("servicePackageDiscountSelected", supportingItems);
},
servicePackage(newValue) {
if (newValue !== null) {
this.selectDefaultPackage();
}
},
},
computed: {
nullSafeAvailableLineItems() {
return this.availableLineItems ?? [];
},
supportingLineItems() {
return this.$store.getters.lineItems?.supportingItems;
},
servicePackageAnswers() {
const cmsWidgetName = this.isInsuranceSelected
? this.insuranceCmsWidgetName
: this.cashCmsWidgetName;
let cmsAnswersContent = this.getCmsContent(cmsWidgetName, "Answers");
if (!cmsAnswersContent) {
return null;
}
const availablePackages = getAvailablePackages(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair
);
cmsAnswersContent = cmsAnswersContent.filter((answer) =>
availablePackages.some((tier) => answer.Name === tier.packageName)
);
const modifiedAnswers = cmsAnswersContent.map((answer) => ({
value: answer.Name,
buttonLabel: this.getHeaderTextFromCms(answer.SubWidgetName),
buttonLabelSubCopy: this.getSubheaderTextFromCms(answer.SubWidgetName),
buttonBodyCopy: this.getBodyTextFromCms(answer.SubWidgetName),
//The package supports service-package-discount if it has the text value in CMS
buttonAuxillaryCopy: this.isInsuranceSelected
? this.getDiscountedPackagePriceString(answer.Name, false)
: this.getDiscountedPackagePriceString(
answer.Name,
this.isServicePackageDiscountOnOrder &&
this.discountPackageNames == answer.Name
),
buttonFooterCopy: this.getFooterTextFromCms(answer.SubWidgetName),
additionalButtonData: {
strikeThroughPrice: this.getPackagePriceString(answer.Name),
servicePackageDiscount:
this.isServicePackageDiscountOnOrder &&
this.discountPackageNames == answer.Name,
Text: this.isInsuranceSelected
? false
: "Special: Save $" + this.getServicePackageDiscountPrice(),
isInsuranceSelected: this.isInsuranceSelected,
},
}));
this.$emit("currentNumberOfPackages", modifiedAnswers.length);
return modifiedAnswers;
},
isServicePackageDiscountOnOrder() {
return containsLineItemWithPartType(
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
this.nullSafeAvailableLineItems
);
},
discountPackageNames() {
const discountServicePackage = experimentMixin.methods.getSettingValue(
experimentSettings.PROMO_ON_PACKAGE
);
return getDiscountedPackageName(discountServicePackage);
},
frontWipersApplicableForTierTwo() {
return shouldFrontWipersBeAvailable(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair,
packageNames.TIER_TWO
);
},
rearWiperApplicableForTierTwo() {
return shouldRearWipersBeAvailable(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair,
packageNames.TIER_TWO
);
},
frontWipersApplicableForTierThree() {
return shouldFrontWipersBeAvailable(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair,
packageNames.TIER_THREE
);
},
rearWiperApplicableForTierThree() {
return shouldRearWipersBeAvailable(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair,
packageNames.TIER_THREE
);
},
rainDefenseApplicableForTierThree() {
return shouldRainDefenseBeAvailable(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair,
packageNames.TIER_THREE
);
},
glassToReplace() {
return this.$store.getters.order.damage.glassToReplace;
},
isRepair() {
return this.$store.getters.order.damage.isRepair;
},
servicePackageDiscountParts() {
return findLineItemsWithPartType(
partTypeStrings.SERVICE_PACKAGE_DISCOUNT,
this.nullSafeAvailableLineItems
);
},
showRecalInServicePackages() {
return this.isRecalibrationOnOrder && !this.shouldHideRecalibration;
},
},
methods: {
processIfStatements,
hasPricingByDay() {
return experimentMixin.methods.hasSettingEqualTo(
experimentSettings.PRICING_BY_DAY,
"true"
);
},
isAfterpayBreakoutDisplay() {
return (
(!this.shouldHideRecalibration || !this.isRecalibrationOnOrder) &&
experimentMixin.methods.hasSettingEqualTo(
experimentSettings.DISPLAY_AFTERPAY_BREAKOUT_DISPLAY,
"true"
)
);
},
getButtonTypeObject() {
if (this.isAfterpayBreakoutDisplay()) {
return this.servicePackageRadioAfterpayExperiment;
}
if (this.hasPricingByDay()) {
return this.servicePackageRadioExperiment;
}
return this.servicePackageRadio;
},
getHeaderTextFromCms(cmsWidgetName) {
return this.getCmsContent(cmsWidgetName, "HeaderText");
},
getSubheaderTextFromCms(cmsWidgetName) {
return this.getCmsContent(cmsWidgetName, "SubheaderText");
},
getBodyTextFromCms(cmsWidgetName) {
const bodyText = this.getCmsContent(cmsWidgetName, "BodyText");
return this.processIfStatements(bodyText, "custom", this.getCustomValueFromString);
},
getFooterTextFromCms(cmsWidgetName) {
const footerText = this.getCmsContent(cmsWidgetName, "FooterText");
return this.processIfStatements(footerText, "custom", this.getCustomValueFromString);
},
getPackagePriceString(packageName) {
const formattedPriceFloat = parseFloat(
this.getPackagePrice(packageName, {
discountedPrice: false,
servicePackageDiscount: false,
})
).toFixed(2);
return "$" + formattedPriceFloat;
},
getDiscountedPackagePriceString(packageName, servicePackageDiscount) {
const formattedPriceFloat = parseFloat(
this.getPackagePrice(packageName, {
discountedPrice: true,
servicePackageDiscount,
})
).toFixed(2);
if (this.hasPricingByDay() && !this.isAfterpayBreakoutDisplay()) {
return "$" + formattedPriceFloat;
}
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
},
getPackagePrice(packageName, { discountedPrice = false, servicePackageDiscount = false }) {
let lineItemsToPrice = [...this.nullSafeAvailableLineItems];
if (this.isRecalibrationOnOrder && this.shouldHideRecalibration) {
lineItemsToPrice = getItemsWithoutRecalParts(lineItemsToPrice);
}
//remove service package discount part
if (this.isServicePackageDiscountOnOrder) {
lineItemsToPrice = lineItemsToPrice.filter((item) => {
return item.partType != this.servicePackageDiscountParts[0].partType;
});
}
if (discountedPrice) {
lineItemsToPrice.push(...removeVapsPromosFromPromoArray(this.activePromos));
}
if (servicePackageDiscount) {
lineItemsToPrice.push(...this.servicePackageDiscountParts);
}
let priceFloat = this.isInsuranceSelected
? 0
: baseMixin.methods.getTierOnePackagePrice(
baseMixin.methods.filterOutFees(lineItemsToPrice)
);
priceFloat += this.getVapsPrice(packageName, discountedPrice);
return priceFloat;
},
getServicePackageDiscountPrice() {
if (this.isServicePackageDiscountOnOrder) {
let price = 0;
price += baseMixin.methods.getTotalLineItemPrice(
this.servicePackageDiscountParts[0]
);
return Math.abs(price);
}
},
getVapsPrice(packageName, applyPromoDiscounts = false) {
const vapsItems = this.getVapsLineItemsForSelectedPackage(packageName);
let price = 0;
vapsItems.forEach((item) => {
price += baseMixin.methods.getTotalLineItemPrice(item);
});
if (applyPromoDiscounts && this.activePromos) {
const relevantPromos = getPromosThatMatchLineItemsOnOrder(
this.activePromos,
vapsItems
);
relevantPromos.forEach((promo) => {
price += baseMixin.methods.getTotalLineItemPrice(promo);
});
}
return price;
},
selectDefaultPackage() {
if (this.servicePackage != null) {
this.selectedPackageName = getPackageNameByType(this.servicePackage);
return;
}
const promosWithAddableVaps = getPromosWithAddableVaps(this.activePromos);
const vapsThatMatchPromos = getLineItemsThatMatchPromos(
promosWithAddableVaps,
this.nullSafeAvailableLineItems
);
const vapsFromStore = this.$store.getters.lineItems.vaps ?? [];
const vapsToUseForDefaultPackageSelection = this.combineLineItemsWithoutDuplicates(
vapsThatMatchPromos,
vapsFromStore
);
this.selectedPackageName = getHighestRequiredTier(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair,
vapsToUseForDefaultPackageSelection
);
},
getVapsLineItemsForSelectedPackage(packageName) {
const packageContentTypes = getPackageContents(
this.glassToReplace,
this.nullSafeAvailableLineItems,
this.isRepair,
packageName
);
let vapsLineItemsForSelectedPackage = [];
packageContentTypes.forEach((vapType) => {
vapsLineItemsForSelectedPackage.push(
...findLineItemsWithPartType(vapType, this.nullSafeAvailableLineItems)
);
});
return vapsLineItemsForSelectedPackage;
},
getServicePackageDiscountPartForSelectedPackage(packageName) {
const selectedPackage = this.servicePackageAnswers.filter(
(item) => item.value === packageName
);
if (selectedPackage?.[0]?.additionalButtonData?.servicePackageDiscount) {
return this.servicePackageDiscountParts;
} else return [];
},
combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) {
const combinedLineItemArray = [...lineItemsTwo];
lineItemsOne.forEach((lineItemOne) => {
if (
!lineItemsTwo.filter((lineItemTwo) => lineItemTwo.id === lineItemOne.id).length
) {
combinedLineItemArray.push(lineItemOne);
}
});
return combinedLineItemArray;
},
getCustomValueFromString(str) {
switch (str) {
case "showRecalInServicePackages":
return this.showRecalInServicePackages;
case "frontWipersApplicableForTierTwo":
return this.frontWipersApplicableForTierTwo;
case "rearWiperApplicableForTierTwo":
return this.rearWiperApplicableForTierTwo;
case "frontWipersApplicableForTierThree":
return this.frontWipersApplicableForTierThree;
case "rearWiperApplicableForTierThree":
return this.rearWiperApplicableForTierThree;
case "rainDefenseApplicableForTierThree":
return this.rainDefenseApplicableForTierThree;
default:
return null;
}
},
},
components: {
buttonQuestion,
},
};
</script>