411 lines
17 KiB
Vue
411 lines
17 KiB
Vue
<template>
|
|
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
|
<loadingModal ref="loadingModal" />
|
|
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
|
|
<div class="container">
|
|
<div class="row">
|
|
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
|
|
<funnelSubHeader
|
|
cmsWidgetName="FunnelSubHeaderWidget"
|
|
class="mt-4 mb-5"
|
|
alignLeft />
|
|
<textboxQuestion
|
|
isRequired
|
|
isDisabled
|
|
class="mb-4 locked-input"
|
|
cmsWidgetName="InsuranceCompanyNameWidget"
|
|
v-model="insuranceCompanyName"
|
|
ref="insuranceCompanyName"
|
|
customInputId="insuranceCompanyName"
|
|
validationRules="insurance-company-name-required" />
|
|
|
|
<textboxQuestion
|
|
isRequired
|
|
class="mb-4"
|
|
cmsWidgetName="PolicyNumberWidget"
|
|
v-model="policyNumber"
|
|
inputId="policyNumber"
|
|
placeholderText="Type your policy number"
|
|
validationRules="policy-number-required" />
|
|
|
|
<datePickerPopup
|
|
isRequired
|
|
class="mb-4"
|
|
cmsWidgetName="DateOfLossWidget"
|
|
v-model="dateOfLoss"
|
|
customInputId="dateOfLoss"
|
|
placeholderText="MM/DD/YYYY"
|
|
validationRules="date-of-loss-required"
|
|
format="MM/dd/yyyy"
|
|
modelType="yyyy-MM-dd"
|
|
:enableTimePicker="false"
|
|
:clearable="false"
|
|
:textInput="true"
|
|
:maxDate="today"
|
|
:preventMinMaxNavigation="true" />
|
|
|
|
<textboxQuestion
|
|
v-if="displayClaimNumber"
|
|
class="mb-4"
|
|
cmsWidgetName="ClaimNumberWidget"
|
|
v-model="claimNumber"
|
|
inputId="claimNumber"
|
|
maxLength="8"
|
|
validationRules="claim-number-numeric|claim-number-format" />
|
|
|
|
<dropdownQuestion
|
|
isRequired
|
|
:questionText="damageTypesQuestionText"
|
|
class="mb-4"
|
|
v-model="damageCause"
|
|
:cmsWidgetName="damageTypesWidgetName"
|
|
customDropdownId="damageTypes"
|
|
:options="damageTypesOptions"
|
|
:valueAsKey="true"
|
|
validationRules="damage-types-required"
|
|
:labelBold="true" />
|
|
|
|
<hr class="my-4" />
|
|
|
|
<textBlock cmsWidgetName="AddressSectionWidget" class="dark" typeStyle="h5" />
|
|
|
|
<textboxQuestion
|
|
isRequired
|
|
class="mb-4"
|
|
cmsWidgetName="StreetAddressWidget"
|
|
v-model="streetAddress"
|
|
inputId="streetAddress"
|
|
validationRules="street-address-required" />
|
|
|
|
<textboxQuestion
|
|
isRequired
|
|
class="mb-4"
|
|
cmsWidgetName="ApartmentWidget"
|
|
v-model="streetAddress2"
|
|
inputId="streetAddress2" />
|
|
|
|
<textboxQuestion
|
|
isRequired
|
|
class="mb-4"
|
|
cmsWidgetName="CityWidget"
|
|
v-model="city"
|
|
inputId="city"
|
|
validationRules="city-required" />
|
|
|
|
<dropdownQuestion
|
|
class="mb-4"
|
|
customDropdownId="policyState"
|
|
cmsWidgetName="StateQuestionWidget"
|
|
v-model="policyState"
|
|
ref="policyState"
|
|
:options="stateOptions"
|
|
validationRules="state-required"
|
|
autocomplete="address-level1"
|
|
placeHolderText="Select State"
|
|
:labelBold="true" />
|
|
|
|
<textboxQuestion
|
|
isRequired
|
|
class="mb-4"
|
|
cmsWidgetName="ZipQuestionWidget"
|
|
v-model="policyZip"
|
|
inputId="policyZip"
|
|
maxLength="5"
|
|
validationRules="zip-code-required|zip-code-format" />
|
|
|
|
<hr class="mb-5" />
|
|
|
|
<saveProgressModalQuestion
|
|
modalWidgetName="SaveProgressModalWidget"
|
|
modalName="SaveProgressModal"
|
|
v-if="showSaveProgressModal"
|
|
pageName="insurance-details" />
|
|
|
|
<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 textboxQuestion from "@/digital-components/textbox-question/textbox-question";
|
|
import datePickerPopup from "@/digital-components/date-picker-popup/date-picker-popup";
|
|
import dropdownQuestion from "@/digital-components/dropdown-question/dropdown-question";
|
|
import textBlock from "@/digital-components/text-block/text-block";
|
|
import { Form, defineRule } from "vee-validate";
|
|
import store from "@/store";
|
|
import { errorMessages } from "@/constants/error-messages";
|
|
import { required } from "@/helpers/validation-rules";
|
|
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
|
import { settleAllPromises } from "@/helpers/layout-helper";
|
|
import { stateOptionsInternational } from "@/constants/state-options";
|
|
import { regex } from "@/helpers/validation-rules";
|
|
import { coverageStatus, coverageStatusEnum } from "@/constants/insurance";
|
|
import saveProgressModalQuestion from "@/fmg-components/save-progress-modal-question/save-progress-modal-question";
|
|
import { hasSaveProgressContactInStore } from "@/helpers/save-progress-popup-contact-helper";
|
|
import { debugLog } from "@/helpers/debug-log-helper";
|
|
import {
|
|
flushPagePrereqsLogs,
|
|
hasServiceZipInfo,
|
|
hasGlassPartsOrRepairInfo,
|
|
hasInsuranceInfo,
|
|
} from "@/helpers/page-prerequisites-helper.js";
|
|
|
|
// DEFINE VALIDATION RULES
|
|
defineRule(
|
|
"insurance-company-name-required",
|
|
required(errorMessages.INSURANCE_COMPANY_NAME_REQUIRED)
|
|
);
|
|
defineRule("policy-number-required", required(errorMessages.POLICY_NUMBER_REQUIRED));
|
|
defineRule("date-of-loss-required", required(errorMessages.DATE_OF_LOSS_REQUIRED));
|
|
defineRule("damage-types-required", required(errorMessages.DAMAGE_TYPES_REQUIRED));
|
|
defineRule("street-address-required", required(errorMessages.STREET_ADDRESS_REQUIRED));
|
|
defineRule("city-required", required(errorMessages.CITY_REQUIRED));
|
|
defineRule("state-required", required(errorMessages.STATE_REQUIRED));
|
|
defineRule("zip-code-required", required(errorMessages.ZIP_CODE_REQUIRED));
|
|
defineRule("zip-code-format", regex(/(^\d{5}$)|(^\d{5}-\d{4}$)/, errorMessages.ZIP_CODE_FORMAT));
|
|
defineRule("claim-number-numeric", regex(/^\d+$/, errorMessages.CLAIM_NUMBER_VALID));
|
|
defineRule("claim-number-format", regex(/^\d{6,8}$/, errorMessages.CLAIM_NUMBER_FORMAT));
|
|
|
|
export default {
|
|
name: "insurance-details",
|
|
mixins: [],
|
|
data() {
|
|
return {
|
|
clientConfig: {},
|
|
insuranceCompanyName: this.getInsuranceCompanyNameFromStore(),
|
|
policyNumber: this.getPolicyNumberFromStore(),
|
|
dateOfLoss: this.getDateOfLossFromStore(),
|
|
damageCause: this.getDamageCauseFromStore(),
|
|
streetAddress: this.getStreetAddressFromStore(),
|
|
streetAddress2: this.getStreetAddress2FromStore(),
|
|
city: this.getCityFromStore(),
|
|
policyState: this.getPolicyStateFromStore(),
|
|
policyZip: this.getPolicyZipFromStore(),
|
|
claimNumber: this.getClaimNumberFromStore(),
|
|
showSaveProgressModal: null,
|
|
isManagedAccount: this.getIsManagedAccountFromStore(),
|
|
};
|
|
},
|
|
components: {
|
|
Form,
|
|
funnelHeader,
|
|
navbar,
|
|
funnelSubHeader,
|
|
textboxQuestion,
|
|
datePickerPopup,
|
|
dropdownQuestion,
|
|
textBlock,
|
|
saveProgressModalQuestion,
|
|
},
|
|
// 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 = `unmanaged_${store.getters.order.payment.parentAccountNumber}`;
|
|
const clientConfigPromise = fetchCmsContentForPage(clientConfigPageName);
|
|
const promiseResultMap = [
|
|
{
|
|
resultKey: "cmsContent",
|
|
promise: cmsContentPromise,
|
|
},
|
|
{
|
|
resultKey: "clientConfig",
|
|
promise: clientConfigPromise,
|
|
},
|
|
];
|
|
const resultMap = await settleAllPromises(promiseResultMap);
|
|
const showSaveProgressModal = !hasSaveProgressContactInStore(store.getters.order?.customer);
|
|
next((vm) => {
|
|
vm.setCmsContent(resultMap.cmsContent);
|
|
vm.showSaveProgressModal = showSaveProgressModal;
|
|
vm.clientConfig = resultMap.clientConfig ?? {};
|
|
// The load-session API can return damageCause in a different case than
|
|
// the CMS answer values. Reconcile it so the dropdown pre-selects.
|
|
vm.damageCause = vm.matchDamageCauseToOption(vm.damageCause);
|
|
debugLog(
|
|
`insurance-details clientConfig::${clientConfigPageName}`,
|
|
JSON.stringify(vm.clientConfig)
|
|
);
|
|
});
|
|
},
|
|
|
|
computed: {
|
|
today() {
|
|
return new Date();
|
|
},
|
|
parsedClientConfig() {
|
|
const raw = this.clientConfig?.ConfigWidget?.Text;
|
|
if (!raw) return {};
|
|
try {
|
|
return JSON.parse(raw);
|
|
} catch (err) {
|
|
console.warn("Failed to parse clientConfig.ConfigWidget.Text", err);
|
|
return {};
|
|
}
|
|
},
|
|
displayClaimNumber() {
|
|
return this.parsedClientConfig?.displayClaimNumberField ?? false;
|
|
},
|
|
stateOptions() {
|
|
return stateOptionsInternational;
|
|
},
|
|
damageTypesWidgetName() {
|
|
return this.isManagedAccount ? "DamageTypesWidget" : "UnmanagedDamageTypesWidget";
|
|
},
|
|
damageCauseQuestionText() {
|
|
if (this.isManagedAccount) {
|
|
return this.getCmsContent("DamageTypesWidget", "QuestionText");
|
|
} else {
|
|
return this.getCmsContent("UnmanagedDamageTypesWidget", "QuestionText");
|
|
}
|
|
},
|
|
damageTypesOptions() {
|
|
const options = {};
|
|
|
|
const answers = this.isManagedAccount
|
|
? this.getCmsContent("DamageTypesWidget", "Answers")
|
|
: this.getCmsContent("UnmanagedDamageTypesWidget", "Answers");
|
|
if (!Array.isArray(answers)) {
|
|
return options;
|
|
}
|
|
for (const answer of answers) {
|
|
options[answer.Name] = answer.Text;
|
|
}
|
|
|
|
return options;
|
|
},
|
|
},
|
|
methods: {
|
|
getIsManagedAccountFromStore() {
|
|
return store.getters.order?.payment?.isManagedAccount ?? false;
|
|
},
|
|
getInsuranceCompanyNameFromStore() {
|
|
return store.getters.order.policy.insuranceCompanyName;
|
|
},
|
|
getPolicyNumberFromStore() {
|
|
return store.getters.order.policy.policyNumber;
|
|
},
|
|
getDateOfLossFromStore() {
|
|
return store.getters.order.damage.dateOfLoss ?? "";
|
|
},
|
|
getDamageCauseFromStore() {
|
|
return store.getters.order.damage.damageCause ?? "";
|
|
},
|
|
// Maps a stored damageCause to the matching dropdown option value using a
|
|
// case-insensitive comparison (load-session can return it uppercased).
|
|
// Returns the canonical option value, or the original value if no match.
|
|
matchDamageCauseToOption(value) {
|
|
if (!value) {
|
|
return value;
|
|
}
|
|
const optionValues = Object.values(this.damageTypesOptions ?? {});
|
|
const match = optionValues.find(
|
|
(option) => option?.toLowerCase() === value.toLowerCase()
|
|
);
|
|
return match ?? value;
|
|
},
|
|
getStreetAddressFromStore() {
|
|
return store.getters.order.customer.address.streetAddress ?? "";
|
|
},
|
|
getStreetAddress2FromStore() {
|
|
return store.getters.order.customer.address.streetAddress2 ?? "";
|
|
},
|
|
getCityFromStore() {
|
|
return store.getters.order.customer.address.city ?? "";
|
|
},
|
|
getPolicyStateFromStore() {
|
|
return store.getters.order.customer.address.state ?? "";
|
|
},
|
|
getPolicyZipFromStore() {
|
|
return store.getters.order.customer.address.zipCode ?? "";
|
|
},
|
|
getClaimNumberFromStore() {
|
|
return store.getters.order.payment.insuranceCoverage.claimNumber ?? "";
|
|
},
|
|
backButtonAction() {
|
|
this.$router.navigateWithoutSaving(
|
|
this.navigationScenarios.CLICKED_BACK,
|
|
this.pageName
|
|
);
|
|
},
|
|
async forwardButtonAction() {
|
|
this.dispatchStoreAction(
|
|
this.storeActions.SAVE_INSURANCE_DETAILS,
|
|
{
|
|
policyNumber: this.policyNumber,
|
|
streetAddress: this.streetAddress,
|
|
streetAddress2: this.streetAddress2,
|
|
city: this.city,
|
|
state: this.policyState,
|
|
zipCode: this.policyZip,
|
|
claimNumber: this.claimNumber,
|
|
currentDeductible: 7777,
|
|
originalDeductible: 7777,
|
|
coverageStatus: coverageStatusEnum(coverageStatus.PENDING),
|
|
coverageSubStatus: "",
|
|
},
|
|
false
|
|
);
|
|
|
|
this.dispatchStoreAction(
|
|
this.storeActions.SAVE_DAMAGE_DETAILS,
|
|
{
|
|
dateOfLoss: this.dateOfLoss,
|
|
damageCause: this.damageCause,
|
|
},
|
|
false
|
|
);
|
|
|
|
this.$router.navigateWithSaving(
|
|
this.navigationScenarios.CLICKED_FORWARD,
|
|
this.pageName
|
|
);
|
|
},
|
|
arePagePrerequisitesValid() {
|
|
const order = store.getters.order;
|
|
const logQueue = [];
|
|
|
|
const serviceZip = hasServiceZipInfo(order, logQueue);
|
|
const glassPartsOrRepair = hasGlassPartsOrRepairInfo(order, logQueue);
|
|
const preReqResult = serviceZip && glassPartsOrRepair;
|
|
|
|
flushPagePrereqsLogs("insurance-details.vue", preReqResult, logQueue);
|
|
return preReqResult;
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.locked-input {
|
|
:deep(.input-wrapper) {
|
|
&::after {
|
|
content: "";
|
|
position: absolute;
|
|
top: 50%;
|
|
right: 1rem;
|
|
transform: translateY(-50%);
|
|
width: 1rem;
|
|
height: 1rem;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236c757d'%3E%3Cpath d='M8 1a3.5 3.5 0 0 0-3.5 3.5V7H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V8a1 1 0 0 0-1-1h-.5V4.5A3.5 3.5 0 0 0 8 1zm-2 6V4.5a2 2 0 1 1 4 0V7H6z'/%3E%3C/svg%3E");
|
|
background-repeat: no-repeat;
|
|
background-position: center;
|
|
background-size: contain;
|
|
pointer-events: none;
|
|
}
|
|
.form-control {
|
|
padding-right: 2.5rem;
|
|
}
|
|
}
|
|
}
|
|
</style>
|