DigitalConsumer.ISS/public/static/error/index.html
2026-05-11 11:05:09 -04:00

427 lines
No EOL
17 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<style>
@font-face {
font-family: Urbanist;
src: url("/static/assets/Urbanist-Regular.woff") format("woff");
}
@font-face {
font-family: UrbanistSemiBold;
src: url("/static/assets/Urbanist-SemiBold.woff") format("woff");
}
body {
font-family: 'Urbanist', Roboto, Arial, Helvetica, sans-serif;
}
.container {
max-width: 960px;
margin: auto;
padding: 1rem;
}
.header, .copy, .cta {
margin-bottom: 3rem;
}
.header .header-image {
width: 165px;
}
.subheader {
font-weight: normal;
font-size: 1.5rem;
}
.cta-button {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
padding-left: 2rem;
padding-right: 2rem;
border-radius: 50rem;
background-color: #db0020;
color: #ffffff;
font-family: inherit;
font-size: 1rem;
border: 0px;
}
.diagnostic-info {
color: #db0020;
font-family: 'UrbanistSemiBold', Roboto, Arial, Helvetica, sans-serif;
word-wrap: break-word;
}
</style>
<title>Error - Safelite</title>
<link rel="icon" href="/favicon.ico">
</head>
<body>
<div class="container">
<div class="header">
<img class="header-image" src="/static/assets/logo.svg" />
</div>
<div class="copy">
<h2 class="subheader">
We're not able to schedule at this time. We apologize for the inconvenience
</h2>
<p>
We encountered an error while processing your appointment. You can return to our site and try scheduling again at a later time.
</p>
</div>
<div class="diagnostic-info" id="diagnostic-container">
<hr />
<h2 class="subheader">
Bailout Information:
</h2>
<div id="bailout-info-container">
</div>
</div>
</div>
<script>
// Helpers
function getCookieValueByName(name) {
const value = "; " + document.cookie;
const parts = value.split("; " + name + "=");
if (parts.length === 2) {
return parts.pop().split(";").shift();
}
return "";
}
function getCurrentEnvironmentData() {
const environmentData = [
{
name: 'Localhost',
hostName: 'localhost',
apiHostname: 'digitalapi.dev.safelite.io',
debug: true,
},
{
name: 'Dev',
hostName: 'selfservice.dev.glassclaim.com',
apiHostname: 'digitalapi.dev.safelite.io',
debug: true,
},
{
name: 'SysTest',
hostName: 'selfservice.test.glassclaim.com',
apiHostname: 'digitalapi.test.safelite.io',
debug: true,
},
{
name: 'QA',
hostName: 'selfservice.qa.glassclaim.com',
apiHostname: 'digitalapi.qa.safelite.io',
debug: false,
},
{
name: 'Prod',
hostName: 'selfservice.glassclaim.com',
apiHostname: 'digitalapi.safelite.io',
debug: false,
},
];
const hostName = window.location.hostname;
const match = environmentData.find(
data => (data.hostName === hostName)
);
return match;
}
function getExperimentSettingsFromStore(storeData) {
const experiments = storeData?.applicationUser?.experiments;
if(experiments) {
return experiments
.filter((e) => !!e.isActive)
.map((e) => e.settings)
.reduce((prev, next) => Object.assign(prev, next), {}) ?? {};
}
return {};
}
function extractDataFromStore(mainStore) {
let bailoutInfo = [];
let headerInfo = [];
try {
// =============== Collect diagnostic data:
bailoutInfo = [];
// App & Site Name
bailoutInfo.push({ name: 'App Name', value: 'ISS' });
bailoutInfo.push({ name: 'Site Name', value: 'ISS 2.0' });
// Not included (yet) from heritage:
// - Site ID
// - Code
// - Module
// - Page
bailoutInfo.push({ name: 'Timestamp', value: `${new Date()}` });
// - URL
// - Server
const sessionId = getCookieValueByName('sid');
bailoutInfo.push({ name: 'Session Id', value: sessionId });
const userAgent = window.navigator.userAgent;
bailoutInfo.push({ name: 'User Agent', value: userAgent });
// - IP
// - Session Log Sequence Number
bailoutInfo.push({ name: 'Referral Seq Number', value: mainStore.order?.referralSequenceNumber });
bailoutInfo.push({ name: 'Referral Number', value: mainStore.order?.referralNumber });
bailoutInfo.push({ name: 'Referral Date', value: mainStore.order?.referralDate });
bailoutInfo.push({ name: 'Referral Provider Number', value: mainStore.order?.serviceLocation?.provider?.providerNumber });
bailoutInfo.push({ name: 'Referral CTU', value: mainStore.order?.serviceLocation?.provider?.address?.zipCodeCtu });
// - Referral Insured Zip
// - Referral Insured Service Zip
bailoutInfo.push({ name: 'Referral CarID', value: mainStore.order?.vehicle?.carId });
const vehicle = mainStore.order?.vehicle;
const vehicleString = vehicle?.year
? `${vehicle.year} ${vehicle.make} ${vehicle.model} - ${vehicle.style}`
: null;
bailoutInfo.push({ name: 'Referral Vehicle', value: vehicleString });
bailoutInfo.push({ name: 'Work Order Number', value: mainStore.order?.workOrderNumber });
bailoutInfo.push({ name: 'Work Order ID', value: mainStore.order?.workOrderId });
bailoutInfo.push({ name: 'Parent Account Number', value: mainStore.order?.parentAccountNumber });
const environmentData = getCurrentEnvironmentData();
const userIdCookieName = `ISSUserId-${environmentData?.name}`;
bailoutInfo.push({ name: 'User Id', value: getCookieValueByName(userIdCookieName) });
bailoutInfo.push({ name: 'Bailout URL', value: mainStore.applicationUser.pageData['bailout-page']?.url });
bailoutInfo.push({ name: 'Bailout Code', value: mainStore.applicationUser.pageData['bailout-page']?.bailoutCode });
bailoutInfo.push({ name: 'Bailout Message', value: mainStore.applicationUser.pageData['bailout-page']?.errorMessage });
// - Parent Account Name
// - Client GUID
// =============== Collect header data:
headerInfo = [];
headerInfo.push({ name: 'X-Experiment-Data', value: JSON.stringify(getExperimentSettingsFromStore(mainStore)) });
headerInfo.push({ name: 'X-Application-Name', value: 'ISS' });
const sessionKeyCookieName = `ISSSessionKey-${environmentData?.name}`;
headerInfo.push({ name: 'X-Session-Sequence-Number', value: getCookieValueByName(sessionKeyCookieName) });
headerInfo.push({ name: 'X-Referral-Sequence-Number', value: mainStore.order?.referralSequenceNumber });
headerInfo.push({ name: 'X-Enterprise-Order-Number', value: mainStore.order?.eon });
headerInfo.push({ name: 'log-enabled', value: mainStore.applicationUser?.loggingOption ?? false });
} finally {
return {
headerInfo: headerInfo,
bailoutInfo: bailoutInfo
};
}
}
function generateRequestHeader(headerInfo) {
let headers = {};
headerInfo.forEach(
keyPair => {
headers[keyPair.name] = keyPair.value;
}
);
headers['X-Transaction-Id'] = crypto.randomUUID();
headers['Content-Type'] = 'application/json';
return headers;
}
function getFieldWithName(info, name) {
const match = info?.find(
(row) => row.name === name
);
return match?.value;
}
function clearApplicationData() {
/*
const environmentData = getCurrentEnvironmentData();
const cookieNames = [
`ISSUserId-${environmentData?.name}`,
`ISSSessionKey-${environmentData?.name}`,
`ISSSessionInfo-${environmentData?.name}`,
`sid`,
`dxdev`,
];
cookieNames.forEach(
(cookieName) => {
let cookieToAdd = `${cookieName}=undefined; path=/; domain=${environmentData.hostName}; max-age=0`;
document.cookie = cookieToAdd;
}
)
*/
}
window.onload = async () => {
// =============== Check for session info:
const existingStoreDataJSON = window.sessionStorage.getItem('main');
const mainStore = existingStoreDataJSON ? JSON.parse(existingStoreDataJSON) : null;
const bailoutData = mainStore.applicationUser.pageData['bailout-page'];
console.log(`================ STORE DATA`);
console.log(mainStore);
console.log(`================ PRIOR BAILOUT DATA`);
console.log(bailoutData);
/*
console.log(`================ PRIOR HEADER DATA`);
console.log(existingHeaderInfo);
*/
let bailoutInfo = null;
let headerInfo = null;
if(mainStore) {
const results = extractDataFromStore(mainStore);
bailoutInfo = results.bailoutInfo;
headerInfo = results.headerInfo;
//clearApplicationData();
if(bailoutInfo) {
window.sessionStorage.setItem('bailoutInfo', JSON.stringify(bailoutInfo));
}
if(headerInfo) {
window.sessionStorage.setItem('headerInfo', JSON.stringify(headerInfo));
}
} else {
bailoutInfo = existingBailoutInfo ?? [];
headerInfo = existingHeaderInfo ?? [];
}
const environmentInfo = getCurrentEnvironmentData();
const shouldShowDebugInfo = environmentInfo?.debug;
if(bailoutInfo && shouldShowDebugInfo) {
try {
// =============== Display diagnostic data:
// Create display nodes
const elements = bailoutInfo.map(
dataPoint => {
const element = document.createElement('li');
element.textContent = `${dataPoint.name}: ${dataPoint.value}`;
return element;
}
);
const fragment = new DocumentFragment();
elements.forEach(
(element) => {
fragment.append(element);
}
);
// Attach nodes to DOM and render
const attachNode = document.getElementById('bailout-info-container');
if(attachNode) {
const ul = attachNode.appendChild(document.createElement('ul'));
ul.append(fragment);
}
} catch(e) {
console.error(`=== ERROR DISPLAYING INFO`);
console.error(e);
const diagnosticContainer = document.getElementById('diagnostic-container');
diagnosticContainer.remove();
}
} else {
const diagnosticContainer = document.getElementById('diagnostic-container');
diagnosticContainer.remove();
}
// TODO: Re-enable logging after some further testing.
/*
const apiHostname = environmentInfo?.apiHostname;
if(apiHostname) {
try {
const endpointUrl = `https://${apiHostname}/analytics/api/v1/logging/log-error`;
const infoString = bailoutInfo?.map(
(entry) => `${entry.name}: ${entry.value}`
)?.reduce(
(prev, next) => `${prev}\n${next}`
);
const entryString = `User encountered bailout page.\n${new Date()}\n${infoString ?? 'No information recoverable'}`;
const headers = generateRequestHeader(headerInfo);
const request = new Request(endpointUrl, {
method: 'POST',
headers: headers,
body: JSON.stringify({
entry: entryString,
}),
});
const response = await fetch(request);
// Don't need data from response, but could get it here with:
// const responseData = await response.json();
} catch(e) {
console.error(`=== ERROR SENDING LOGGING`);
console.error(e);
}
try {
const endpointUrl = `https://${apiHostname}/analytics/api/v1/analytics/log-page-view`;
const headers = generateRequestHeader(headerInfo);
const payload = {
AppName: "ISS",
action: "",
applicationName: "ISS",
event: "ENTRY",
experimentsForUser: [],
pageName: "static-error",
parentAccountNumber: getFieldWithName(bailoutInfo, 'Parent Account Number') ?? 0,
referralSequenceNumber: getFieldWithName(bailoutInfo, 'Referral Seq Number'),
sessionId: getFieldWithName(bailoutInfo, 'Session Id'),
sessionKey: getFieldWithName(headerInfo, 'X-Session-Sequence-Number'),
shouldUseSessionId: false,
userId: getFieldWithName(bailoutInfo, 'User Id'),
};
const request = new Request(endpointUrl, {
method: 'POST',
headers: headers,
body: JSON.stringify(payload),
});
const response = await fetch(request);
} catch(e) {
console.error(`=== ERROR SENDING PAGEVIEW`);
console.error(e);
}
}
*/
};
</script>
</body>
</html>