Merge branch 'develop' into feature/CSR-1855

This commit is contained in:
CarlNation 2024-01-15 11:27:44 -05:00
commit 1d0b297f63
16 changed files with 233 additions and 18 deletions

View file

@ -19,6 +19,7 @@ const queryStrings = {
AUTH_CODE: "auth_code",
TRANSACTION_ID: "transaction_id",
TRANS_REFERENCE_NUMBER: "auth_trans_ref_no",
LAST_FOUR: "last_four",
DISPLAY_PIA_ALERT: "displayPiaAlert",
};

View file

@ -265,8 +265,8 @@ describe("Question Chain component", () => {
],
},
],
index: 0,
});
await wrapper.setProps({ index: 0 });
//Act
const result = wrapper.vm.getQuestionChainAnswerIfComplete(testReturnedAnswer);

View file

@ -834,7 +834,7 @@ export default {
display: flex;
justify-content: space-between;
padding: 0.5rem 1.5rem;
&:nth-last-child(-n + 3) {
&:nth-last-child(-n + 4) {
background-color: $green-100;
}
&:last-child {

View file

@ -5,11 +5,13 @@
:isMetaValid="meta.valid"
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
v-if="questionsData"
:questionsData="questionsData"
validationRules="questions-required"
v-model="selectedAnswers"
@forwardButtonAction="forwardButtonAction"
@back-click="navigateBack"
:key="currentGlassIndex"
:index="currentGlassIndex" />
</Form>
</template>
@ -55,7 +57,7 @@ export default {
},
data() {
return {
questionsData: [],
questionsData: null,
selectedAnswers: {},
currentGlassIndex: 0,
};
@ -120,6 +122,12 @@ export default {
return updatedGlass;
});
// if no preanswered questions then make sure index starts with the correct value
this.currentGlassIndex = this.calculateQuestionIndex(
this.currentGlassIndex,
this.questionsData
);
},
async forwardButtonAction() {
const questionAnswersArray = this.questionsData.map((glass) => {

View file

@ -145,6 +145,8 @@ export default {
computed: {
ShowCart() {
if (this.isPia && store.getters.submittedOrder.settledTenderAmount == 0) {
// settleTenderAmount always shows 0 via localhost or dev.
// Temporarily set return true to see cart in localhost or dev environment
return false;
}

View file

@ -5,11 +5,13 @@
:isMetaValid="meta.valid"
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
v-if="questionsData"
:questionsData="questionsData"
validationRules="questions-required"
v-model="selectedAnswers"
@forwardButtonAction="forwardButtonAction"
@back-click="navigateBack"
:key="currentGlassIndex"
:index="currentGlassIndex" />
</Form>
</template>
@ -55,7 +57,7 @@ export default {
},
data() {
return {
questionsData: [],
questionsData: null,
selectedAnswers: {},
currentGlassIndex: 0,
};
@ -119,6 +121,12 @@ export default {
return updatedGlass;
});
// if no preanswered questions then make sure index starts with the correct value
this.currentGlassIndex = this.calculateQuestionIndex(
this.currentGlassIndex,
this.questionsData
);
},
async forwardButtonAction() {
const questionAnswersArray = this.questionsData.map((glass) => {

View file

@ -5,11 +5,13 @@
:isMetaValid="meta.valid"
:alertFewMoreQuestionsHeader="AlertFewMoreQuestionsHeader"
:alertFewMoreQuestionsCopy="AlertFewMoreQuestionsCopy"
v-if="questionsData"
:questionsData="questionsData"
validationRules="questions-required"
v-model="selectedAnswers"
@forwardButtonAction="forwardButtonAction"
@back-click="navigateBack"
:key="currentGlassIndex"
:index="currentGlassIndex" />
</Form>
</template>
@ -55,7 +57,7 @@ export default {
},
data() {
return {
questionsData: [],
questionsData: null,
selectedAnswers: {},
currentGlassIndex: 0,
};
@ -71,7 +73,7 @@ export default {
return this.$store.getters.pageData(fmgPageValues.PART_QUESTIONS).partsOrQuestions;
},
},
created() {
mounted() {
this.getInitialQuestionData();
},
methods: {
@ -117,6 +119,12 @@ export default {
return updatedGlass;
});
// if no preanswered questions then make sure index starts with the correct value
this.currentGlassIndex = this.calculateQuestionIndex(
this.currentGlassIndex,
this.questionsData
);
},
async forwardButtonAction() {
const questionAnswersArray = this.questionsData.map((glass) => {

View file

@ -15,10 +15,6 @@
<funnelSubHeader class="mb-5 mt-4" cmsWidgetName="FunnelSubHeaderWidget" />
<p v-if="isPiaDisabled" class="fw-normal no-pia-disclaimer">
<span>{{ noPiaDisclaimer }}</span>
</p>
<hr class="my-0" />
<reviewDropdown ref="reviewDropdown" />
@ -56,6 +52,13 @@
v-model="paymentMethodInternalModel"
validationRules="option-required" />
<alert
v-if="isPiaDisabled"
:isDismissible="false"
alertClass="alert-info"
cmsWidgetName="NoPiaDisclaimerWidget"
shouldScrollToOnMount="false" />
<navbar
cmsWidgetName="FunnelFooterWidget"
ref="navbar"
@ -307,6 +310,7 @@ export default {
availableVaps: [],
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
inactivePromos: this.getInactivePromosFromStore(),
isPiaDisabled: this.getPiaStatusFromStore(),
};
},
methods: {
@ -499,6 +503,13 @@ export default {
this.$route
);
},
getPiaStatusFromStore() {
const piaExperience = this.getSettingValue(experimentSettings.PIA_EXPERIENCE);
const isEnabled = piaExperience === "PIA Optional" || piaExperience === "PIA Required";
return !isEnabled;
},
},
computed: {
damageInfo() {
@ -519,13 +530,6 @@ export default {
return null;
}
},
isPiaDisabled() {
const piaExperience = this.getSettingValue(experimentSettings.PIA_EXPERIENCE);
const isEnabled = piaExperience === "PIA Optional" || piaExperience === "PIA Required";
return !isEnabled;
},
paymentMethod() {
if (this.isPiaDisabled) {
return paymentMethods.LATER;

View file

@ -43,7 +43,9 @@ export default {
},
methods: {
validateAlphanumeric() {
this.value = this.value.replace(ALPHANUMERIC_REGEX, "");
setTimeout(() => {
this.value = this.value.replace(ALPHANUMERIC_REGEX, "");
});
},
},
components: {

View file

@ -106,6 +106,7 @@ export default {
const transReferenceNumber = getQuerystringParameter(
queryStrings.TRANS_REFERENCE_NUMBER
);
const lastFour = getQuerystringParameter(queryStrings.LAST_FOUR);
var ccToken = {
subscriptionId: subscriptionID,
@ -119,6 +120,7 @@ export default {
authCode: authCode,
transactionId: transactionId,
transReferenceNumber: transReferenceNumber,
lastFour: lastFour,
};
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_CCTOKEN, ccToken, false);
await this.saveAndSubmitWorkOrder();

View file

@ -0,0 +1,111 @@
<template>
<div class="alert fade show my-2 py-2 border-0 alert-info" role="alert">
<component :is="'script'" src="https://js.afterpay.com/afterpay-1.x.js" async></component>
<div class="mx-4 my-0 fw-bold alert-heading">
<span v-for="token in afterpayCopyTokens" :key="token">
<span v-if="isAfterpayPriceToken(token)">{{ afterpayPrice }}</span>
<span v-else-if="isInlineImageToken(token)">
<img v-if="hasImage" :src="imageUrl" :alt="getInlineAltText(token)" />
<span v-else>{{ getInlineAltText(token) }}</span>
</span>
<span v-else>
{{ token }}
</span>
</span>
</div>
<div class="mx-4 my-0 fw-bold alert-heading">
<a
id="afterpay-learnmore"
href="#"
data-afterpay-modal="en_US-safelite"
data-bind="click:afterpayLearnMore">
{{ modalCopy }}
</a>
</div>
</div>
</template>
<script>
import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper";
import baseMixin from "@/mixins/base-mixin.js";
const INLINE_IMAGE_TOKEN = "custom:inlineImage";
const AFTERPAY_PRICE_TOKEN = "custom:afterpayPrice";
function isInlineImageToken(token) {
return token.includes(INLINE_IMAGE_TOKEN);
}
function isAfterpayPriceToken(token) {
return token.includes(AFTERPAY_PRICE_TOKEN);
}
function getInlineAltText(token) {
const innerTokens = token.split(",");
return innerTokens[1] ?? "";
}
export default {
name: "afterpay-modal-banner",
props: {
cmsWidgetName: String,
lineItems: Array,
},
data() {
return {};
},
methods: {
isInlineImageToken,
isAfterpayPriceToken,
getInlineAltText,
},
computed: {
nullSafeLineItems() {
return this.lineItems ?? [];
},
imageUrl() {
return this.getCmsContent(this.cmsWidgetName, "Image");
},
hasImage() {
return !!this.imageUrl;
},
afterpayCopyTokens() {
return splitCopyOnCMSPlaceHolder(this.getCmsContent(this.cmsWidgetName, "HeaderText"));
},
modalCopy() {
return this.getCmsContent(this.cmsWidgetName, "SubheaderText");
},
afterpayPrice() {
const price = baseMixin.methods.getTierOnePackagePrice(
baseMixin.methods.filterOutFees(this.nullSafeLineItems)
);
const adjusted = (price / 4).toFixed(2);
return `$${adjusted}`;
},
},
components: {},
};
</script>
<style lang="scss" scoped>
.alert {
padding: 0.675rem 0;
&.alert-info {
background-color: $blue-100;
.alert-heading {
color: $blue-700;
}
svg {
fill: $blue-700;
width: 1rem;
height: 1rem;
}
}
& .alert-heading {
font-size: 0.875rem;
}
}
</style>

View file

@ -34,6 +34,11 @@
validationRules="option-required"
isRequired />
<afterpayModalBanner
v-if="!isInsuranceSelected"
cmsWidgetName="AfterpayModalWidget"
:lineItems="availableLineItems" />
<textBlock
cmsWidgetName="quoteDisclaimer"
justifyText="left"
@ -68,6 +73,7 @@ import servicePackageQuestion from "./service-package-question/service-package-q
import textBlock from "@/digital-components/text-block/text-block";
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import afterpayModalBanner from "@/layouts/quote/afterpay-modal-banner/afterpay-modal-banner";
import baseMixin from "@/mixins/base-mixin.js";
import vehicleQuestionsMixin from "../../mixins/vehicle-questions-mixin";
import { settleAllPromises } from "@/helpers/layout-helper";
@ -315,6 +321,7 @@ export default {
servicePackageQuestion,
contentGroupModal,
loadingModal,
afterpayModalBanner,
},
};
</script>

View file

@ -146,6 +146,13 @@ export default {
return glass;
},
calculateQuestionIndex(currentGlassIndex, questionsData) {
// if no preanswered questions then make sure index starts with the correct value
if (currentGlassIndex === 0) {
return questionsData?.findIndex((glass) => glass.questions?.length > 0);
}
return currentGlassIndex;
},
handleCompletedQuestionChainAnswers(answer, glassKey, vm) {
// only runs when all questions in a question-chain have been answered
// when selectedAnswers updates, user has completed this part's question chain and has a final answer

View file

@ -411,6 +411,57 @@ describe("vehicle-questions-mixin", () => {
});
});
describe("calculateQuestionIndex", () => {
describe("if currentGlassIndex is zero...", () => {
test("should return index of first glass piece with questions", () => {
// Arrange
const questionsData = [
{
glassName: "Single",
glassLocation: "Windshield",
},
{
glassName: "Front",
glassLocation: "Driver",
questions: ["example question"],
},
];
const glassIndex = 0;
const { wrapper } = setupMocks({});
// Act
const returnedIndex = wrapper.vm.calculateQuestionIndex(glassIndex, questionsData);
// Assert
expect(returnedIndex).toBe(1);
});
});
describe("if currentGlassIndex is NOT zero...", () => {
test("should return currentGlassIndex value", () => {
// Arrange
const questionsData = [
{
glassName: "Single",
glassLocation: "Windshield",
},
{
glassName: "Front",
glassLocation: "Driver",
questions: ["example question"],
},
];
const glassIndex = 1;
const { wrapper } = setupMocks({});
// Act
const returnedIndex = wrapper.vm.calculateQuestionIndex(glassIndex, questionsData);
// Assert
expect(returnedIndex).toBe(1);
});
});
});
describe("handleCompletedQuestionChainAnswers", () => {
describe("selectedAnswers", () => {
test("should be cleared to be empty", () => {

View file

@ -115,6 +115,7 @@ const getDefaultState = () => {
authCode: null,
transactionId: null,
transReferenceNumber: null,
lastFour: null,
},
},
schedule: {
@ -274,6 +275,7 @@ export const mutations = {
state.order.payment.ccToken.authCode = ccToken.authCode;
state.order.payment.ccToken.transactionId = ccToken.transactionId;
state.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber;
state.order.payment.ccToken.lastFour = ccToken.lastFour;
},
updatePaypalToken(state, ppToken) {
state.order.payment.paypalToken = ppToken;
@ -1680,6 +1682,7 @@ export const actions = {
authCode: order.payment.ccToken.authCode,
transactionId: order.payment.ccToken.transactionId,
transReferenceNumber: order.payment.ccToken.transReferenceNumber,
lastFour: order.payment.ccToken.lastFour,
},
},
serviceLocation: {

View file

@ -742,6 +742,7 @@ describe("Actions", () => {
authCode: null,
transactionId: null,
transReferenceNumber: null,
lastFour: null,
},
},
serviceLocation: {},