merging with develop
This commit is contained in:
commit
ca97fbd658
20 changed files with 558 additions and 312 deletions
17
src/App.vue
17
src/App.vue
|
|
@ -39,6 +39,23 @@ export default {
|
|||
}
|
||||
}
|
||||
};
|
||||
// Add a global Javascript exception handler for logging exceptions, this handler will log when there is an uncaught exception
|
||||
window.onerror = (msg, url, line, col, error) => {
|
||||
// Log the windows error
|
||||
// Note that col & error are new to the HTML 5 spec and may not be
|
||||
// supported in every browser. It worked for me in Chrome.
|
||||
global.$logger.logError(msg, {
|
||||
url: url,
|
||||
line: line,
|
||||
column: col ?? "",
|
||||
error: error ?? "",
|
||||
});
|
||||
|
||||
// If you return true, then error alerts (like in older versions of
|
||||
// Internet Explorer) will be suppressed.
|
||||
var suppressErrorAlert = true;
|
||||
return suppressErrorAlert;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
|
|
|||
|
|
@ -22,7 +22,8 @@ const applicationConfig = Object.freeze({
|
|||
GOOGLE_CALENDAR: 'https://www.google.com/calendar/render?action=TEMPLATE',
|
||||
YAHOO_CALENDAR: 'https://calendar.yahoo.com/?v=60',
|
||||
OUTLOOK_CALENDAR:
|
||||
'https://outlook.office.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent'
|
||||
'https://outlook.office.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent',
|
||||
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging"
|
||||
});
|
||||
|
||||
export default applicationConfig;
|
||||
|
|
|
|||
11
src/constants/axios-response-interceptor-messages.js
Normal file
11
src/constants/axios-response-interceptor-messages.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
const axiosResponseInterceptorMessages = {
|
||||
NETWORK_ERROR:
|
||||
"A network error occurred. " +
|
||||
"This could be a bad URL, a CORS issue, or a dropped internet connection. " +
|
||||
"It is impossible for us to know.",
|
||||
STATUS_CODE_ERROR: "Status Code Error",
|
||||
NO_RESPONSE_ERROR: "The request was made but no response was received",
|
||||
GENERIC_ERROR: "Error",
|
||||
};
|
||||
|
||||
export default axiosResponseInterceptorMessages;
|
||||
|
|
@ -141,11 +141,11 @@ const endpoints = Object.freeze({
|
|||
method: 'POST'
|
||||
},
|
||||
LookupVinByAddress: {
|
||||
url: `${VEHICLE_BASE_URL}/lookup-by-address`,
|
||||
url: `${VEHICLE_BASE_URL}/lookup-vin-by-address`,
|
||||
method: 'POST'
|
||||
},
|
||||
LookupVinByPlate: {
|
||||
url: `${VEHICLE_BASE_URL}/lookup-by-plate`,
|
||||
url: `${VEHICLE_BASE_URL}/lookup-vin-by-plate`,
|
||||
method: 'POST'
|
||||
},
|
||||
InitializeSession: {
|
||||
|
|
|
|||
8
src/constants/logging-endpoint-methods.js
Normal file
8
src/constants/logging-endpoint-methods.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
const loggingEndpointMethods = {
|
||||
LOG_INFORMATION: "log-information",
|
||||
LOG_WARNING: "log-warning",
|
||||
LOG_ERROR: "log-error",
|
||||
LOG_CRITICAL: "log-critical",
|
||||
};
|
||||
|
||||
export default loggingEndpointMethods;
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
const submitType = Object.freeze({
|
||||
SAFELITE: 0,
|
||||
TPA: 1
|
||||
TPA: 1,
|
||||
BAILOUT: 2
|
||||
});
|
||||
|
||||
export default submitType;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,50 @@ import { useMainStore } from '@/store';
|
|||
import applicationConfig from '@/constants/application-config.js';
|
||||
import { GaCategories, GaActions, GaLabels } from '@/constants/analytics';
|
||||
import headerKeys from '@/constants/header-keys';
|
||||
import axiosResponseInterceptorMessages from "@/constants/axios-response-interceptor-messages.js";
|
||||
|
||||
// Add a response interceptor for global axios error handing.
|
||||
axios.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
let rejectionError = "";
|
||||
if (typeof error.response === "undefined") {
|
||||
// The request was not made, could be a bad url, bad connection or a CORS error.
|
||||
rejectionError = {
|
||||
message:
|
||||
"A network error occurred. " +
|
||||
"This could be a CORS issue or a dropped internet connection. " +
|
||||
"It is impossible for us to know.",
|
||||
cause: error,
|
||||
response: error,
|
||||
message: axiosResponseInterceptorMessages.NETWORK_ERROR
|
||||
};
|
||||
} else if (error.response) {
|
||||
// The request was made and the server responded with a status code
|
||||
// that falls out of the range of 2xx
|
||||
rejectionError = {
|
||||
response: error.response,
|
||||
message: axiosResponseInterceptorMessages.STATUS_CODE_ERROR,
|
||||
};
|
||||
} else if (error.request) {
|
||||
// The request was made but no response was received
|
||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||
// http.ClientRequest in node.js
|
||||
rejectionError = {
|
||||
response: error.request,
|
||||
message: axiosResponseInterceptorMessages.NO_RESPONSE_ERROR,
|
||||
};
|
||||
} else {
|
||||
// Something happened in setting up the request that triggered an Error
|
||||
rejectionError = {
|
||||
response: error.message,
|
||||
message: axiosResponseInterceptorMessages.GENERIC_ERROR,
|
||||
};
|
||||
}
|
||||
|
||||
return Promise.reject(rejectionError);
|
||||
}
|
||||
);
|
||||
|
||||
export default {
|
||||
callHttpClient({ method, endpoint, payload, logApiCall = true }) {
|
||||
|
|
@ -37,13 +81,23 @@ export default {
|
|||
return resolve(response);
|
||||
},
|
||||
(error) => {
|
||||
window.console.error(error);
|
||||
|
||||
// implement if analytics service is down
|
||||
if (endpoint.includes('analytics')) {
|
||||
return resolve({ data: '' });
|
||||
if (logApiCall) {
|
||||
analyticsMixIn.methods.pushEventToGA(
|
||||
GaCategories.API_RESPONSE,
|
||||
GaActions.RESULT,
|
||||
`${GaLabels.ERROR}_${endpoint}`,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (error.response.status != "404") {
|
||||
|
||||
|
||||
global.$logger.logError(
|
||||
`${method}: ${endpoint}: ${error.message}`,
|
||||
error.response
|
||||
);
|
||||
}
|
||||
return reject(error.response);
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,13 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
|||
jest.mock('axios');
|
||||
jest.mock('@/mixins/analytics-mixin');
|
||||
|
||||
global.$logger = {
|
||||
logInformation: jest.fn(),
|
||||
logWarning: jest.fn(),
|
||||
logError: jest.fn(),
|
||||
logCritical: jest.fn(),
|
||||
};
|
||||
|
||||
/** @ignore */
|
||||
function setupMocksForHttpClient({
|
||||
endpoint = null,
|
||||
|
|
|
|||
93
src/helpers/logger.js
Normal file
93
src/helpers/logger.js
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import applicationConfig from "@/constants/application-config.js";
|
||||
import axios from "axios";
|
||||
import { useMainStore } from "@/store";
|
||||
import loggingEndpointMethods from "@/constants/logging-endpoint-methods";
|
||||
|
||||
import headerKeys from "@/constants/header-keys";
|
||||
|
||||
export class Logger {
|
||||
logInformation(message, details) {
|
||||
this.writeLogEntry(
|
||||
loggingEndpointMethods.LOG_INFORMATION,
|
||||
this.formatLogEntry(message, details)
|
||||
);
|
||||
}
|
||||
|
||||
logWarning(message, details) {
|
||||
this.writeLogEntry(
|
||||
loggingEndpointMethods.LOG_WARNING,
|
||||
this.formatLogEntry(message, details)
|
||||
);
|
||||
}
|
||||
|
||||
logError(message, details) {
|
||||
this.writeLogEntry(loggingEndpointMethods.LOG_ERROR, this.formatLogEntry(message, details));
|
||||
}
|
||||
|
||||
logCritical(message, details) {
|
||||
this.writeLogEntry(
|
||||
loggingEndpointMethods.LOG_CRITICAL,
|
||||
this.formatLogEntry(message, details)
|
||||
);
|
||||
}
|
||||
|
||||
formatLogEntry(message, details) {
|
||||
return `Application: ${applicationConfig.APPLICATION_NAME}\n${message}\n${
|
||||
details ? JSON.stringify(details, undefined, 2) : ""
|
||||
}`;
|
||||
}
|
||||
|
||||
writeLogEntry(endpoint, logEntry) {
|
||||
const store = useMainStore();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
// If running locally or in the Dev environment show the log entries in the console.
|
||||
if (
|
||||
applicationConfig.CURRENT_ENVIRONMENT === "Localhost" ||
|
||||
applicationConfig.CURRENT_ENVIRONMENT === "Dev" ||
|
||||
applicationConfig.CURRENT_ENVIRONMENT === "SysTest"
|
||||
) {
|
||||
switch (endpoint) {
|
||||
case loggingEndpointMethods.LOG_INFORMATION:
|
||||
console.info(logEntry);
|
||||
break;
|
||||
case loggingEndpointMethods.LOG_WARNING:
|
||||
console.warn(logEntry);
|
||||
break;
|
||||
case loggingEndpointMethods.LOG_ERROR:
|
||||
console.error(logEntry);
|
||||
break;
|
||||
case loggingEndpointMethods.LOG_CRITICAL:
|
||||
console.error(logEntry);
|
||||
break;
|
||||
default:
|
||||
console.log(logEntry);
|
||||
}
|
||||
}
|
||||
|
||||
const url =
|
||||
applicationConfig.CONSUMER_CF_DISTRO + applicationConfig.FRONTEND_LOGGER_PATH;
|
||||
const headers = {
|
||||
[headerKeys.EXPERIMENT]: JSON.stringify(store.experimentSettings),
|
||||
};
|
||||
|
||||
axios({
|
||||
method: "POST",
|
||||
url: `${url}/${endpoint}`,
|
||||
data: { entry: logEntry },
|
||||
crossDomain: true,
|
||||
responseType: {},
|
||||
headers: headers,
|
||||
}).then(
|
||||
(response) => {
|
||||
return resolve(response);
|
||||
},
|
||||
(error) => {
|
||||
return reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default Logger;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { useMainStore } from '@/store';
|
||||
import { updateOrCreateISSCookie } from '@/helpers/cookie-helper';
|
||||
import submitType from '@/constants/submit-type';
|
||||
|
||||
/*
|
||||
Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing
|
||||
|
|
@ -43,3 +44,10 @@ export async function submitWorkOrder({ submitType }) {
|
|||
});
|
||||
store.createSubmittedOrder(submitType);
|
||||
}
|
||||
|
||||
export async function submitBailout() {
|
||||
const store = useMainStore();
|
||||
store.resetSubmittedOrder();
|
||||
await store.saveSession({});
|
||||
store.createSubmittedOrder(submitType.BAILOUT);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ import canBailoutNavigateBack from '@/helpers/bailout-helper';
|
|||
import BailoutCode from '@/constants/bailoutCode';
|
||||
import issPageValues from '@/router/router-constants/issPage-values';
|
||||
import MaskaFormattedMasks from '@/constants/maska-masks';
|
||||
import { saveSession } from '@/helpers/order-helper';
|
||||
import { submitBailout } from '@/helpers/order-helper';
|
||||
|
||||
export default {
|
||||
name: 'bailout-page',
|
||||
|
|
@ -203,7 +203,7 @@ export default {
|
|||
},
|
||||
async forwardButtonAction() {
|
||||
this.mainStore.setBailoutContactInfo(this.bailoutPageModel);
|
||||
await saveSession({ shouldAwaitSaveSessionQueue: true });
|
||||
await submitBailout();
|
||||
this.$router.navigate(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route,
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ export default {
|
|||
this.$refs.siteFooter.updateButtonText(newValue);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
await useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
||||
useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
||||
|
||||
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
servicePackageRadio,
|
||||
selectedPackageName: packageNames.TIER_ONE
|
||||
selectedPackageName: ''
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -64,10 +64,6 @@ export default {
|
|||
servicePackageAnswers() {
|
||||
if (!this.cmsWidgetName) return [];
|
||||
const cmsAnswersContent = [];
|
||||
cmsAnswersContent.push({
|
||||
Name: 'TierOne',
|
||||
cmsWidgetName: 'EconomyServicePackage'
|
||||
});
|
||||
if (this.shouldDisplayTierTwoPackage) {
|
||||
cmsAnswersContent.push({
|
||||
Name: 'TierTwo',
|
||||
|
|
@ -78,6 +74,10 @@ export default {
|
|||
Name: 'TierThree',
|
||||
cmsWidgetName: 'PremiumServicePackage'
|
||||
});
|
||||
cmsAnswersContent.push({
|
||||
Name: 'TierOne',
|
||||
cmsWidgetName: 'EconomyServicePackage'
|
||||
});
|
||||
// if cms content has not yet loaded, skip
|
||||
if (!this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText')
|
||||
|| this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText') === '') {
|
||||
|
|
|
|||
|
|
@ -7,17 +7,20 @@
|
|||
:class="[buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||
for="testradio">
|
||||
<div class="package-specs">
|
||||
<p class="m-0">
|
||||
<span v-html="buttonLabel"></span>
|
||||
<span
|
||||
class="pricing-info"
|
||||
v-html="buttonAuxiliaryCopy"></span>
|
||||
</p>
|
||||
<p
|
||||
v-if="buttonLabelSubCopy"
|
||||
class="sub-label m-0"
|
||||
v-html="buttonLabelSubCopy"></p>
|
||||
<div>
|
||||
<p class="m-0">
|
||||
<span v-html="buttonLabel"></span>
|
||||
<span
|
||||
class="pricing-info"
|
||||
v-html="buttonAuxiliaryCopy"></span>
|
||||
</p>
|
||||
<p
|
||||
v-if="buttonLabelSubCopy"
|
||||
class="sub-label m-0"
|
||||
v-html="buttonLabelSubCopy">
|
||||
</p>
|
||||
</div>
|
||||
<div class="hide-when-closed">
|
||||
<ul>
|
||||
<li
|
||||
v-for="listItem in arrayOfListItemsFromBodyText"
|
||||
|
|
@ -139,9 +142,13 @@ export default {
|
|||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
min-height: 60px;
|
||||
max-height: 100px;
|
||||
@include media-breakpoint-up(md) {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
&.has-subheader {
|
||||
min-height: 80px;
|
||||
min-height: 86px;
|
||||
}
|
||||
|
||||
&:before {
|
||||
|
|
@ -222,19 +229,21 @@ export default {
|
|||
|
||||
.package-footer {
|
||||
color: $red;
|
||||
font-weight: $font-weight-bold;
|
||||
margin-top: 0.5rem;
|
||||
font-weight: $font-weight-bold; // 600 in fmg
|
||||
margin-top: 0.5rem; // not in fmg
|
||||
}
|
||||
|
||||
.package-specs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-height: 1000px;
|
||||
transition: all 0.5s ease;
|
||||
|
||||
max-height: 0;
|
||||
transition: all 1s ease;
|
||||
@include media-breakpoint-up(md) {
|
||||
max-height: 500px;
|
||||
}
|
||||
p {
|
||||
font-weight: 500;
|
||||
font-weight: $font-weight-bold; // 600 in fmg
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
|
|
@ -253,16 +262,16 @@ export default {
|
|||
}
|
||||
|
||||
ul {
|
||||
margin: 1rem 0 0 -.6rem;
|
||||
margin: 1rem 0 0 -.6rem; // .9375rem in fmg
|
||||
padding: 0;
|
||||
|
||||
li {
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.714;
|
||||
line-height: 1.5rem;
|
||||
|
||||
a {
|
||||
line-height: 1.714;
|
||||
line-height: 1.5rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -278,6 +287,14 @@ export default {
|
|||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hide-when-closed {
|
||||
display: none;
|
||||
@include media-breakpoint-up(md) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ export default {
|
|||
this.navigate(
|
||||
this.navigationScenarios.SAVE_SESSION_FAILED,
|
||||
this.$route,
|
||||
{ query: { issPage: this.issPageValues.TPA_SUBMIT } }
|
||||
{ issPage: this.issPageValues.TPA_SUBMIT }
|
||||
);
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
15
src/main.js
15
src/main.js
|
|
@ -13,6 +13,10 @@ import defineGlobalRules from '@/helpers/global-rule-definer';
|
|||
import router from './router';
|
||||
import App from './App.vue';
|
||||
|
||||
import Logger from "@/helpers/logger";
|
||||
// Instantiate global logging object
|
||||
global.$logger = new Logger();
|
||||
|
||||
// Vue App Setup
|
||||
const vueApp = createApp(App);
|
||||
|
||||
|
|
@ -35,6 +39,17 @@ vueApp.mixin(baseMixin);
|
|||
vueApp.mixin(analyticsMixin);
|
||||
vueApp.mixin(experimentMixin);
|
||||
|
||||
// Vue Error Handling
|
||||
vueApp.config.errorHandler = (err, vm, info) => {
|
||||
global.$logger.logError(
|
||||
`Page Name - ${vm.getPageNameByQueryString()} - ${info}: ${err.message}\n${err.stack}`
|
||||
);
|
||||
};
|
||||
|
||||
// Vue Router Error Handling
|
||||
router.onError((err) => {
|
||||
global.$logger.logError(err.message, err.cause);
|
||||
});
|
||||
vueApp.mount('#app');
|
||||
|
||||
// define global rules
|
||||
|
|
|
|||
|
|
@ -377,6 +377,8 @@ function getConfirmationPageFromOrder(order) {
|
|||
return issPageValues.ORDER_CONFIRMATION;
|
||||
case submitType.TPA:
|
||||
return issPageValues.TPA_CONFIRMATION;
|
||||
case submitType.BAILOUT:
|
||||
return issPageValues.CONTACT_CONFIRMATION;
|
||||
default:
|
||||
return issPageValues.ORDER_CONFIRMATION;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1306,12 +1306,7 @@ export const useMainStore = defineStore({
|
|||
isCreditCard: payment.payInAdvanceType === paymentMethods.CREDIT_CARD,
|
||||
isAfterpay: payment.payInAdvanceType === paymentMethods.AFTERPAY,
|
||||
nextGenSettledAmount: payment.nextGenSettledAmount,
|
||||
CCToken: payment.creditCardToken,
|
||||
insuranceCoverage: {
|
||||
isVerified: this.isVerified,
|
||||
coverageStatus: this.isNoComp ? coverageStatuses.NO_COVERAGE : this.isVerified ? coverageStatuses.VERIFIED : coverageStatuses.PENDING,
|
||||
claimNumber: insuranceCoverage.claimNumber
|
||||
}
|
||||
CCToken: payment.creditCardToken
|
||||
},
|
||||
serviceLocation: {
|
||||
address: {
|
||||
|
|
@ -1374,90 +1369,83 @@ export const useMainStore = defineStore({
|
|||
|
||||
async loadSession(duplicate) {
|
||||
const { order, issConfig } = this;
|
||||
try {
|
||||
const response = await globalMethods.callHttpClient({
|
||||
method: endpoints.LoadSession.method,
|
||||
endpoint: endpoints.LoadSession.url,
|
||||
payload: {
|
||||
referralNumber: duplicate.referralNumber,
|
||||
referralDate: duplicate.responseDate,
|
||||
parentAccountNumber: issConfig.parentAccountNumber,
|
||||
referralCorrelationId: duplicate.correlationId
|
||||
const response = await globalMethods.callHttpClient({
|
||||
method: endpoints.LoadSession.method,
|
||||
endpoint: endpoints.LoadSession.url,
|
||||
payload: {
|
||||
referralNumber: duplicate.referralNumber,
|
||||
referralDate: duplicate.responseDate,
|
||||
parentAccountNumber: issConfig.parentAccountNumber,
|
||||
referralCorrelationId: duplicate.correlationId
|
||||
}
|
||||
});
|
||||
const { data } = response;
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isPolicyLookupSuccessful) {
|
||||
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.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;
|
||||
}
|
||||
});
|
||||
const { data } = response;
|
||||
if (!data) {
|
||||
// TODO how should we handle this case?
|
||||
return response;
|
||||
order.insuranceCoverage.claimNumber = data?.payment?.insuranceCoverage?.claimNumber;
|
||||
}
|
||||
|
||||
if (this.isPolicyLookupSuccessful) {
|
||||
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.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;
|
||||
}
|
||||
|
||||
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)
|
||||
});
|
||||
}
|
||||
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.referralNumber = data?.referralNumber;
|
||||
order.referralDate = data?.referralDate;
|
||||
order.referralCorrelationId = data?.referralCorrelationId;
|
||||
order.referralSequenceNumber = data?.referralSequenceNumber;
|
||||
order.eon = data?.eon;
|
||||
order.loadedFromDupeCheck = true;
|
||||
order.loadedSessionClearedPreviousData = false;
|
||||
return data;
|
||||
} catch (ex) {
|
||||
// TODO how should we handle this case?
|
||||
throw ex;
|
||||
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.referralNumber = data?.referralNumber;
|
||||
order.referralDate = data?.referralDate;
|
||||
order.referralCorrelationId = data?.referralCorrelationId;
|
||||
order.referralSequenceNumber = data?.referralSequenceNumber;
|
||||
order.eon = data?.eon;
|
||||
order.loadedFromDupeCheck = true;
|
||||
order.loadedSessionClearedPreviousData = false;
|
||||
},
|
||||
updateCreditCardToken(token) {
|
||||
this.order.payment.creditCardToken.subscriptionId = token.subscriptionId;
|
||||
|
|
|
|||
|
|
@ -1107,21 +1107,6 @@ describe('Store', () => {
|
|||
endpoint: endpoints.LoadSession.url
|
||||
}));
|
||||
});
|
||||
it('Returns expected response object', async () => {
|
||||
// Arrange
|
||||
const response = { data: { ReferralNumber: getRandomString(6, 6) } };
|
||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
|
||||
const duplicate = {
|
||||
referralNumber: getRandomString(6, 6),
|
||||
referralCorrelationId: getRandomGuid()
|
||||
};
|
||||
|
||||
// Act
|
||||
const result = store.loadSession(duplicate);
|
||||
|
||||
// Asserts
|
||||
await expect(result).resolves.toBe(response.data);
|
||||
});
|
||||
it('sets expected vehicle data', async () => {
|
||||
// Arrange
|
||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse));
|
||||
|
|
|
|||
|
|
@ -1,189 +1,228 @@
|
|||
html {
|
||||
.has-error {
|
||||
// START HOVER
|
||||
&.list-button-horizontal,
|
||||
&.list-button,
|
||||
&.list-button.list-group,
|
||||
&.list-card
|
||||
&.option-label {
|
||||
border: 1px solid $red;
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
.has-error {
|
||||
|
||||
.button-content {
|
||||
border: none;
|
||||
}
|
||||
// START HOVER
|
||||
&.list-button-horizontal,
|
||||
&.list-button,
|
||||
&.list-button.list-group,
|
||||
&.list-card &.option-label {
|
||||
border: 1px solid $red;
|
||||
position: relative;
|
||||
z-index: 4;
|
||||
|
||||
&:hover {
|
||||
@include box-shadow-hover($red-200);
|
||||
z-index: 5;
|
||||
}
|
||||
input[type="radio"]:focus + .list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
}
|
||||
.button-content {
|
||||
border: none;
|
||||
}
|
||||
|
||||
&.list-card {
|
||||
border: 1px solid $red;
|
||||
}
|
||||
|
||||
&.ui-radio {
|
||||
&:hover {
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
@include box-shadow-hover($red-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
.form-check-input {
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
}
|
||||
// END HOVER
|
||||
&:hover {
|
||||
@include box-shadow-hover($red-200);
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
&.list-button,
|
||||
&.list-card {
|
||||
color: $red;
|
||||
input[type="radio"]:focus+.list-button-content {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="checkbox"]:focus + label,
|
||||
input[type="radio"]:focus + label {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
input[type="checkbox"]:checked + label {
|
||||
box-shadow: 0 0 0 1px $red;
|
||||
}
|
||||
&:hover {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
&.list-button-horizontal {
|
||||
color: $red;
|
||||
input[type="checkbox"]:focus + label,
|
||||
input[type="radio"]:focus + label {
|
||||
box-shadow: 0 0 1px $red;
|
||||
}
|
||||
}
|
||||
&.list-card {
|
||||
border: 1px solid $red;
|
||||
}
|
||||
|
||||
&.grid-item {
|
||||
input[type="radio"] {
|
||||
+ label {
|
||||
border: 1px solid $red;
|
||||
&:hover {
|
||||
background-color: $blue-100;
|
||||
box-shadow: 0px 0px 0px 4px $red-200;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.ui-radio,
|
||||
&.ui-checkbox {
|
||||
input[type="checkbox"],
|
||||
input[type="radio"],
|
||||
input[type="radio"] + label:before,
|
||||
input[type="checkbox"] + label:before {
|
||||
border: 1px solid $red;
|
||||
background-color: initial;
|
||||
}
|
||||
input[type="checkbox"]:checked + label:before {
|
||||
border: 1px solid $blue;
|
||||
}
|
||||
}
|
||||
&.textbox-question,
|
||||
&.dropdown-question {
|
||||
p {
|
||||
color: $red;
|
||||
}
|
||||
input,
|
||||
input.form-control,
|
||||
select,
|
||||
select.form-select {
|
||||
border: 1px solid $red;
|
||||
&:focus {
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
&.ui-radio {
|
||||
&:hover {
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0px 0px 0px 4px $red-200;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid $red;
|
||||
}
|
||||
}
|
||||
select,
|
||||
select.form-select {
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%23d4281c'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
background-size: 16px 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Restore to default style if alert box is present
|
||||
.alertError {
|
||||
.has-error {
|
||||
&.list-button,
|
||||
&.list-card {
|
||||
border: 1px solid $gray-500;
|
||||
input:not(:focus) {
|
||||
+ label {
|
||||
border: none;
|
||||
box-shadow: 0 0 0 1px $gray-500;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
input:checked:focus {
|
||||
+ label {
|
||||
border: none;
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
input:checked:not(:focus) {
|
||||
+ label {
|
||||
box-shadow: 0 0 0 1px $blue;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
input:focus {
|
||||
border: 1px solid $gray-500;
|
||||
+ label {
|
||||
box-shadow: 0 0 0 2.5px transparent;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
+ label {
|
||||
box-shadow: 0 0 0 2.5px transparent;
|
||||
border: 1px solid $blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
@include box-shadow-hover($red-200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-test-error {
|
||||
color: $red;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-check-input {
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
}
|
||||
|
||||
.form-test-invalid {
|
||||
&.btn.btn-primary {
|
||||
color: $gray-600;
|
||||
background: $gray-200;
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
font-weight: $font-weight-normal;
|
||||
// END HOVER
|
||||
|
||||
&.list-button,
|
||||
&.list-card {
|
||||
color: $red;
|
||||
|
||||
input[type="checkbox"]:focus+label,
|
||||
input[type="radio"]:focus+label {
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked+label {
|
||||
box-shadow: 0 0 0 1px $red;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.list-button-horizontal {
|
||||
color: $red;
|
||||
|
||||
input[type="checkbox"]:focus+label,
|
||||
input[type="radio"]:focus+label {
|
||||
box-shadow: 0 0 1px $red;
|
||||
}
|
||||
}
|
||||
|
||||
&.grid-item {
|
||||
input[type="radio"] {
|
||||
+label {
|
||||
border: 1px solid $red;
|
||||
|
||||
&:hover {
|
||||
background-color: $blue-100;
|
||||
box-shadow: 0px 0px 0px 4px $red-200;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.ui-radio,
|
||||
&.ui-checkbox {
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"],
|
||||
input[type="radio"]+label:before,
|
||||
input[type="checkbox"]+label:before {
|
||||
border: 1px solid $red;
|
||||
background-color: initial;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked+label:before {
|
||||
border: 1px solid $blue;
|
||||
}
|
||||
}
|
||||
|
||||
&.textbox-question,
|
||||
&.dropdown-question {
|
||||
p {
|
||||
color: $red;
|
||||
}
|
||||
|
||||
input,
|
||||
input.form-control,
|
||||
select,
|
||||
select.form-select {
|
||||
border: 1px solid $red;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid transparent;
|
||||
box-shadow: 0 0 0 2.5px $red;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0px 0px 0px 4px $red-200;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid $red;
|
||||
}
|
||||
}
|
||||
|
||||
select,
|
||||
select.form-select {
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%23d4281c'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
background-size: 16px 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.btn.btn-primary:hover,
|
||||
&.btn.btn-primary:focus {
|
||||
background: $gray-200;
|
||||
box-shadow: none;
|
||||
|
||||
//Quote page radio button group
|
||||
.package-main {
|
||||
.package-wrapper {
|
||||
.has-error {
|
||||
input[type="radio"] {
|
||||
+.package-label {
|
||||
border: 1px solid $red;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&.btn.btn-primary:focus-visible {
|
||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $gray-700;
|
||||
|
||||
//Restore to default style if alert box is present
|
||||
.alertError {
|
||||
.has-error {
|
||||
|
||||
&.list-button,
|
||||
&.list-card {
|
||||
border: 1px solid $gray-500;
|
||||
|
||||
input:not(:focus) {
|
||||
+label {
|
||||
border: none;
|
||||
box-shadow: 0 0 0 1px $gray-500;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
input:checked:focus {
|
||||
+label {
|
||||
border: none;
|
||||
box-shadow: 0 0 0 2.5px $blue;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
input:checked:not(:focus) {
|
||||
+label {
|
||||
box-shadow: 0 0 0 1px $blue;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border: 1px solid $gray-500;
|
||||
|
||||
+label {
|
||||
box-shadow: 0 0 0 2.5px transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 4px $blue-300;
|
||||
|
||||
+label {
|
||||
box-shadow: 0 0 0 2.5px transparent;
|
||||
border: 1px solid $blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-test-error {
|
||||
color: $red;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-test-invalid {
|
||||
&.btn.btn-primary {
|
||||
color: $gray-600;
|
||||
background: $gray-200;
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
font-weight: $font-weight-normal;
|
||||
}
|
||||
|
||||
&.btn.btn-primary:hover,
|
||||
&.btn.btn-primary:focus {
|
||||
background: $gray-200;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&.btn.btn-primary:focus-visible {
|
||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $gray-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue