diff --git a/src/helpers/cookie-helper.js b/src/helpers/cookie-helper.js index 7faaa8c4..fbd6caad 100644 --- a/src/helpers/cookie-helper.js +++ b/src/helpers/cookie-helper.js @@ -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 + }); + } } /* diff --git a/src/helpers/object-helper.js b/src/helpers/object-helper.js index 5c1cafd6..1ae4916a 100644 --- a/src/helpers/object-helper.js +++ b/src/helpers/object-helper.js @@ -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; +} diff --git a/src/helpers/order-helper.js b/src/helpers/order-helper.js index 1d3004da..58d8bc38 100644 --- a/src/helpers/order-helper.js +++ b/src/helpers/order-helper.js @@ -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(); } /* diff --git a/src/iss-components/continue-modal/continue-modal.vue b/src/iss-components/continue-modal/continue-modal.vue new file mode 100644 index 00000000..0edf4299 --- /dev/null +++ b/src/iss-components/continue-modal/continue-modal.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/src/layouts/entry-page/entry-page.vue b/src/layouts/entry-page/entry-page.vue index 8fc1d6e5..a75cb2f0 100644 --- a/src/layouts/entry-page/entry-page.vue +++ b/src/layouts/entry-page/entry-page.vue @@ -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); diff --git a/src/layouts/welcome-page/welcome-page.vue b/src/layouts/welcome-page/welcome-page.vue index a41760de..87c38f5f 100644 --- a/src/layouts/welcome-page/welcome-page.vue +++ b/src/layouts/welcome-page/welcome-page.vue @@ -120,6 +120,11 @@ isRequired isSmallQuestionLabelText disableAutoFill /> +
@@ -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; +} diff --git a/src/router/index.js b/src/router/index.js index 8948388d..65265dbb 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -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. diff --git a/src/store/index.js b/src/store/index.js index 99d0c7bb..c6bfe704 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -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;