Merge branch 'develop' into feature/CSR-1388
This commit is contained in:
commit
dd01528864
13 changed files with 514 additions and 45 deletions
|
|
@ -33,6 +33,7 @@ const errorMessages = {
|
|||
MAKE_REQUIRED: "Please select your vehicle make",
|
||||
MODEL_REQUIRED: "Please select your vehicle model",
|
||||
STYLE_REQUIRED: "Please select your vehicle style",
|
||||
PROMO_REQUIRED: "Please enter a promo code",
|
||||
};
|
||||
|
||||
export { errorMessages };
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ export default {
|
|||
name: "funnel-header",
|
||||
data() {
|
||||
return {
|
||||
alertIdCounter: 0,
|
||||
globalAlertMessages: [],
|
||||
};
|
||||
},
|
||||
|
|
@ -47,8 +46,7 @@ export default {
|
|||
methods: {
|
||||
pushGlobalAlert(alertToPush, isAutoDismissing) {
|
||||
alertToPush.displayAlert = true;
|
||||
alertToPush.id = this.alertIdCounter;
|
||||
this.alertIdCounter++;
|
||||
alertToPush.id = crypto.randomUUID();
|
||||
if (isAutoDismissing) {
|
||||
setTimeout(() => {
|
||||
alertToPush.displayAlert = false;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
const windowPageShowCallback = function (evt) {
|
||||
if (evt.persisted) {
|
||||
setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 10);
|
||||
}
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "Modal",
|
||||
data() {
|
||||
|
|
@ -93,17 +101,11 @@ export default {
|
|||
this.isModalTextCarouselVisible = showTextCarousel;
|
||||
this.isModalVisible = true;
|
||||
//Force page reload on back button
|
||||
window.addEventListener(
|
||||
"pageshow",
|
||||
function (evt) {
|
||||
if (evt.persisted) {
|
||||
setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 10);
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
window.addEventListener("pageshow", windowPageShowCallback, false);
|
||||
},
|
||||
hideModal() {
|
||||
this.isModalVisible = false;
|
||||
window.removeEventListener("pageshow", windowPageShowCallback, false);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ export function getDateDifferenceInDays(startDate, endDate) {
|
|||
// Use the built-in method to get the difference in milliseconds
|
||||
var difference = date1 - date2;
|
||||
// Convert milliseconds to days and return the result
|
||||
return difference / (1000 * 3600 * 24);
|
||||
return Math.floor(difference / (1000 * 3600 * 24));
|
||||
}
|
||||
export function get12HourTimeFormat(time) {
|
||||
// Check correct time format and split into components
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export const addableVapsPromoPartNumbers = [
|
|||
promoPartNumberStrings.WIPER_DISCOUNT_PART_NUMBER,
|
||||
];
|
||||
|
||||
const promoErrorCodes = {
|
||||
export const promoErrorCodes = {
|
||||
UNKNOWN: "Unknown",
|
||||
PROMO_NOT_YET_IN_USE: "PromoNotYetInUse",
|
||||
PROMO_USAGE_COUNT_EXCEEDED: "PromoUsageCountExceeded",
|
||||
|
|
@ -246,6 +246,20 @@ export function getVapsThatNeedToBeAddedToSatisfyPromos(
|
|||
}
|
||||
}
|
||||
|
||||
export function removeCurrentlyActivePromoCodesFromInactivePromos(
|
||||
activePromoObjects,
|
||||
inactivePromos
|
||||
) {
|
||||
activePromoObjects = activePromoObjects ?? [];
|
||||
inactivePromos = inactivePromos ?? [];
|
||||
const activePromoCodes = activePromoObjects.map((promoObject) =>
|
||||
getPromoCodeWithoutBundleIdentifier(promoObject.promoCode).toUpperCase()
|
||||
);
|
||||
return inactivePromos.filter((inactivePromo) => {
|
||||
return !activePromoCodes.includes(inactivePromo.toUpperCase());
|
||||
});
|
||||
}
|
||||
|
||||
// bundle promos look like: "bundlePromo/###"" for each promo, this returns "bundlePromo" only
|
||||
export function getPromoCodeWithoutBundleIdentifier(promoCode) {
|
||||
return promoCode.split("/")[0];
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||
<loadingModal notFullScreen ref="loadingModal" />
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -30,6 +30,12 @@
|
|||
recyclingModalCmsWidgetName="RecycleModal" />
|
||||
|
||||
<hr class="my-5" />
|
||||
<promoModalQuestion
|
||||
class="pb-3"
|
||||
v-model="lineItems"
|
||||
:availableVaps="availableVaps"
|
||||
linkWidgetName="PromoLinkWidget"
|
||||
modalWidgetName="PromoModalWidget" />
|
||||
|
||||
<div>
|
||||
<alert
|
||||
|
|
@ -73,6 +79,7 @@ import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-heade
|
|||
import paymentMethodQuestion from "@/layouts/payment-method/payment-method-question/payment-method-question";
|
||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||
import cart from "@/fmg-components/cart/cart";
|
||||
import promoModalQuestion from "@/layouts/payment-method/promo-modal-question/promo-modal-question";
|
||||
import addVapsModalButtons from "./add-vaps-modal-buttons/add-vaps-modal-buttons";
|
||||
import { submitWorkOrder } from "@/helpers/heritage-integration/order-helper.js";
|
||||
import alert from "@/ux-components/alert/alert";
|
||||
|
|
@ -316,6 +323,7 @@ export default {
|
|||
return this.$store.getters.order.payment.inactivePromos;
|
||||
},
|
||||
async revalidatePromos() {
|
||||
this.$refs.loadingModal.showModal();
|
||||
const revalidatePromoResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||
storeActions.REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA,
|
||||
{
|
||||
|
|
@ -337,6 +345,7 @@ export default {
|
|||
|
||||
this.lineItems.promos = revalidatePromoResponse.promoLineItems;
|
||||
this.inactivePromos = revalidatePromoResponse.errors.map((x) => x.promoCode);
|
||||
this.$refs.loadingModal.hideModal();
|
||||
},
|
||||
backButtonAction() {
|
||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
|
|
@ -487,6 +496,7 @@ export default {
|
|||
alert,
|
||||
addVapsModalButtons,
|
||||
paymentMethodQuestion,
|
||||
promoModalQuestion,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
import { mount, shallowMount } from "@vue/test-utils";
|
||||
import promoModalQuestion from "./promo-modal-question";
|
||||
|
||||
jest.mock("@/digital-components/textbox-question/textbox-question", () => ({
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return widgetName[cmsFieldName];
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock("@/digital-components/modal/modal", () => ({
|
||||
methods: {
|
||||
closeModal: jest.fn(),
|
||||
resetButtonStyle: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
const linkWidgetName = "linkWidgetName";
|
||||
const modalWidgetName = "modalWidgetName";
|
||||
|
||||
const mockLinkCmsContent = {
|
||||
BodyText: "Sample link body text here.",
|
||||
};
|
||||
|
||||
const mockModalCmsContent = {
|
||||
FooterText: "Sample modal footer text here.",
|
||||
};
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
if (widgetName === linkWidgetName) {
|
||||
return mockLinkCmsContent[cmsFieldName];
|
||||
}
|
||||
|
||||
if (widgetName === modalWidgetName) {
|
||||
return mockModalCmsContent[cmsFieldName];
|
||||
}
|
||||
|
||||
return null;
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
describe("promo-modal-question.vue", () => {
|
||||
it("Should reset all alerts on onModalClosed", async () => {
|
||||
// Arrange
|
||||
|
||||
const wrapper = mount(promoModalQuestion, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
linkWidgetName: linkWidgetName,
|
||||
modalWidgetName: modalWidgetName,
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
|
||||
// Act
|
||||
wrapper.vm.onModalClosed();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.displayInvalidPromoAlert).toBe(false);
|
||||
expect(wrapper.vm.displayInvalidOnOrderPromoAlert).toBe(false);
|
||||
});
|
||||
it("Should emit update:modelValue on Modal closed", async () => {
|
||||
// Arrange
|
||||
const lineItems = {
|
||||
glassParts: [],
|
||||
supportingItems: [],
|
||||
vaps: [],
|
||||
promos: [],
|
||||
};
|
||||
|
||||
const wrapper = mount(promoModalQuestion, {
|
||||
mixins: [mockMixin],
|
||||
props: {
|
||||
modelValue: lineItems,
|
||||
linkWidgetName: linkWidgetName,
|
||||
modalWidgetName: modalWidgetName,
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
|
||||
// Act
|
||||
|
||||
await wrapper.vm.onModalClosed();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted("update:modelValue")).toEqual([[lineItems]]);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
<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;
|
||||
this.focusOnPromoInput();
|
||||
this.resetModalButtonStyle();
|
||||
} 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>
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import promoQuestion from "./promo-question";
|
||||
|
||||
describe("promo-question.vue", () => {
|
||||
it("Should get the modelValue", async () => {
|
||||
// Arrange
|
||||
const text = "test";
|
||||
const wrapper = shallowMount(promoQuestion, {
|
||||
props: {
|
||||
modelValue: text,
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
|
||||
// Act
|
||||
const modelValueText = wrapper.vm.value;
|
||||
wrapper.vm.value = "test also";
|
||||
|
||||
// Assert
|
||||
expect(modelValueText).toEqual("test");
|
||||
});
|
||||
|
||||
it("Should emit to set value", async () => {
|
||||
// Arrange
|
||||
const text = "test";
|
||||
const wrapper = shallowMount(promoQuestion, {
|
||||
props: {
|
||||
modelValue: text,
|
||||
},
|
||||
attachTo: document.body,
|
||||
});
|
||||
|
||||
// Act
|
||||
const modelValueText = wrapper.vm.value;
|
||||
wrapper.vm.value = "test also";
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted("update:modelValue")).toEqual([["test also"]]);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<textboxQuestion
|
||||
ref="promoInputTextQuestion"
|
||||
:cmsWidgetName="cmsWidgetName"
|
||||
v-model="value"
|
||||
inputId="promoCode"
|
||||
questionAlignment="center"
|
||||
cornerStyle="rounded"
|
||||
:displayQuestionText="false"
|
||||
isRequired
|
||||
validationRules="promo-required" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import textboxQuestion from "@/digital-components/textbox-question/textbox-question";
|
||||
|
||||
//Supporting Files
|
||||
import { defineRule } from "vee-validate";
|
||||
import { required } from "@/helpers/validation-rules";
|
||||
import { errorMessages } from "@/constants/error-messages";
|
||||
|
||||
// Define Validation Rules
|
||||
defineRule("promo-required", required(errorMessages.PROMO_REQUIRED));
|
||||
|
||||
export default {
|
||||
name: "promo-question",
|
||||
props: {
|
||||
modelValue: String,
|
||||
cmsWidgetName: String,
|
||||
},
|
||||
computed: {
|
||||
value: {
|
||||
get: function () {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
textboxQuestion,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -131,6 +131,7 @@ export default {
|
|||
}
|
||||
|
||||
this.$refs.loadingModal.isModalVisible = false;
|
||||
await baseMixin.methods.dispatchStoreAction(storeActions.CREATE_SUBMITTED_ORDER);
|
||||
this.$router.navigateWithoutSaving(this.navigationScenarios.PIA_SUCCESS, this.$route);
|
||||
},
|
||||
forwardButtonAction() {
|
||||
|
|
|
|||
|
|
@ -169,7 +169,16 @@ router.beforeEach(async (to, from, next) => {
|
|||
showFmgLoadingModal(true);
|
||||
}
|
||||
|
||||
next();
|
||||
const toQueryPage = to.query?.fmgPage;
|
||||
const notToPIAReturn = toQueryPage != "payment-pia-return";
|
||||
const isInIframe = window !== window.top;
|
||||
|
||||
if (isInIframe && notToPIAReturn) {
|
||||
const newUrl = `${window.top.location.origin}${to.href}`;
|
||||
window.top.location.href = newUrl;
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
router.afterEach(async (to, from) => {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,10 @@ import {
|
|||
getDisplayTextForDurationLength,
|
||||
} from "@/layouts/schedule/helpers/schedule-helper";
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
import { getPromoCodeWithoutBundleIdentifier } from "@/helpers/promotions-helper";
|
||||
import {
|
||||
getPromoCodeWithoutBundleIdentifier,
|
||||
removeCurrentlyActivePromoCodesFromInactivePromos,
|
||||
} from "@/helpers/promotions-helper";
|
||||
import { getDateDifferenceInDays } from "@/helpers/date-helper";
|
||||
// Export State
|
||||
const getDefaultState = () => {
|
||||
|
|
@ -543,7 +546,6 @@ export const mutations = {
|
|||
state.order.customer.phoneNumber = sessionInformation.order.customer.phoneNumber;
|
||||
state.order.customer.isSmsOptIn = sessionInformation.order.customer.isSmsOptIn;
|
||||
|
||||
state.order.existingPromoCode = sessionInformation.order.existingPromoCode;
|
||||
state.applicationUser.experiments = sessionInformation.applicationUser.experiments;
|
||||
state.applicationUser.crmCustomerId = sessionInformation.applicationUser.crmCustomerId;
|
||||
state.applicationUser.pageData = sessionInformation.applicationUser.pageData;
|
||||
|
|
@ -1715,7 +1717,6 @@ export const actions = {
|
|||
jobMaxMinutes: order.schedule?.jobMaxMinutes,
|
||||
jobMinMinutes: order.schedule?.jobMinMinutes,
|
||||
},
|
||||
existingPromoCode: null,
|
||||
referralCorrelationId: order.referralCorrelationId,
|
||||
referralDate: order.referralDate,
|
||||
referralNumber: order.referralNumber?.toString(),
|
||||
|
|
@ -2120,13 +2121,6 @@ export const actions = {
|
|||
addGuidToLineItemsIfNotAlreadyThere(vaps);
|
||||
context.commit(storeMutations.UPDATE_VAPS, vaps);
|
||||
},
|
||||
// COMBINE THESE
|
||||
savePromos(context, promos) {
|
||||
context.commit(storeMutations.UPDATE_PROMOS, promos);
|
||||
},
|
||||
saveInactivePromos(context, inactivePromos) {
|
||||
context.commit(storeMutations.UPDATE_INACTIVE_PROMOS, inactivePromos);
|
||||
},
|
||||
// Manage promo saving to ensure a promoCode never ends up in both active and inactive
|
||||
saveActiveAndOrInactivePromos(context, { activePromos = null, inactivePromos = null }) {
|
||||
let activePromosToSave;
|
||||
|
|
@ -2138,12 +2132,10 @@ export const actions = {
|
|||
} else if (activePromos && inactivePromos) {
|
||||
// Prioritize active promos when both inactive and active are supplied
|
||||
activePromosToSave = activePromos;
|
||||
const activePromoCodes = activePromos.map((promoObject) =>
|
||||
getPromoCodeWithoutBundleIdentifier(promoObject.promoCode)
|
||||
inactivePromosToSave = removeCurrentlyActivePromoCodesFromInactivePromos(
|
||||
activePromosToSave,
|
||||
inactivePromos
|
||||
);
|
||||
inactivePromosToSave = inactivePromos.filter((inactivePromo) => {
|
||||
return !activePromoCodes.includes(inactivePromo);
|
||||
});
|
||||
} else if (!activePromos) {
|
||||
// Only inactivePromos supplied
|
||||
inactivePromosToSave = inactivePromos;
|
||||
|
|
@ -2155,13 +2147,9 @@ export const actions = {
|
|||
} else if (!inactivePromos) {
|
||||
// Only activePromos supplied
|
||||
activePromosToSave = activePromos;
|
||||
const activePromoCodes = activePromos.map((promoObject) =>
|
||||
getPromoCodeWithoutBundleIdentifier(promoObject.promoCode)
|
||||
);
|
||||
inactivePromosToSave = (context.getters.payment.inactivePromos ?? []).filter(
|
||||
(inactivePromo) => {
|
||||
return !activePromoCodes.includes(inactivePromo);
|
||||
}
|
||||
inactivePromosToSave = removeCurrentlyActivePromoCodesFromInactivePromos(
|
||||
activePromosToSave,
|
||||
context.getters.payment.inactivePromos ?? []
|
||||
);
|
||||
}
|
||||
context.commit(storeMutations.UPDATE_PROMOS, activePromosToSave);
|
||||
|
|
@ -2360,10 +2348,15 @@ export const actions = {
|
|||
const order = context.getters.order;
|
||||
|
||||
activePromosToUse = activePromosToUse ?? order.lineItems.promos;
|
||||
inactivePromosToUse = inactivePromosToUse ?? order.payment.inactivePromos;
|
||||
lineItemsToUse = lineItemsToUse ? deepClone(lineItemsToUse) : deepClone(order.lineItems);
|
||||
lineItemsToUse.promos = activePromosToUse;
|
||||
|
||||
inactivePromosToUse = inactivePromosToUse ?? order.payment.inactivePromos;
|
||||
inactivePromosToUse = removeCurrentlyActivePromoCodesFromInactivePromos(
|
||||
lineItemsToUse.promos,
|
||||
inactivePromosToUse
|
||||
);
|
||||
|
||||
let requestObject = {
|
||||
inactivePromos: inactivePromosToUse,
|
||||
order: {
|
||||
|
|
@ -2797,15 +2790,15 @@ function convertGlassPieceToBackEndCompatibleFormat(glassPieces) {
|
|||
function renameGlassToReplaceAttributes(glassToReplace) {
|
||||
let newGlassToReplace = [];
|
||||
if (glassToReplace) {
|
||||
glassToReplace.forEach((item) => {
|
||||
newGlassToReplace.push({ location: item.glassLocation, name: item.glassName });
|
||||
newGlassToReplace = glassToReplace.map((item) => {
|
||||
return { location: item.glassLocation, name: item.glassName };
|
||||
});
|
||||
}
|
||||
return newGlassToReplace;
|
||||
}
|
||||
|
||||
function addGuidToLineItemsIfNotAlreadyThere(lineItems) {
|
||||
lineItems.forEach((lineItem) => {
|
||||
lineItems?.forEach((lineItem) => {
|
||||
if (!lineItem.id) {
|
||||
lineItem.id = crypto.randomUUID();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue