Merge remote-tracking branch 'origin/develop' into feature/skiener/CSR-1452

This commit is contained in:
Scott Kiener 2023-11-14 09:04:24 -05:00
commit 4556e28457
4 changed files with 179 additions and 48 deletions

View file

@ -52,7 +52,15 @@
:text="recycleFeeCartItem.name" :text="recycleFeeCartItem.name"
href="#!" href="#!"
@click-event="openModal(recyclingModalCmsWidgetName)" /> @click-event="openModal(recyclingModalCmsWidgetName)" />
<span>{{ currencyFormatter.format(cartItem.subTotal) }}</span> <span
>{{
`${
cartItem.category == "promos"
? "(" + currencyFormatter.format(cartItem.subTotal * -1) + ")"
: currencyFormatter.format(cartItem.subTotal)
}`
}}
</span>
</div> </div>
<!-- Sub total, sales tax, total columns --> <!-- Sub total, sales tax, total columns -->
@ -88,6 +96,7 @@ import baseMixin from "@/mixins/base-mixin.js";
// Helpers // Helpers
import { deepClone } from "@/helpers/object-helper"; import { deepClone } from "@/helpers/object-helper";
import { getHighestFullySatisfiedTier, getPackageContents } from "@/helpers/service-package-helper"; import { getHighestFullySatisfiedTier, getPackageContents } from "@/helpers/service-package-helper";
import { getPromoCodeWithoutBundleIdentifier } from "@/helpers/promotions-helper";
// Constants // Constants
import { partTypeStrings } from "@/constants/part-type-strings"; import { partTypeStrings } from "@/constants/part-type-strings";
@ -216,33 +225,16 @@ export default {
cartItems.push(this.mobileFeeCartItem); cartItems.push(this.mobileFeeCartItem);
} }
// Create a cart item for each promo
this.promos.forEach((promoLineItem) => {
let cartItem = null;
cartItem = {
name: promoLineItem?.promoCode, // get from CMS?
category: cartItemCategories.PROMOS,
cartItemType: promoLineItem?.partType,
isDisplayed: true,
subTotal:
(promoLineItem?.kitPrice ?? 0) +
(promoLineItem?.laborAmount ?? 0) +
(promoLineItem?.sellingPrice ?? 0),
salesTax: promoLineItem?.salesTax,
lineItems: [],
};
promoLineItem.cartItemType = cartItem.cartItemType;
cartItem.lineItems.push(promoLineItem);
cartItems.push(cartItem);
});
if (this.premiumAppointmentDiscountCartItem) { if (this.premiumAppointmentDiscountCartItem) {
cartItems.push(this.premiumAppointmentDiscountCartItem); cartItems.push(this.premiumAppointmentDiscountCartItem);
} }
if (this.promoCartItems) {
this.promoCartItems.forEach((promoCartItem) => {
cartItems.push(promoCartItem);
});
}
return cartItems; return cartItems;
}, },
}, },
@ -346,6 +338,7 @@ export default {
category: cartItemCategories.VAPS, category: cartItemCategories.VAPS,
cartItemType: cartItemTypes.FRONT_WIPERS, cartItemType: cartItemTypes.FRONT_WIPERS,
isDisplayed: true, isDisplayed: true,
isRemovable: true,
subTotal: 0, subTotal: 0,
salesTax: 0, salesTax: 0,
lineItems: [], lineItems: [],
@ -382,6 +375,7 @@ export default {
category: cartItemCategories.VAPS, category: cartItemCategories.VAPS,
cartItemType: cartItemTypes.REAR_WIPERS, cartItemType: cartItemTypes.REAR_WIPERS,
isDisplayed: true, isDisplayed: true,
isRemovable: true,
subTotal: 0, subTotal: 0,
salesTax: 0, salesTax: 0,
lineItems: [], lineItems: [],
@ -547,10 +541,7 @@ export default {
otherSupportingItemsCartItem() { otherSupportingItemsCartItem() {
let cartItem = null; let cartItem = null;
let otherSupportingItemsLineItems = baseMixin.methods.filterOutFees( const otherSupportingItemsLineItems = this.supportingItems.filter(
this.supportingItems
);
otherSupportingItemsLineItems = otherSupportingItemsLineItems.filter(
(lineItem) => lineItem.partType != partTypeStrings.EARLY_BIRD (lineItem) => lineItem.partType != partTypeStrings.EARLY_BIRD
); );
@ -597,6 +588,7 @@ export default {
category: cartItemCategories.SUPPORTING_ITEMS, category: cartItemCategories.SUPPORTING_ITEMS,
cartItemType: cartItemTypes.EARLY_BIRD, cartItemType: cartItemTypes.EARLY_BIRD,
isDisplayed: true, isDisplayed: true,
isRemovable: true,
subTotal: 0, subTotal: 0,
salesTax: 0, salesTax: 0,
lineItems: [], lineItems: [],
@ -615,6 +607,57 @@ export default {
return cartItem; return cartItem;
}, },
promoCartItems() {
const promoCartItems = [];
// clone the promos array
const promosClone = deepClone(this.promo);
// 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: [],
};
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() { removeLinkText() {
return this.getCmsContent("RemoveCartItemTextWidget", "Text"); return this.getCmsContent("RemoveCartItemTextWidget", "Text");
}, },

View file

@ -5,7 +5,7 @@ export function getDateDifferenceInDays(startDate, endDate) {
// Use the built-in method to get the difference in milliseconds // Use the built-in method to get the difference in milliseconds
var difference = date1 - date2; var difference = date1 - date2;
// Convert milliseconds to days and return the result // Convert milliseconds to days and return the result
return difference / (1000 * 3600 * 24); return Math.floor(difference / (1000 * 3600 * 24));
} }
export function get12HourTimeFormat(time) { export function get12HourTimeFormat(time) {
// Check correct time format and split into components // Check correct time format and split into components

View file

@ -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]]);
});
});

View file

@ -98,16 +98,16 @@ export default {
return this.getCmsContent("AlertInvalidPromoOnOrderWidget", "HeadlineText"); return this.getCmsContent("AlertInvalidPromoOnOrderWidget", "HeadlineText");
}, },
InvalidPromoOnOrderText() { InvalidPromoOnOrderText() {
return this.PromoText?.replaceAll("{custom:NEWPROMOCODE}", this.promoCode).replaceAll( return this.PromoOnOrderText?.replaceAll(
"{custom:OLDPROMOCODE}", "{custom:NEWPROMOCODE}",
this.promoCode this.promoCode.toUpperCase()
); ).replaceAll("{custom:OLDPROMOCODE}", this.getPromoCode().toUpperCase());
}, },
PromoText() { PromoText() {
return this.getCmsContent("AlertInvalidPromoWidget", "HeadlineText"); return this.getCmsContent("AlertInvalidPromoWidget", "HeadlineText");
}, },
InvalidPromoText() { InvalidPromoText() {
return this.PromoText?.replaceAll("{custom:PROMOCODE}", this.promoCode); return this.PromoText?.replaceAll("{custom:PROMOCODE}", this.promoCode.toUpperCase());
}, },
removeLinkText() { removeLinkText() {
return this.getCmsContent("RemoveCartItemTextWidget", "Text"); return this.getCmsContent("RemoveCartItemTextWidget", "Text");
@ -115,6 +115,7 @@ export default {
}, },
methods: { methods: {
resetAlerts() { resetAlerts() {
this.displayInvalidOnOrderPromoAlert = false;
this.displayInvalidPromoAlert = false; this.displayInvalidPromoAlert = false;
}, },
resetsOnPromoInput() { resetsOnPromoInput() {
@ -123,6 +124,9 @@ export default {
getPromoList() { getPromoList() {
return this.lineItems.promos; return this.lineItems.promos;
}, },
getPromoCode() {
return this.lineItems.promos?.[0].promoCode;
},
openModal() { openModal() {
this.modal.openModal(); this.modal.openModal();
}, },
@ -130,7 +134,9 @@ export default {
this.modal.closeModal(); this.modal.closeModal();
}, },
onModalClosed() { onModalClosed() {
this.resetAlerts();
this.$emit("update:modelValue", this.lineItems); this.$emit("update:modelValue", this.lineItems);
this.promoCode = "";
}, },
focusOnPromoInput() { focusOnPromoInput() {
const input = document.getElementById(this.promoTextInputId); const input = document.getElementById(this.promoTextInputId);
@ -139,16 +145,8 @@ export default {
resetModalButtonStyle() { resetModalButtonStyle() {
this.modal.resetButtonStyle(); this.modal.resetButtonStyle();
}, },
getPromoAddedMessage() {
return this.AddPromoSuccessMessageFromCms?.replaceAll(
"{custom:PROMOCODE}",
this.promoCode
);
},
async getPromoCodeData(promoCode, lineItems, availableVaps, pageNameToLog = null) { async getPromoCodeData(promoCode, lineItems, availableVaps, pageNameToLog = null) {
const pageName = pageNameToLog ?? this.$options?.name; const pageName = pageNameToLog ?? this.$options?.name;
//const addableVaps = getAddableVapsFromAvailableLineItems(availableLineItems);
//const lineItemsToUse = lineItems.Length > 0 ? lineItems : null;
const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging( const promoValidationResponse = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA, storeActions.VALIDATE_ORDER_PROMO_AND_SAVE_SERVER_DATA,
{ {
@ -216,16 +214,16 @@ export default {
this.lineItems?.promos.push(...promoCodeData.promoCode); this.lineItems?.promos.push(...promoCodeData.promoCode);
this.lineItems.vaps?.push(...getVaps); this.lineItems.vaps?.push(...getVaps);
this.closeModal(); this.closeModal();
this.promoCode = "";
} else { } else {
if (promoCodeData.errorCode == promoErrorCodes.PROMO_STACKING_NOT_ALLOWED) { if (promoCodeData.errorCode == promoErrorCodes.PROMO_STACKING_NOT_ALLOWED) {
this.displayInvalidPromoOnOrderAlert = true; this.displayInvalidOnOrderPromoAlert = true;
this.focusOnPromoInput();
this.resetModalButtonStyle();
} else {
this.displayInvalidPromoAlert = true;
this.focusOnPromoInput(); this.focusOnPromoInput();
this.resetModalButtonStyle(); this.resetModalButtonStyle();
} }
this.displayInvalidPromoAlert = true;
this.focusOnPromoInput();
this.resetModalButtonStyle();
} }
} }
}, },
@ -253,7 +251,7 @@ export default {
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.applied-promo { .applied-promo {
padding-right: 5rem; padding-right: 4rem;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
line-height: 24px; line-height: 24px;