Merge branch 'develop' into feature/CSR-2182-ajc
This commit is contained in:
commit
737ef41ad1
47 changed files with 11119 additions and 36820 deletions
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"tabWidth": 4,
|
||||
"bracketSameLine": true,
|
||||
"printWidth": 100
|
||||
"printWidth": 100,
|
||||
"trailingComma" : "es5"
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ pr:
|
|||
resources:
|
||||
containers:
|
||||
- container: node
|
||||
image: packagerepository.sagaws.net:8082/safelite/node-build:15
|
||||
image: packagerepository.sagaws.net:8082/safelite/node-build:18
|
||||
- container: awscli
|
||||
image: packagerepository.sagaws.net:8082/safelite/awscli2-build:3.9
|
||||
- container: prettier-node
|
||||
|
|
@ -28,7 +28,7 @@ resources:
|
|||
type: github
|
||||
name: Safelite/AzureDevOps
|
||||
endpoint: Safelite
|
||||
ref: refs/tags/t5.5.40
|
||||
ref: refs/tags/t5.6.41
|
||||
|
||||
variables:
|
||||
- group: Digital-Infrastructure
|
||||
|
|
@ -37,15 +37,15 @@ variables:
|
|||
stages:
|
||||
# PR's
|
||||
- ${{ if eq(variables['Build.Reason'], 'PullRequest') }}:
|
||||
- stage: TestFormat
|
||||
displayName: Test Code Format
|
||||
jobs:
|
||||
- job: checkFormatting
|
||||
displayName: Check formatting
|
||||
container: prettier-node
|
||||
steps:
|
||||
- bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)"
|
||||
displayName: Run Prettier check
|
||||
# - stage: TestFormat
|
||||
# displayName: Test Code Format
|
||||
# jobs:
|
||||
# - job: checkFormatting
|
||||
# displayName: Check formatting
|
||||
# container: prettier-node
|
||||
# steps:
|
||||
# - bash: prettier --check "$(Build.SourcesDirectory)/src/**/*.(js|vue)"
|
||||
# displayName: Run Prettier check
|
||||
|
||||
- stage: TestPr
|
||||
displayName: Run Unit Tests For PullRequest
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module.exports = {
|
|||
coverageReporters: ["html", "text", "jest-junit", "cobertura"],
|
||||
testResultsProcessor: "jest-junit",
|
||||
preset: "@vue/cli-plugin-unit-jest",
|
||||
transform: { "^.+\\.vue$": "vue-jest" },
|
||||
transform: { "^.+\\.vue$": "@vue/vue3-jest" },
|
||||
moduleFileExtensions: ["js", "vue"],
|
||||
modulePathIgnorePatterns: ["vin-lookup"],
|
||||
collectCoverageFrom: [
|
||||
|
|
|
|||
47337
package-lock.json
generated
47337
package-lock.json
generated
File diff suppressed because it is too large
Load diff
61
package.json
61
package.json
|
|
@ -11,42 +11,39 @@
|
|||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.10.2",
|
||||
"axios": "^0.23.0",
|
||||
"bootstrap": "^5.1.1",
|
||||
"canvas-confetti": "^1.4.0",
|
||||
"core-js": "^3.6.5",
|
||||
"http-status-codes": "^2.1.4",
|
||||
"iframe-resizer": "^4.3.7",
|
||||
"jest-junit": "^13.0.0",
|
||||
"bootstrap": "^5.3.3",
|
||||
"core-js": "^3.38.1",
|
||||
"http-status-codes": "^2.3.0",
|
||||
"iframe-resizer": "^4.4.5",
|
||||
"jest-junit": "^13.2.0",
|
||||
"jquery": "^3.7.1",
|
||||
"jquery-ui": "^1.13.2",
|
||||
"maska": "^1.5.0",
|
||||
"vee-validate": "^4.5.7",
|
||||
"vue": "^3.0.0",
|
||||
"vue-plugin-load-script": "^2.1.0",
|
||||
"vue-router": "^4.0.11",
|
||||
"vuex": "^4.0.2",
|
||||
"vuex-persistedstate": "^4.1.0",
|
||||
"yup": "^0.32.11"
|
||||
"jquery-ui": "^1.14.0",
|
||||
"maska": "^1.5.2",
|
||||
"vee-validate": "^4.13.2",
|
||||
"vue": "^3.4.38",
|
||||
"vue-plugin-load-script": "^2.1.1",
|
||||
"vue-router": "^4.4.3",
|
||||
"vuex": "^4.1.0",
|
||||
"vuex-persistedstate": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-unit-jest": "~4.5.0",
|
||||
"@vue/cli-service": "~4.5.0",
|
||||
"@vue/compiler-sfc": "^3.0.0",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"@vue/test-utils": "^2.0.0-0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"prettier": "^2.2.1",
|
||||
"sass": "^1.26.5",
|
||||
"@babel/eslint-parser": "^7.25.1",
|
||||
"@vue/cli-plugin-babel": "~5.0.8",
|
||||
"@vue/cli-plugin-eslint": "~5.0.8",
|
||||
"@vue/cli-plugin-unit-jest": "~5.0.8",
|
||||
"@vue/cli-service": "~5.0.8",
|
||||
"@vue/compiler-sfc": "^3.4.38",
|
||||
"@vue/eslint-config-prettier": "^9.0.0",
|
||||
"@vue/test-utils": "^2.4.6",
|
||||
"@vue/vue3-jest": "^27.0.0",
|
||||
"eslint": "8.57",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-vue": "^9.27.0",
|
||||
"prettier": "^3.3.3",
|
||||
"sass": "^1.77.8",
|
||||
"sass-loader": "^8.0.2",
|
||||
"typescript": "~3.9.3",
|
||||
"vue-jest": "^5.0.0-0"
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"root": true,
|
||||
|
|
@ -58,7 +55,7 @@
|
|||
"eslint:recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint"
|
||||
"parser": "@babel/eslint-parser"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off"
|
||||
|
|
|
|||
|
|
@ -2,5 +2,12 @@ module.exports = {
|
|||
env: {
|
||||
jest: true,
|
||||
},
|
||||
rules: {
|
||||
"vue/multi-word-component-names": "off",
|
||||
"vue/valid-next-tick": "off",
|
||||
"vue/no-v-text-v-html-on-component": "off",
|
||||
"vue/no-reserved-component-names": "off",
|
||||
"vue/require-toggle-inside-transition": "off",
|
||||
},
|
||||
//...
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const applicationConfig = {
|
|||
"https://outlook.office.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent",
|
||||
FRONTEND_LOGGER_PATH: "/analytics/api/v1/logging",
|
||||
AFFILIATE_COOKIE_CONTAINING_NAME: "_Track",
|
||||
COOKIE_NAME_LENGTH_MAX_LIMIT: 44,
|
||||
};
|
||||
|
||||
export { applicationConfig };
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@ const cookieNames = {
|
|||
DXDEV: "dxdev",
|
||||
SESSION_ID: "sid",
|
||||
SESSION_KEY: "skey",
|
||||
|
||||
//Commission Junction Cookie
|
||||
CJE: "cje",
|
||||
};
|
||||
|
||||
const cookieExpirations = {
|
||||
|
|
@ -17,6 +20,8 @@ const cookieExpirations = {
|
|||
DXDEV: convertToSeconds({ years: 1 }),
|
||||
FUNNEL_USER_ID: convertToSeconds({ weeks: 1 }),
|
||||
FUNNEL_SESSION_KEY: convertToSeconds({ minutes: 30 }),
|
||||
CJE: convertToSeconds({ days: 395 }),
|
||||
NON_CJ: convertToSeconds({ days: 100000 }),
|
||||
};
|
||||
|
||||
export { cookieNames, cookieExpirations };
|
||||
|
|
|
|||
|
|
@ -36,6 +36,13 @@ const queryStrings = {
|
|||
VIN_SELECTION: "vinselection",
|
||||
SERVICE_PACKAGE: "servicepackage",
|
||||
NUMBER_OF_CHIPS: "numberofchips",
|
||||
UTM_SOURCE: "_source",
|
||||
UTM_MEDIUM: "_medium",
|
||||
UTM_CAMPAIGN: "_campaign",
|
||||
CJ_EVENT: "cjevent",
|
||||
CJUNCTION: "cjunction",
|
||||
ORGANIC: "organic",
|
||||
ORGANIC_SOCIAL: "organic_social",
|
||||
};
|
||||
|
||||
export { queryStrings };
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ describe("baseInputButton.vue", () => {
|
|||
describe("mouse clicks", () => {
|
||||
describe("checkbox", () => {
|
||||
describe("clicked once", () => {
|
||||
test("correct event and value are emitted", async () => {
|
||||
test("correct event and value are emitted and input is checked", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mockData: {
|
||||
|
|
@ -71,31 +71,12 @@ describe("baseInputButton.vue", () => {
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Act
|
||||
await wrapper.trigger("click");
|
||||
await wrapper.find("input").setChecked();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.emitted()["update:modelValue"][0][0]).toEqual(["X"]);
|
||||
});
|
||||
|
||||
test("input is checked", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mockData: {
|
||||
propsData: {
|
||||
isMultiSelect: true,
|
||||
value: "X",
|
||||
},
|
||||
},
|
||||
});
|
||||
const input = wrapper.find("input");
|
||||
|
||||
// Act
|
||||
await wrapper.trigger("click");
|
||||
|
||||
// Assert
|
||||
expect(input.element.checked).toBe(true);
|
||||
expect(wrapper.find("input").element.checked).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -135,25 +116,7 @@ describe("baseInputButton.vue", () => {
|
|||
});
|
||||
const input = wrapper.find("input");
|
||||
|
||||
// Act
|
||||
await wrapper.trigger("click");
|
||||
|
||||
// Assert
|
||||
expect(input.element.checked).toBe(false);
|
||||
});
|
||||
|
||||
test("input is unchecked", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({
|
||||
mockData: {
|
||||
propsData: {
|
||||
isMultiSelect: true,
|
||||
value: "X",
|
||||
modelValue: ["X"],
|
||||
},
|
||||
},
|
||||
});
|
||||
const input = wrapper.find("input");
|
||||
expect(input.element.checked).toBe(true);
|
||||
|
||||
// Act
|
||||
await wrapper.trigger("click");
|
||||
|
|
|
|||
|
|
@ -1147,7 +1147,12 @@ function setupMocks(mountOptionsMockData = {}) {
|
|||
const baseMountOptions = getMountOptions(
|
||||
Object.assign(defaultMountOptions, mountOptionsMockData)
|
||||
);
|
||||
|
||||
const allMountOptions = Object.assign(defaultMountOptions, baseMountOptions);
|
||||
// Add in group name to avoid vee-validate failures
|
||||
if (!allMountOptions.propsData.groupName) {
|
||||
allMountOptions.propsData.groupName = "group-name";
|
||||
}
|
||||
|
||||
return allMountOptions;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,8 +177,8 @@ export default {
|
|||
const baseClasses = this.isOverflowScrollable
|
||||
? "container-fluid overflow-scroll position-absolute px-5 pt-1 py-0"
|
||||
: this.buttonTypeString == "listCard"
|
||||
? "w-100"
|
||||
: "";
|
||||
? "w-100"
|
||||
: "";
|
||||
const withSmallQuestionClass = this.isSmallQuestionText
|
||||
? baseClasses + " small-question-text"
|
||||
: baseClasses;
|
||||
|
|
|
|||
|
|
@ -732,7 +732,9 @@ export default {
|
|||
margin: 0 auto 2rem auto;
|
||||
max-width: 414px;
|
||||
position: relative;
|
||||
transition: height ease 2s, opacity ease 2s;
|
||||
transition:
|
||||
height ease 2s,
|
||||
opacity ease 2s;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
justify-content: center;
|
||||
|
|
@ -805,7 +807,9 @@ export default {
|
|||
outline: none;
|
||||
height: 1.5rem;
|
||||
opacity: 1;
|
||||
transition: height ease 250ms, opacity ease 250ms;
|
||||
transition:
|
||||
height ease 250ms,
|
||||
opacity ease 250ms;
|
||||
|
||||
input[type="radio"] {
|
||||
position: absolute; //override bootstrap
|
||||
|
|
@ -818,7 +822,9 @@ export default {
|
|||
|
||||
&:focus + label,
|
||||
&:checked:focus + label {
|
||||
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #1574a1;
|
||||
box-shadow:
|
||||
0 0 0 3px #fff,
|
||||
0 0 0 5.5px #1574a1;
|
||||
background-color: $blue;
|
||||
color: $white;
|
||||
&.current-day {
|
||||
|
|
|
|||
|
|
@ -76,13 +76,17 @@ export default {
|
|||
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
|
||||
}
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px,
|
||||
0 0 0 5.5px $blue-700;
|
||||
}
|
||||
&:focus, // Mouse, touch, stylus focus
|
||||
&:focus-visible {
|
||||
// Keyboard focus for accessibility
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px,
|
||||
0 0 0 5.5px $blue-700;
|
||||
color: $white;
|
||||
background: linear-gradient(270deg, rgba(6, 87, 124, 1) 0%, rgba(6, 87, 124, 1) 100%);
|
||||
}
|
||||
|
|
@ -100,7 +104,9 @@ export default {
|
|||
&.has-loader {
|
||||
color: $white;
|
||||
background: $blue-700;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px,
|
||||
0 0 0 5.5px $blue-700;
|
||||
pointer-events: none;
|
||||
}
|
||||
&.delay {
|
||||
|
|
@ -125,7 +131,9 @@ export default {
|
|||
&:focus-visible {
|
||||
// Keyboard focus for accessibility
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px $white,
|
||||
0 0 0 5.5px $blue-700;
|
||||
color: $white;
|
||||
@include blue-gradient;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { cookieNames, cookieExpirations } from "@/constants/cookie-names";
|
||||
import store from "@/store";
|
||||
import { applicationConfig } from "@/constants/application-config";
|
||||
|
||||
import { getQuerystringParameter } from "@/helpers/querystring-helper";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
//import { cookieParameters } from "@/constants/cookie-parameters";
|
||||
/*
|
||||
Will update the cookie if present, or create a new one if not.
|
||||
*/
|
||||
|
|
@ -221,6 +223,79 @@ export function getAffiliateCookies() {
|
|||
return affiliateCookies;
|
||||
}
|
||||
|
||||
export function setupAdvertiserTracking() {
|
||||
var utmSource = getQuerystringParameter(queryStrings.UTM_SOURCE);
|
||||
var utmMedium = getQuerystringParameter(queryStrings.UTM_MEDIUM);
|
||||
var utmCampaign = getQuerystringParameter(queryStrings.UTM_CAMPAIGN);
|
||||
const cjEvent = getQuerystringParameter(queryStrings.CJ_EVENT);
|
||||
// helper check for if an object is defined (but maybe falsey)
|
||||
const isDefined = (x) => x !== null && x !== undefined;
|
||||
if (isDefined(cjEvent) != "") {
|
||||
const cjeCookieName = cookieNames.CJE;
|
||||
if (!isCookieSet(cjeCookieName)) {
|
||||
createCJEventCookie(cjEvent, cjeCookieName);
|
||||
}
|
||||
}
|
||||
//Firstly, Can't continue without utm-source or utm-medium.
|
||||
//Secondly, Ignore the advertiser for CJ-affiliate-click and Email-click.
|
||||
if (
|
||||
!isDefined(utmSource) ||
|
||||
isDefined(utmSource) == "" ||
|
||||
!isDefined(utmMedium) ||
|
||||
isDefined(utmMedium) == "" ||
|
||||
utmSource?.toLowerCase() == queryStrings.CJUNCTION ||
|
||||
utmMedium?.toLowerCase() == queryStrings.EMAIL ||
|
||||
utmMedium?.toLowerCase() == queryStrings.ORGANIC ||
|
||||
utmMedium?.toLowerCase() == queryStrings.ORGANIC_SOCIAL
|
||||
) {
|
||||
return;
|
||||
}
|
||||
//UTC date time format yyyy-MM-dd/HH:mm:ss
|
||||
const currentDateTime = new Date().toISOString().replace(/T/, "/").replace(/\..+/, "");
|
||||
|
||||
//Format cookie, by removing spaces and special characters.
|
||||
utmSource = FormatCookieElementName(utmSource);
|
||||
utmMedium = FormatCookieElementName(utmMedium);
|
||||
utmCampaign = FormatCookieElementName(utmCampaign);
|
||||
|
||||
var cookieNameBuilder = utmSource + "_" + utmMedium;
|
||||
//Since utmCampaign is optional, ignore the rest.
|
||||
if (isDefined(utmCampaign) && utmCampaign != "") {
|
||||
cookieNameBuilder = cookieNameBuilder + "_" + utmCampaign;
|
||||
}
|
||||
const cookieName =
|
||||
(cookieNameBuilder.length > applicationConfig.COOKIE_NAME_LENGTH_MAX_LIMIT
|
||||
? cookieNameBuilder.substring(0, applicationConfig.COOKIE_NAME_LENGTH_MAX_LIMIT)
|
||||
: cookieNameBuilder) + applicationConfig.AFFILIATE_COOKIE_CONTAINING_NAME;
|
||||
|
||||
if (!isCookieSet(cookieName)) {
|
||||
const values = [
|
||||
`utm_source= ${utmSource}`,
|
||||
`utm_medium= ${utmMedium}`,
|
||||
`utm_campaign= ${utmCampaign}`,
|
||||
`timestamp= ${currentDateTime}`,
|
||||
`tagEvent= ${cjEvent}`,
|
||||
];
|
||||
let valueString = values.join("&");
|
||||
createOrUpdateCookie(cookieName, valueString, {
|
||||
useDefaultFunnelCookieAttributes: true,
|
||||
maxAge: cookieExpirations.NON_CJ,
|
||||
});
|
||||
} else {
|
||||
const cookieValue = getCookieValueByName(cookieName);
|
||||
if (cookieValue) {
|
||||
let cookieValueObj = convertStringToObject(cookieValue);
|
||||
cookieValueObj.timestamp = currentDateTime; // Update the property
|
||||
// Set the updated cookie
|
||||
const cookieValueString = objectToString(cookieValueObj);
|
||||
createOrUpdateCookie(cookieName, cookieValueString, {
|
||||
useDefaultFunnelCookieAttributes: true,
|
||||
maxAge: cookieExpirations.NON_CJ,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
= PRIVATE FUNCTIONS =
|
||||
|
|
@ -253,7 +328,7 @@ function setFunnelCookieProperties(properties) {
|
|||
function createOrUpdateCookie(
|
||||
key,
|
||||
value = "",
|
||||
{ useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true }
|
||||
{ useDefaultFunnelCookieAttributes = true, maxAge, isSecure = true, crossSiteAccess = false }
|
||||
) {
|
||||
let cookieToAdd = `${key}=${value}; `;
|
||||
|
||||
|
|
@ -266,6 +341,9 @@ function createOrUpdateCookie(
|
|||
if (!isNaN(maxAge)) {
|
||||
cookieToAdd += `max-age=${maxAge};`;
|
||||
}
|
||||
if (crossSiteAccess && isSecure) {
|
||||
cookieToAdd += `sameSite=None;`;
|
||||
}
|
||||
|
||||
document.cookie = cookieToAdd;
|
||||
}
|
||||
|
|
@ -315,3 +393,42 @@ function getCookiesContainingName(name) {
|
|||
}
|
||||
return matchingCookies;
|
||||
}
|
||||
function createCJEventCookie(cjEvent, cookieName) {
|
||||
createOrUpdateCookie(cookieName, cjEvent, {
|
||||
useDefaultFunnelCookieAttributes: true,
|
||||
maxAge: cookieExpirations.CJE,
|
||||
isSecure: true,
|
||||
crossSiteAccess: true,
|
||||
});
|
||||
}
|
||||
|
||||
function FormatCookieElementName(cookie) {
|
||||
// Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
||||
const problemSymbols = '\\s\\(\\)<>@,;:\\\\/\\[\\]\\?=\\{}"';
|
||||
const otherSymbols = "!#$%^&+\\-*|~`";
|
||||
const symbolsToIgnore = new RegExp("[" + problemSymbols + otherSymbols + "]+", "g");
|
||||
|
||||
return (cookie || "").replace(symbolsToIgnore, ".");
|
||||
}
|
||||
|
||||
function convertStringToObject(str) {
|
||||
let obj = {};
|
||||
let pairs = str.split("&");
|
||||
|
||||
pairs.forEach((pair) => {
|
||||
let [key, value] = pair.split("=");
|
||||
obj[key] = value;
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
function objectToString(obj) {
|
||||
let str = "";
|
||||
for (let key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
str += key + "=" + obj[key] + "&";
|
||||
}
|
||||
}
|
||||
// Remove the trailing '&'
|
||||
return str.slice(0, -1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { settleAllPromises } from "@/helpers/layout-helper";
|
|||
import experimentMixin from "@/mixins/experiment-mixin";
|
||||
import { experimentSettings } from "@/constants/experiments";
|
||||
import { includesWindshieldReplacement } from "@/helpers/damage-helper";
|
||||
import { applicationConfig } from "@/constants/application-config.js";
|
||||
import store from "@/store";
|
||||
import router from "@/router";
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ export async function getDirectNavigation(toRoute) {
|
|||
// vehicle -> vehicle-damage
|
||||
// quote -> vin-lookup/estimate
|
||||
// insurance-company -> vin-lookup/estimate
|
||||
if (store.getters.requiresVerifiedRedirecting) {
|
||||
if (store.getters.payment?.insuranceCoverage?.isVerified) {
|
||||
if (fmgPageValue === fmgPageValues.VEHICLE) {
|
||||
return fmgPageValues.VEHICLE_DAMAGE;
|
||||
}
|
||||
|
|
@ -106,6 +107,8 @@ export async function getImplicitNavigation(toRoute) {
|
|||
*/
|
||||
|
||||
export async function navigateToHeritageFunnel({ shouldSaveSession, pageNameToLog }) {
|
||||
console.log(new Date() + " navigateToHeritageFunnel: " + JSON.stringify(applicationConfig));
|
||||
console.log(new Date() + " navigateToHeritageFunnel: " + applicationConfig.HERITAGE_FUNNEL);
|
||||
// Create the order (or save existing order) when navigating to Heritage Funnel.
|
||||
if (shouldSaveSession) {
|
||||
await saveSession({ pageNameToLog: pageNameToLog, shouldAwaitSaveSessionQueue: true });
|
||||
|
|
@ -133,7 +136,7 @@ export async function navigateToHeritageFunnel({ shouldSaveSession, pageNameToLo
|
|||
heritageParms["forceEndToEndInsurance"] = true;
|
||||
}
|
||||
|
||||
router.navigateToExternalUrl(externalUrls.HERITAGE_FUNNEL, heritageParms);
|
||||
router.navigateToExternalUrl(applicationConfig.HERITAGE_FUNNEL, heritageParms);
|
||||
}
|
||||
|
||||
export async function skipVinLookup() {
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ describe("capabilityQuestions.vue", () => {
|
|||
test("Should trigger handleCompletedQuestionChainAnswers if watched data changes", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
wrapper.vm.handleCompletedQuestionChainAnswers = jest.fn();
|
||||
const spy = jest.spyOn(wrapper.vm, "handleCompletedQuestionChainAnswers");
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -215,9 +215,10 @@ describe("estimate.vue", () => {
|
|||
|
||||
describe("estimate.vue", () => {
|
||||
test("should call forwardButtonAction if isExternalParameter is true and form is valid", async () => {
|
||||
store.commit(storeMutations.UPDATE_IS_EXTERNAL_PARAMETER, true);
|
||||
store.commit(storeMutations.UPDATE_EXTERNAL_PARAMETER_VIN_SELECTION, "decline");
|
||||
|
||||
store.getters = {
|
||||
isExternalParameter: true,
|
||||
externalParameterEstimate: { vinSelection: "decline" },
|
||||
};
|
||||
// Set up the component
|
||||
const { wrapper } = setupMocks({});
|
||||
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ describe("moldingQuestions.vue", () => {
|
|||
test("Should trigger handleCompletedQuestionChainAnswers if watched data changes", async () => {
|
||||
// Arrange
|
||||
const { wrapper } = setupMocks({});
|
||||
wrapper.vm.handleCompletedQuestionChainAnswers = jest.fn();
|
||||
const spy = jest.spyOn(wrapper.vm, "handleCompletedQuestionChainAnswers");
|
||||
|
||||
// Act
|
||||
|
|
@ -268,6 +269,7 @@ describe("moldingQuestions.vue", () => {
|
|||
},
|
||||
};
|
||||
});
|
||||
|
||||
const spy = jest.spyOn(wrapper.vm, "dispatchStoreAction");
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -164,6 +164,7 @@ describe("partQuestions.vue...", () => {
|
|||
order: {},
|
||||
};
|
||||
const { wrapper } = setupMocks({});
|
||||
wrapper.vm.handleCompletedQuestionChainAnswers = jest.fn();
|
||||
const spy = jest.spyOn(wrapper.vm, "handleCompletedQuestionChainAnswers");
|
||||
|
||||
// Act
|
||||
|
|
|
|||
|
|
@ -225,12 +225,12 @@ export default {
|
|||
// instead of what comes from the backend. This is to prevent issues with part interchange.
|
||||
const availableFrontWipers = orderHasFrontWipers
|
||||
? frontWipersOnOrder
|
||||
: resultMap.wipers.filter((wiper) => wiper.partType == partTypeStrings.FRONT_WIPER) ??
|
||||
[];
|
||||
: (resultMap.wipers.filter((wiper) => wiper.partType == partTypeStrings.FRONT_WIPER) ??
|
||||
[]);
|
||||
const availableRearWipers = orderHasRearWipers
|
||||
? rearWipersOnOrder
|
||||
: resultMap.wipers.filter((wiper) => wiper.partType == partTypeStrings.REAR_WIPER) ??
|
||||
[];
|
||||
: (resultMap.wipers.filter((wiper) => wiper.partType == partTypeStrings.REAR_WIPER) ??
|
||||
[]);
|
||||
|
||||
const lineItemsToTax = [
|
||||
resultMap.rainDefense,
|
||||
|
|
@ -526,14 +526,18 @@ export default {
|
|||
await submitWorkOrder({ pageNameToLog: "payment-method", submitAfterSave: true });
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_PIA_ALERT]: false }
|
||||
);
|
||||
} else {
|
||||
if (this.paymentMethod == paymentMethods.INSURANCE) {
|
||||
this.dispatchStoreAction(this.storeActions.SAVE_PAYMENT_TYPE, true, false);
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_INSURANCE,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_PIA_ALERT]: false }
|
||||
);
|
||||
} else {
|
||||
this.setupPia();
|
||||
|
|
@ -555,14 +559,16 @@ export default {
|
|||
} catch (error) {
|
||||
console.log("error: response from pia submit work order:" + error.message);
|
||||
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||
this.$route.params[routerParams.DISPLAY_PIA_ALERT] = true;
|
||||
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_PAY_NOW,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_PIA_ALERT]: false }
|
||||
);
|
||||
},
|
||||
hasSubmittedOrder() {
|
||||
|
|
@ -683,7 +689,7 @@ export default {
|
|||
shouldDisplayPiaAlert() {
|
||||
return (
|
||||
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] ||
|
||||
this.$route.params[routerParams.DISPLAY_PIA_ALERT]
|
||||
eval(window.history.state.displayPiaAlert)
|
||||
);
|
||||
},
|
||||
// Necessary to make the watcher of lineItems work
|
||||
|
|
|
|||
|
|
@ -747,7 +747,7 @@ export default {
|
|||
shouldDisplayPiaAlert(payMethod) {
|
||||
return (
|
||||
this.$route.query[queryStrings.DISPLAY_PIA_ALERT] === payMethod ||
|
||||
this.$route.params[routerParams.DISPLAY_PIA_ALERT] === payMethod
|
||||
eval(window.history.state.displayPiaAlert)
|
||||
);
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ import { partTypeStrings } from "@/constants/part-type-strings";
|
|||
import { containsLineItemWithPartType } from "@/helpers/service-package-helper";
|
||||
import { nextTick } from "vue";
|
||||
import { packageNames } from "@/constants/package-names";
|
||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
defineRule("option-required", required(errorMessages.OPTION_REQUIRED));
|
||||
|
||||
export default {
|
||||
|
|
@ -271,6 +272,20 @@ export default {
|
|||
validateAlerts[0].shouldAutoFade
|
||||
);
|
||||
}
|
||||
|
||||
const payment = store.getters.payment;
|
||||
const policy = store.getters.policy;
|
||||
if (payment?.isInsurance) {
|
||||
const vehicleChangedDuringPolicyLookupInHeritage =
|
||||
payment.insuranceCoverage?.coverageStatus && policy?.policyNumber !== "";
|
||||
|
||||
// This is a safeguard to prevent insurance from seeing quote page again.
|
||||
// Usually this is caught in vehicle-questions-mixin with a referral length 6 check
|
||||
if (vehicleChangedDuringPolicyLookupInHeritage) {
|
||||
navigateToHeritageFunnel({ shouldSaveSession: true, pageNameToLog: "quote" });
|
||||
}
|
||||
}
|
||||
|
||||
if (store.getters.isExternalParameter) {
|
||||
if (store.getters.externalParameterQuote.isInsurance == true) {
|
||||
vm.isInsuranceSelected = true;
|
||||
|
|
|
|||
|
|
@ -384,6 +384,7 @@ describe("service-package-question.vue", () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
wrapper.vm.selectDefaultPackage = jest.fn();
|
||||
const selectDefaultPackageMock = jest.spyOn(wrapper.vm, "selectDefaultPackage");
|
||||
await nextTick();
|
||||
|
||||
|
|
|
|||
|
|
@ -233,7 +233,10 @@ export default {
|
|||
},
|
||||
getDiscountedPackagePriceString(packageName, servicePackageDiscount) {
|
||||
const formattedPriceFloat = parseFloat(
|
||||
this.getPackagePrice(packageName, { discountedPrice: true, servicePackageDiscount })
|
||||
this.getPackagePrice(packageName, {
|
||||
discountedPrice: true,
|
||||
servicePackageDiscount,
|
||||
})
|
||||
).toFixed(2);
|
||||
return (this.isInsuranceSelected ? "As little as $" : "$") + formattedPriceFloat;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ describe("service-package-radio.vue", () => {
|
|||
});
|
||||
|
||||
const mockProps = {
|
||||
groupName: "group-name",
|
||||
buttonLabel: "buttonLabel test copy",
|
||||
buttonLabelAuxillaryCopy: "buttonLabelAuxillaryCopy test copy",
|
||||
buttonLabelSubCopy: "buttonLabelSubCopy test copy",
|
||||
|
|
|
|||
|
|
@ -173,7 +173,8 @@ export default {
|
|||
width: 100%;
|
||||
padding: 1rem;
|
||||
border: 1px solid $gray-300;
|
||||
box-shadow: 0px 4px 8px -4px rgba(0, 0, 0, 0.15),
|
||||
box-shadow:
|
||||
0px 4px 8px -4px rgba(0, 0, 0, 0.15),
|
||||
0px 4px 24px -8px rgba(0, 0, 0, 0.2);
|
||||
border-radius: 0.5rem;
|
||||
overflow: hidden;
|
||||
|
|
@ -220,7 +221,9 @@ export default {
|
|||
+ .package-label {
|
||||
&:before {
|
||||
border: 1px solid #8e9292;
|
||||
box-shadow: 0px 0px 0px 4px #9fcee6, 0px 1px 4px rgba(0, 0, 0, 0.2);
|
||||
box-shadow:
|
||||
0px 0px 0px 4px #9fcee6,
|
||||
0px 1px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ describe("service-zip.vue", () => {
|
|||
|
||||
// Act
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||
jest.spyOn(wrapper.vm, "navigateForwardWithSingleCarMatch").mockImplementation();
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
|
@ -329,7 +329,7 @@ describe("service-zip.vue", () => {
|
|||
|
||||
// Act
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||
jest.spyOn(wrapper.vm, "navigateForwardWithSingleCarMatch").mockImplementation();
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
|
@ -397,6 +397,7 @@ describe("service-zip.vue", () => {
|
|||
wrapper.vm.displayInvalidZipAlert = true;
|
||||
wrapper.vm.displayNonServiceableZipAlert = true;
|
||||
|
||||
wrapper.vm.navigateForwardWithSingleCarMatch = jest.fn();
|
||||
jest.spyOn(wrapper.vm, "navigateForwardWithSingleCarMatch").mockImplementation();
|
||||
|
||||
await wrapper.vm.forwardButtonAction();
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ import {
|
|||
skipVinLookupNotRepair,
|
||||
} from "@/helpers/heritage-integration/navigation-helper";
|
||||
import vinPagesMixin from "@/mixins/vin-pages-mixin";
|
||||
import { navigateToHeritageFunnel } from "@/helpers/heritage-integration/navigation-helper";
|
||||
import { saveSession } from "@/helpers/heritage-integration/order-helper.js";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import { queryStrings } from "@/constants/query-strings";
|
||||
|
|
@ -208,17 +207,7 @@ export default {
|
|||
const payment = this.$store.getters.payment;
|
||||
const policy = this.$store.getters.policy;
|
||||
|
||||
const vehicleChangedDuringPolicyLookupInHeritage =
|
||||
payment.isInsurance &&
|
||||
payment.insuranceCoverage.coverageStatus &&
|
||||
policy.policyNumber !== "";
|
||||
|
||||
if (vehicleChangedDuringPolicyLookupInHeritage) {
|
||||
navigateToHeritageFunnel({
|
||||
shouldSaveSession: true,
|
||||
pageNameToLog: "estimate",
|
||||
});
|
||||
} else if (this.$store.getters.order.referralNumber?.length === 6) {
|
||||
if (this.$store.getters.order.referralNumber?.length === 6) {
|
||||
await this.navigateForwardWithSingleCarMatch();
|
||||
} else if (this.isRepair) {
|
||||
const supportingItemsPromise = await this.dispatchStoreActionWithLogging(
|
||||
|
|
|
|||
|
|
@ -75,8 +75,13 @@ export default {
|
|||
: [];
|
||||
return filteredAnswers.map((ans) => {
|
||||
const newName = ans.Name.includes("-") ? ans.Name.split("-")[1] : ans.Name;
|
||||
ans.Name = newName;
|
||||
return ans;
|
||||
return {
|
||||
Name: newName,
|
||||
AnswerImageUrl: ans.AnswerImageUrl,
|
||||
ImageId: ans.ImageId,
|
||||
SubText: ans.SubText,
|
||||
Text: ans.Text,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -83,8 +83,13 @@ export default {
|
|||
|
||||
return filteredAnswers.map((ans) => {
|
||||
const newName = ans.Name.includes("-") ? ans.Name.split("-")[1] : ans.Name;
|
||||
ans.Name = newName;
|
||||
return ans;
|
||||
return {
|
||||
Name: newName,
|
||||
AnswerImageUrl: ans.AnswerImageUrl,
|
||||
ImageId: ans.ImageId,
|
||||
SubText: ans.SubText,
|
||||
Text: ans.Text,
|
||||
};
|
||||
});
|
||||
},
|
||||
shouldDisplayReplaceOptionsQuestion() {
|
||||
|
|
|
|||
|
|
@ -142,8 +142,13 @@ export default {
|
|||
|
||||
return filteredAnswers.map((ans) => {
|
||||
const newName = ans.Name.includes("-") ? ans.Name.split("-")[1] : ans.Name;
|
||||
ans.Name = newName;
|
||||
return ans;
|
||||
return {
|
||||
Name: newName,
|
||||
AnswerImageUrl: ans.AnswerImageUrl,
|
||||
ImageId: ans.ImageId,
|
||||
SubText: ans.SubText,
|
||||
Text: ans.Text,
|
||||
};
|
||||
});
|
||||
},
|
||||
isDriverSideReplaceOptionsQuestionAvailable() {
|
||||
|
|
|
|||
|
|
@ -310,12 +310,11 @@ describe("vehicle-damage.vue", () => {
|
|||
describe("alert", () => {
|
||||
test("when displayVehicleChangeAlert router params is true, the alert: 'vehicleChangeAlert' should be rendered", () => {
|
||||
// Arrange & Act
|
||||
window.history.pushState({ displayVehicleChangeAlert: "true" }, "", "");
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
route: {
|
||||
params: {
|
||||
[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: true,
|
||||
},
|
||||
state: { displayVehicleChangeAlert: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
@ -325,21 +324,24 @@ describe("vehicle-damage.vue", () => {
|
|||
|
||||
test("when displayVehicleChangeAlert router params is false, the alert: 'vehicleChangeAlert' should not be rendered", () => {
|
||||
// Arrange & Act
|
||||
window.history.pushState({ displayVehicleChangeAlert: "false" }, "", "");
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
route: {
|
||||
params: {
|
||||
state: {
|
||||
[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
expect(wrapper.findComponent({ ref: "vehicleChangeAlert" }).exists()).toBe(false);
|
||||
});
|
||||
|
||||
test("when displayVehicleChangeAlert router params is undefined, the alert: 'vehicleChangeAlert' should not be rendered", () => {
|
||||
// Arrange & Act
|
||||
window.history.pushState({ displayVehicleChangeAlert: "false" }, "", "");
|
||||
const { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
route: {
|
||||
|
|
@ -850,7 +852,7 @@ function setupMocks({ pageHeaderWidgetHeaderText, mountOptionsMockData, funnelCo
|
|||
navigateWithSaving: jest.fn(),
|
||||
},
|
||||
route: {
|
||||
params: {
|
||||
state: {
|
||||
[routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false,
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ import { errorMessages } from "@/constants/error-messages";
|
|||
import { damageLocationsCms } from "@/constants/damage-locations-cms.js";
|
||||
import { damageLocationsSelected } from "@/constants/damage-locations-selected.js";
|
||||
import { getFunnelCookie } from "@/helpers/heritage-integration/cookie-helper";
|
||||
import { routerParams } from "@/router/router-constants/router-params";
|
||||
|
||||
import store from "@/store";
|
||||
import baseMixin from "@/mixins/base-mixin";
|
||||
|
|
@ -405,20 +406,26 @@ export default {
|
|||
if (skipVin) {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD_WITH_SKIP_VIN,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
|
||||
);
|
||||
} else {
|
||||
if (store.getters.damage.isRepair) {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios
|
||||
.CLICKED_FORWARD_WITH_REPAIR_AND_VERIFIED_INSURANCE,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
|
||||
);
|
||||
} else {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios
|
||||
.CLICKED_FORWARD_WITH_REPLACE_AND_VERIFIED_INSURANCE,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -427,17 +434,23 @@ export default {
|
|||
else if (store.getters.vehicle.vin) {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD_WITH_VIN,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
|
||||
);
|
||||
} else if (skipVin) {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD_WITH_SKIP_VIN,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
|
||||
);
|
||||
} else {
|
||||
this.$router.navigateWithSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD_WITHOUT_VIN,
|
||||
this.$route
|
||||
this.$route,
|
||||
{},
|
||||
{ [routerParams.DISPLAY_VEHICLE_CHANGE_ALERT]: false }
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
@ -566,7 +579,7 @@ export default {
|
|||
);
|
||||
},
|
||||
shouldDisplayVehicleChangeAlert() {
|
||||
return this.$route.params[this.routerParams.DISPLAY_VEHICLE_CHANGE_ALERT];
|
||||
return eval(window.history.state.displayVehicleChangeAlert);
|
||||
},
|
||||
shouldHideBackButton() {
|
||||
return this.$store.getters.requiresVerifiedRedirecting;
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@ defineRule(
|
|||
defineRule(
|
||||
"check-for-repair-and-replace",
|
||||
(selectedWindshieldDamageType, selectedDamageLocations) => {
|
||||
// vee-validate adds an extra arrray on initial selection
|
||||
// remove here
|
||||
selectedDamageLocations[0] = selectedDamageLocations[0].filter((location) => {
|
||||
return !Array.isArray(location);
|
||||
});
|
||||
return (
|
||||
selectedWindshieldDamageType.toString() != damageLocationsSelected.REPAIR ||
|
||||
(!selectedDamageLocations.includes(damageLocationsSelected.WINDSHIELD) &&
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ const basePartResponse = {
|
|||
};
|
||||
|
||||
describe("vehicle-parts.vue", () => {
|
||||
test("Set cms content called on load", async (done) => {
|
||||
test("Set cms content called on load", (done) => {
|
||||
//Arrange
|
||||
store.getters.pageData.mockReturnValue(basePartResponse);
|
||||
store.getters.lineItems = { glassParts: null };
|
||||
|
|
|
|||
|
|
@ -398,11 +398,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
isDisabled(options) {
|
||||
if (
|
||||
!options.length ||
|
||||
store.getters.requiresVerifiedRedirecting ||
|
||||
getFunnelCookie()?.HasDelayedClaimRegistration
|
||||
) {
|
||||
if (!options.length || store.getters.payment?.insuranceCoverage?.isVerified) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -222,12 +222,7 @@ export default {
|
|||
|
||||
// Provider Ctu
|
||||
if (isDefined(order.serviceLocation.zipCodeCtu)) {
|
||||
const parsedCtu = parseInt(order.serviceLocation.zipCodeCtu);
|
||||
if (!isNaN(parsedCtu)) {
|
||||
payload.providerCtu = parseInt(order.serviceLocation.zipCodeCtu);
|
||||
} else {
|
||||
payload.providerCtu = "";
|
||||
}
|
||||
payload.providerCtu = order.serviceLocation.zipCodeCtu;
|
||||
} else {
|
||||
payload.providerCtu = "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ describe("input-button-wrapper-mixin", () => {
|
|||
expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
|
||||
expect(wrapper.vm.value).toEqual([]);
|
||||
|
||||
await inputButtonOne.find("input").trigger("click");
|
||||
await inputButtonTwo.find("input").trigger("click");
|
||||
await inputButtonOne.find("input").setChecked();
|
||||
await inputButtonTwo.find("input").setChecked();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.value).toEqual(["value1", "value2"]);
|
||||
|
|
@ -52,9 +52,9 @@ describe("input-button-wrapper-mixin", () => {
|
|||
expect(inputButtonTwo.vm.isMultiSelect).toBe(true);
|
||||
expect(wrapper.vm.value).toEqual([]);
|
||||
|
||||
await inputButtonOne.find("input").trigger("click");
|
||||
await inputButtonTwo.find("input").trigger("click");
|
||||
await inputButtonOne.find("input").trigger("click");
|
||||
await inputButtonOne.find("input").setChecked();
|
||||
await inputButtonTwo.find("input").setChecked();
|
||||
await inputButtonOne.find("input").setChecked(false);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.value).toEqual(["value2"]);
|
||||
|
|
@ -80,8 +80,8 @@ describe("input-button-wrapper-mixin", () => {
|
|||
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
|
||||
expect(wrapper.vm.value).toEqual("");
|
||||
|
||||
await inputButtonOne.find("input").trigger("click");
|
||||
await inputButtonTwo.find("input").trigger("click");
|
||||
await inputButtonOne.find("input").setChecked();
|
||||
await inputButtonTwo.find("input").setChecked();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.value).toEqual("value2");
|
||||
|
|
@ -105,9 +105,9 @@ describe("input-button-wrapper-mixin", () => {
|
|||
expect(inputButtonTwo.vm.isMultiSelect).toBe(false);
|
||||
expect(wrapper.vm.value).toEqual("");
|
||||
|
||||
await inputButtonOne.find("input").trigger("click");
|
||||
await inputButtonTwo.find("input").trigger("click");
|
||||
await inputButtonOne.find("input").trigger("click");
|
||||
await inputButtonOne.find("input").setChecked();
|
||||
await inputButtonTwo.find("input").setChecked();
|
||||
await inputButtonOne.find("input").setChecked();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.value).toEqual("value1");
|
||||
|
|
@ -295,23 +295,20 @@ function setupBaseInputButtonWrapper({ mockData = {} }) {
|
|||
parentComponentTemplate += `<baseInputButtonWrapper v-model="value" groupName="myGroupName" :isMultiSelect="${mockData.isMultiSelect}" value="value1" />`;
|
||||
parentComponentTemplate += `<baseInputButtonWrapper v-model="value" groupName="myGroupName" :isMultiSelect="${mockData.isMultiSelect}" value="value2" />`;
|
||||
parentComponentTemplate += `</div>`;
|
||||
const wrapper = mount(
|
||||
{
|
||||
data() {
|
||||
return {
|
||||
value: mockData.initialValue ?? (mockData.isMultiSelect ? [] : ""),
|
||||
$route: {
|
||||
query: {
|
||||
fmgPage: "myPage",
|
||||
},
|
||||
const wrapper = mount({
|
||||
data() {
|
||||
return {
|
||||
value: mockData.initialValue ?? (mockData.isMultiSelect ? [] : ""),
|
||||
$route: {
|
||||
query: {
|
||||
fmgPage: "myPage",
|
||||
},
|
||||
};
|
||||
},
|
||||
template: parentComponentTemplate,
|
||||
components: { baseInputButtonWrapper },
|
||||
},
|
||||
};
|
||||
},
|
||||
{}
|
||||
);
|
||||
template: parentComponentTemplate,
|
||||
components: { baseInputButtonWrapper },
|
||||
});
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,9 +123,8 @@ export default {
|
|||
answerString;
|
||||
// mark this question as suppressed if needed (question-chain uses this)
|
||||
if (answeredQuestion.suppressThisQuestion) {
|
||||
glass.questions[
|
||||
answeredQuestion.questionNum - 1
|
||||
].suppressThisQuestion = true;
|
||||
glass.questions[answeredQuestion.questionNum - 1].suppressThisQuestion =
|
||||
true;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
updateSessionIdCookie,
|
||||
deleteFunnelCookie,
|
||||
getAffiliateCookies,
|
||||
setupAdvertiserTracking,
|
||||
} from "@/helpers/heritage-integration/cookie-helper";
|
||||
import { loadSessionIfPresent, saveSession } from "@/helpers/heritage-integration/order-helper";
|
||||
import {
|
||||
|
|
@ -103,7 +104,7 @@ const routes = [
|
|||
if (affiliateCookies != null && affiliateCookies.length > 0) {
|
||||
store.commit(storeMutations.UPDATE_AFFILIATE_COOKIES, affiliateCookies);
|
||||
}
|
||||
|
||||
setupAdvertiserTracking();
|
||||
const loadSessionResponse = await loadSessionIfPresent(
|
||||
to.query.isInsurance != null
|
||||
? to.query.isInsurance == "true"
|
||||
|
|
@ -129,7 +130,7 @@ const routes = [
|
|||
// Reroute around pages that should not be available.
|
||||
|
||||
// Exception 1: Integrated Users should not see vehicle or quote pages.
|
||||
if (store.getters.requiresVerifiedRedirecting) {
|
||||
if (store.getters.payment?.insuranceCoverage?.isVerified) {
|
||||
if (to.query.fmgPage === fmgPageValues.VEHICLE) {
|
||||
to.query.fmgPage = fmgPageValues.VEHICLE_DAMAGE;
|
||||
} else if (
|
||||
|
|
@ -286,7 +287,7 @@ router.afterEach(async (to, from) => {
|
|||
store.commit(storeMutations.UPDATE_LAST_PAGE_VISITED, to.name);
|
||||
|
||||
// If saving on navigation is requested, check for saved SessionId or EmailAddress to determine if saving is appropriate
|
||||
if (eval(to.params.isSavingNavigation)) {
|
||||
if (eval(window.history.state.isSavingNavigation)) {
|
||||
if (
|
||||
store.getters.applicationUser.savedSessionId ||
|
||||
store.getters.order.customer?.emailAddress
|
||||
|
|
@ -394,7 +395,7 @@ async function navigate(
|
|||
destinationFmgPageValue,
|
||||
Object.keys(optionalPageData).length > 0
|
||||
? optionalPageData
|
||||
: existingPageDataForPage ?? {}
|
||||
: (existingPageDataForPage ?? {})
|
||||
);
|
||||
|
||||
optionalParams.isSavingNavigation = isSavingNavigation;
|
||||
|
|
@ -430,7 +431,7 @@ async function navigate(
|
|||
router.push({
|
||||
name: "root",
|
||||
query: Object.assign(optionalQuery, queryStringsObject),
|
||||
params: optionalParams,
|
||||
state: optionalParams,
|
||||
});
|
||||
} else if (matchingScenarioMap.destinationUrl !== undefined) {
|
||||
navigateToUrl(matchingScenarioMap.destinationUrl, optionalQuery);
|
||||
|
|
@ -524,7 +525,7 @@ async function DisplayPageError() {
|
|||
// we use the pageError querystring as a counter to how many times a user has experienced an error and been routed here.
|
||||
// once they receive more than 1 pageerrors, we'll reset their state to hopefully correct any issues they may be having.
|
||||
var navPage = fmgPageValues.VEHICLE;
|
||||
if (store.getters.requiresVerifiedRedirecting) {
|
||||
if (store.getters.payment?.insuranceCoverage?.isVerified) {
|
||||
navPage = fmgPageValues.VEHICLE_DAMAGE;
|
||||
}
|
||||
|
||||
|
|
@ -590,7 +591,7 @@ async function runExperiments(nextPage) {
|
|||
}
|
||||
|
||||
function getRedirectedStartPage() {
|
||||
if (store.getters.requiresVerifiedRedirecting) {
|
||||
if (store.getters.payment?.insuranceCoverage?.isVerified) {
|
||||
return fmgPageValues.VEHICLE_DAMAGE;
|
||||
} else {
|
||||
return funnelStartPageName;
|
||||
|
|
|
|||
|
|
@ -214,7 +214,9 @@ html {
|
|||
box-shadow: none;
|
||||
}
|
||||
&.btn.btn-primary:focus-visible {
|
||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $gray-700;
|
||||
box-shadow:
|
||||
0 0 0 3px $white,
|
||||
0 0 0 5.5px $gray-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,13 +75,17 @@ export default {
|
|||
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
|
||||
}
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px,
|
||||
0 0 0 5.5px $blue-700;
|
||||
}
|
||||
&:focus, // Mouse, touch, stylus focus
|
||||
&:focus-visible {
|
||||
// Keyboard focus for accessibility
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px,
|
||||
0 0 0 5.5px $blue-700;
|
||||
color: $white;
|
||||
background: linear-gradient(270deg, rgba(6, 87, 124, 1) 0%, rgba(6, 87, 124, 1) 100%);
|
||||
}
|
||||
|
|
@ -99,7 +103,9 @@ export default {
|
|||
&.has-loader {
|
||||
color: $white;
|
||||
background: $blue-700;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px,
|
||||
0 0 0 5.5px $blue-700;
|
||||
pointer-events: auto;
|
||||
}
|
||||
&.delay {
|
||||
|
|
@ -124,7 +130,9 @@ export default {
|
|||
&:focus-visible {
|
||||
// Keyboard focus for accessibility
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px $white,
|
||||
0 0 0 5.5px $blue-700;
|
||||
color: $white;
|
||||
@include blue-gradient;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ describe("checkbox.vue", () => {
|
|||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: {
|
||||
groupName: "checkbox-button-test",
|
||||
buttonLabel: "label text",
|
||||
value: "test value",
|
||||
},
|
||||
|
|
@ -42,7 +43,15 @@ describe("checkbox.vue", () => {
|
|||
|
||||
it("Should have correct screenreader-only text", async () => {
|
||||
// Act
|
||||
let { wrapper } = setupMocks({});
|
||||
let { wrapper } = setupMocks({
|
||||
mountOptionsMockData: {
|
||||
propsData: {
|
||||
groupName: "checkbox-button-test",
|
||||
buttonLabel: "label text",
|
||||
value: "test value",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Arrange
|
||||
await wrapper.setProps({
|
||||
|
|
|
|||
|
|
@ -141,7 +141,9 @@ export default {
|
|||
}
|
||||
|
||||
&:checked:focus + .list-button-horizontal-content {
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
|
||||
box-shadow:
|
||||
0 0 0 3px,
|
||||
0 0 0 5.5px $blue-700;
|
||||
}
|
||||
|
||||
&:checked + .list-button-horizontal-content p:first-child {
|
||||
|
|
|
|||
|
|
@ -295,6 +295,12 @@ describe("list-button.vue", () => {
|
|||
});
|
||||
|
||||
function setupMocks({ mockData }) {
|
||||
// Add in group name to avoid vee-validate failures
|
||||
if (!mockData.propsData) {
|
||||
mockData.propsData = { groupName: "group-name" };
|
||||
} else if (!mockData.propsData.groupName) {
|
||||
mockData.propsData.groupName = "group-name";
|
||||
}
|
||||
const wrapper = mount(listButton, {
|
||||
...mockData,
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
|
|
|
|||
|
|
@ -57,6 +57,12 @@ describe("radio.vue", () => {
|
|||
});
|
||||
|
||||
function setupMocks({ mountOptionsMockData = {} }) {
|
||||
// Add in group name to avoid vee-validate failures
|
||||
if (!mountOptionsMockData.propsData) {
|
||||
mountOptionsMockData.propsData = { groupName: "group-name" };
|
||||
} else if (!mountOptionsMockData.propsData.groupName) {
|
||||
mountOptionsMockData.propsData.groupName = "group-name";
|
||||
}
|
||||
const wrapper = mount(radio, {
|
||||
...mountOptionsMockData,
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
|
|
|
|||
Loading…
Reference in a new issue