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

This commit is contained in:
Scott Kiener 2023-11-15 11:12:21 -05:00
commit 8d9fbdf985
10 changed files with 117 additions and 54 deletions

View file

@ -1,20 +1,21 @@
<template> <template>
<div class="cart mb-5"> <div class="cart">
<div class="px-0"> <div class="px-0">
<div <div
class="row vin-toggle flex align-items-center" class="row vin-toggle flex align-items-center py-4"
:class="[isExpanded ? 'expanded' : '']" :class="[isExpanded ? 'expanded' : '']"
@click="toggleIsExpanded()"> @click="toggleIsExpanded()">
<div class="col d-flex justify-content-between"> <div class="col d-flex justify-content-between">
<span class="label">{{ amountDueText }}</span <span class="label">{{ amountDueText }}</span
><span class="label amount-due">{{ currencyFormatter.format(amountDue) }}</span> ><span class="label amount-due">{{ getFormattedAmount("", amountDue) }}</span>
</div> </div>
</div> </div>
<div class="price-table"> <div class="price-table">
<div class="service-type"> <div class="service-type">
<textBlock :cmsWidgetName="servicePackageTitleWidget" /><span>{{ <textBlock :cmsWidgetName="servicePackageTitleWidget" />
currencyFormatter.format(packagePrice) <span>
}}</span> {{ getFormattedAmount("", packagePrice) }}
</span>
</div> </div>
<!-- Packaged Cart Items --> <!-- Packaged Cart Items -->
@ -47,34 +48,33 @@
href="#!" href="#!"
@click-event="removeItem(cartItem.cartItemType, cartItem.category)" /> @click-event="removeItem(cartItem.cartItemType, cartItem.category)" />
<textLink <textLink
v-else-if="cartItem == recycleFeeCartItem" v-else-if="cartItem == recycleFeeCartItem && recyclingModalCmsWidgetName"
linkType="text" linkType="text"
:text="recycleFeeCartItem.name" :text="recycleFeeCartItem.name"
href="#!" href="#!"
@click-event="openModal(recyclingModalCmsWidgetName)" /> @click-event="openModal(recyclingModalCmsWidgetName)" />
<span <span v-else-if="cartItem == recycleFeeCartItem">
>{{ {{ recycleFeeCartItem.name }}
`${
cartItem.category == "promos"
? "(" + currencyFormatter.format(cartItem.subTotal * -1) + ")"
: currencyFormatter.format(cartItem.subTotal)
}`
}}
</span> </span>
<span>{{ getFormattedAmount(cartItem.category, cartItem.subTotal) }}</span>
</div> </div>
<!-- Sub total, sales tax, total columns --> <!-- Sub total, sales tax, total columns -->
<div class="sub-total"> <div class="sub-total">
<span>{{ subtotalText }}</span <span>{{ subtotalText }}</span
><span>{{ currencyFormatter.format(subTotal) }}</span> ><span>{{ getFormattedAmount("", subTotal) }}</span>
</div> </div>
<div class="sales-tax"> <div class="sales-tax">
<span>{{ salesTaxText }}</span <span>{{ salesTaxText }}</span
><span>{{ currencyFormatter.format(salesTax) }}</span> ><span>{{ getFormattedAmount("", salesTax) }}</span>
</div>
<div v-if="showAsPaid" class="amount-paid">
<span>{{ amountPaidText }}</span
><span>{{ getFormattedAmount("", amountPaid) }}</span>
</div> </div>
<div class="amount-due"> <div class="amount-due">
<span>{{ amountDueText }}</span <span>{{ amountDueText }}</span
><span>{{ currencyFormatter.format(amountDue) }}</span> ><span>{{ getFormattedAmount("", amountDue) }}</span>
</div> </div>
</div> </div>
</div> </div>
@ -112,6 +112,7 @@ export default {
availableVaps: Object, availableVaps: Object,
allowItemRemoval: Boolean, allowItemRemoval: Boolean,
recyclingModalCmsWidgetName: String, recyclingModalCmsWidgetName: String,
showAsPaid: Boolean,
}, },
data() { data() {
return { return {
@ -172,6 +173,11 @@ export default {
return vapsTypeName.Text; return vapsTypeName.Text;
}, },
getFormattedAmount(category, amount) {
return category == "promos"
? "(" + this.currencyFormatter.format(amount * -1) + ")"
: this.currencyFormatter.format(amount);
},
removeItem(cartItemType, category) { removeItem(cartItemType, category) {
this.lineItems[category] = this.lineItems[category].filter( this.lineItems[category] = this.lineItems[category].filter(
(lineItemsToKeep) => lineItemsToKeep.cartItemType != cartItemType (lineItemsToKeep) => lineItemsToKeep.cartItemType != cartItemType
@ -319,7 +325,6 @@ export default {
} }
} }
}); });
return nonpackageCartItems; return nonpackageCartItems;
}, },
frontWiperCartItemName() { frontWiperCartItemName() {
@ -670,6 +675,9 @@ export default {
amountDueText() { amountDueText() {
return this.getCmsContent("AmountDueTextWidget", "Text"); return this.getCmsContent("AmountDueTextWidget", "Text");
}, },
amountPaidText() {
return this.getCmsContent("AmountPaidTextWidget", "Text");
},
subtotalText() { subtotalText() {
return this.getCmsContent("SubtotalTextWidget", "Text"); return this.getCmsContent("SubtotalTextWidget", "Text");
}, },
@ -691,6 +699,15 @@ export default {
return salesTax; return salesTax;
}, },
amountDue() { amountDue() {
if (this.showAsPaid) {
return 0;
}
return this.subTotal + this.salesTax;
},
amountPaid() {
if (!this.showAsPaid) {
return 0;
}
return this.subTotal + this.salesTax; return this.subTotal + this.salesTax;
}, },
}, },
@ -712,6 +729,8 @@ export default {
<style lang="scss"> <style lang="scss">
.cart { .cart {
margin-bottom: 1rem;
h5 { h5 {
border-bottom: 1px solid $gray-500; border-bottom: 1px solid $gray-500;
color: $black; color: $black;
@ -735,6 +754,7 @@ export default {
max-height: 0; max-height: 0;
transition: all 350ms ease-in; transition: all 350ms ease-in;
overflow: hidden; overflow: hidden;
div { div {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -798,7 +818,8 @@ export default {
} }
.sub-total, .sub-total,
.sales-tax, .sales-tax,
.amount-due { .amount-due,
.amount-paid {
font-weight: 500; font-weight: 500;
} }
.sub-total { .sub-total {
@ -825,7 +846,7 @@ export default {
display: inline-flex; display: inline-flex;
position: relative; position: relative;
right: 0.75rem; right: 0.75rem;
margin: 1rem 0 1rem 1rem; margin: 0.5rem 0 0.5rem 1rem;
cursor: pointer; cursor: pointer;
} }
&.expanded:after { &.expanded:after {
@ -835,6 +856,7 @@ export default {
max-height: 650px; max-height: 650px;
transition: all 350ms ease-in; transition: all 350ms ease-in;
overflow: hidden; overflow: hidden;
padding-top: 1rem;
} }
} }
} }

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 Math.floor(difference / (1000 * 3600 * 24)); return Math.round(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

@ -56,6 +56,9 @@ beforeEach(() => {
damage: { damage: {
isRepair: false, isRepair: false,
}, },
payment: {
isPia: true,
},
referralNumber: "1234567", referralNumber: "1234567",
vehicle: { vehicle: {
year: "2004", year: "2004",
@ -113,6 +116,7 @@ beforeEach(() => {
emailAddress: "test@test.com", emailAddress: "test@test.com",
}, },
}, },
damage: {},
payment: { payment: {
isInsurance: true, isInsurance: true,
}, },

View file

@ -37,6 +37,15 @@
<div class="appoinmenttext" v-html="AppointmentWordingText"></div> <div class="appoinmenttext" v-html="AppointmentWordingText"></div>
</div> </div>
<hr />
<cart
:damage="damageInfo"
:availableVaps="vaps"
:allowItemRemoval="false"
v-model="lineItems"
:showAsPaid="isPia"
servicePackageOptionsCmsName="ServicePackageTitle" />
<hr class="mb-5" />
<div class="emailtext" v-html="ConfirmationEmailText"></div> <div class="emailtext" v-html="ConfirmationEmailText"></div>
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
@ -57,19 +66,21 @@ import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner"; import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
import navbar from "@/fmg-components/nav-bar/nav-bar"; import navbar from "@/fmg-components/nav-bar/nav-bar";
import addToCalendar from "@/layouts/confirmation/add-to-calendar/add-to-calendar"; import addToCalendar from "@/layouts/confirmation/add-to-calendar/add-to-calendar";
import cart from "@/fmg-components/cart/cart";
//Supporting files //Supporting files
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
import store from "@/store";
import { storeActions } from "@/constants/store-actions"; import { storeActions } from "@/constants/store-actions";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper"; import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { AppointmentTypeStrings } from "@/constants/schedule-constants"; import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { applicationConfig } from "@/constants/application-config.js"; import { applicationConfig } from "@/constants/application-config.js";
import { convertDateStringToDate } from "@/layouts/schedule/helpers/schedule-helper"; import { convertDateStringToDate } from "@/layouts/schedule/helpers/schedule-helper";
import { deepClone } from "@/helpers/object-helper";
import { Form } from "vee-validate"; import { Form } from "vee-validate";
import store from "@/store";
import { get12HourTimeFormat, get12HourTimeMobileFormat } from "@/helpers/date-helper"; import { get12HourTimeFormat, get12HourTimeMobileFormat } from "@/helpers/date-helper";
export default { export default {
name: "confirmation", name: "confirmation",
async beforeRouteEnter(to, from, next) { async beforeRouteEnter(to, from, next) {
@ -87,11 +98,21 @@ export default {
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
const lineItemsFromSubmittedOrder = deepClone(store.getters.submittedOrder.lineItems);
// Call the "next" function to complete the transition to this page. // Call the "next" function to complete the transition to this page.
next((vm) => { next((vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
vm.lineItems = lineItemsFromSubmittedOrder;
vm.vaps = lineItemsFromSubmittedOrder.vaps;
}); });
}, },
data() {
return {
lineItems: [],
vaps: [],
};
},
computed: { computed: {
ScheduleConfirmationText() { ScheduleConfirmationText() {
return this.getCmsContent("ScheduleConfirmationWidget", "BodyText"); return this.getCmsContent("ScheduleConfirmationWidget", "BodyText");
@ -209,6 +230,12 @@ export default {
vehicleBannerImageUrl() { vehicleBannerImageUrl() {
return store.getters.submittedOrder?.vehicle.imageUrl; return store.getters.submittedOrder?.vehicle.imageUrl;
}, },
damageInfo() {
return store.getters.damage;
},
isPia() {
return store.getters.submittedOrder?.payment.isPia;
},
}, },
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
@ -258,12 +285,14 @@ export default {
navbar, navbar,
vehicleBanner, vehicleBanner,
addToCalendar, addToCalendar,
cart,
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss">
.main { .main {
margin-bottom: 1.5rem;
padding: 1rem 1.5rem 1.5rem; padding: 1rem 1.5rem 1.5rem;
box-shadow: 0 3px 10px rgb(0 0 0 / 0.2); box-shadow: 0 3px 10px rgb(0 0 0 / 0.2);
border-radius: 5px; border-radius: 5px;
@ -336,7 +365,7 @@ export default {
} }
.emailtext { .emailtext {
padding: 1.5rem 0 0; padding: 0.5rem 0 0;
p { p {
font-size: 0.875rem; font-size: 0.875rem;

View file

@ -287,13 +287,6 @@ export default {
return answers[answerIndex]; return answers[answerIndex];
}; };
if (!this.rainDefenseInCart) {
// NO RAIN DEFENSE IN CART; SHOW RAIN DEFENSE BUTTON
const modalData = getAnswer("RainDefenseModal", this.answersCmsData);
modalData.SubText = "+$" + this.rainDefenseModal?.listPrice;
buttons.push(modalData);
}
const modalData = getAnswer("WipersModal", this.answersCmsData); const modalData = getAnswer("WipersModal", this.answersCmsData);
if (this.wipersOffered === wipersOfferedStrings.BOTH) { if (this.wipersOffered === wipersOfferedStrings.BOTH) {
// NO REAR WIPERS or FRONT WIPERS IN CART; SHOW COMBO BUTTON // NO REAR WIPERS or FRONT WIPERS IN CART; SHOW COMBO BUTTON
@ -318,6 +311,13 @@ export default {
buttons.push(modalData); buttons.push(modalData);
} }
if (!this.rainDefenseInCart) {
// NO RAIN DEFENSE IN CART; SHOW RAIN DEFENSE BUTTON
const modalData = getAnswer("RainDefenseModal", this.answersCmsData);
modalData.SubText = "+$" + this.rainDefenseModal?.listPrice;
buttons.push(modalData);
}
return buttons; return buttons;
}, },
wipersOfferedStrings() { wipersOfferedStrings() {

View file

@ -19,7 +19,7 @@
<span>{{ noPiaDisclaimer }}</span> <span>{{ noPiaDisclaimer }}</span>
</p> </p>
<hr /> <hr class="my-0" />
<cart <cart
:damage="damageInfo" :damage="damageInfo"
@ -29,14 +29,15 @@
servicePackageOptionsCmsName="ServicePackageTitle" servicePackageOptionsCmsName="ServicePackageTitle"
recyclingModalCmsWidgetName="RecycleModal" /> recyclingModalCmsWidgetName="RecycleModal" />
<hr class="my-5" />
<promoModalQuestion <promoModalQuestion
class="pb-3" class="pb-2"
v-model="lineItems" v-model="lineItems"
:availableVaps="availableVaps" :availableVaps="availableVaps"
linkWidgetName="PromoLinkWidget" linkWidgetName="PromoLinkWidget"
modalWidgetName="PromoModalWidget" /> modalWidgetName="PromoModalWidget" />
<hr class="mb-5" />
<div> <div>
<alert <alert
ref="piaErrorAlert" ref="piaErrorAlert"
@ -413,7 +414,6 @@ export default {
return; return;
} }
} }
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
this.$router.navigateWithoutSaving( this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_PAY_NOW, this.navigationScenarios.CLICKED_PAY_NOW,

View file

@ -217,13 +217,11 @@ export default {
} else { } else {
if (promoCodeData.errorCode == promoErrorCodes.PROMO_STACKING_NOT_ALLOWED) { if (promoCodeData.errorCode == promoErrorCodes.PROMO_STACKING_NOT_ALLOWED) {
this.displayInvalidOnOrderPromoAlert = true; this.displayInvalidOnOrderPromoAlert = true;
this.focusOnPromoInput();
this.resetModalButtonStyle();
} else { } else {
this.displayInvalidPromoAlert = true; this.displayInvalidPromoAlert = true;
this.focusOnPromoInput();
this.resetModalButtonStyle();
} }
this.focusOnPromoInput();
this.resetModalButtonStyle();
} }
} }
}, },

View file

@ -8,6 +8,7 @@
cornerStyle="rounded" cornerStyle="rounded"
:displayQuestionText="false" :displayQuestionText="false"
isRequired isRequired
@input="validateAlphanumeric"
validationRules="promo-required" /> validationRules="promo-required" />
</template> </template>
@ -22,6 +23,8 @@ import { errorMessages } from "@/constants/error-messages";
// Define Validation Rules // Define Validation Rules
defineRule("promo-required", required(errorMessages.PROMO_REQUIRED)); defineRule("promo-required", required(errorMessages.PROMO_REQUIRED));
const ALPHANUMERIC_REGEX = /[^a-zA-Z0-9]/g;
export default { export default {
name: "promo-question", name: "promo-question",
props: { props: {
@ -38,6 +41,11 @@ export default {
}, },
}, },
}, },
methods: {
validateAlphanumeric() {
this.value = this.value.replace(ALPHANUMERIC_REGEX, "");
},
},
components: { components: {
textboxQuestion, textboxQuestion,
}, },

View file

@ -26,13 +26,13 @@
<cart <cart
:damage="damageInfo" :damage="damageInfo"
:availableLineItems="availableLineItems" :availableVaps="availableVaps"
:allowItemRemoval="false" :allowItemRemoval="false"
v-model="lineItems" v-model="lineItems"
servicePackageOptionsCmsName="ServicePackageTitle" servicePackageOptionsCmsName="ServicePackageTitle"
recyclingModalCmsWidgetName="RecycleModal" /> recyclingModalCmsWidgetName="RecycleModal" />
<hr /> <hr class="mb-5" />
<paymentSwitch <paymentSwitch
cmsWidgetName="PaymentMethodWidget" cmsWidgetName="PaymentMethodWidget"
@ -267,12 +267,6 @@ export default {
"payment" "payment"
); );
const supportingItemsPromise = baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.GET_SUPPORTING_ITEMS,
null,
"payment"
);
// TODO: Data fetching Promise declarations // TODO: Data fetching Promise declarations
const promiseResultMap = [ const promiseResultMap = [
@ -292,10 +286,6 @@ export default {
resultKey: "rainDefense", resultKey: "rainDefense",
promise: rainDefensePromise, promise: rainDefensePromise,
}, },
{
resultKey: "supportingItems",
promise: supportingItemsPromise,
},
]; ];
const resultMap = await settleAllPromises(promiseResultMap); const resultMap = await settleAllPromises(promiseResultMap);
@ -363,12 +353,14 @@ export default {
taxedVaps, taxedVaps,
lineItems lineItems
); );
lineItems.vaps = lineItems.vaps ?? [];
lineItems.vaps.push(...vapsToAddToCart); lineItems.vaps.push(...vapsToAddToCart);
// Call the "next" function to complete the transition to this page. // Call the "next" function to complete the transition to this page.
next(async (vm) => { next(async (vm) => {
vm.setCmsContent(resultMap.cmsContent); vm.setCmsContent(resultMap.cmsContent);
vm.fetchSignatureInfo(resultMap.signature); vm.fetchSignatureInfo(resultMap.signature);
vm.setIFrameListener();
vm.availableVaps = taxedVaps; vm.availableVaps = taxedVaps;
vm.lineItems = lineItems; vm.lineItems = lineItems;
@ -586,6 +578,16 @@ export default {
this.submitHopForm(); this.submitHopForm();
}, },
handleIFrameContentWindwMessage(event) {
if (event.data.indexOf("afterpayClosed") > -1) {
this.backButtonAction();
}
},
setIFrameListener() {
window.addEventListener("message", (event) =>
this.handleIFrameContentWindwMessage(event)
);
},
}, },
components: { components: {
funnelHeader, funnelHeader,

View file

@ -95,7 +95,7 @@ export default {
} }
&.allow-ui-interaction::before { &.allow-ui-interaction::before {
//no-block to enable clicking on certain buttons with loaders while the loader is actives //no-block to enable clicking on certain buttons with loaders while the loader is actives
z-index: -1; pointer-events: none;
} }
} }
</style> </style>