Merge branch 'develop' into feature/CASH-2952
This commit is contained in:
commit
71766a922e
19 changed files with 443 additions and 41 deletions
|
|
@ -208,6 +208,10 @@ const endpoints = {
|
||||||
url: "/account/api/v1/account/bill-to-account-number",
|
url: "/account/api/v1/account/bill-to-account-number",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
},
|
},
|
||||||
|
GetAccountDetails: {
|
||||||
|
url: "/account/api/v1/account/account-details",
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
ClosestApplicableShops: {
|
ClosestApplicableShops: {
|
||||||
url: "/location/api/v1/location/closest-applicable-shops",
|
url: "/location/api/v1/location/closest-applicable-shops",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ const storeActions = {
|
||||||
REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA: "revalidateOrderPromosAndSaveServerData",
|
REVALIDATE_ORDER_PROMOS_AND_SAVE_SERVER_DATA: "revalidateOrderPromosAndSaveServerData",
|
||||||
GET_INSURANCE_COMPANY_LIST: "getInsuranceCompanyList",
|
GET_INSURANCE_COMPANY_LIST: "getInsuranceCompanyList",
|
||||||
GET_BILL_TO_ACCOUNT_NUMBER: "getBillToAccountNumber",
|
GET_BILL_TO_ACCOUNT_NUMBER: "getBillToAccountNumber",
|
||||||
|
GET_ACCOUNT_DETAILS: "getAccountDetails",
|
||||||
GET_RECAL_PARTS_AND_SAVE_TO_LINE_ITEMS: "getRecalPartsAndSaveToLineItems",
|
GET_RECAL_PARTS_AND_SAVE_TO_LINE_ITEMS: "getRecalPartsAndSaveToLineItems",
|
||||||
GET_CLOSEST_APPLICABLE_SHOPS: "getClosestApplicableShops",
|
GET_CLOSEST_APPLICABLE_SHOPS: "getClosestApplicableShops",
|
||||||
|
|
||||||
|
|
@ -100,8 +101,7 @@ const storeActions = {
|
||||||
SAVE_PAYMENT_METHOD_CHOICE: "savePaymentMethodChoice",
|
SAVE_PAYMENT_METHOD_CHOICE: "savePaymentMethodChoice",
|
||||||
SAVE_PARENT_ACCOUNT_NUMBER: "saveParentAccountNumber",
|
SAVE_PARENT_ACCOUNT_NUMBER: "saveParentAccountNumber",
|
||||||
SAVE_ACCOUNT_NAME: "saveAccountName",
|
SAVE_ACCOUNT_NAME: "saveAccountName",
|
||||||
SAVE_IS_CLAIM_AND_COVERAGE: "saveIsClaimAndCoverage",
|
SAVE_INSURANCE_ACCOUNT_DETAILS: "saveInsuranceAccountDetails",
|
||||||
SAVE_CAN_SCHEDULE_ONLINE: "saveCanScheduleOnline",
|
|
||||||
SAVE_BILL_TO_ACCOUNT_NUMBER: "saveBillToAccountNumber",
|
SAVE_BILL_TO_ACCOUNT_NUMBER: "saveBillToAccountNumber",
|
||||||
SAVE_SUPPORTING_ITEMS: "saveSupportingItems",
|
SAVE_SUPPORTING_ITEMS: "saveSupportingItems",
|
||||||
SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING:
|
SAVE_SUPPORTING_ITEMS_SUPPRESSING_STATE_RESETTING:
|
||||||
|
|
@ -120,6 +120,7 @@ const storeActions = {
|
||||||
SAVE_IS_OEM_GLASS_SELECTED: "saveIsOemGlassSelected",
|
SAVE_IS_OEM_GLASS_SELECTED: "saveIsOemGlassSelected",
|
||||||
SAVE_IS_MSR_FEE_APPLICABLE: "saveIsMSRFeeApplicable",
|
SAVE_IS_MSR_FEE_APPLICABLE: "saveIsMSRFeeApplicable",
|
||||||
SAVE_IS_MSR_FEE_COVERED_BY_INSURANCE: "saveIsMSRFeeCoveredByInsurance",
|
SAVE_IS_MSR_FEE_COVERED_BY_INSURANCE: "saveIsMSRFeeCoveredByInsurance",
|
||||||
|
SAVE_IS_NEW_INSURANCE_FLOW: "saveIsNewInsuranceFlow",
|
||||||
|
|
||||||
CREATE_SUBMITTED_STATE: "createSubmittedState",
|
CREATE_SUBMITTED_STATE: "createSubmittedState",
|
||||||
RESET_SUBMITTED_STATE: "resetSubmittedState",
|
RESET_SUBMITTED_STATE: "resetSubmittedState",
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ const storeMutations = {
|
||||||
UPDATE_ACCOUNT_NAME: "updateAccountName",
|
UPDATE_ACCOUNT_NAME: "updateAccountName",
|
||||||
UPDATE_IS_CLAIM_AND_COVERAGE: "updateIsClaimAndCoverage",
|
UPDATE_IS_CLAIM_AND_COVERAGE: "updateIsClaimAndCoverage",
|
||||||
UPDATE_CAN_SCHEDULE_ONLINE: "updateCanScheduleOnline",
|
UPDATE_CAN_SCHEDULE_ONLINE: "updateCanScheduleOnline",
|
||||||
|
UPDATE_IS_MANAGED_ACCOUNT: "updateIsManagedAccount",
|
||||||
UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber",
|
UPDATE_BILL_TO_ACCT_NUMBER: "updateBillToAcctNumber",
|
||||||
UPDATE_EON: "updateEON",
|
UPDATE_EON: "updateEON",
|
||||||
UPDATE_IS_INSURANCE: "updateIsInsurance",
|
UPDATE_IS_INSURANCE: "updateIsInsurance",
|
||||||
|
|
@ -83,6 +84,7 @@ const storeMutations = {
|
||||||
UPDATE_IS_OEM_GLASS_SELECTED: "updateIsOemGlassSelected",
|
UPDATE_IS_OEM_GLASS_SELECTED: "updateIsOemGlassSelected",
|
||||||
UPDATE_IS_MSR_FEE_APPLICABLE: "updateIsMSRFeeApplicable",
|
UPDATE_IS_MSR_FEE_APPLICABLE: "updateIsMSRFeeApplicable",
|
||||||
UPDATE_IS_MSR_FEE_COVERED_BY_INSURANCE: "updateIsMSRFeeCoveredByInsurance",
|
UPDATE_IS_MSR_FEE_COVERED_BY_INSURANCE: "updateIsMSRFeeCoveredByInsurance",
|
||||||
|
UPDATE_IS_NEW_INSURANCE_FLOW: "updateIsNewInsuranceFlow",
|
||||||
UPDATE_CASH_PRICE_SUBTOTAL: "updateCashPriceSubTotal",
|
UPDATE_CASH_PRICE_SUBTOTAL: "updateCashPriceSubTotal",
|
||||||
|
|
||||||
// EVENT BUS MUTATIONS
|
// EVENT BUS MUTATIONS
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
class="my-4 caption modal-sub-body"
|
class="my-4 caption modal-sub-body"
|
||||||
v-if="ModalSubBodyText"
|
v-if="ModalSubBodyText"
|
||||||
v-html="ModalSubBodyText"></p>
|
v-html="ModalSubBodyText"></p>
|
||||||
|
<p class="my-4 caption" v-if="ModalFooter2Text" v-html="ModalFooter2Text"></p>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</modal>
|
</modal>
|
||||||
|
|
@ -58,6 +59,9 @@ export default {
|
||||||
ModalCloseButtonText() {
|
ModalCloseButtonText() {
|
||||||
return this.getCmsContent(this.cmsWidgetName, "FooterText");
|
return this.getCmsContent(this.cmsWidgetName, "FooterText");
|
||||||
},
|
},
|
||||||
|
ModalFooter2Text() {
|
||||||
|
return this.getCmsContent(this.cmsWidgetName, "FooterText2");
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openModal() {
|
openModal() {
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ import modal from "@/digital-components/modal/modal";
|
||||||
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal.vue";
|
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal.vue";
|
||||||
import textBlock from "@/digital-components/text-block/text-block.vue";
|
import textBlock from "@/digital-components/text-block/text-block.vue";
|
||||||
import { debugLog } from "@/helpers/debug-log-helper";
|
import { debugLog } from "@/helpers/debug-log-helper";
|
||||||
|
import { loadSessionIfPresent } from "@/helpers/heritage-integration/order-helper";
|
||||||
export default {
|
export default {
|
||||||
name: "coverage-statement",
|
name: "coverage-statement",
|
||||||
mixins: [],
|
mixins: [],
|
||||||
|
|
@ -186,6 +187,13 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
|
// The safelite api will often remove fees when switching cash to insurance. Heritage does the same.
|
||||||
|
// The heritage flow triggers a load session when returning to pick up new parts to make sure we're in-sync.
|
||||||
|
// The new insurance flow needs to trigger a load session to pick up these same type of part changes.
|
||||||
|
if (store.getters.order.isNewInsuranceFlow) {
|
||||||
|
await loadSessionIfPresent(false, this.pageName);
|
||||||
|
}
|
||||||
|
|
||||||
this.$router.navigateWithSaving(
|
this.$router.navigateWithSaving(
|
||||||
this.navigationScenarios.CLICKED_FORWARD,
|
this.navigationScenarios.CLICKED_FORWARD,
|
||||||
this.pageName
|
this.pageName
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ export default {
|
||||||
accountName: this.accountNameFromStore(),
|
accountName: this.accountNameFromStore(),
|
||||||
isClaimAndCoverage: this.isClaimAndCoverageFromStore(),
|
isClaimAndCoverage: this.isClaimAndCoverageFromStore(),
|
||||||
canScheduleOnline: this.canScheduleOnlineFromStore(),
|
canScheduleOnline: this.canScheduleOnlineFromStore(),
|
||||||
|
isManagedAccount: this.isManagedAccountFromStore(),
|
||||||
},
|
},
|
||||||
originalList: [],
|
originalList: [],
|
||||||
};
|
};
|
||||||
|
|
@ -156,6 +157,9 @@ export default {
|
||||||
canScheduleOnlineFromStore() {
|
canScheduleOnlineFromStore() {
|
||||||
return store.getters.order?.payment?.canScheduleOnline;
|
return store.getters.order?.payment?.canScheduleOnline;
|
||||||
},
|
},
|
||||||
|
isManagedAccountFromStore() {
|
||||||
|
return store.getters.order?.payment?.isManagedAccount;
|
||||||
|
},
|
||||||
arePagePrerequisitesValid() {
|
arePagePrerequisitesValid() {
|
||||||
return store.getters.order.payment.isInsurance === true;
|
return store.getters.order.payment.isInsurance === true;
|
||||||
},
|
},
|
||||||
|
|
@ -192,15 +196,24 @@ export default {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
await this.dispatchStoreAction(
|
// Fetch the latest account details for the selected parent account so that
|
||||||
this.storeActions.SAVE_IS_CLAIM_AND_COVERAGE,
|
// routing and the saved values below reflect the current source of truth.
|
||||||
this.selectedAccount.isClaimAndCoverage,
|
const accountDetails = await baseMixin.methods.dispatchStoreActionWithLogging(
|
||||||
|
storeActions.GET_ACCOUNT_DETAILS,
|
||||||
|
{ parentAccountNumber: this.selectedAccount.parentAccountNumber },
|
||||||
|
"insurance-company",
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.selectedAccount.isManagedAccount = accountDetails.isManagedAccount;
|
||||||
|
|
||||||
await this.dispatchStoreAction(
|
await this.dispatchStoreAction(
|
||||||
this.storeActions.SAVE_CAN_SCHEDULE_ONLINE,
|
this.storeActions.SAVE_INSURANCE_ACCOUNT_DETAILS,
|
||||||
this.selectedAccount.canScheduleOnline,
|
{
|
||||||
|
isClaimAndCoverage: this.selectedAccount.isClaimAndCoverage,
|
||||||
|
canScheduleOnline: this.selectedAccount.canScheduleOnline,
|
||||||
|
isManagedAccount: this.selectedAccount.isManagedAccount,
|
||||||
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -236,6 +249,11 @@ export default {
|
||||||
debugLog(
|
debugLog(
|
||||||
`--- ${this.selectedAccount.parentAccountNumber} C&C experiment active for this parent account number, sending to vue app Policy Info page ---`
|
`--- ${this.selectedAccount.parentAccountNumber} C&C experiment active for this parent account number, sending to vue app Policy Info page ---`
|
||||||
);
|
);
|
||||||
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_IS_NEW_INSURANCE_FLOW,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
this.$router.navigateWithSaving(
|
this.$router.navigateWithSaving(
|
||||||
this.navigationScenarios.CLICKED_FORWARD_POLICY_INFO,
|
this.navigationScenarios.CLICKED_FORWARD_POLICY_INFO,
|
||||||
this.pageName
|
this.pageName
|
||||||
|
|
@ -248,6 +266,11 @@ export default {
|
||||||
debugLog(
|
debugLog(
|
||||||
`--- ${this.selectedAccount.parentAccountNumber} C&C experiment setting is false, but is a C&C client, sending to heritage ---`
|
`--- ${this.selectedAccount.parentAccountNumber} C&C experiment setting is false, but is a C&C client, sending to heritage ---`
|
||||||
);
|
);
|
||||||
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_IS_NEW_INSURANCE_FLOW,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
navigateToHeritageFunnel({
|
navigateToHeritageFunnel({
|
||||||
shouldSaveSession: true,
|
shouldSaveSession: true,
|
||||||
pageNameToLog: this.pageName,
|
pageNameToLog: this.pageName,
|
||||||
|
|
@ -265,6 +288,11 @@ export default {
|
||||||
debugLog(
|
debugLog(
|
||||||
`--- ${this.selectedAccount.parentAccountNumber} Non integrated experiment setting is true, sending to vue app Insurance Details page ---`
|
`--- ${this.selectedAccount.parentAccountNumber} Non integrated experiment setting is true, sending to vue app Insurance Details page ---`
|
||||||
);
|
);
|
||||||
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_IS_NEW_INSURANCE_FLOW,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
this.$router.navigateWithSaving(
|
this.$router.navigateWithSaving(
|
||||||
this.navigationScenarios.CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE,
|
this.navigationScenarios.CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE,
|
||||||
this.pageName
|
this.pageName
|
||||||
|
|
@ -290,6 +318,11 @@ export default {
|
||||||
debugLog(
|
debugLog(
|
||||||
`--- ${this.selectedAccount.parentAccountNumber} Non integrated experiment setting is false, but a parent account is NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT experiment contains a specific parent account number, sending to vue app Insurance Details page ---`
|
`--- ${this.selectedAccount.parentAccountNumber} Non integrated experiment setting is false, but a parent account is NON_CLAIM_AND_COVERAGE_TEST_PARENT_ACCOUNT experiment contains a specific parent account number, sending to vue app Insurance Details page ---`
|
||||||
);
|
);
|
||||||
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_IS_NEW_INSURANCE_FLOW,
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
);
|
||||||
this.$router.navigateWithSaving(
|
this.$router.navigateWithSaving(
|
||||||
this.navigationScenarios.CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE,
|
this.navigationScenarios.CLICKED_FORWARD_NON_CLAIM_AND_COVERAGE,
|
||||||
this.pageName
|
this.pageName
|
||||||
|
|
@ -297,6 +330,11 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_IS_NEW_INSURANCE_FLOW,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
navigateToHeritageFunnel({
|
navigateToHeritageFunnel({
|
||||||
shouldSaveSession: true,
|
shouldSaveSession: true,
|
||||||
pageNameToLog: "insurance-company",
|
pageNameToLog: "insurance-company",
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
:questionText="damageTypesQuestionText"
|
:questionText="damageTypesQuestionText"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
v-model="damageCause"
|
v-model="damageCause"
|
||||||
cmsWidgetName="DamageTypesWidget"
|
:cmsWidgetName="damageTypesWidgetName"
|
||||||
customDropdownId="damageTypes"
|
customDropdownId="damageTypes"
|
||||||
:options="damageTypesOptions"
|
:options="damageTypesOptions"
|
||||||
:valueAsKey="true"
|
:valueAsKey="true"
|
||||||
|
|
@ -183,6 +183,7 @@ export default {
|
||||||
policyZip: this.getPolicyZipFromStore(),
|
policyZip: this.getPolicyZipFromStore(),
|
||||||
claimNumber: this.getClaimNumberFromStore(),
|
claimNumber: this.getClaimNumberFromStore(),
|
||||||
showSaveProgressModal: null,
|
showSaveProgressModal: null,
|
||||||
|
isManagedAccount: this.getIsManagedAccountFromStore(),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -249,13 +250,22 @@ export default {
|
||||||
stateOptions() {
|
stateOptions() {
|
||||||
return stateOptionsInternational;
|
return stateOptionsInternational;
|
||||||
},
|
},
|
||||||
|
damageTypesWidgetName() {
|
||||||
|
return this.isManagedAccount ? "DamageTypesWidget" : "UnmanagedDamageTypesWidget";
|
||||||
|
},
|
||||||
damageCauseQuestionText() {
|
damageCauseQuestionText() {
|
||||||
return this.getCmsContent("DamageTypesWidget", "QuestionText");
|
if (this.isManagedAccount) {
|
||||||
|
return this.getCmsContent("DamageTypesWidget", "QuestionText");
|
||||||
|
} else {
|
||||||
|
return this.getCmsContent("UnmanagedDamageTypesWidget", "QuestionText");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
damageTypesOptions() {
|
damageTypesOptions() {
|
||||||
const options = {};
|
const options = {};
|
||||||
|
|
||||||
const answers = this.getCmsContent("DamageTypesWidget", "Answers");
|
const answers = this.isManagedAccount
|
||||||
|
? this.getCmsContent("DamageTypesWidget", "Answers")
|
||||||
|
: this.getCmsContent("UnmanagedDamageTypesWidget", "Answers");
|
||||||
if (!Array.isArray(answers)) {
|
if (!Array.isArray(answers)) {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
@ -267,6 +277,9 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getIsManagedAccountFromStore() {
|
||||||
|
return store.getters.order?.payment?.isManagedAccount ?? false;
|
||||||
|
},
|
||||||
getInsuranceCompanyNameFromStore() {
|
getInsuranceCompanyNameFromStore() {
|
||||||
return store.getters.order.policy.insuranceCompanyName;
|
return store.getters.order.policy.insuranceCompanyName;
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -777,6 +777,12 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
storeActions.SAVE_IS_NEW_INSURANCE_FLOW,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
this.dispatchStoreAction(
|
this.dispatchStoreAction(
|
||||||
this.storeActions.SAVE_PAYMENT_TYPE,
|
this.storeActions.SAVE_PAYMENT_TYPE,
|
||||||
this.isInsuranceSelected,
|
this.isInsuranceSelected,
|
||||||
|
|
@ -795,12 +801,15 @@ export default {
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
this.dispatchStoreAction(
|
this.dispatchStoreAction(
|
||||||
this.storeActions.SAVE_IS_CLAIM_AND_COVERAGE,
|
this.storeActions.SAVE_INSURANCE_ACCOUNT_DETAILS,
|
||||||
false,
|
{
|
||||||
|
isClaimAndCoverage: false,
|
||||||
|
canScheduleOnline: false,
|
||||||
|
isManagedAccount: false,
|
||||||
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
this.dispatchStoreAction(this.storeActions.RESET_INSURANCE_DETAILS, false, false);
|
this.dispatchStoreAction(this.storeActions.RESET_INSURANCE_DETAILS, false, false);
|
||||||
this.dispatchStoreAction(this.storeActions.SAVE_CAN_SCHEDULE_ONLINE, false, false);
|
|
||||||
this.dispatchStoreAction(this.storeActions.SAVE_ACCOUNT_NAME, null, false);
|
this.dispatchStoreAction(this.storeActions.SAVE_ACCOUNT_NAME, null, false);
|
||||||
} else {
|
} else {
|
||||||
baseMixin.methods.dispatchStoreAction(
|
baseMixin.methods.dispatchStoreAction(
|
||||||
|
|
|
||||||
|
|
@ -243,4 +243,27 @@ describe("inshop-scheduling-card.vue", () => {
|
||||||
expect(wrapper.find(".inshop-scheduling-card__body").isVisible()).toBe(false);
|
expect(wrapper.find(".inshop-scheduling-card__body").isVisible()).toBe(false);
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("isLoading prop", () => {
|
||||||
|
test("shows the skeleton loader and hides real content when isLoading is true", () => {
|
||||||
|
const wrapper = mountComponent({ isLoading: true });
|
||||||
|
expect(wrapper.find("scheduling-card-loader-stub").exists()).toBe(true);
|
||||||
|
expect(wrapper.find(".inshop-scheduling-card__header").exists()).toBe(false);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("hides the skeleton loader and shows real content when isLoading is false", () => {
|
||||||
|
const wrapper = mountComponent({ isLoading: false });
|
||||||
|
expect(wrapper.find("scheduling-card-loader-stub").exists()).toBe(false);
|
||||||
|
expect(wrapper.find(".inshop-scheduling-card__header").exists()).toBe(true);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("defaults isLoading to false", () => {
|
||||||
|
const wrapper = mountComponent();
|
||||||
|
expect(wrapper.props("isLoading")).toBe(false);
|
||||||
|
expect(wrapper.find("scheduling-card-loader-stub").exists()).toBe(false);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="inshop-scheduling-card">
|
<div class="inshop-scheduling-card">
|
||||||
<div class="inshop-scheduling-card__panel">
|
<div v-if="isLoading" class="inshop-scheduling-card__panel">
|
||||||
|
<schedulingCardLoader />
|
||||||
|
</div>
|
||||||
|
<div v-else class="inshop-scheduling-card__panel">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="inshop-scheduling-card__header"
|
class="inshop-scheduling-card__header"
|
||||||
|
|
@ -113,6 +116,7 @@ import {
|
||||||
INSHOP_INITIAL_VISIBLE_TIME_SLOTS,
|
INSHOP_INITIAL_VISIBLE_TIME_SLOTS,
|
||||||
mapInshopTimeSlotToDisplaySlot,
|
mapInshopTimeSlotToDisplaySlot,
|
||||||
} from "@/layouts/schedule/helpers/schedule-helper";
|
} from "@/layouts/schedule/helpers/schedule-helper";
|
||||||
|
import schedulingCardLoader from "@/layouts/scheduling/scheduling-card-loader/scheduling-card-loader";
|
||||||
|
|
||||||
function toTitleCase(str) {
|
function toTitleCase(str) {
|
||||||
if (!str) return "";
|
if (!str) return "";
|
||||||
|
|
@ -155,6 +159,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: "DropoffQuestionWidget",
|
default: "DropoffQuestionWidget",
|
||||||
},
|
},
|
||||||
|
isLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -317,6 +325,9 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
schedulingCardLoader,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -167,4 +167,33 @@ describe("mobile-scheduling-card.vue", () => {
|
||||||
expect(wrapper.find(".mobile-scheduling-card__body").isVisible()).toBe(true);
|
expect(wrapper.find(".mobile-scheduling-card__body").isVisible()).toBe(true);
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("isLoading prop", () => {
|
||||||
|
test("shows the skeleton loader and hides real content when isLoading is true", () => {
|
||||||
|
const wrapper = mountComponent({ isLoading: true });
|
||||||
|
expect(wrapper.find("scheduling-card-loader-stub").exists()).toBe(true);
|
||||||
|
expect(wrapper.find(".mobile-scheduling-card__header").exists()).toBe(false);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("hides the skeleton loader and shows real content when isLoading is false", () => {
|
||||||
|
const wrapper = mountComponent({ isLoading: false });
|
||||||
|
expect(wrapper.find("scheduling-card-loader-stub").exists()).toBe(false);
|
||||||
|
expect(wrapper.find(".mobile-scheduling-card__header").exists()).toBe(true);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("hides the free flag when isLoading is true even if showFreeFlag is true", () => {
|
||||||
|
const wrapper = mountComponent({ isLoading: true, showFreeFlag: true });
|
||||||
|
expect(wrapper.find(".mobile-scheduling-card__free-flag").exists()).toBe(false);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("defaults isLoading to false", () => {
|
||||||
|
const wrapper = mountComponent();
|
||||||
|
expect(wrapper.props("isLoading")).toBe(false);
|
||||||
|
expect(wrapper.find("scheduling-card-loader-stub").exists()).toBe(false);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mobile-scheduling-card">
|
<div class="mobile-scheduling-card">
|
||||||
<div v-if="showFreeFlag" class="mobile-scheduling-card__free-flag">
|
<div v-if="showFreeFlag && !isLoading" class="mobile-scheduling-card__free-flag">
|
||||||
<img
|
<img
|
||||||
class="mobile-scheduling-card__free-flag-icon"
|
class="mobile-scheduling-card__free-flag-icon"
|
||||||
src="@/assets/img/party.svg"
|
src="@/assets/img/party.svg"
|
||||||
|
|
@ -8,7 +8,11 @@
|
||||||
aria-hidden="true" />
|
aria-hidden="true" />
|
||||||
<span class="mobile-scheduling-card__free-flag-text">{{ freeFlagText }}</span>
|
<span class="mobile-scheduling-card__free-flag-text">{{ freeFlagText }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="isLoading" class="mobile-scheduling-card__panel">
|
||||||
|
<schedulingCardLoader />
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
|
v-else
|
||||||
class="mobile-scheduling-card__panel"
|
class="mobile-scheduling-card__panel"
|
||||||
:class="{ 'mobile-scheduling-card__panel--with-free-flag': showFreeFlag }">
|
:class="{ 'mobile-scheduling-card__panel--with-free-flag': showFreeFlag }">
|
||||||
<button
|
<button
|
||||||
|
|
@ -86,7 +90,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { PREMIUM_TIME_SLOT_ID_FLAG, AppointmentTypeStrings } from "@/constants/schedule-constants";
|
import { PREMIUM_TIME_SLOT_ID_FLAG, AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||||
import { militaryToTwelveHourTime } from "@/layouts/schedule/helpers/schedule-helper";
|
import { militaryToTwelveHourTime } from "@/layouts/schedule/helpers/schedule-helper";
|
||||||
|
import schedulingCardLoader from "@/layouts/scheduling/scheduling-card-loader/scheduling-card-loader.vue";
|
||||||
export default {
|
export default {
|
||||||
name: "mobile-scheduling-card",
|
name: "mobile-scheduling-card",
|
||||||
emits: ["update:modelValue", "zip-code-clicked"],
|
emits: ["update:modelValue", "zip-code-clicked"],
|
||||||
|
|
@ -123,6 +127,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: "MobileCardWidget",
|
default: "MobileCardWidget",
|
||||||
},
|
},
|
||||||
|
isLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -228,6 +236,9 @@ export default {
|
||||||
return routeCode + PREMIUM_TIME_SLOT_ID_FLAG;
|
return routeCode + PREMIUM_TIME_SLOT_ID_FLAG;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
schedulingCardLoader,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import schedulingCardLoader from "./scheduling-card-loader";
|
||||||
|
|
||||||
|
describe("scheduling-card-loader.vue", () => {
|
||||||
|
test("renders the loader container with aria-hidden", () => {
|
||||||
|
const wrapper = shallowMount(schedulingCardLoader);
|
||||||
|
expect(wrapper.find(".scheduling-card-loader").exists()).toBe(true);
|
||||||
|
expect(wrapper.find(".scheduling-card-loader").attributes("aria-hidden")).toBe("true");
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders exactly two skeleton rows", () => {
|
||||||
|
const wrapper = shallowMount(schedulingCardLoader);
|
||||||
|
expect(wrapper.findAll(".scheduling-card-loader__row").length).toBe(2);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("each row contains a wide shimmer bar", () => {
|
||||||
|
const wrapper = shallowMount(schedulingCardLoader);
|
||||||
|
wrapper.findAll(".scheduling-card-loader__row").forEach((row) => {
|
||||||
|
expect(row.find(".scheduling-card-loader__bar--wide").exists()).toBe(true);
|
||||||
|
});
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<div class="scheduling-card-loader" aria-hidden="true">
|
||||||
|
<div class="scheduling-card-loader__row">
|
||||||
|
<span class="scheduling-card-loader__bar scheduling-card-loader__bar--wide"></span>
|
||||||
|
</div>
|
||||||
|
<div class="scheduling-card-loader__row">
|
||||||
|
<span class="scheduling-card-loader__bar scheduling-card-loader__bar--wide"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "scheduling-card-loader",
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.scheduling-card-loader {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bar {
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: linear-gradient(90deg, $gray-200 25%, $gray-100 50%, $gray-200 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: scheduling-card-shimmer 1.5s ease-in-out infinite;
|
||||||
|
|
||||||
|
&--wide {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scheduling-card-shimmer {
|
||||||
|
0% {
|
||||||
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
110
src/layouts/scheduling/scheduling.spec.js
Normal file
110
src/layouts/scheduling/scheduling.spec.js
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import scheduling from "./scheduling";
|
||||||
|
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||||
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||||
|
|
||||||
|
jest.mock("@/store", () => ({
|
||||||
|
dispatch: jest.fn().mockResolvedValue(null),
|
||||||
|
getters: {
|
||||||
|
order: {
|
||||||
|
serviceLocation: { zipCode: "43235", appointmentType: null },
|
||||||
|
payment: { isInsurance: false, insuranceCoverage: { isVerified: false } },
|
||||||
|
referralNumber: "",
|
||||||
|
damage: { isRepair: false },
|
||||||
|
lineItems: { glassParts: [] },
|
||||||
|
policy: { isItac: false, isNoComp: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/layout-helper", () => ({
|
||||||
|
settleAllPromises: jest.fn().mockResolvedValue({}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||||
|
fetchCmsContentForPage: jest.fn().mockResolvedValue({}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/heritage-integration/navigation-helper", () => ({
|
||||||
|
navigateToHeritageFunnel: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/debug-log-helper", () => ({
|
||||||
|
debugLog: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock("@/helpers/page-prerequisites-helper.js", () => ({
|
||||||
|
flushPagePrereqsLogs: jest.fn(),
|
||||||
|
hasServiceZipInfo: jest.fn(() => true),
|
||||||
|
hasGlassPartsOrRepairInfo: jest.fn(() => true),
|
||||||
|
hasInsuranceInfo: jest.fn(() => true),
|
||||||
|
}));
|
||||||
|
|
||||||
|
function setupMocks() {
|
||||||
|
const baseMixin = {
|
||||||
|
methods: {
|
||||||
|
getCmsContent: jest.fn(() => ""),
|
||||||
|
setCmsContent: jest.fn(),
|
||||||
|
getTotalLineItemPrice: jest.fn(() => 0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const mountOptions = getMountOptions({
|
||||||
|
route: { name: "scheduling" },
|
||||||
|
router: {
|
||||||
|
navigate: jest.fn(),
|
||||||
|
navigateWithSaving: jest.fn(),
|
||||||
|
navigateWithoutSaving: jest.fn(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
mountOptions.global.mixins = [baseMixin];
|
||||||
|
const wrapper = shallowMount(scheduling, mountOptions);
|
||||||
|
return { wrapper };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("scheduling.vue", () => {
|
||||||
|
describe("intercept overlay", () => {
|
||||||
|
test("does not render interceptOverlay when isLoadingDates is false", () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
expect(wrapper.find("intercept-overlay-stub").exists()).toBe(false);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders interceptOverlay when isLoadingDates is true", async () => {
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
await wrapper.setData({ isLoadingDates: true });
|
||||||
|
expect(wrapper.find("intercept-overlay-stub").exists()).toBe(true);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("handleRequestMoreDates", () => {
|
||||||
|
test("sets isLoadingDates to true while fetching and false after resolving", async () => {
|
||||||
|
let resolve;
|
||||||
|
settleAllPromises.mockReturnValueOnce(
|
||||||
|
new Promise((r) => {
|
||||||
|
resolve = r;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
const fetchPromise = wrapper.vm.handleRequestMoreDates();
|
||||||
|
|
||||||
|
expect(wrapper.vm.isLoadingDates).toBe(true);
|
||||||
|
|
||||||
|
resolve({});
|
||||||
|
await fetchPromise;
|
||||||
|
|
||||||
|
expect(wrapper.vm.isLoadingDates).toBe(false);
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("completes without invoking loadingModal methods (stub has none)", async () => {
|
||||||
|
// The loadingModal stub rendered by shallowMount has no showModal/hideModal.
|
||||||
|
// If those calls were still in handleRequestMoreDates they would throw here.
|
||||||
|
settleAllPromises.mockResolvedValueOnce({});
|
||||||
|
const { wrapper } = setupMocks();
|
||||||
|
await expect(wrapper.vm.handleRequestMoreDates()).resolves.toBeUndefined();
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
|
||||||
|
<interceptOverlay v-if="isLoadingDates" />
|
||||||
<loadingModal notFullScreen ref="loadingModal" />
|
<loadingModal notFullScreen ref="loadingModal" />
|
||||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
||||||
<div class="container page-container-grouped-styles">
|
<div class="container page-container-grouped-styles">
|
||||||
|
|
@ -29,6 +30,7 @@
|
||||||
:zipCode="serviceZipCode"
|
:zipCode="serviceZipCode"
|
||||||
:showFreeFlag="showMobileFreeFlag"
|
:showFreeFlag="showMobileFreeFlag"
|
||||||
:radioGroupName="schedulingRadioGroupName"
|
:radioGroupName="schedulingRadioGroupName"
|
||||||
|
:isLoading="isLoadingDates"
|
||||||
@zip-code-clicked="onMobileZipCodeClicked" />
|
@zip-code-clicked="onMobileZipCodeClicked" />
|
||||||
<inshopSchedulingCard
|
<inshopSchedulingCard
|
||||||
v-for="{ provider } in inShopProvidersAndTimeslots"
|
v-for="{ provider } in inShopProvidersAndTimeslots"
|
||||||
|
|
@ -39,6 +41,7 @@
|
||||||
:provider="provider"
|
:provider="provider"
|
||||||
:timeSlots="getInshopTimeSlotsForSelectedDate(provider.providerNumber)"
|
:timeSlots="getInshopTimeSlotsForSelectedDate(provider.providerNumber)"
|
||||||
:radioGroupName="schedulingRadioGroupName"
|
:radioGroupName="schedulingRadioGroupName"
|
||||||
|
:isLoading="isLoadingDates"
|
||||||
@address-clicked="onInshopAddressClicked(provider)" />
|
@address-clicked="onInshopAddressClicked(provider)" />
|
||||||
<navbar
|
<navbar
|
||||||
cmsWidgetName="FunnelFooterWidget"
|
cmsWidgetName="FunnelFooterWidget"
|
||||||
|
|
@ -60,6 +63,7 @@ import datePicker from "@/layouts/scheduling/date-picker/date-picker";
|
||||||
import mobileSchedulingCard from "@/layouts/scheduling/mobile-scheduling-card/mobile-scheduling-card";
|
import mobileSchedulingCard from "@/layouts/scheduling/mobile-scheduling-card/mobile-scheduling-card";
|
||||||
import inshopSchedulingCard from "@/layouts/scheduling/inshop-scheduling-card/inshop-scheduling-card";
|
import inshopSchedulingCard from "@/layouts/scheduling/inshop-scheduling-card/inshop-scheduling-card";
|
||||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||||
|
import interceptOverlay from "@/ux-components/intercept-overlay/intercept-overlay";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
|
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from "@/constants/schedule-constants";
|
||||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||||
|
|
@ -88,6 +92,20 @@ function toDateString(offsetDays, base = new Date()) {
|
||||||
const SCHEDULE_FETCH_DAYS = 15;
|
const SCHEDULE_FETCH_DAYS = 15;
|
||||||
const SCHEDULING_RADIO_GROUP_NAME = "schedulingTimeSlot";
|
const SCHEDULING_RADIO_GROUP_NAME = "schedulingTimeSlot";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends days from newSlots into entry.timeSlots, initializing it if absent.
|
||||||
|
* @param {{ timeSlots: { days: any[] } | null }} entry
|
||||||
|
* @param {{ days: any[] } | null | undefined} newSlots
|
||||||
|
*/
|
||||||
|
function appendDays(entry, newSlots) {
|
||||||
|
if (!newSlots) return;
|
||||||
|
if (!entry.timeSlots) {
|
||||||
|
entry.timeSlots = newSlots;
|
||||||
|
} else {
|
||||||
|
entry.timeSlots.days = [...(entry.timeSlots.days ?? []), ...(newSlots.days ?? [])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise for inshop time slots for a single provider.
|
* Returns a promise for inshop time slots for a single provider.
|
||||||
* @param {{ startDate: string, endDate: string, providerNumber: string, pageNameToLog: string }} params
|
* @param {{ startDate: string, endDate: string, providerNumber: string, pageNameToLog: string }} params
|
||||||
|
|
@ -294,7 +312,6 @@ export default {
|
||||||
},
|
},
|
||||||
async handleRequestMoreDates() {
|
async handleRequestMoreDates() {
|
||||||
this.isLoadingDates = true;
|
this.isLoadingDates = true;
|
||||||
this.$refs.loadingModal.showModal();
|
|
||||||
|
|
||||||
const newStartDate = toDateString(1, this.datePickerEndDate);
|
const newStartDate = toDateString(1, this.datePickerEndDate);
|
||||||
const newEndDate = toDateString(SCHEDULE_FETCH_DAYS, this.datePickerEndDate);
|
const newEndDate = toDateString(SCHEDULE_FETCH_DAYS, this.datePickerEndDate);
|
||||||
|
|
@ -326,34 +343,17 @@ export default {
|
||||||
|
|
||||||
const resultMap = await settleAllPromises(promiseResultMap);
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
|
|
||||||
|
// Provider order is fixed after beforeRouteEnter, so index keys are stable.
|
||||||
this.inShopProvidersAndTimeslots.forEach((entry, index) => {
|
this.inShopProvidersAndTimeslots.forEach((entry, index) => {
|
||||||
const newSlots = resultMap[`inshopTimeSlots_${index}`];
|
appendDays(entry, resultMap[`inshopTimeSlots_${index}`]);
|
||||||
if (!newSlots) return;
|
|
||||||
if (!entry.timeSlots) {
|
|
||||||
entry.timeSlots = newSlots;
|
|
||||||
} else {
|
|
||||||
entry.timeSlots.days = [
|
|
||||||
...(entry.timeSlots.days ?? []),
|
|
||||||
...(newSlots.days ?? []),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.mobileProviderAndTimeSlot && resultMap.mobileTimeSlots) {
|
if (this.mobileProviderAndTimeSlot) {
|
||||||
const newSlots = resultMap.mobileTimeSlots;
|
appendDays(this.mobileProviderAndTimeSlot, resultMap.mobileTimeSlots);
|
||||||
if (!this.mobileProviderAndTimeSlot.timeSlots) {
|
|
||||||
this.mobileProviderAndTimeSlot.timeSlots = newSlots;
|
|
||||||
} else {
|
|
||||||
this.mobileProviderAndTimeSlot.timeSlots.days = [
|
|
||||||
...(this.mobileProviderAndTimeSlot.timeSlots.days ?? []),
|
|
||||||
...(newSlots.days ?? []),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.datePickerEndDate = newEndDate;
|
this.datePickerEndDate = newEndDate;
|
||||||
this.isLoadingDates = false;
|
this.isLoadingDates = false;
|
||||||
this.$refs.loadingModal.hideModal();
|
|
||||||
},
|
},
|
||||||
forwardButtonAction() {
|
forwardButtonAction() {
|
||||||
const appointmentType = store.getters.order.serviceLocation.appointmentType; // TODO: remove this once we have a proper appointment type
|
const appointmentType = store.getters.order.serviceLocation.appointmentType; // TODO: remove this once we have a proper appointment type
|
||||||
|
|
@ -379,6 +379,7 @@ export default {
|
||||||
mobileSchedulingCard,
|
mobileSchedulingCard,
|
||||||
inshopSchedulingCard,
|
inshopSchedulingCard,
|
||||||
loadingModal,
|
loadingModal,
|
||||||
|
interceptOverlay,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,7 @@ const getDefaultState = () => {
|
||||||
accountName: null,
|
accountName: null,
|
||||||
isClaimAndCoverage: false,
|
isClaimAndCoverage: false,
|
||||||
canScheduleOnline: false,
|
canScheduleOnline: false,
|
||||||
|
isManagedAccount: false,
|
||||||
billToAccountNumber: null,
|
billToAccountNumber: null,
|
||||||
isPia: null,
|
isPia: null,
|
||||||
piaType: null,
|
piaType: null,
|
||||||
|
|
@ -213,6 +214,7 @@ const getDefaultState = () => {
|
||||||
isRecalAcknowledgedForScheduling: "",
|
isRecalAcknowledgedForScheduling: "",
|
||||||
isMSRFeeApplicable: false,
|
isMSRFeeApplicable: false,
|
||||||
isMSRFeeCoveredByInsurance: false,
|
isMSRFeeCoveredByInsurance: false,
|
||||||
|
isNewInsuranceFlow: false,
|
||||||
},
|
},
|
||||||
applicationUser: {
|
applicationUser: {
|
||||||
eventBus: [],
|
eventBus: [],
|
||||||
|
|
@ -386,6 +388,9 @@ export const mutations = {
|
||||||
updateCanScheduleOnline(state, canScheduleOnline) {
|
updateCanScheduleOnline(state, canScheduleOnline) {
|
||||||
state.order.payment.canScheduleOnline = canScheduleOnline;
|
state.order.payment.canScheduleOnline = canScheduleOnline;
|
||||||
},
|
},
|
||||||
|
updateIsManagedAccount(state, isManagedAccount) {
|
||||||
|
state.order.payment.isManagedAccount = isManagedAccount;
|
||||||
|
},
|
||||||
updateBillToAcctNumber(state, billToAcctNumber) {
|
updateBillToAcctNumber(state, billToAcctNumber) {
|
||||||
state.order.payment.billToAccountNumber = billToAcctNumber;
|
state.order.payment.billToAccountNumber = billToAcctNumber;
|
||||||
},
|
},
|
||||||
|
|
@ -451,6 +456,9 @@ export const mutations = {
|
||||||
updateIsMSRFeeCoveredByInsurance(state, isMSRFeeCoveredByInsurance) {
|
updateIsMSRFeeCoveredByInsurance(state, isMSRFeeCoveredByInsurance) {
|
||||||
state.order.isMSRFeeCoveredByInsurance = isMSRFeeCoveredByInsurance;
|
state.order.isMSRFeeCoveredByInsurance = isMSRFeeCoveredByInsurance;
|
||||||
},
|
},
|
||||||
|
updateIsNewInsuranceFlow(state, isNewInsuranceFlow) {
|
||||||
|
state.order.isNewInsuranceFlow = isNewInsuranceFlow;
|
||||||
|
},
|
||||||
updateCashPriceSubTotal(state, cashPriceSubTotal) {
|
updateCashPriceSubTotal(state, cashPriceSubTotal) {
|
||||||
state.order.cashPriceSubTotal =
|
state.order.cashPriceSubTotal =
|
||||||
cashPriceSubTotal === "" ? null : cashPriceSubTotal.toString();
|
cashPriceSubTotal === "" ? null : cashPriceSubTotal.toString();
|
||||||
|
|
@ -2709,6 +2717,7 @@ export const actions = {
|
||||||
billToAccountNumber: order.payment.billToAccountNumber,
|
billToAccountNumber: order.payment.billToAccountNumber,
|
||||||
isClaimAndCoverage: order.payment.isClaimAndCoverage,
|
isClaimAndCoverage: order.payment.isClaimAndCoverage,
|
||||||
canScheduleOnline: order.payment.canScheduleOnline,
|
canScheduleOnline: order.payment.canScheduleOnline,
|
||||||
|
isManagedAccount: order.payment.isManagedAccount,
|
||||||
inactivePromos: order.payment.inactivePromos,
|
inactivePromos: order.payment.inactivePromos,
|
||||||
isCreditCard:
|
isCreditCard:
|
||||||
order.payment.piaType == paymentMethods.CREDIT_CARD ? true : false,
|
order.payment.piaType == paymentMethods.CREDIT_CARD ? true : false,
|
||||||
|
|
@ -3225,17 +3234,23 @@ export const actions = {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
saveIsNewInsuranceFlow(context, isNewInsuranceFlow) {
|
||||||
|
context.commit(storeMutations.UPDATE_IS_NEW_INSURANCE_FLOW, isNewInsuranceFlow);
|
||||||
|
},
|
||||||
|
|
||||||
saveParentAccountNumber(context, parentAccountNumber) {
|
saveParentAccountNumber(context, parentAccountNumber) {
|
||||||
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
|
context.commit(storeMutations.UPDATE_PARENT_ACCT_NUMBER, parentAccountNumber);
|
||||||
},
|
},
|
||||||
saveAccountName(context, accountName) {
|
saveAccountName(context, accountName) {
|
||||||
context.commit(storeMutations.UPDATE_ACCOUNT_NAME, accountName);
|
context.commit(storeMutations.UPDATE_ACCOUNT_NAME, accountName);
|
||||||
},
|
},
|
||||||
saveIsClaimAndCoverage(context, isClaimAndCoverage) {
|
saveInsuranceAccountDetails(
|
||||||
|
context,
|
||||||
|
{ isClaimAndCoverage, canScheduleOnline, isManagedAccount }
|
||||||
|
) {
|
||||||
context.commit(storeMutations.UPDATE_IS_CLAIM_AND_COVERAGE, isClaimAndCoverage);
|
context.commit(storeMutations.UPDATE_IS_CLAIM_AND_COVERAGE, isClaimAndCoverage);
|
||||||
},
|
|
||||||
saveCanScheduleOnline(context, canScheduleOnline) {
|
|
||||||
context.commit(storeMutations.UPDATE_CAN_SCHEDULE_ONLINE, canScheduleOnline);
|
context.commit(storeMutations.UPDATE_CAN_SCHEDULE_ONLINE, canScheduleOnline);
|
||||||
|
context.commit(storeMutations.UPDATE_IS_MANAGED_ACCOUNT, isManagedAccount);
|
||||||
},
|
},
|
||||||
saveBillToAccountNumber(context, billToAccountNumber) {
|
saveBillToAccountNumber(context, billToAccountNumber) {
|
||||||
context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber);
|
context.commit(storeMutations.UPDATE_BILL_TO_ACCT_NUMBER, billToAccountNumber);
|
||||||
|
|
@ -3626,6 +3641,15 @@ export const actions = {
|
||||||
|
|
||||||
return billToAccountNumberResponse.data.toString();
|
return billToAccountNumberResponse.data.toString();
|
||||||
},
|
},
|
||||||
|
// Get Account Details
|
||||||
|
async getAccountDetails(context, { payload: { parentAccountNumber }, pageNameToLog }) {
|
||||||
|
const accountDetailsResponse = await globalMethods.callHttpClient({
|
||||||
|
method: endpoints.GetAccountDetails.method,
|
||||||
|
endpoint: `${endpoints.GetAccountDetails.url}/${parentAccountNumber}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return accountDetailsResponse.data;
|
||||||
|
},
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
// END OF Account Service Calls //
|
// END OF Account Service Calls //
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { shallowMount } from "@vue/test-utils";
|
||||||
|
import interceptOverlay from "./intercept-overlay";
|
||||||
|
|
||||||
|
describe("intercept-overlay.vue", () => {
|
||||||
|
test("renders the overlay container with aria-hidden", () => {
|
||||||
|
const wrapper = shallowMount(interceptOverlay);
|
||||||
|
expect(wrapper.find(".intercept-overlay").exists()).toBe(true);
|
||||||
|
expect(wrapper.find(".intercept-overlay").attributes("aria-hidden")).toBe("true");
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("renders as a single root element with no visible content", () => {
|
||||||
|
const wrapper = shallowMount(interceptOverlay);
|
||||||
|
expect(wrapper.text()).toBe("");
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
});
|
||||||
21
src/ux-components/intercept-overlay/intercept-overlay.vue
Normal file
21
src/ux-components/intercept-overlay/intercept-overlay.vue
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
<template>
|
||||||
|
<div class="intercept-overlay" aria-hidden="true"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "intercept-overlay",
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.intercept-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in a new issue