264 lines
9.4 KiB
Vue
264 lines
9.4 KiB
Vue
<template>
|
|
<div>
|
|
<textLink
|
|
id="promoLinkPromptId"
|
|
linkType="text"
|
|
:text="promoLinkText"
|
|
href="#!"
|
|
@click-event="openModal" />
|
|
<modal
|
|
:ref="modalName"
|
|
:headerText="modalHeaderText"
|
|
:onModalClosedCallback="onModalClosed"
|
|
:footerButtonText="modalFooterText"
|
|
@footer-button-event="addPromoCode">
|
|
<promoQuestion
|
|
ref="promoQuestion"
|
|
customInputId="promoCode"
|
|
v-model="promoCode"
|
|
cmsWidgetName="PromoQuestionWidget" />
|
|
<alert
|
|
ref="alertInvalidPromo"
|
|
v-if="displayInvalidPromoAlert"
|
|
v-html="InvalidPromoText"
|
|
class="my-4 alert"
|
|
cmsWidgetName="AlertInvalidPromoWidget"
|
|
alertClass="alert-danger"
|
|
v-bind:isDismissible="true" />
|
|
<alert
|
|
ref="alertInvalidPromoOnOrder"
|
|
v-if="displayInvalidOnOrderPromoAlert"
|
|
v-html="InvalidPromoOnOrderText"
|
|
class="my-4 alert"
|
|
cmsWidgetName="AlertInvalidPromoOnOrderWidget"
|
|
alertClass="alert-danger"
|
|
v-bind:isDismissible="true" />
|
|
<div v-for="(promo, i) in this.getPromoList()" :key="i">
|
|
<span class="applied-promo">Promo code "{{ promo.promoCode }}" applied </span>
|
|
<textLink
|
|
ref="removeLink"
|
|
linkType="text"
|
|
:text="removeLinkText"
|
|
href="#!"
|
|
@click-event="removeItem(promo.promoCode)" />
|
|
</div>
|
|
</modal>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import textLink from "@/ux-components/text-link/text-link";
|
|
import promoQuestion from "@/layouts/payment-method/promo-modal-question/promo-question/promo-question";
|
|
import modal from "@/digital-components/modal/modal";
|
|
import alert from "@/ux-components/alert/alert";
|
|
import { storeActions } from "@/constants/store-actions.js";
|
|
import {
|
|
getVapsThatNeedToBeAddedToSatisfyPromos,
|
|
promoErrorCodes,
|
|
} from "@/helpers/promotions-helper";
|
|
import { deepClone } from "@/helpers/object-helper";
|
|
import baseMixin from "@/mixins/base-mixin.js";
|
|
import { cartItemCategories } from "@/constants/cart-item-categories";
|
|
import store from "@/store";
|
|
import { mapTaxedLineItemsToStoreFormat } from "@/store";
|
|
export default {
|
|
name: "promo-modal-question",
|
|
|
|
data() {
|
|
return {
|
|
promoCode: "",
|
|
promoTextInputId: "",
|
|
displayInvalidPromoAlert: false,
|
|
displayInvalidOnOrderPromoAlert: false,
|
|
lineItems: deepClone(this.modelValue),
|
|
};
|
|
},
|
|
props: {
|
|
modelValue: Object,
|
|
linkWidgetName: String,
|
|
modalWidgetName: String,
|
|
availableVaps: Object,
|
|
},
|
|
computed: {
|
|
promoLinkText() {
|
|
return this.getCmsContent(this.linkWidgetName, "BodyText");
|
|
},
|
|
modalHeaderText() {
|
|
return this.getCmsContent("PromoQuestionWidget", "QuestionText");
|
|
},
|
|
modalFooterText() {
|
|
return this.getCmsContent(this.modalWidgetName, "FooterText");
|
|
},
|
|
modalName() {
|
|
return this.modalWidgetName;
|
|
},
|
|
modal() {
|
|
return this.$refs[this.modalName];
|
|
},
|
|
PromoOnOrderText() {
|
|
return this.getCmsContent("AlertInvalidPromoOnOrderWidget", "HeadlineText");
|
|
},
|
|
InvalidPromoOnOrderText() {
|
|
return this.PromoOnOrderText?.replaceAll(
|
|
"{custom:NEWPROMOCODE}",
|
|
this.promoCode.toUpperCase()
|
|
).replaceAll("{custom:OLDPROMOCODE}", this.getPromoCode().toUpperCase());
|
|
},
|
|
PromoText() {
|
|
return this.getCmsContent("AlertInvalidPromoWidget", "HeadlineText");
|
|
},
|
|
InvalidPromoText() {
|
|
return this.PromoText?.replaceAll("{custom:PROMOCODE}", this.promoCode.toUpperCase());
|
|
},
|
|
removeLinkText() {
|
|
return this.getCmsContent("RemoveCartItemTextWidget", "Text");
|
|
},
|
|
},
|
|
methods: {
|
|
resetAlerts() {
|
|
this.displayInvalidOnOrderPromoAlert = false;
|
|
this.displayInvalidPromoAlert = false;
|
|
},
|
|
resetsOnPromoInput() {
|
|
this.resetAlerts();
|
|
},
|
|
getPromoList() {
|
|
return this.lineItems.promos;
|
|
},
|
|
getPromoCode() {
|
|
return this.lineItems.promos?.[0].promoCode;
|
|
},
|
|
openModal() {
|
|
this.modal.openModal();
|
|
},
|
|
closeModal() {
|
|
this.modal.closeModal();
|
|
},
|
|
onModalClosed() {
|
|
this.resetAlerts();
|
|
this.$emit("update:modelValue", this.lineItems);
|
|
this.promoCode = "";
|
|
},
|
|
focusOnPromoInput() {
|
|
const input = document.getElementById(this.promoTextInputId);
|
|
input?.focus();
|
|
},
|
|
resetModalButtonStyle() {
|
|
this.modal.resetButtonStyle();
|
|
},
|
|
async getPromoCodeData(promoCode, lineItems, availableVaps, pageNameToLog = null) {
|
|
const pageName = pageNameToLog ?? this.$options?.name;
|
|
const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA,
|
|
{
|
|
promoCode: promoCode,
|
|
lineItemsToUse: lineItems,
|
|
addableVaps: availableVaps,
|
|
},
|
|
pageName,
|
|
false
|
|
);
|
|
|
|
return {
|
|
isValid: !("errorCode" in promoValidationResponse),
|
|
promoCode: promoValidationResponse?.orderPromos,
|
|
errorCode: promoValidationResponse?.errorCode,
|
|
};
|
|
},
|
|
removeItem(promo) {
|
|
this.lineItems[cartItemCategories.PROMOS] = this.lineItems[
|
|
cartItemCategories.PROMOS
|
|
].filter((lineItemsToKeep) => lineItemsToKeep.promoCode != promo);
|
|
},
|
|
async addPromoCode() {
|
|
if (this.promoCode) {
|
|
this.resetAlerts();
|
|
|
|
const promoCodeData = await this.getPromoCodeData(
|
|
this.promoCode,
|
|
this.lineItems,
|
|
this.availableVaps,
|
|
"payment-method"
|
|
);
|
|
|
|
if (promoCodeData.isValid) {
|
|
const pricedLineItemsToTax = [];
|
|
pricedLineItemsToTax.push(...promoCodeData.promoCode);
|
|
const taxedLineItems = await baseMixin.methods.dispatchStoreActionWithLogging(
|
|
storeActions.TAX_ORDER_ITEMS_AND_SAVE_SERVER_DATA,
|
|
{
|
|
billToAccountNumber: "87291",
|
|
providerNumber:
|
|
store.getters.order.serviceLocation.provider.providerNumber,
|
|
appointmentType: store.getters.order.serviceLocation.appointmentType,
|
|
serviceLocationCity: store.getters.order.serviceLocation.city,
|
|
serviceLocationState: store.getters.order.serviceLocation.state,
|
|
serviceLocationZipCode: store.getters.order.serviceLocation.zipCode,
|
|
pricedLineItems: pricedLineItemsToTax,
|
|
},
|
|
"payment-method",
|
|
false
|
|
);
|
|
// Match all line items to the line items as they are in the store
|
|
// and rebuild the original structure.
|
|
this.lineItems = mapTaxedLineItemsToStoreFormat(taxedLineItems, this.lineItems);
|
|
const taxedVaps = mapTaxedLineItemsToStoreFormat(
|
|
taxedLineItems,
|
|
this.availableVaps
|
|
);
|
|
|
|
const getVaps = getVapsThatNeedToBeAddedToSatisfyPromos(
|
|
promoCodeData.promoCode,
|
|
taxedVaps,
|
|
this.lineItems
|
|
);
|
|
this.lineItems?.promos.push(...promoCodeData.promoCode);
|
|
this.lineItems.vaps?.push(...getVaps);
|
|
this.closeModal();
|
|
} else {
|
|
if (promoCodeData.errorCode == promoErrorCodes.PROMO_STACKING_NOT_ALLOWED) {
|
|
this.displayInvalidOnOrderPromoAlert = true;
|
|
} else {
|
|
this.displayInvalidPromoAlert = true;
|
|
}
|
|
this.focusOnPromoInput();
|
|
this.resetModalButtonStyle();
|
|
}
|
|
}
|
|
},
|
|
},
|
|
watch: {
|
|
promoCode() {
|
|
this.displayInvalidPromoAlert = false;
|
|
this.displayInvalidOnOrderPromoAlert = false;
|
|
},
|
|
modelValue: {
|
|
handler(newValue) {
|
|
this.lineItems = deepClone(newValue);
|
|
},
|
|
deep: true,
|
|
},
|
|
},
|
|
|
|
components: {
|
|
textLink,
|
|
promoQuestion,
|
|
modal,
|
|
alert,
|
|
},
|
|
};
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.applied-promo {
|
|
padding-right: 4rem;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
line-height: 24px;
|
|
color: #0c7e47;
|
|
}
|
|
.alert {
|
|
color: #d4281c;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
line-height: 24px;
|
|
}
|
|
</style>
|