Continue with Cookie

Handles scenario 1,2,5
Will work on 3,4 while this PR is up.
3: TPA previously chosen
4: finished flow.
This commit is contained in:
Bill Richardson 2024-08-13 16:03:51 -04:00
parent 30f8729dae
commit 449c3ae634
8 changed files with 329 additions and 25 deletions

View file

@ -96,7 +96,7 @@ export function getISSCookie() {
Used to set properties on the ISS cookie.
Takes an object with properties to set. Will overwrite existing properties.
*/
function setISSCookieProperties(properties) {
export function setISSCookieProperties(properties) {
if (typeof properties === 'object') {
const cookie = getISSCookie();
@ -114,20 +114,24 @@ function setISSCookieProperties(properties) {
/*
Will update the cookie if present, or create a new one if not.
*/
export function updateOrCreateISSCookie() {
export function updateOrCreateISSCookie(forceCreate = false) {
const store = useMainStore();
// Set up cookie with all the props.
setISSCookieProperties({
LastTouched: new Date().toUTCString(),
SavedSessionTimeoutDate: store.applicationUser.savedSessionTimeout,
ShouldResetState: false,
ReferralNumber: store.order.referralNumber,
ReferralDate: store.order.referralDate,
ReferralCorrelationId: store.order.referralCorrelationId,
ReferralParentAccountNumber: store.order.parentAccountNumber,
SavedSessionId: store.applicationUser.savedSessionId
});
if (forceCreate || store.order?.referralDate) {
setISSCookieProperties({
LastTouched: new Date().toUTCString(),
SavedSessionTimeoutDate: store.applicationUser.savedSessionTimeout,
ShouldResetState: false,
ReferralNumber: store.order.referralNumber,
ReferralDate: store.order.referralDate,
ReferralCorrelationId: store.order.referralCorrelationId,
ReferralParentAccountNumber: store.order.parentAccountNumber,
SavedSessionId: store.applicationUser.savedSessionId,
VehicleMake: store.order.vehicle?.make,
VehicleModel: store.order.vehicle?.model
});
}
}
/*

View file

@ -78,3 +78,12 @@ export function deepEqual(obj1, obj2) {
return obj1 === obj2;
}
export function getPropertyCaseInsensitive(obj, property) {
const props = [];
for (const i in obj) if (Object.prototype.hasOwnProperty.call(obj, i)) props.push(i);
let prop;
// eslint-disable-next-line no-cond-assign
while (prop = props.pop()) if (prop.toLowerCase() === property.toLowerCase()) return prop;
return property;
}

View file

@ -1,5 +1,4 @@
import { useMainStore } from '@/store';
import { updateOrCreateISSCookie } from '@/helpers/cookie-helper';
import submitType from '@/constants/submit-type';
/*
@ -10,7 +9,6 @@ async function saveSessionHelper(store, { submitAfterSave }) {
if (savedSessionInfo) {
store.setSaveSessionInfo(savedSessionInfo.data);
}
updateOrCreateISSCookie();
}
/*

View file

@ -0,0 +1,99 @@
<template>
<transition
name="fade"
mode="out-in">
<div class="continue-modal-container">
<modal
ref="continueModal"
:headerText="modalHeaderText"
:footerButtonText="modalFooterText"
@isModalOpened="setModalStatus"
@footerButtonEvent="startNewReferral">
<template v-if="1===1">
<p class="mb-2 subheader-text text-center">
{{ modalSubHeaderText }}
</p>
<button
id="btnContinueReferral"
type="button"
class="btn btn-white-blue continue-referral align-items-center justify-content-center mt-2 py-3 px-4 delay w-100"
@click="continueReferral">
{{ modalBodyText }}
</button>
</template>
</modal>
</div>
</transition>
</template>
<script>
import modal from '@/digital-components/modal/modal.vue';
import { getISSCookie } from '@/helpers/cookie-helper.js';
export default {
name: 'continue-modal',
components: {
modal
},
emits: ['continue-previous-referral', 'start-new-referral'],
data() {
return {
isModalOpened: false
};
},
computed: {
getMakeModelString() {
const cookie = getISSCookie();
if (cookie) {
return `${cookie.VehicleMake} ${cookie.VehicleModel}`;
}
return 'CAR NOT SELECTED';
},
modalBodyText() {
return this.getCmsContent('ContinueReferralModalWidget', 'BodyText');
},
modalHeaderText() {
return this.getCmsContent('ContinueReferralModalWidget', 'HeaderText');
},
modalFooterText() {
return this.getCmsContent('ContinueReferralModalWidget', 'FooterText');
},
modalSubHeaderText() {
return this.getCmsContent('ContinueReferralModalWidget', 'SubheaderText')
.replaceAll('{custom:mmFound}', this.getMakeModelString);
}
},
methods: {
openModal() {
this.$refs.continueModal.openModal();
},
setModalStatus(isOpened) {
this.isModalOpened = isOpened;
},
closeModal() {
this.$refs.continueModal.closeModal();
},
continueReferral() {
this.$emit('continue-previous-referral');
},
startNewReferral() {
this.$emit('start-new-referral');
}
}
};
</script>
<style lang="scss" scoped>
.btn-white-blue {
border-radius: 0.5rem;
border-color: $blue;
color: $blue;
font-size: 1rem;
font-weight: 500;
line-height: 1.5rem;
background-color: #ffffff;
--bs-btn-focus-shadow-rgb: 218, 72, 62;
--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
}
</style>

View file

@ -10,6 +10,7 @@
// Supporting files
import issPageValues from '@/router/router-constants/issPage-values';
import { validateISSClientTag, validateISSClientSignature } from '@/helpers/clientauth-helper';
import { getISSCookie, updateOrCreateISSCookie } from '@/helpers/cookie-helper.js';
import { useMainStore } from '@/store';
import applicationConfig from '@/constants/application-config';
@ -41,6 +42,24 @@ export default {
if (isAuthorized) {
this.populateISSConfigValues(clientData);
// Check cookie
const issCookie = getISSCookie();
if (issCookie !== null) {
const clientNumber = clientData.parentAccountNumber;
const cookieClient = issCookie.ReferralParentAccountNumber;
if (clientNumber === cookieClient) {
const savedSessionTimeStamp = new Date(issCookie.SavedSessionTimeoutDate);
const isSavedSessionTimedOut = new Date(new Date().toUTCString()) > savedSessionTimeStamp;
if (!isSavedSessionTimedOut) {
this.mainStore.issConfig.enableContinueFromCookie = true;
}
}
} else {
updateOrCreateISSCookie(true);
}
if (clientData.parameters?.length > 0) {
const finalParams = this.combineClientParameters(clientData.parameters, queryStringParams);
this.populateStoreItemsFromParams(finalParams);

View file

@ -120,6 +120,11 @@
isRequired
isSmallQuestionLabelText
disableAutoFill />
<continueModal
ref="continueModal"
modalWidgetName="ContinueModalWidget"
@continuePreviousReferral="loadReferralFromCookie"
@startNewReferral="startNewReferral" />
<div
id="welcomeFooter"
class="row">
@ -153,6 +158,7 @@ import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import alert from '@/ux-components/alert/alert.vue';
import continueModal from '@/iss-components/continue-modal/continue-modal.vue';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
@ -174,7 +180,9 @@ import states from '@/constants/states';
import globalRules from '@/constants/global-rules';
import routerParams from '@/router/router-constants/router-params';
import MaskaFormattedMasks from '@/constants/maska-masks';
import { getPropertyCaseInsensitive } from '@/helpers/object-helper';
import { saveSession } from '@/helpers/order-helper';
import { getISSCookie, setISSCookieProperties } from '@/helpers/cookie-helper.js';
import bailoutMessage from '@/constants/bailoutMessage';
// define validation rules
@ -191,6 +199,7 @@ export default {
footerImage,
alert,
buttonQuestion,
continueModal,
textboxQuestion,
dropdownQuestion,
siteFooter,
@ -222,6 +231,7 @@ export default {
next((vm) => {
updateCmsSiteHeader(resultMap.globalSiteHeaderCmsContent);
vm.setCmsContent(resultMap.cmsContent);
vm.checkContinueFromCookie();
});
},
setup() {
@ -235,6 +245,7 @@ export default {
data() {
return {
welcomePageModel: this.getWelcomePageModelFromStore(),
answeredContinueModal: false,
displayInvalidZipAlert: false,
duplicates: [],
rules: {
@ -302,11 +313,13 @@ export default {
async forwardButtonAction() {
try {
this.mainStore.updatePolicyData(this.welcomePageModel);
await Promise.allSettled([
this.configureZip().then(async () => await this.mainStore.getBillToInfo()),
this.mainStore.getDuplicateReferrals(),
this.mainStore.getCoveragePolicyInfo()
]);
const promises = [];
promises.push(this.configureZip().then(async () => await this.mainStore.getBillToInfo()));
if (!this.mainStore.order.loadedFromCookie) {
promises.push(this.mainStore.getDuplicateReferrals());
}
promises.push(this.mainStore.getCoveragePolicyInfo());
await Promise.allSettled(promises);
} catch (e) {
console.error(e);
// TODO: Bailout?
@ -339,7 +352,8 @@ export default {
{},
{ [routerParams.SKIP_SAVE_SESSION]: true }
);
} else if (this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false) {
} else if ((this.mainStore.applicationUser.duplicateOrders?.length > 0 ?? false)
&& !this.answeredContinueModal) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_DUPLICATES,
this.$route,
@ -389,6 +403,55 @@ export default {
email: this.mainStore.order.customer.emailAddress,
isPolicyNumberDisabled: this.mainStore.order.policy.isPolicyNumberDisabled
};
},
updateWelcomePageModel(response) {
const getDamageCause = this.findDamageCause(response.policy.damageCause);
this.mainStore.order.policy.damageCause = getDamageCause;
this.welcomePageModel.policyNumber = response.policy.policyNumber;
this.welcomePageModel.policyZipCode = response.policy.policyZipCode;
this.welcomePageModel.dateOfLoss = response.policy.dateOfLoss;
this.welcomePageModel.damageCause = getDamageCause;
this.welcomePageModel.damageState = response.policy.damageState;
this.welcomePageModel.damageCity = response.policy.damageCity;
this.welcomePageModel.isDamageGlassOnly = response.policy.isDamageGlassOnly;
this.welcomePageModel.phoneNumber = response.customer.homePhone;
this.welcomePageModel.email = response.customer.emailAddress;
},
findDamageCause(damageCause) {
const damageCauseOptions = this.DamageCauseOptions;
return getPropertyCaseInsensitive(damageCauseOptions, damageCause);
},
checkContinueFromCookie() {
if (this.mainStore.issConfig.enableContinueFromCookie) {
this.showCookieDrawer();
}
},
showCookieDrawer() {
this.$refs.continueModal.openModal();
},
async loadReferralFromCookie() {
const issCookie = getISSCookie();
if (issCookie) {
const cookieReferral = {
referralNumber: issCookie.ReferralNumber,
responseDate: issCookie.ReferralDate,
parentAccountNumber: issCookie.ReferralParentAccountNumber,
correlationId: issCookie.ReferralCorrelationId
};
await this.mainStore.loadSessionFromCookie(cookieReferral)
.then((response) => {
this.updateWelcomePageModel(response);
this.answeredContinueModal = true;
});
this.$refs.continueModal.closeModal();
}
},
startNewReferral() {
this.mainStore.issConfig.enableContinueFromCookie = false;
this.answeredContinueModal = true;
this.$refs.continueModal.closeModal();
}
}
};
@ -415,4 +478,8 @@ form {
}
}
}
.temp-div {
text-decoration: underline;
color: blue;
}
</style>

View file

@ -17,9 +17,8 @@ import analyticsMixin from '@/mixins/analytics-mixin';
import { saveSession } from '@/helpers/order-helper.js';
import routerParams from '@/router/router-constants/router-params';
import canBailoutNavigateBack from '@/helpers/bailout-helper';
import bailoutMessage from '@/constants/bailoutMessage';
import navigationScenarios from './router-constants/navigation-scenarios';
import submitType from '@/constants/submit-type';
import navigationScenarios from './router-constants/navigation-scenarios';
const routes = [
{
@ -28,6 +27,7 @@ const routes = [
async beforeEnter(to, from, next) {
try {
const issPageToUse = !to.query.issPage ? issPageValues.WELCOME_PAGE : to.query.issPage;
const fromQueryPage = from.query?.issPage;
if ((issPageToUse === issPageValues.ACCESS_DENIED
|| (issPageToUse !== issPageValues.ENTRY_PAGE && !useMainStore().issConfig.parentAccountNumber))
@ -61,7 +61,11 @@ const routes = [
}
// Process ISS cookie.
updateOrCreateISSCookie();
// Skip if Entry Page or Refreshing Welcome page
if (issPageToUse !== issPageValues.ENTRY_PAGE
&& !(issPageToUse === issPageValues.WELCOME_PAGE && fromQueryPage === undefined)) {
updateOrCreateISSCookie();
}
if (router.hasRoute(issPageToUse)) {
// Since our route is already in scope, we can grab the component and call the arePagePrerequisitesValid function.

View file

@ -12,7 +12,6 @@ import issPageValues from '@/router/router-constants/issPage-values';
import damageLocationsSelected from '@/constants/damage-locations-selected';
import coverageStatuses from '@/constants/coverage-statuses';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import { deepClone } from '@/helpers/object-helper';
import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper';
import { paymentMethods } from '@/constants/payment-method-constants';
import webStorageConstants from '@/constants/web-storage-constants';
@ -212,6 +211,7 @@ export const getDefaultState = () => ({
originalDeductible: null,
currentDeductible: null,
carrierPhoneNumber: null,
loadedFromCookie: null,
loadedFromDupeCheck: null,
loadedSessionClearedPreviousData: null,
availableVaps: null
@ -240,6 +240,7 @@ export const getDefaultState = () => ({
isCoverageEnabled: false, // Indicates if we should be calling coverage on this flow.
isClaimRegistrationRequired: false, // Indicates if the claim registration call needs to be made for a client to complete coverage verification.
isAuthenticated: false, // Indicates if user is authenticated or not.
enableContinueFromCookie: false, // Indicates if the continue from cookie should appear.
enableTPAFlow: false, // Indicates if the TPA flow is supported for this client.
successReturnURL: null, // Client URL to return the user to upon a successfull flow completetion (order submission).
failureReturnURL: null, // Client URL to return the user to when they encounter an error or bailout and are unable to complete the flow.
@ -1369,7 +1370,18 @@ export const useMainStore = defineStore({
}, (error) => reject(error));
});
},
async getReferralByPayload(payload) {
return await globalMethods.callHttpClient({
method: endpoints.LoadSession.method,
endpoint: endpoints.LoadSession.url,
payload: {
referralNumber: payload.referralNumber,
referralDate: payload.responseDate,
parentAccountNumber: payload.parentAccountNumber,
referralCorrelationId: payload.correlationId
}
});
},
async loadSession(duplicate) {
const { order, issConfig } = this;
const response = await globalMethods.callHttpClient({
@ -1450,6 +1462,97 @@ export const useMainStore = defineStore({
order.loadedFromDupeCheck = true;
order.loadedSessionClearedPreviousData = false;
},
async loadSessionFromCookie(cookie) {
const { order, issConfig } = this;
// eslint-disable-next-line no-useless-catch
try {
const response = await this.getReferralByPayload(cookie);
const { data } = response;
if (!data) {
// TODO how should we handle this case?
return response;
}
order.customer.address.streetAddress = data.customer?.address?.streetAddress;
order.customer.address.streetAddress2 = data.customer?.address?.streetAddress2;
order.customer.address.city = data.customer?.address?.city;
order.customer.address.state = data.customer?.address?.state;
order.customer.address.zipCode = data.customer?.address?.zipCode;
order.customer.emailAddress = data.customer?.emailAddress;
order.contactInfo.firstName = data?.customer?.firstName;
order.contactInfo.lastName = data?.customer?.lastName;
order.contactInfo.emailAddress = data?.customer?.emailAddress;
order.contactInfo.homePhone = data?.customer?.homePhone;
order.contactInfo.servicePhone = data?.customer?.servicePhone;
order.contactInfo.alternativePhone = data?.customer?.alternativePhone;
order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn;
if (data.insuranceCoverage) {
order.insuranceCoverage.coverageType = data?.insuranceCoverage?.coverageType;
order.insuranceCoverage.coverageStatus = data?.insuranceCoverage?.coverageStatus;
order.insuranceCoverage.claimNumber = data?.insuranceCoverage?.claimNumber;
} else if (data?.payment?.insuranceCoverage) {
if (data?.payment?.insuranceCoverage?.isVerified) {
order.insuranceCoverage.coverageStatus = coverageStatuses.VERIFIED;
}
order.insuranceCoverage.claimNumber = data?.payment?.insuranceCoverage?.claimNumber;
} else {
order.customer.firstName = data?.customer?.firstName;
order.customer.lastName = data?.customer?.lastName;
}
if (order.policy.vehicles.length !== 0 && data.vehicle?.carId) {
order.vehicle.registration.licensePlate = data?.vehicle?.licensePlateNumber;
if (data.vehicle.vin) {
const vehicle = order.policy.vehicles.find((v) => v.vin === data.vehicle.vin);
if (vehicle) {
const vehicleResponse = await this.lookupVehicleByVin(vehicle.vin);
if (vehicleResponse) {
this.updateVehicle({
...vehicleResponse.data,
policyVehicleId: vehicle.id,
vin: vehicle.vin
});
this.updateVehicleCoverage({
noCoverage: noCoverageForSelectedVehicle(vehicle),
deductible: deductibleForSelectedVehicle(vehicle),
repairWaived: repairWaivedForSelectedVehicle(vehicle),
endorsements: endorsementsForSelectedVehicle(vehicle)
});
}
}
}
order.vehicle.year = data.vehicle.year;
order.vehicle.make = data.vehicle.make;
order.vehicle.model = data.vehicle.model;
order.vehicle.style = data.vehicle.style;
}
order.policy.damageCause = data?.policy?.damageCause;
order.policy.damageCity = data?.policy?.damageCity;
order.policy.damageState = data?.policy?.damageState;
order.policy.dateOfLoss = data?.policy?.dateOfLoss;
order.policy.isDamageGlassOnly = data?.policy?.isDamageGlassOnly;
order.policy.policyNumber = data?.policy?.policyNumber;
order.policy.policyZipCode = data?.policy?.policyZipCode;
order.referralNumber = data?.referralNumber;
order.referralDate = data?.referralDate;
order.referralCorrelationId = data?.referralCorrelationId;
order.referralSequenceNumber = data?.referralSequenceNumber;
order.eon = data?.eon;
order.loadedFromCookie = true;
order.loadedSessionClearedPreviousData = false;
issConfig.enableContinueFromCookie = false;
return data;
} catch (ex) {
// TODO how should we handle this case?
throw ex;
}
},
updateCreditCardToken(token) {
this.order.payment.creditCardToken.subscriptionId = token.subscriptionId;
this.order.payment.creditCardToken.expMonth = token.expMonth;
@ -1855,6 +1958,7 @@ export const useMainStore = defineStore({
this.issConfig.styleSheet = '';
this.issConfig.isCoverageEnabled = false;
this.issConfig.isAuthenticated = false;
this.issConfig.enableContinueFromCookie = false;
this.issConfig.enableTPAFlow = false;
this.issConfig.isClaimRegistrationRequired = false;
this.issConfig.successReturnURL = null;