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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ const applicationConfig = Object.freeze({
|
||||||
GOOGLE_CALENDAR: 'https://www.google.com/calendar/render?action=TEMPLATE',
|
GOOGLE_CALENDAR: 'https://www.google.com/calendar/render?action=TEMPLATE',
|
||||||
YAHOO_CALENDAR: 'https://calendar.yahoo.com/?v=60',
|
YAHOO_CALENDAR: 'https://calendar.yahoo.com/?v=60',
|
||||||
OUTLOOK_CALENDAR:
|
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;
|
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'
|
method: 'POST'
|
||||||
},
|
},
|
||||||
LookupVinByAddress: {
|
LookupVinByAddress: {
|
||||||
url: `${VEHICLE_BASE_URL}/lookup-by-address`,
|
url: `${VEHICLE_BASE_URL}/lookup-vin-by-address`,
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
},
|
},
|
||||||
LookupVinByPlate: {
|
LookupVinByPlate: {
|
||||||
url: `${VEHICLE_BASE_URL}/lookup-by-plate`,
|
url: `${VEHICLE_BASE_URL}/lookup-vin-by-plate`,
|
||||||
method: 'POST'
|
method: 'POST'
|
||||||
},
|
},
|
||||||
InitializeSession: {
|
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({
|
const submitType = Object.freeze({
|
||||||
SAFELITE: 0,
|
SAFELITE: 0,
|
||||||
TPA: 1
|
TPA: 1,
|
||||||
|
BAILOUT: 2
|
||||||
});
|
});
|
||||||
|
|
||||||
export default submitType;
|
export default submitType;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,50 @@ import { useMainStore } from '@/store';
|
||||||
import applicationConfig from '@/constants/application-config.js';
|
import applicationConfig from '@/constants/application-config.js';
|
||||||
import { GaCategories, GaActions, GaLabels } from '@/constants/analytics';
|
import { GaCategories, GaActions, GaLabels } from '@/constants/analytics';
|
||||||
import headerKeys from '@/constants/header-keys';
|
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 {
|
export default {
|
||||||
callHttpClient({ method, endpoint, payload, logApiCall = true }) {
|
callHttpClient({ method, endpoint, payload, logApiCall = true }) {
|
||||||
|
|
@ -37,13 +81,23 @@ export default {
|
||||||
return resolve(response);
|
return resolve(response);
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
window.console.error(error);
|
if (logApiCall) {
|
||||||
|
analyticsMixIn.methods.pushEventToGA(
|
||||||
// implement if analytics service is down
|
GaCategories.API_RESPONSE,
|
||||||
if (endpoint.includes('analytics')) {
|
GaActions.RESULT,
|
||||||
return resolve({ data: '' });
|
`${GaLabels.ERROR}_${endpoint}`,
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error.response.status != "404") {
|
||||||
|
|
||||||
|
|
||||||
|
global.$logger.logError(
|
||||||
|
`${method}: ${endpoint}: ${error.message}`,
|
||||||
|
error.response
|
||||||
|
);
|
||||||
|
}
|
||||||
return reject(error.response);
|
return reject(error.response);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,13 @@ import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
jest.mock('axios');
|
jest.mock('axios');
|
||||||
jest.mock('@/mixins/analytics-mixin');
|
jest.mock('@/mixins/analytics-mixin');
|
||||||
|
|
||||||
|
global.$logger = {
|
||||||
|
logInformation: jest.fn(),
|
||||||
|
logWarning: jest.fn(),
|
||||||
|
logError: jest.fn(),
|
||||||
|
logCritical: jest.fn(),
|
||||||
|
};
|
||||||
|
|
||||||
/** @ignore */
|
/** @ignore */
|
||||||
function setupMocksForHttpClient({
|
function setupMocksForHttpClient({
|
||||||
endpoint = null,
|
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 { useMainStore } from '@/store';
|
||||||
import { updateOrCreateISSCookie } from '@/helpers/cookie-helper';
|
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
|
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);
|
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 BailoutCode from '@/constants/bailoutCode';
|
||||||
import issPageValues from '@/router/router-constants/issPage-values';
|
import issPageValues from '@/router/router-constants/issPage-values';
|
||||||
import MaskaFormattedMasks from '@/constants/maska-masks';
|
import MaskaFormattedMasks from '@/constants/maska-masks';
|
||||||
import { saveSession } from '@/helpers/order-helper';
|
import { submitBailout } from '@/helpers/order-helper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'bailout-page',
|
name: 'bailout-page',
|
||||||
|
|
@ -203,7 +203,7 @@ export default {
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
this.mainStore.setBailoutContactInfo(this.bailoutPageModel);
|
this.mainStore.setBailoutContactInfo(this.bailoutPageModel);
|
||||||
await saveSession({ shouldAwaitSaveSessionQueue: true });
|
await submitBailout();
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
this.navigationScenarios.CLICKED_FORWARD,
|
this.navigationScenarios.CLICKED_FORWARD,
|
||||||
this.$route,
|
this.$route,
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@ export default {
|
||||||
this.$refs.siteFooter.updateButtonText(newValue);
|
this.$refs.siteFooter.updateButtonText(newValue);
|
||||||
},
|
},
|
||||||
async forwardButtonAction() {
|
async forwardButtonAction() {
|
||||||
await useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
||||||
|
|
||||||
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
|
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
servicePackageRadio,
|
servicePackageRadio,
|
||||||
selectedPackageName: packageNames.TIER_ONE
|
selectedPackageName: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -64,10 +64,6 @@ export default {
|
||||||
servicePackageAnswers() {
|
servicePackageAnswers() {
|
||||||
if (!this.cmsWidgetName) return [];
|
if (!this.cmsWidgetName) return [];
|
||||||
const cmsAnswersContent = [];
|
const cmsAnswersContent = [];
|
||||||
cmsAnswersContent.push({
|
|
||||||
Name: 'TierOne',
|
|
||||||
cmsWidgetName: 'EconomyServicePackage'
|
|
||||||
});
|
|
||||||
if (this.shouldDisplayTierTwoPackage) {
|
if (this.shouldDisplayTierTwoPackage) {
|
||||||
cmsAnswersContent.push({
|
cmsAnswersContent.push({
|
||||||
Name: 'TierTwo',
|
Name: 'TierTwo',
|
||||||
|
|
@ -78,6 +74,10 @@ export default {
|
||||||
Name: 'TierThree',
|
Name: 'TierThree',
|
||||||
cmsWidgetName: 'PremiumServicePackage'
|
cmsWidgetName: 'PremiumServicePackage'
|
||||||
});
|
});
|
||||||
|
cmsAnswersContent.push({
|
||||||
|
Name: 'TierOne',
|
||||||
|
cmsWidgetName: 'EconomyServicePackage'
|
||||||
|
});
|
||||||
// if cms content has not yet loaded, skip
|
// if cms content has not yet loaded, skip
|
||||||
if (!this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText')
|
if (!this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText')
|
||||||
|| this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText') === '') {
|
|| this.getCmsContent(cmsAnswersContent[0].cmsWidgetName, 'HeaderText') === '') {
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,20 @@
|
||||||
:class="[buttonLabelSubCopy ? 'has-subheader' : '']"
|
:class="[buttonLabelSubCopy ? 'has-subheader' : '']"
|
||||||
for="testradio">
|
for="testradio">
|
||||||
<div class="package-specs">
|
<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>
|
<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>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="listItem in arrayOfListItemsFromBodyText"
|
v-for="listItem in arrayOfListItemsFromBodyText"
|
||||||
|
|
@ -139,9 +142,13 @@ export default {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
|
max-height: 100px;
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
&.has-subheader {
|
&.has-subheader {
|
||||||
min-height: 80px;
|
min-height: 86px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
|
|
@ -222,19 +229,21 @@ export default {
|
||||||
|
|
||||||
.package-footer {
|
.package-footer {
|
||||||
color: $red;
|
color: $red;
|
||||||
font-weight: $font-weight-bold;
|
font-weight: $font-weight-bold; // 600 in fmg
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem; // not in fmg
|
||||||
}
|
}
|
||||||
|
|
||||||
.package-specs {
|
.package-specs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-height: 1000px;
|
max-height: 0;
|
||||||
transition: all 0.5s ease;
|
transition: all 1s ease;
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
max-height: 500px;
|
||||||
|
}
|
||||||
p {
|
p {
|
||||||
font-weight: 500;
|
font-weight: $font-weight-bold; // 600 in fmg
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
|
|
@ -253,16 +262,16 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
margin: 1rem 0 0 -.6rem;
|
margin: 1rem 0 0 -.6rem; // .9375rem in fmg
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.714;
|
line-height: 1.5rem;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
line-height: 1.714;
|
line-height: 1.5rem;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -278,6 +287,14 @@ export default {
|
||||||
opacity: 0;
|
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.navigate(
|
||||||
this.navigationScenarios.SAVE_SESSION_FAILED,
|
this.navigationScenarios.SAVE_SESSION_FAILED,
|
||||||
this.$route,
|
this.$route,
|
||||||
{ query: { issPage: this.issPageValues.TPA_SUBMIT } }
|
{ issPage: this.issPageValues.TPA_SUBMIT }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} 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 router from './router';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
|
|
||||||
|
import Logger from "@/helpers/logger";
|
||||||
|
// Instantiate global logging object
|
||||||
|
global.$logger = new Logger();
|
||||||
|
|
||||||
// Vue App Setup
|
// Vue App Setup
|
||||||
const vueApp = createApp(App);
|
const vueApp = createApp(App);
|
||||||
|
|
||||||
|
|
@ -35,6 +39,17 @@ vueApp.mixin(baseMixin);
|
||||||
vueApp.mixin(analyticsMixin);
|
vueApp.mixin(analyticsMixin);
|
||||||
vueApp.mixin(experimentMixin);
|
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');
|
vueApp.mount('#app');
|
||||||
|
|
||||||
// define global rules
|
// define global rules
|
||||||
|
|
|
||||||
|
|
@ -377,6 +377,8 @@ function getConfirmationPageFromOrder(order) {
|
||||||
return issPageValues.ORDER_CONFIRMATION;
|
return issPageValues.ORDER_CONFIRMATION;
|
||||||
case submitType.TPA:
|
case submitType.TPA:
|
||||||
return issPageValues.TPA_CONFIRMATION;
|
return issPageValues.TPA_CONFIRMATION;
|
||||||
|
case submitType.BAILOUT:
|
||||||
|
return issPageValues.CONTACT_CONFIRMATION;
|
||||||
default:
|
default:
|
||||||
return issPageValues.ORDER_CONFIRMATION;
|
return issPageValues.ORDER_CONFIRMATION;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1306,12 +1306,7 @@ export const useMainStore = defineStore({
|
||||||
isCreditCard: payment.payInAdvanceType === paymentMethods.CREDIT_CARD,
|
isCreditCard: payment.payInAdvanceType === paymentMethods.CREDIT_CARD,
|
||||||
isAfterpay: payment.payInAdvanceType === paymentMethods.AFTERPAY,
|
isAfterpay: payment.payInAdvanceType === paymentMethods.AFTERPAY,
|
||||||
nextGenSettledAmount: payment.nextGenSettledAmount,
|
nextGenSettledAmount: payment.nextGenSettledAmount,
|
||||||
CCToken: payment.creditCardToken,
|
CCToken: payment.creditCardToken
|
||||||
insuranceCoverage: {
|
|
||||||
isVerified: this.isVerified,
|
|
||||||
coverageStatus: this.isNoComp ? coverageStatuses.NO_COVERAGE : this.isVerified ? coverageStatuses.VERIFIED : coverageStatuses.PENDING,
|
|
||||||
claimNumber: insuranceCoverage.claimNumber
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
serviceLocation: {
|
serviceLocation: {
|
||||||
address: {
|
address: {
|
||||||
|
|
@ -1374,90 +1369,83 @@ export const useMainStore = defineStore({
|
||||||
|
|
||||||
async loadSession(duplicate) {
|
async loadSession(duplicate) {
|
||||||
const { order, issConfig } = this;
|
const { order, issConfig } = this;
|
||||||
try {
|
const response = await globalMethods.callHttpClient({
|
||||||
const response = await globalMethods.callHttpClient({
|
method: endpoints.LoadSession.method,
|
||||||
method: endpoints.LoadSession.method,
|
endpoint: endpoints.LoadSession.url,
|
||||||
endpoint: endpoints.LoadSession.url,
|
payload: {
|
||||||
payload: {
|
referralNumber: duplicate.referralNumber,
|
||||||
referralNumber: duplicate.referralNumber,
|
referralDate: duplicate.responseDate,
|
||||||
referralDate: duplicate.responseDate,
|
parentAccountNumber: issConfig.parentAccountNumber,
|
||||||
parentAccountNumber: issConfig.parentAccountNumber,
|
referralCorrelationId: duplicate.correlationId
|
||||||
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;
|
||||||
}
|
}
|
||||||
});
|
order.insuranceCoverage.claimNumber = data?.payment?.insuranceCoverage?.claimNumber;
|
||||||
const { data } = response;
|
|
||||||
if (!data) {
|
|
||||||
// TODO how should we handle this case?
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isPolicyLookupSuccessful) {
|
if (order.policy.vehicles.length !== 0 && data.vehicle?.carId) {
|
||||||
order.customer.address.streetAddress = data.customer?.address?.streetAddress;
|
order.vehicle.registration.licensePlate = data?.vehicle?.licensePlateNumber;
|
||||||
order.customer.address.streetAddress2 = data.customer?.address?.streetAddress2;
|
if (data.vehicle.vin) {
|
||||||
order.customer.address.city = data.customer?.address?.city;
|
const vehicle = order.policy.vehicles.find((v) => v.vin === data.vehicle.vin);
|
||||||
order.customer.address.state = data.customer?.address?.state;
|
if (vehicle) {
|
||||||
order.customer.address.zipCode = data.customer?.address?.zipCode;
|
const vehicleResponse = await this.lookupVehicleByVin(vehicle.vin);
|
||||||
|
if (vehicleResponse) {
|
||||||
order.contactInfo.firstName = data?.customer?.firstName;
|
this.updateVehicle({
|
||||||
order.contactInfo.lastName = data?.customer?.lastName;
|
...vehicleResponse.data,
|
||||||
order.contactInfo.emailAddress = data?.customer?.emailAddress;
|
policyVehicleId: vehicle.id,
|
||||||
order.contactInfo.homePhone = data?.customer?.homePhone;
|
vin: vehicle.vin
|
||||||
order.contactInfo.servicephone = data?.customer?.servicePhone;
|
});
|
||||||
order.contactInfo.alternativePhone = data?.customer?.alternativePhone;
|
this.updateVehicleCoverage({
|
||||||
order.contactInfo.requestTextUpdates = data?.customer?.isSmsOptIn;
|
noCoverage: noCoverageForSelectedVehicle(vehicle),
|
||||||
|
deductible: deductibleForSelectedVehicle(vehicle),
|
||||||
if (data.insuranceCoverage) {
|
repairWaived: repairWaivedForSelectedVehicle(vehicle),
|
||||||
order.insuranceCoverage.coverageType = data?.insuranceCoverage?.coverageType;
|
endorsements: endorsementsForSelectedVehicle(vehicle)
|
||||||
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)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.vehicle.year = data.vehicle.year;
|
||||||
order.referralDate = data?.referralDate;
|
order.vehicle.make = data.vehicle.make;
|
||||||
order.referralCorrelationId = data?.referralCorrelationId;
|
order.vehicle.model = data.vehicle.model;
|
||||||
order.referralSequenceNumber = data?.referralSequenceNumber;
|
order.vehicle.style = data.vehicle.style;
|
||||||
order.eon = data?.eon;
|
}
|
||||||
order.loadedFromDupeCheck = true;
|
|
||||||
order.loadedSessionClearedPreviousData = false;
|
|
||||||
return data;
|
|
||||||
} catch (ex) {
|
|
||||||
// TODO how should we handle this case?
|
|
||||||
throw ex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
updateCreditCardToken(token) {
|
||||||
this.order.payment.creditCardToken.subscriptionId = token.subscriptionId;
|
this.order.payment.creditCardToken.subscriptionId = token.subscriptionId;
|
||||||
|
|
|
||||||
|
|
@ -1107,21 +1107,6 @@ describe('Store', () => {
|
||||||
endpoint: endpoints.LoadSession.url
|
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 () => {
|
it('sets expected vehicle data', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse));
|
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(fullApiResponse));
|
||||||
|
|
|
||||||
|
|
@ -1,189 +1,228 @@
|
||||||
html {
|
html {
|
||||||
.has-error {
|
.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;
|
|
||||||
|
|
||||||
.button-content {
|
// START HOVER
|
||||||
border: none;
|
&.list-button-horizontal,
|
||||||
}
|
&.list-button,
|
||||||
|
&.list-button.list-group,
|
||||||
|
&.list-card &.option-label {
|
||||||
|
border: 1px solid $red;
|
||||||
|
position: relative;
|
||||||
|
z-index: 4;
|
||||||
|
|
||||||
&:hover {
|
.button-content {
|
||||||
@include box-shadow-hover($red-200);
|
border: none;
|
||||||
z-index: 5;
|
}
|
||||||
}
|
|
||||||
input[type="radio"]:focus + .list-button-content {
|
|
||||||
box-shadow: 0 0 0 2.5px $red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.list-card {
|
&:hover {
|
||||||
border: 1px solid $red;
|
@include box-shadow-hover($red-200);
|
||||||
}
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
&.ui-radio {
|
input[type="radio"]:focus+.list-button-content {
|
||||||
&:hover {
|
box-shadow: 0 0 0 2.5px $red;
|
||||||
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
|
|
||||||
|
|
||||||
&.list-button,
|
&.list-card {
|
||||||
&.list-card {
|
border: 1px solid $red;
|
||||||
color: $red;
|
}
|
||||||
|
|
||||||
input[type="checkbox"]:focus + label,
|
&.ui-radio {
|
||||||
input[type="radio"]:focus + label {
|
&:hover {
|
||||||
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"],
|
||||||
input[type="radio"] {
|
input[type="checkbox"] {
|
||||||
+ label {
|
@include box-shadow-hover($red-200);
|
||||||
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 {
|
.form-check-input {
|
||||||
box-shadow: 0px 0px 0px 4px $red-200;
|
&:focus {
|
||||||
border-radius: 0.5rem;
|
box-shadow: 0 0 0 2.5px $red;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-test-error {
|
// END HOVER
|
||||||
color: $red;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
&.list-button,
|
||||||
|
&.list-card {
|
||||||
|
color: $red;
|
||||||
|
|
||||||
.form-test-invalid {
|
input[type="checkbox"]:focus+label,
|
||||||
&.btn.btn-primary {
|
input[type="radio"]:focus+label {
|
||||||
color: $gray-600;
|
box-shadow: 0 0 0 2.5px $red;
|
||||||
background: $gray-200;
|
}
|
||||||
cursor: pointer;
|
|
||||||
pointer-events: all;
|
input[type="checkbox"]:checked+label {
|
||||||
font-weight: $font-weight-normal;
|
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 {
|
//Quote page radio button group
|
||||||
background: $gray-200;
|
.package-main {
|
||||||
box-shadow: none;
|
.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