Merge pull request #3001 from Safelite/feature/CASH-2025
Feature/cash 2025
This commit is contained in:
commit
03cdb0058e
6 changed files with 229 additions and 12 deletions
|
|
@ -111,6 +111,7 @@ const storeActions = {
|
|||
SAVE_PAYPAL_TOKEN: "savePaypalToken",
|
||||
SAVE_NEXTGEN_SETTLED_AMOUNT: "saveNextGenSettledAmount",
|
||||
SAVE_IS_RECAL_ACK_OPT_IN: "saveIsRecalAckOptIn",
|
||||
SAVE_IS_OEM_GLASS_SELECTED: "saveIsOemGlassSelected",
|
||||
SAVE_IS_MSR_FEE_APPLICABLE: "saveIsMSRFeeApplicable",
|
||||
|
||||
CREATE_SUBMITTED_STATE: "createSubmittedState",
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ const storeMutations = {
|
|||
LOCK_TOKEN: "updateLockToken",
|
||||
UPDATE_SETTLED_TENDER_AMOUNT: "updateSettledTenderAmount",
|
||||
UPDATE_IS_RECAL_ACK_OPT_IN: "updateIsRecalAckOptIn",
|
||||
UPDATE_IS_OEM_GLASS_SELECTED: "updateIsOemGlassSelected",
|
||||
UPDATE_IS_MSR_FEE_APPLICABLE: "updateIsMSRFeeApplicable",
|
||||
UPDATE_CASH_PRICE_SUBTOTAL: "updateCashPriceSubTotal",
|
||||
|
||||
|
|
|
|||
139
src/layouts/quote/oem-glass-question/oem-glass-question.vue
Normal file
139
src/layouts/quote/oem-glass-question/oem-glass-question.vue
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
<template>
|
||||
<div
|
||||
class="oem-glass-question-container py-5 mt-3 mb-6"
|
||||
:class="[isExpanded ? 'expanded' : '']">
|
||||
<div class="oem-glass-question-header" @click="toggleIsExpanded">
|
||||
{{ headerText }}
|
||||
</div>
|
||||
<div class="oem-glass-question-body">
|
||||
<div class="oem-glass-question-copy" v-html="bodyText"></div>
|
||||
<div class="oem-glass-question-option">
|
||||
<checkboxQuestion
|
||||
class="mt-3"
|
||||
cmsWidgetName="OemGlassInputQuestionWidget"
|
||||
v-model="installOemGlass" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question";
|
||||
|
||||
export default {
|
||||
name: "oem-part-question",
|
||||
props: {
|
||||
cmsWidgetName: String,
|
||||
modelValue: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isExpanded: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
headerText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "HeaderText");
|
||||
},
|
||||
bodyText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "BodyText");
|
||||
},
|
||||
footerText() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "FooterText");
|
||||
},
|
||||
installOemGlass: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set(newValue) {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleIsExpanded() {
|
||||
this.setIsExpanded(!this.isExpanded);
|
||||
},
|
||||
setIsExpanded(newVal) {
|
||||
this.isExpanded = newVal;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
checkboxQuestion,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.oem-glass-question-container {
|
||||
border-top: 1px solid gray;
|
||||
|
||||
.oem-glass-question-header {
|
||||
font-family: UrbanistSemibold, Arial, Helvetica, sans-serif;
|
||||
color: $blue;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
span {
|
||||
flex-grow: 1;
|
||||
color: $black;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
transition: all 0.5s ease;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 9'%3E%3Cpath d='M7.99282 0.117702C7.75716 0.116049 7.53044 0.207797 7.3623 0.37286L0.255553 7.46878C0.0862976 7.63796 -0.00878906 7.86742 -0.00878906 8.10667C-0.00878906 8.34593 0.0862976 8.57539 0.255553 8.74457C0.424808 8.91374 0.654368 9.00879 0.893731 9.00879C1.13309 9.00879 1.36265 8.91374 1.53191 8.74457L7.99282 2.27378L14.4614 8.74457C14.6307 8.91205 14.8595 9.00547 15.0977 9.00428C15.3359 9.00308 15.5638 8.90737 15.7314 8.73819C15.8989 8.56901 15.9924 8.34022 15.9912 8.10216C15.99 7.8641 15.8942 7.63627 15.725 7.46878L8.6259 0.377963C8.45765 0.21088 8.22999 0.117289 7.99282 0.117702Z' fill='%230C7E47'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
color: $blue;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.oem-glass-question-body {
|
||||
max-height: 0;
|
||||
transition: all 350ms ease-in;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
|
||||
.oem-glass-question-option {
|
||||
margin-top: 0.5em;
|
||||
font-family: UrbanistSemibold, Arial, Helvetica, sans-serif;
|
||||
|
||||
.oem-glass-question-strikethrough-price {
|
||||
font-size: smaller;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.oem-glass-question-free-price {
|
||||
display: inline-block;
|
||||
font-weight: bolder;
|
||||
border-radius: 1em;
|
||||
background-color: $green-300;
|
||||
padding: 0 0.5em;
|
||||
margin-inline-start: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
.oem-glass-question-header {
|
||||
&::after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.oem-glass-question-body {
|
||||
visibility: visible;
|
||||
max-height: none;
|
||||
padding-top: 0.5em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -118,6 +118,9 @@ jest.mock("@/mixins/experiment-mixin.js", () => ({
|
|||
if (settingName === mockExperimentSettings.DISPLAY_AFTERPAY_BREAKOUT_DISPLAY) {
|
||||
return false;
|
||||
}
|
||||
if (settingName === mockExperimentSettings.OFFER_OEM) {
|
||||
return false;
|
||||
}
|
||||
return "test";
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -86,6 +86,11 @@
|
|||
isInsuranceSelected ? isInsuranceContinueButtonText : ''
|
||||
" />
|
||||
|
||||
<oemGlassQuestion
|
||||
cmsWidgetName="OemGlassQuestionWidget"
|
||||
v-if="offerOem"
|
||||
v-model="isOemGlassSelected" />
|
||||
|
||||
<saveProgressModalQuestion
|
||||
modalWidgetName="SaveProgressModalWidget"
|
||||
modalName="SaveProgressModal"
|
||||
|
|
@ -129,6 +134,7 @@ import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-
|
|||
import recalDisclaimer from "@/layouts/quote/recal-disclaimer/recal-disclaimer.vue";
|
||||
import saveProgressModalQuestion from "@/fmg-components/save-progress-modal-question/save-progress-modal-question";
|
||||
import saveProgressPopupQuestion from "@/fmg-components/save-progress-popup-question/save-progress-popup-question";
|
||||
import oemGlassQuestion from "./oem-glass-question/oem-glass-question.vue";
|
||||
|
||||
// Supporting files
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
|
|
@ -218,19 +224,15 @@ export default {
|
|||
null,
|
||||
"quote"
|
||||
);
|
||||
|
||||
// call API oem-after-market-parts method
|
||||
const offerOem = experimentMixin.methods.hasSettingEqualTo(
|
||||
const experimentAllowsOfferOem = experimentMixin.methods.hasSettingEqualTo(
|
||||
experimentSettings.OFFER_OEM,
|
||||
"true"
|
||||
);
|
||||
if (offerOem) {
|
||||
const oemAfterMarketParts = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||
storeActions.GET_OEM_AFTERMARKET_PARTS,
|
||||
null,
|
||||
"quote"
|
||||
);
|
||||
}
|
||||
const oemGlassCheckPromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||
storeActions.GET_OEM_AFTERMARKET_PARTS,
|
||||
null,
|
||||
"quote"
|
||||
);
|
||||
|
||||
const shouldExposeSkipQuote = store.getters.isRecalibrationOnOrder;
|
||||
const skipQuoteExperiment = store.getters.applicationUser.experiments.find(
|
||||
|
|
@ -304,6 +306,10 @@ export default {
|
|||
resultKey: "supportingItems",
|
||||
promise: supportingItemsPromise,
|
||||
},
|
||||
{
|
||||
resultKey: "oemGlassCheck",
|
||||
promise: oemGlassCheckPromise,
|
||||
},
|
||||
];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
|
@ -325,6 +331,18 @@ export default {
|
|||
lineItems.vaps = lineItems.vaps ?? [];
|
||||
const nullSafeGlassParts = lineItems.glassParts ?? [];
|
||||
|
||||
const oemGlassCheck = resultMap.oemGlassCheck;
|
||||
const offerOem = experimentAllowsOfferOem ? oemGlassCheck?.offerOem : false;
|
||||
const oemGlassPieceParts = oemGlassCheck?.glassPieceParts;
|
||||
const oemGlassParts =
|
||||
oemGlassPieceParts && oemGlassPieceParts.length > 0
|
||||
? oemGlassPieceParts[0].parts
|
||||
: null;
|
||||
const isOemGlassSelected = store.getters.order.damage?.installOemGlass ?? false;
|
||||
|
||||
let alternateGlassPartsForOem;
|
||||
if (oemGlassParts) alternateGlassPartsForOem = oemGlassParts;
|
||||
|
||||
const quotePageDiscountPartsInfo = getAvailableQuotePageDiscounts();
|
||||
|
||||
const quotePageDiscountParts = quotePageDiscountPartsInfo.map((partInfo) => ({
|
||||
|
|
@ -403,6 +421,9 @@ export default {
|
|||
vm.holdParentAccountNumber = holdParentAccountNumber;
|
||||
vm.holdBillToAccountNumber = holdBillToAccountNumber;
|
||||
vm.skipToInsurance = shouldSkipToInsurance;
|
||||
vm.offerOem = offerOem;
|
||||
vm.alternateGlassPartsForOem = alternateGlassPartsForOem; // oemParts
|
||||
vm.isOemGlassSelected = isOemGlassSelected;
|
||||
|
||||
if (revalidatePromoResponse) {
|
||||
const revalidateAlerts = buildToastMessagesFromRevalidateOrValidatePromoResponse(
|
||||
|
|
@ -570,6 +591,8 @@ export default {
|
|||
availableLineItems: null,
|
||||
lineItems: [],
|
||||
addableVaps: [],
|
||||
offerOem: null,
|
||||
alternateGlassPartsForOem: null,
|
||||
servicePackage: null,
|
||||
holdParentAccountNumber: null,
|
||||
holdBillToAccountNumber: null,
|
||||
|
|
@ -579,6 +602,7 @@ export default {
|
|||
packageNumber: null,
|
||||
skipToInsurance: null,
|
||||
servicePackageSelected: null,
|
||||
isOemGlassSelected: false,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
|
|
@ -743,6 +767,20 @@ export default {
|
|||
this.lineItems.supportingItems = this.filterOutFees(this.lineItems.supportingItems);
|
||||
}
|
||||
|
||||
if (
|
||||
this.lineItems.glassParts &&
|
||||
this.alternateGlassPartsForOem &&
|
||||
this.alternateGlassPartsForOem.length > 0
|
||||
) {
|
||||
let isOEMGlassOnOrder = this.isOEMGlassOnOrder(this.lineItems.glassParts);
|
||||
if (
|
||||
(this.isOemGlassSelected && !isOEMGlassOnOrder) ||
|
||||
(!this.isOemGlassSelected && isOEMGlassOnOrder)
|
||||
) {
|
||||
this.swapOEMGlassPartsOnOrder();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.lineItems.glassParts?.length > 0) {
|
||||
this.dispatchStoreAction(
|
||||
this.storeActions.SAVE_GLASS_PARTS_SUPPRESSING_STATE_RESETTING,
|
||||
|
|
@ -775,6 +813,11 @@ export default {
|
|||
},
|
||||
false
|
||||
);
|
||||
this.dispatchStoreAction(
|
||||
this.storeActions.SAVE_IS_OEM_GLASS_SELECTED,
|
||||
this.isOemGlassSelected,
|
||||
false
|
||||
);
|
||||
|
||||
await savePageData(
|
||||
this.pageName,
|
||||
|
|
@ -893,6 +936,25 @@ export default {
|
|||
const alert = createPromoSuccessAlert(lineItems.promos[0].promoCode);
|
||||
this.$refs.funnelHeader.pushGlobalAlert(alert, alert.shouldAutoFade);
|
||||
},
|
||||
isOEMGlassOnOrder(glassParts) {
|
||||
if (glassParts && glassParts.length > 0) {
|
||||
return glassParts.some((part) => part.partNumber.endsWith("OEM"));
|
||||
}
|
||||
return false;
|
||||
},
|
||||
swapOEMGlassPartsOnOrder() {
|
||||
const windshieldString = "WINDSHIELD";
|
||||
this.lineItems.glassParts.forEach((part, index) => {
|
||||
if (part.partType === windshieldString) {
|
||||
let altPartToUse = this.alternateGlassPartsForOem.find(
|
||||
(altPart) => altPart.partType === windshieldString
|
||||
);
|
||||
if (altPartToUse) {
|
||||
this.lineItems.glassParts[index] = altPartToUse;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
components: {
|
||||
funnelHeader,
|
||||
|
|
@ -909,6 +971,7 @@ export default {
|
|||
recalDisclaimer,
|
||||
saveProgressModalQuestion,
|
||||
saveProgressPopupQuestion,
|
||||
oemGlassQuestion,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ const getDefaultState = () => {
|
|||
capabilityQuestionAnswers: null,
|
||||
dateOfLoss: null,
|
||||
damageCause: null,
|
||||
installOemGlass: null,
|
||||
},
|
||||
lineItems: {
|
||||
glassParts: null,
|
||||
|
|
@ -342,6 +343,9 @@ export const mutations = {
|
|||
updateIsRecalAckOptIn(state, isRecalAckOptIn) {
|
||||
state.order.isRecalAckOptIn = isRecalAckOptIn;
|
||||
},
|
||||
updateIsOemGlassSelected(state, isOemGlassSelected) {
|
||||
state.order.damage.installOemGlass = isOemGlassSelected;
|
||||
},
|
||||
updateIsMSRFeeApplicable(state, isMSRFeeApplicable) {
|
||||
state.order.isMSRFeeApplicable = isMSRFeeApplicable;
|
||||
},
|
||||
|
|
@ -712,6 +716,8 @@ export const mutations = {
|
|||
state.order.damage.capabilityQuestionAnswers =
|
||||
sessionInformation.order.damage.capabilityQuestionAnswers;
|
||||
|
||||
state.order.damage.installOemGlass = sessionInformation.order.damage.installOemGlass;
|
||||
|
||||
state.order.lineItems.glassParts = sessionInformation.order.lineItems.glassParts;
|
||||
state.order.lineItems.supportingItems = sessionInformation.order.lineItems.supportingItems;
|
||||
state.order.lineItems.vaps = sessionInformation.order.lineItems.vaps ?? [];
|
||||
|
|
@ -1853,8 +1859,7 @@ export const actions = {
|
|||
const serviceType = order.serviceLocation?.appointmentType;
|
||||
const referralSeqNumber = order.referralSequenceNumber;
|
||||
const parentAccountNumber = applicationConfig.CASH_PARENT_ACCOUNT_NUMBER;
|
||||
const oemEndorsementFlag = false; // Need to update from the store when available
|
||||
|
||||
const oemEndorsementFlag = order.damage.installOemGlass || false;
|
||||
// create a new array to avoid mutating state
|
||||
const glassArrayForPayload = convertGlassPieceNamingForApi(glassArray);
|
||||
const resultsArrayForPayload = convertResultsForApi(resultsArray);
|
||||
|
|
@ -2453,6 +2458,7 @@ export const actions = {
|
|||
partQuestionAnswers: order.damage.partQuestionAnswers,
|
||||
moldingQuestionAnswers: order.damage.moldingQuestionAnswers,
|
||||
capabilityQuestionAnswers: order.damage.capabilityQuestionAnswers,
|
||||
installOemGlass: order.damage.installOemGlass,
|
||||
},
|
||||
lineItems: {
|
||||
glassParts: lineItems.glassParts,
|
||||
|
|
@ -2959,6 +2965,10 @@ export const actions = {
|
|||
context.commit(storeMutations.UPDATE_IS_RECAL_ACK_OPT_IN, isRecalAckOptIn);
|
||||
},
|
||||
|
||||
saveIsOemGlassSelected(context, isOemGlassSelected) {
|
||||
context.commit(storeMutations.UPDATE_IS_OEM_GLASS_SELECTED, isOemGlassSelected);
|
||||
},
|
||||
|
||||
saveIsMSRFeeApplicable(context, isMSRFeeApplicable) {
|
||||
context.commit(storeMutations.UPDATE_IS_MSR_FEE_APPLICABLE, isMSRFeeApplicable);
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue