DigitalConsumer.FixMyGlass/src/layouts/coverage-statement/coverage-statement.vue
Carl Nation c21ff3c249 CASH-2844 more non C&C cleanup
CASH-2844 more non C&C cleanup.  load session to handle any part changes(fees) changed by safelite api.
dynamic damage types form managed vs unmanaged accounts
2026-06-24 10:31:30 -04:00

266 lines
10 KiB
Vue

<template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<funnelHeader
cmsWidgetName="FunnelHeaderWidget"
ref="funnelHeader"
:overrideImageSrc="clientLogoImageSrc" />
<div class="page-gradient"></div>
<div class="container">
<div class="row">
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
<div v-if="showUnverifiedContent" class="my-5" ref="unverified-block">
<funnelSubHeader cmsWidgetName="SubHeaderWidgetUnverified" alignLeft />
<customerInstructions
:cmsWidgetName="getUnverifiedInstructionsWidgetName"
:isRepair="isRepair"
v-on="{ textLinkClicked: openModalAction }" />
</div>
<div v-if="showVerifiedContent" class="my-5" ref="verified-block">
<funnelSubHeader cmsWidgetName="SubHeaderWidgetVerified" alignLeft />
<priceDisplay
cmsWidgetName="PriceWidgetVerified"
:price="deductibleAmount" />
<customerInstructions
cmsWidgetName="InstructionsWidgetVerified"
v-on="{ textLinkClicked: openModalAction }" />
<contentGroupModal ref="OemModal" cmsWidgetName="OemModalWidget" />
<afterpayBreakout
cmsWidgetName="AfterpayBreakoutWidget"
:totalAmount="cashPrice" />
</div>
<div v-if="showItacContent" class="my-5" ref="itac-block">
<funnelSubHeader
class="mb-4"
cmsWidgetName="SubHeaderWidgetItac"
alignLeft />
<div class="price-compare">
<priceDisplay
cmsWidgetName="DeductibleWidgetItac"
:price="deductibleAmount" />
<priceDisplay cmsWidgetName="PriceWidgetItac" :price="cashPrice" />
</div>
</div>
<div v-if="showNoCompContent" class="my-5" ref="nocomp-block">
<funnelSubHeader
class="mb-4"
cmsWidgetName="SubHeaderWidgetNocomp"
alignLeft />
<textBlock cmsWidgetName="NocompHeaderWidget" fontWeight="bold" />
<textBlock cmsWidgetName="NocompCopyWidget" />
<priceDisplay
cmsWidgetName="PriceWidgetNocomp"
:price="cashPrice"
class="my-4" />
<afterpayBreakout
cmsWidgetName="AfterpayBreakoutWidget"
:totalAmount="cashPrice" />
</div>
<saveProgressModalQuestion
modalWidgetName="SaveProgressModalWidget"
modalName="SaveProgressModal"
pageName="coverage-statement" />
<navbar
cmsWidgetName="FunnelFooterWidget"
ref="navbar"
:isForwardActionDisabled="!meta.valid"
@back-clicked="backButtonAction"
@ForwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</Form>
</template>
<script>
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar";
import funnelSubHeader from "@/fmg-components/funnel-sub-header/funnel-sub-header";
import { Form } from "vee-validate";
import store from "@/store";
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper";
import customerInstructions from "./customer-instructions/customer-instructions.vue";
import priceDisplay from "./price-display/price-display.vue";
import saveProgressModalQuestion from "@/fmg-components/save-progress-modal-question/save-progress-modal-question.vue";
import afterpayBreakout from "../payment-method/afterpay-breakout/afterpay-breakout.vue";
import modal from "@/digital-components/modal/modal";
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal.vue";
import textBlock from "@/digital-components/text-block/text-block.vue";
import { debugLog } from "@/helpers/debug-log-helper";
import { loadSessionIfPresent } from "@/helpers/heritage-integration/order-helper";
export default {
name: "coverage-statement",
mixins: [],
data() {
return {
isClaimAndCoverage: this.isClaimAndCoverageFromStore(),
isVerified: this.isVerifiedInsuranceFromStore(),
isItac: this.isItacFromStore(),
isNoComp: this.isNoCompFromStore(),
isRecalibrationOnOrder: this.isRecalibrationOnOrderFromStore(),
isRepair: this.isRepairFromStore(),
clientConfig: {},
};
},
components: {
Form,
funnelHeader,
navbar,
funnelSubHeader,
customerInstructions,
priceDisplay,
saveProgressModalQuestion,
afterpayBreakout,
contentGroupModal,
textBlock,
},
// Ensure CMS content is fetched during route navigation without depending on `to`/`from`
async beforeRouteEnter(to, from, next) {
const pageName = to.name;
const cmsContentPromise = fetchCmsContentForPage(pageName);
const clientConfigPageName = `client_${store.getters.order.payment.parentAccountNumber}`;
const promiseResultMap = [
{
resultKey: "cmsContent",
promise: cmsContentPromise,
},
];
// Only fetch the client-specific config when this is a claim & coverage order.
if (store.getters.order?.payment?.isClaimAndCoverage) {
promiseResultMap.push({
resultKey: "clientConfig",
promise: fetchCmsContentForPage(clientConfigPageName),
});
}
const resultMap = await settleAllPromises(promiseResultMap);
next((vm) => {
vm.setCmsContent(resultMap.cmsContent);
vm.clientConfig = resultMap.clientConfig ?? {};
debugLog(
`coverage-statement clientConfig::${clientConfigPageName}`,
JSON.stringify(vm.clientConfig)
);
});
},
methods: {
isClaimAndCoverageFromStore() {
return store.getters.order?.payment?.isClaimAndCoverage;
},
isVerifiedInsuranceFromStore() {
return store.getters.order?.payment?.insuranceCoverage.isVerified;
},
isItacFromStore() {
return store.getters.order?.policy?.isItac;
},
isNoCompFromStore() {
return store.getters.order?.policy?.isNoComp;
},
isRecalibrationOnOrderFromStore() {
return store.getters.isRecalibrationOnOrder;
},
isRepairFromStore() {
return store.getters.order?.damage?.isRepair;
},
backButtonAction() {
if (!this.isClaimAndCoverage) {
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_BACK_NON_CLAIM_AND_COVERAGE,
this.pageName
);
return;
}
if (this.isRecalibrationOnOrder) {
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_BACK_RECALIBRATION_INFO,
this.pageName
);
return;
}
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_BACK,
this.pageName
);
},
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.navigationScenarios.CLICKED_FORWARD,
this.pageName
);
},
arePagePrerequisitesValid() {
return true;
},
openModalAction(modalName) {
this.$refs[modalName]?.openModal();
},
},
computed: {
showVerifiedContent() {
return this.isVerified && !this.isItac && !this.isNoComp;
},
showUnverifiedContent() {
return !this.isVerified;
},
showItacContent() {
return this.isItac;
},
showNoCompContent() {
return this.isNoComp;
},
getUnverifiedInstructionsWidgetName() {
if (!this.isVerified) {
if (this.isRepair) {
return "InstructionsWidgetUnverifiedRepair";
}
return "InstructionsWidgetUnverified";
}
return "";
},
clientLogoImageSrc() {
return this.clientConfig?.ClientLogoWidget?.Image || "";
},
deductibleAmount() {
return Number(this.$store.getters.order.policy.currentDeductible);
},
cashPrice() {
const lineItems = this.$store.getters.order.lineItems;
const lineItemsFlattened = [
...(lineItems?.glassParts ?? []),
...(lineItems?.promos ?? []),
...(lineItems?.supportingItems ?? []),
...(lineItems?.vaps ?? []),
];
const price = this.getTotalPriceOfAllLineItemsAndChildParts(lineItemsFlattened, false);
return price;
},
},
};
</script>
<style lang="scss">
.funnel-sub-header {
margin-bottom: 1.5rem;
}
.price-compare {
display: flex;
> :not(:last-child) {
padding-right: 1em;
margin-right: 1em;
border-right: 2px solid $gray-300;
}
}
</style>