Merge branch 'develop' into feature/jnou/fix-iss-regression
This commit is contained in:
commit
9835de34c7
20 changed files with 1408 additions and 2105 deletions
BIN
src/assets/img/tints/GlassTint.png
Normal file
BIN
src/assets/img/tints/GlassTint.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
|
|
@ -93,6 +93,10 @@ const endpoints = Object.freeze({
|
||||||
) => `${LOCATION_BASE_URL}/providers/${zipCode}/${damageType}/${radius}/${parentAccountNumber}/${safeliteOnly}/${carId}/${recalPartNumber != null ? `${recalPartNumber}/` : ''}${isBigTruck}`,
|
) => `${LOCATION_BASE_URL}/providers/${zipCode}/${damageType}/${radius}/${parentAccountNumber}/${safeliteOnly}/${carId}/${recalPartNumber != null ? `${recalPartNumber}/` : ''}${isBigTruck}`,
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
},
|
},
|
||||||
|
GetTpaAndSafeliteProviders: {
|
||||||
|
url: `${LOCATION_BASE_URL}/tpa-and-safelite-providers`,
|
||||||
|
method: 'GET'
|
||||||
|
},
|
||||||
GetCapabilityQuestions: {
|
GetCapabilityQuestions: {
|
||||||
url: `${PARTS_BASE_URL}/capability-questions`,
|
url: `${PARTS_BASE_URL}/capability-questions`,
|
||||||
method: 'GET'
|
method: 'GET'
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,10 @@ const errorMessages = Object.freeze({
|
||||||
DATE_REQUIRED: 'Please select a date',
|
DATE_REQUIRED: 'Please select a date',
|
||||||
TIME_REQUIRED: 'Please select an appointment time.',
|
TIME_REQUIRED: 'Please select an appointment time.',
|
||||||
PRIMARY_PHONE_REQUIRED: 'Primary phone number is required.',
|
PRIMARY_PHONE_REQUIRED: 'Primary phone number is required.',
|
||||||
BAILOUT_EMAIL_ADDRESS_REQUIRED: 'Email address is required.'
|
BAILOUT_EMAIL_ADDRESS_REQUIRED: 'Email address is required.',
|
||||||
|
TPA_SEARCH_ZIP_FORMAT: 'Please enter a valid Zip code.',
|
||||||
|
TPA_SEARCH_SHOP_FORMAT: 'Please enter a valid shop name.',
|
||||||
|
TPA_SEARCH_REQUIRED: 'Please enter a shop name or ZIP code.'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default errorMessages;
|
export default errorMessages;
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,8 @@ const globalRules = Object.freeze({
|
||||||
ZIP_CODE_SEARCH_FORMAT: 'zip-code-search-format',
|
ZIP_CODE_SEARCH_FORMAT: 'zip-code-search-format',
|
||||||
OPTION_REQUIRED: 'option-required',
|
OPTION_REQUIRED: 'option-required',
|
||||||
PRIMARY_PHONE_REQUIRED: 'primary-phone-required',
|
PRIMARY_PHONE_REQUIRED: 'primary-phone-required',
|
||||||
BAILOUT_EMAIL_ADDRESS_REQUIRED: 'bailout-email-address-required'
|
BAILOUT_EMAIL_ADDRESS_REQUIRED: 'bailout-email-address-required',
|
||||||
|
TPA_SEARCH_FORMAT: 'tpa-search-format'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default globalRules;
|
export default globalRules;
|
||||||
|
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
// TintMap with array keys by location, lowercase to avoid as much string mismatching as possible.
|
|
||||||
// Src assumes you have a @/assets/img/tints/, making the final value @/assets/img/tints/{Src} in the markup.
|
|
||||||
// See vehicle-parts for implementation example.
|
|
||||||
const tintMap = Object.freeze({
|
|
||||||
other: [
|
|
||||||
// Blue Shade
|
|
||||||
{ name: 'blue tint, blue shade', src: 'Glass-BlueShade-BlueTint.svg' },
|
|
||||||
{ name: 'brown tint, blue shade', src: 'Glass-BlueShade-BrownTint.svg' },
|
|
||||||
{ name: 'gray tint, blue shade', src: 'Glass-BlueShade-GrayTint.svg' },
|
|
||||||
{ name: 'green tint, blue shade', src: 'Glass-BlueShade-GreenTint.svg' },
|
|
||||||
{ name: 'clear, blue shade', src: 'Glass-BlueShade-NoTint.svg' },
|
|
||||||
|
|
||||||
// Brown Shade
|
|
||||||
{ name: 'brown tint, brown shade', src: 'Glass-BrownShade-BrownTint.svg' },
|
|
||||||
|
|
||||||
// Gray Shade
|
|
||||||
{ name: 'blue tint, gray shade', src: 'Glass-GrayShade-BlueTint.svg' },
|
|
||||||
{ name: 'brown tint, gray shade', src: 'Glass-GrayShade-BrownTint.svg' },
|
|
||||||
{ name: 'gray tint, gray shade', src: 'Glass-GrayShade-GrayTint.svg' },
|
|
||||||
{ name: 'green tint, gray shade', src: 'Glass-GrayShade-GreenTint.svg' },
|
|
||||||
|
|
||||||
// Green Shade
|
|
||||||
{ name: 'blue tint, green shade', src: 'Glass-GreenShade-BlueTint.svg' },
|
|
||||||
{ name: 'brown tint, green shade', src: 'Glass-GreenShade-BrownTint.svg' },
|
|
||||||
{ name: 'green tint, green shade', src: 'Glass-GreenShade-GreenTint.svg' },
|
|
||||||
|
|
||||||
// Tints Only
|
|
||||||
{ name: 'blue tint privacy', src: 'Glass-NoShade-BlueTint.svg' },
|
|
||||||
{ name: 'bronze tint', src: 'Glass-NoShade-BrownTint.svg' },
|
|
||||||
{ name: 'dark brown tint', src: 'Glass-NoShade-DarkBrownTint.svg' },
|
|
||||||
{ name: 'privacy, black frame', src: 'Glass-NoShade-Privacy.svg' },
|
|
||||||
{ name: 'gray tint', src: 'Glass-NoShade-GrayTint.svg' },
|
|
||||||
{ name: 'green tint', src: 'Glass-NoShade-GreenTint.svg' },
|
|
||||||
{ name: 'gray tint privacy', src: 'Glass-NoShade-GrayTint.svg' },
|
|
||||||
{ name: 'blue tint', src: 'Glass-NoShade-BlueTint.svg' },
|
|
||||||
{ name: 'green tint privacy', src: 'Glass-NoShade-GreenTint.svg' },
|
|
||||||
|
|
||||||
// No shade or tint
|
|
||||||
{ name: 'clear', src: 'Glass-NoShade-NoTint.svg' }
|
|
||||||
],
|
|
||||||
|
|
||||||
windshield: [
|
|
||||||
// Blue Shade
|
|
||||||
{ name: 'blue tint, blue shade', src: 'Windshield-BlueShade-BlueTint.svg' },
|
|
||||||
{ name: 'bronze tint, blue shade', src: 'Windshield-BlueShade-BrownTint.svg' },
|
|
||||||
{ name: 'gray tint, blue shade', src: 'Windshield-BlueShade-GrayTint.svg' },
|
|
||||||
{ name: 'green tint, blue shade', src: 'Windshield-BlueShade-GreenTint.svg' },
|
|
||||||
{ name: 'clear, blue shade', src: 'Windshield-BlueShade-NoTint.svg' },
|
|
||||||
|
|
||||||
// Brown Shade
|
|
||||||
{ name: 'bronze tint, bronze shade', src: 'Windshield-BrownShade-BrownTint.svg' },
|
|
||||||
|
|
||||||
// Gray Shade
|
|
||||||
{ name: 'blue tint, gray shade', src: 'Windshield-GrayShade-BlueTint.svg' },
|
|
||||||
{ name: 'brown tint, gray shade', src: 'Windshield-GrayShade-BrownTint.svg' },
|
|
||||||
{ name: 'gray tint, gray shade', src: 'Windshield-GrayShade-GrayTint.svg' },
|
|
||||||
{ name: 'green tint, gray shade', src: 'Windshield-GrayShade-GreenTint.svg' },
|
|
||||||
|
|
||||||
// Green Shade
|
|
||||||
{ name: 'blue tint, green shade', src: 'Windshield-GreenShade-BlueTint.svg' },
|
|
||||||
{ name: 'brown tint, green shade', src: 'Windshield-GreenShade-BrownTint.svg' },
|
|
||||||
{ name: 'green tint, green shade', src: 'Windshield-GreenShade-GreenTint.svg' },
|
|
||||||
|
|
||||||
// Tints Only
|
|
||||||
{ name: 'blue tint', src: 'Windshield-NoShade-BlueTint.svg' },
|
|
||||||
{ name: 'bronze tint', src: 'Windshield-NoShade-BrownTint.svg' },
|
|
||||||
{ name: 'dark brown tint', src: 'Windshield-NoShade-DarkBrownTint.svg' },
|
|
||||||
{ name: 'privacy, black frame', src: 'Windshield-NoShade-Privacy.svg' },
|
|
||||||
{ name: 'gray tint', src: 'Windshield-NoShade-GrayTint.svg' },
|
|
||||||
{ name: 'green tint', src: 'Windshield-NoShade-GreenTint.svg' },
|
|
||||||
{ name: 'gray tint privacy', src: 'Windshield-NoShade-GrayTint.svg' },
|
|
||||||
|
|
||||||
// No shade or tint
|
|
||||||
{ name: 'clear', src: 'Windshield-NoShade-NoTint.svg' }
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Gets the tint image source string given the glass location, and the tint description (like 'Green Tint')
|
|
||||||
// Use lowered strings here to try to avoid mismatch. Returns an empty string if array key doesn't exist.
|
|
||||||
// Returns undefined if no items are found.
|
|
||||||
const getTintImage = (glassLocation, colorString) => {
|
|
||||||
// Windshield glass has special images, all other glass uses the same though.
|
|
||||||
const glassLoc = (glassLocation.toLowerCase() !== 'windshield') ? 'other' : 'windshield';
|
|
||||||
if (tintMap[glassLoc] === undefined) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return tintMap[glassLoc].find((item) => item.name.toLowerCase() === colorString.toLowerCase());
|
|
||||||
};
|
|
||||||
|
|
||||||
export default getTintImage;
|
|
||||||
|
|
@ -310,22 +310,31 @@ input::-webkit-date-and-time-value {
|
||||||
.input-wrapper {
|
.input-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
&.has-search-icon {
|
&.has-search-icon {
|
||||||
|
display:flex;
|
||||||
|
.form-control {
|
||||||
|
&:focus, &:focus-within {
|
||||||
|
border: 1px solid #0070d1;
|
||||||
|
}
|
||||||
|
max-height: 3rem;
|
||||||
|
}
|
||||||
input[type='text'] {
|
input[type='text'] {
|
||||||
border-radius: $border-radius;
|
border-color: #0070d1;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.2) 0rem 0.0625rem .25rem 0rem;
|
||||||
|
border-right: none;
|
||||||
|
border-radius: 4.5rem 0 0 4.5rem;
|
||||||
|
height: 3rem;
|
||||||
|
&:focus, &:focus-within {
|
||||||
|
border-right:none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
button[type='submit'] {
|
button[type='submit'] {
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
right: 0;
|
|
||||||
background-image: url($svg-search-icon);
|
background-image: url($svg-search-icon);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
border-radius: 0 $border-radius-lg $border-radius-lg 0;
|
border-radius: 0 4.5rem 4.5rem 0;
|
||||||
background-color: $blue-100;
|
background-color: $blue-100;
|
||||||
width: 2.75rem;
|
width: 2.75rem;
|
||||||
height: 100%;
|
border: 1px solid #0070d1;
|
||||||
border: 1px solid $gray-500;
|
|
||||||
border-left: none;
|
border-left: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,28 @@ function defineGlobalZipCodeRules() {
|
||||||
defineRule(globalRules.ZIP_CODE_SEARCH_FORMAT, regex(/^\d{5}$/, errorMessages.ZIP_FORMAT));
|
defineRule(globalRules.ZIP_CODE_SEARCH_FORMAT, regex(/^\d{5}$/, errorMessages.ZIP_FORMAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Define global rules related to the zip code/shop name search on TPA Search page
|
||||||
|
*/
|
||||||
|
function defineGlobalTpaSearchRules() {
|
||||||
|
defineRule(globalRules.TPA_SEARCH_FORMAT, (value) => {
|
||||||
|
if (value.length === 0) {
|
||||||
|
return errorMessages.TPA_SEARCH_REQUIRED;
|
||||||
|
}
|
||||||
|
// Non Numeric
|
||||||
|
if (isNaN(value)) {
|
||||||
|
if (value.length < 3) {
|
||||||
|
return errorMessages.TPA_SEARCH_SHOP_FORMAT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (value.length != 5) {
|
||||||
|
return errorMessages.TPA_SEARCH_ZIP_FORMAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function defineGlobalRules
|
* @function defineGlobalRules
|
||||||
* @summary Define all global rules
|
* @summary Define all global rules
|
||||||
|
|
@ -138,6 +160,6 @@ export default function defineGlobalRules() {
|
||||||
defineGlobalPolicyNumberRules();
|
defineGlobalPolicyNumberRules();
|
||||||
defineGlobalPolicyZipCodeRules();
|
defineGlobalPolicyZipCodeRules();
|
||||||
defineGlobalZipCodeRules();
|
defineGlobalZipCodeRules();
|
||||||
|
defineGlobalTpaSearchRules();
|
||||||
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));
|
defineRule(globalRules.OPTION_REQUIRED, required(errorMessages.OPTION_REQUIRED));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ export function createUnorderedListFromStringOfParagraphs(stringOfParagraphs) {
|
||||||
*/
|
*/
|
||||||
export function toTitleCase(text) {
|
export function toTitleCase(text) {
|
||||||
let temp = text?.toLowerCase() ?? '';
|
let temp = text?.toLowerCase() ?? '';
|
||||||
return temp.replace(/(^|\s|-)\S/g, (letter) => letter.toUpperCase());
|
return temp.replace(/(^|\s|-|\/)\S/g, (letter) => letter.toUpperCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<div class="iss-heritage-container-width">
|
<div class="iss-heritage-container-width">
|
||||||
<div class="questions-page-layout-container iss-heritage-content-container-width">
|
<div class="questions-page-layout-container iss-heritage-content-container-width">
|
||||||
<siteSubHeader
|
<siteSubHeader
|
||||||
class="mt-4"
|
class="mt-4 subheader"
|
||||||
cmsWidgetName="SiteSubHeaderWidget" />
|
cmsWidgetName="SiteSubHeaderWidget" />
|
||||||
<alert
|
<alert
|
||||||
v-if="alertFewMoreQuestionsHeader || alertFewMoreQuestionsCopy"
|
v-if="alertFewMoreQuestionsHeader || alertFewMoreQuestionsCopy"
|
||||||
|
|
@ -129,6 +129,13 @@ export default {
|
||||||
padding-left: .9375rem;
|
padding-left: .9375rem;
|
||||||
padding-right: .9375rem;
|
padding-right: .9375rem;
|
||||||
}
|
}
|
||||||
|
.subheader {
|
||||||
|
:deep(strong) {
|
||||||
|
color: $black;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.questions-page {
|
.questions-page {
|
||||||
|
|
@ -141,6 +148,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.need-help-link-container {
|
.need-help-link-container {
|
||||||
|
margin-top: 1.875rem;
|
||||||
margin-bottom: 2.25rem;
|
margin-bottom: 2.25rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,13 @@
|
||||||
id="stacked"
|
id="stacked"
|
||||||
class="col button-col d-flex px-0">
|
class="col button-col d-flex px-0">
|
||||||
<buttonMain
|
<buttonMain
|
||||||
v-if="!isForwardButtonHidden"
|
|
||||||
ref="buttonMain"
|
ref="buttonMain"
|
||||||
variant="navigation"
|
variant="navigation"
|
||||||
:buttonText="buttonText"
|
:buttonText="buttonText"
|
||||||
:class="
|
:class="{
|
||||||
(disableForwardAction || isForwardActionDisabled) &&
|
'form-test-invalid': (disableForwardAction || isForwardActionDisabled),
|
||||||
'form-test-invalid'
|
'hide-button': isForwardButtonHidden
|
||||||
"
|
}"
|
||||||
:aria-disabled="disableForwardAction || isForwardActionDisabled"
|
:aria-disabled="disableForwardAction || isForwardActionDisabled"
|
||||||
:isDisabled="disableForwardAction || isForwardActionDisabled"
|
:isDisabled="disableForwardAction || isForwardActionDisabled"
|
||||||
data-test-id="site-footer-main-button"
|
data-test-id="site-footer-main-button"
|
||||||
|
|
@ -149,5 +148,8 @@ export default {
|
||||||
margin-top: 1.25rem;
|
margin-top: 1.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hide-button {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
119
src/iss-components/tpa-shop-list-button/tpa-shop-list-button.vue
Normal file
119
src/iss-components/tpa-shop-list-button/tpa-shop-list-button.vue
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
<template>
|
||||||
|
<transition
|
||||||
|
name="fade"
|
||||||
|
mode="out-in">
|
||||||
|
<baseInputButton
|
||||||
|
v-bind="$props"
|
||||||
|
v-model="selectedValue"
|
||||||
|
buttonWrapperClasses="list-group base-input-button list-button rounded-3 d-flex flex-column w-100 label-margin-bottom no-hover">
|
||||||
|
<div
|
||||||
|
:aria-label="buttonLabel"
|
||||||
|
class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
||||||
|
<div class="row-one">
|
||||||
|
<span
|
||||||
|
id="buttonLabelSpan"
|
||||||
|
class="m-0 button-label-copy"
|
||||||
|
:class="textPosition">{{ buttonLabel }}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
id="buttonLabelSubCopySpan"
|
||||||
|
class="m-0 caption ms-2"
|
||||||
|
:class="textPosition">{{ buttonLabelSubCopy }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="row-two">
|
||||||
|
<span
|
||||||
|
v-if="buttonBodyCopy"
|
||||||
|
id="buttonBodyCopy"
|
||||||
|
class="m-0 button-label-sub-copy"
|
||||||
|
v-html="buttonBodyCopy"></span>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
v-if="screenReaderOnlyText"
|
||||||
|
id="screenReaderOnlyTextSpan"
|
||||||
|
class="sr-only">
|
||||||
|
{{ screenReaderOnlyText }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</baseInputButton>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import baseInputButton from '@/digital-components/base-input-button/base-input-button.vue';
|
||||||
|
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin';
|
||||||
|
import loader from '@/ux-components/loader/loader.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'tpa-shop-list-button',
|
||||||
|
components: {
|
||||||
|
baseInputButton,
|
||||||
|
loader
|
||||||
|
},
|
||||||
|
mixins: [inputButtonWrapperMixin],
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "@/styles/ux-variables-svg-strings.scss";
|
||||||
|
|
||||||
|
.list-button {
|
||||||
|
outline: none;
|
||||||
|
input[type="radio"],
|
||||||
|
input[type="checkbox"] {
|
||||||
|
position: static; //override bootstrap
|
||||||
|
|
||||||
|
&:checked + .list-button-content {
|
||||||
|
background: #e7f1f6;
|
||||||
|
border: 1px solid #0070d1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.list-button-content {
|
||||||
|
color: $gray-600;
|
||||||
|
position: relative;
|
||||||
|
background: $white;
|
||||||
|
transition: all 150ms linear;
|
||||||
|
border-radius: $border-radius-lg;
|
||||||
|
border: 1px solid $gray-500;
|
||||||
|
width: 100%;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
span {
|
||||||
|
&.small {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: $gray-550;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.button-content {
|
||||||
|
row-gap: 0.25rem;
|
||||||
|
color: #4d4e53;
|
||||||
|
font-size: .9375rem;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.625rem;
|
||||||
|
|
||||||
|
.row-one {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
|
||||||
|
.button-label-copy {
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
#buttonLabelSubCopySpan {
|
||||||
|
font-size: .75rem;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-two {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
div.col:not(:last-child) >.label-margin-bottom{
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,214 +0,0 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`TPA search page returns the initial data 1`] = `
|
|
||||||
Object {
|
|
||||||
"additionalButtonData": Object {
|
|
||||||
"displayAvailabilityIndicators": false,
|
|
||||||
},
|
|
||||||
"dataLoaded": false,
|
|
||||||
"filter": "",
|
|
||||||
"mapZipCode": null,
|
|
||||||
"providers": Array [],
|
|
||||||
"reloadingProviders": false,
|
|
||||||
"rules": Object {
|
|
||||||
"filter": "option-required",
|
|
||||||
"provider": "option-required",
|
|
||||||
"zipCode": "zip-code-required|zip-code-search-format",
|
|
||||||
},
|
|
||||||
"selectedProviderNumber": "",
|
|
||||||
"shopListButton": Object {
|
|
||||||
"beforeMount": [Function],
|
|
||||||
"components": Object {
|
|
||||||
"baseInputButton": Object {
|
|
||||||
"computed": Object {
|
|
||||||
"buttonId": [Function],
|
|
||||||
"eventTypes": [Function],
|
|
||||||
"inputType": [Function],
|
|
||||||
"isChecked": [Function],
|
|
||||||
"isValueSelectedOnClick": [Function],
|
|
||||||
},
|
|
||||||
"data": [Function],
|
|
||||||
"emits": Array [
|
|
||||||
"update:modelValue",
|
|
||||||
],
|
|
||||||
"methods": Object {
|
|
||||||
"handleBlur": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"handleEventAction": [Function],
|
|
||||||
"handleFocus": [Function],
|
|
||||||
"handleSelectionChange": [Function],
|
|
||||||
},
|
|
||||||
"mounted": [Function],
|
|
||||||
"name": "base-input-button",
|
|
||||||
"props": Object {
|
|
||||||
"buttonWrapperClasses": Array [
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
],
|
|
||||||
"groupName": Object {
|
|
||||||
"required": true,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"inputClasses": Array [
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
],
|
|
||||||
"isMultiSelect": [Function],
|
|
||||||
"isRequired": Object {
|
|
||||||
"default": true,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"lastValuePushedToGa": Array [
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
],
|
|
||||||
"modelValue": Object {
|
|
||||||
"required": true,
|
|
||||||
"validator": [Function],
|
|
||||||
},
|
|
||||||
"selectingInitiatesLoad": Object {
|
|
||||||
"default": false,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"setLastValuePushedToGa": [Function],
|
|
||||||
"suppressError": [Function],
|
|
||||||
"validationRules": Object {
|
|
||||||
"default": "",
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"value": Object {
|
|
||||||
"required": true,
|
|
||||||
"type": Array [
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"valueToLogType": [Function],
|
|
||||||
},
|
|
||||||
"render": [Function],
|
|
||||||
"setup": [Function],
|
|
||||||
},
|
|
||||||
"loader": Object {
|
|
||||||
"computed": Object {
|
|
||||||
"cssProps": [Function],
|
|
||||||
},
|
|
||||||
"methods": Object {
|
|
||||||
"captureClick": [Function],
|
|
||||||
},
|
|
||||||
"name": "loader",
|
|
||||||
"props": Object {
|
|
||||||
"allowPageInteraction": Object {
|
|
||||||
"default": false
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"height": Object {
|
|
||||||
"default": 1,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"loaderColor": Object {
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"loaderPosition": Object {
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"width": Object {
|
|
||||||
"default": 1,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"render": [Function],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"computed": Object {
|
|
||||||
"availabilityRatingClass": [Function],
|
|
||||||
"badgeText": [Function],
|
|
||||||
"isLoaderDisplayed": [Function],
|
|
||||||
},
|
|
||||||
"data": [Function],
|
|
||||||
"mixins": Array [
|
|
||||||
Object {
|
|
||||||
"computed": Object {
|
|
||||||
"selectedValue": Object {
|
|
||||||
"get": [Function],
|
|
||||||
"set": [Function],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"model": Object {
|
|
||||||
"event": "change",
|
|
||||||
"prop": "modelValue",
|
|
||||||
},
|
|
||||||
"props": Object {
|
|
||||||
"additionalButtonData": [Function],
|
|
||||||
"additionalButtonStyling": [Function],
|
|
||||||
"altText": Object {
|
|
||||||
"default": "",
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"buttonAuxiliaryCopy": [Function],
|
|
||||||
"buttonBodyCopy": [Function],
|
|
||||||
"buttonFooterCopy": [Function],
|
|
||||||
"buttonImage": [Function],
|
|
||||||
"buttonImageId": [Function],
|
|
||||||
"buttonLabel": Array [
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
],
|
|
||||||
"buttonLabelSubCopy": [Function],
|
|
||||||
"groupName": Object {
|
|
||||||
"required": true,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"isMultiSelect": [Function],
|
|
||||||
"isRequired": Object {
|
|
||||||
"default": true,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"isWide": [Function],
|
|
||||||
"lastValuePushedToGa": Array [
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
],
|
|
||||||
"modelValue": Object {
|
|
||||||
"required": true,
|
|
||||||
"validator": [Function],
|
|
||||||
},
|
|
||||||
"screenReaderOnlyText": [Function],
|
|
||||||
"selectingInitiatesLoad": Object {
|
|
||||||
"default": false,
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"setLastValuePushedToGa": [Function],
|
|
||||||
"suppressError": [Function],
|
|
||||||
"textPosition": [Function],
|
|
||||||
"validationRules": Object {
|
|
||||||
"default": "",
|
|
||||||
"type": [Function],
|
|
||||||
},
|
|
||||||
"value": Object {
|
|
||||||
"required": true,
|
|
||||||
"type": Array [
|
|
||||||
[Function],
|
|
||||||
[Function],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"valueToLogType": [Function],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"name": "shop-list-button",
|
|
||||||
"render": [Function],
|
|
||||||
},
|
|
||||||
"widget": Object {
|
|
||||||
"filterByQuestion": "FilterByQuestion",
|
|
||||||
"noNetworkShopsAlert": "NoNetworkShopsAlertWidget",
|
|
||||||
"searchInstructions": "SearchInstructions",
|
|
||||||
"shopNotListedLink": "ShopNotListedLink",
|
|
||||||
"siteFooter": "SiteFooterWidget",
|
|
||||||
"siteHeader": "SiteHeaderWidget",
|
|
||||||
"tpaSearchQuestion": "TPASearchQuestion",
|
|
||||||
},
|
|
||||||
"zipCode": null,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -15,26 +15,26 @@
|
||||||
<label
|
<label
|
||||||
id="tpaSearchQuestionLabel"
|
id="tpaSearchQuestionLabel"
|
||||||
for="tpaSearchQuestionField"
|
for="tpaSearchQuestionField"
|
||||||
class="text-center fs-5 mt-5 mb-0 text-black w-100">
|
class="fs-5 mt-5 text-black w-100">
|
||||||
{{ tpaSearchQuestionLabel }}
|
{{ tpaSearchQuestionLabel }}
|
||||||
</label>
|
</label>
|
||||||
<label
|
<label
|
||||||
id="searchInstructions"
|
id="searchInstructions"
|
||||||
for="tpaSearchQuestionField"
|
for="tpaSearchQuestionField"
|
||||||
class="text-center small darker-gray w-100 mb-4">
|
class="darker-gray w-100 mb-4">
|
||||||
{{ searchInstructionsText }}
|
{{ searchInstructionsText }}
|
||||||
</label>
|
</label>
|
||||||
<div class="mb-5">
|
<div class="mb-5">
|
||||||
<textboxQuestion
|
<textboxQuestion
|
||||||
id="tpaSearchQuestionField"
|
id="tpaSearchQuestionField"
|
||||||
v-model="zipCode"
|
v-model="tpaSearchValue"
|
||||||
inputId="tpaSearchQuestionFieldInput"
|
inputId="tpaSearchQuestionFieldInput"
|
||||||
:cmsWidgetName="widget.tpaSearchQuestion"
|
:cmsWidgetName="widget.tpaSearchQuestion"
|
||||||
:includeSearchIcon="true"
|
:includeSearchIcon="true"
|
||||||
:displayQuestionText="false"
|
:displayQuestionText="false"
|
||||||
isRequired
|
isRequired
|
||||||
:isDisabled="reloadingProviders"
|
:isDisabled="reloadingProviders"
|
||||||
:validationRules="rules.zipCode"
|
:validationRules="rules.tpaSearch"
|
||||||
@clickEvent="searchClick" />
|
@clickEvent="searchClick" />
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
@ -52,10 +52,10 @@
|
||||||
@invalidSubmit="onInvalidSubmit">
|
@invalidSubmit="onInvalidSubmit">
|
||||||
<dropdownQuestion
|
<dropdownQuestion
|
||||||
id="searchRadiusFilter"
|
id="searchRadiusFilter"
|
||||||
v-model="filter"
|
v-model="radiusFilter"
|
||||||
:cmsWidgetName="widget.filterByQuestion"
|
:cmsWidgetName="widget.filterByQuestion"
|
||||||
inputId="searchRadiusFilterInput"
|
inputId="searchRadiusFilterInput"
|
||||||
:options="filterOptions"
|
:options="radiusFilterOptions"
|
||||||
disableAutoFill
|
disableAutoFill
|
||||||
:isDisabled="reloadingProviders"
|
:isDisabled="reloadingProviders"
|
||||||
:validationRules="rules.filter" />
|
:validationRules="rules.filter" />
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
id="selectProviderQuestion"
|
id="selectProviderQuestion"
|
||||||
v-model="selectedProviderNumber"
|
v-model="selectedProviderNumber"
|
||||||
buttonTypeString="shopListButton"
|
buttonTypeString="shopListButton"
|
||||||
:buttonTypeObject="shopListButton"
|
:buttonTypeObject="tpaShopListButton"
|
||||||
class="radioQuestion"
|
class="radioQuestion"
|
||||||
:answers="providerButtonData"
|
:answers="providerButtonData"
|
||||||
groupName="chooseShop"
|
groupName="chooseShop"
|
||||||
|
|
@ -99,12 +99,23 @@
|
||||||
:text="shopNotListedModalLink"
|
:text="shopNotListedModalLink"
|
||||||
@clickEvent="doNotSeeMyShopLinkClick" />
|
@clickEvent="doNotSeeMyShopLinkClick" />
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
<siteFooter
|
<siteFooter
|
||||||
|
class="mt-6"
|
||||||
ref="siteFooter"
|
ref="siteFooter"
|
||||||
:cmsWidgetName="widget.siteFooter"
|
:cmsWidgetName="widget.siteFooter"
|
||||||
:isForwardActionDisabled="!meta.valid"
|
:isForwardActionDisabled="!meta.valid"
|
||||||
@ForwardClicked="forwardButtonAction"
|
@ForwardClicked="forwardButtonAction"
|
||||||
@backClicked="navigateBack" />
|
@backClicked="navigateBack" />
|
||||||
|
<div class="need-help-link-container">
|
||||||
|
<textLink
|
||||||
|
id="needHelpLink"
|
||||||
|
v-if="needHelpLinkText"
|
||||||
|
linkType="navigation"
|
||||||
|
:text="needHelpLinkText"
|
||||||
|
href="#"
|
||||||
|
@clickEvent="needHelpLinkClick" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -123,7 +134,7 @@ import textLink from '@/ux-components/text-link/text-link.vue';
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import alert from '@/ux-components/alert/alert.vue';
|
||||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||||
import googleMap from '@/iss-components/google-map/google-map.vue';
|
import googleMap from '@/iss-components/google-map/google-map.vue';
|
||||||
import shopListButton from '@/iss-components/shop-list-button/shop-list-button.vue';
|
import tpaShopListButton from '@/iss-components/tpa-shop-list-button/tpa-shop-list-button.vue';
|
||||||
import loader from '@/ux-components/loader/loader.vue';
|
import loader from '@/ux-components/loader/loader.vue';
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
|
|
@ -135,53 +146,9 @@ import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
import { shallowRef } from 'vue';
|
import { shallowRef } from 'vue';
|
||||||
import { toTitleCase, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
|
import { toTitleCase, toDisplayPhoneNumber } from '@/helpers/text-helper.js';
|
||||||
import bailoutMessage from '@/constants/bailoutMessage';
|
import bailoutMessage from '@/constants/bailoutMessage';
|
||||||
|
import settleAllPromises from '@/helpers/layout-helper';
|
||||||
|
import issPageValues from '@/router/router-constants/issPage-values';
|
||||||
|
|
||||||
const radiusFilterPairs = [
|
|
||||||
{ radius: 15, filter: '15 miles' },
|
|
||||||
{ radius: 25, filter: '25 miles' },
|
|
||||||
{ radius: 50, filter: '50 miles' },
|
|
||||||
{ radius: 100, filter: '100 miles' }
|
|
||||||
];
|
|
||||||
|
|
||||||
function convertRadiusFilterToInteger(filter) {
|
|
||||||
const pair = radiusFilterPairs.find((p) => p.filter === filter);
|
|
||||||
return pair?.radius ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getInitialSearchData() {
|
|
||||||
const customerZipCode = useMainStore().order.customer.address.zipCode;
|
|
||||||
const serviceLocationZipCode = useMainStore().order.serviceLocation.zipCode;
|
|
||||||
const zipCode = serviceLocationZipCode ?? customerZipCode;
|
|
||||||
|
|
||||||
const { searchFilter } = useMainStore().order.serviceLocation;
|
|
||||||
let { providerNumber } = useMainStore().order.serviceLocation.provider;
|
|
||||||
|
|
||||||
let providers = [];
|
|
||||||
let radius = 0;
|
|
||||||
if (searchFilter) {
|
|
||||||
radius = convertRadiusFilterToInteger(searchFilter);
|
|
||||||
const result = await useMainStore().getTpaProviders(zipCode, radius);
|
|
||||||
providers = result?.data?.shopProviders ?? [];
|
|
||||||
|
|
||||||
return { zipCode, filter: searchFilter, providers, providerNumber };
|
|
||||||
}
|
|
||||||
|
|
||||||
providerNumber = null;
|
|
||||||
let pairIndex = 0;
|
|
||||||
let filter = '';
|
|
||||||
while (providers.length === 0 && pairIndex < radiusFilterPairs.length) {
|
|
||||||
const pair = radiusFilterPairs[pairIndex];
|
|
||||||
radius = pair.radius;
|
|
||||||
filter = pair.filter;
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
const result = await useMainStore().getTpaProviders(zipCode, radius);
|
|
||||||
providers = result?.data?.shopProviders ?? [];
|
|
||||||
|
|
||||||
pairIndex += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { zipCode, filter, providers, providerNumber };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'tpa-search',
|
name: 'tpa-search',
|
||||||
|
|
@ -200,23 +167,40 @@ export default {
|
||||||
},
|
},
|
||||||
mixins: [BaseFormMixin],
|
mixins: [BaseFormMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
const { zipCode, filter, providers, providerNumber } =
|
const zipCode = useMainStore().order.customer.address.zipCode;
|
||||||
await getInitialSearchData();
|
const pageData = useMainStore().pageData(to.query.issPage);
|
||||||
const cmsContent = await fetchCmsContentForPage(to.query.issPage);
|
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||||
|
const providersPromise = useMainStore().getTpaAndSafeliteProviders(zipCode, pageData?.tpaSearchValue ?? '');
|
||||||
|
const promiseResultMap = [
|
||||||
|
{
|
||||||
|
resultKey: 'cmsContent',
|
||||||
|
promise: cmsContentPromise
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resultKey: 'providers',
|
||||||
|
promise: providersPromise
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const resultMap = await settleAllPromises(promiseResultMap);
|
||||||
next(async (vm) => {
|
next(async (vm) => {
|
||||||
vm.setCmsContent(cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
vm.setInitialSearchData(zipCode, filter, providers, providerNumber);
|
vm.mapZipCode = zipCode;
|
||||||
|
vm.providers = resultMap.providers;
|
||||||
|
if (pageData) {
|
||||||
|
vm.tpaSearchValue = pageData?.tpaSearchValue ?? vm.mapZipCode;
|
||||||
|
vm.radiusFilter = pageData?.radiusFilter ?? 25;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dataLoaded: false,
|
dataLoaded: false,
|
||||||
zipCode: null,
|
pageData: null,
|
||||||
|
tpaSearchValue: null,
|
||||||
mapZipCode: null,
|
mapZipCode: null,
|
||||||
filter: '',
|
radiusFilter: null,
|
||||||
providers: [],
|
providers: [],
|
||||||
selectedProviderNumber: '',
|
selectedProviderNumber: useMainStore().order.serviceLocation.provider.providerNumber,
|
||||||
reloadingProviders: false,
|
reloadingProviders: false,
|
||||||
additionalButtonData: {
|
additionalButtonData: {
|
||||||
displayAvailabilityIndicators: false
|
displayAvailabilityIndicators: false
|
||||||
|
|
@ -228,28 +212,28 @@ export default {
|
||||||
filterByQuestion: 'FilterByQuestion',
|
filterByQuestion: 'FilterByQuestion',
|
||||||
noNetworkShopsAlert: 'NoNetworkShopsAlertWidget',
|
noNetworkShopsAlert: 'NoNetworkShopsAlertWidget',
|
||||||
shopNotListedLink: 'ShopNotListedLink',
|
shopNotListedLink: 'ShopNotListedLink',
|
||||||
siteFooter: 'SiteFooterWidget'
|
siteFooter: 'SiteFooterWidget',
|
||||||
|
needHelpLink: 'NeedHelpLink'
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
zipCode: `${globalRules.ZIP_CODE_REQUIRED}|${globalRules.ZIP_CODE_SEARCH_FORMAT}`,
|
tpaSearch: globalRules.TPA_SEARCH_FORMAT,
|
||||||
filter: globalRules.OPTION_REQUIRED, // TODO do we even need this?
|
filter: globalRules.OPTION_REQUIRED, // TODO do we even need this?
|
||||||
provider: globalRules.OPTION_REQUIRED
|
provider: globalRules.OPTION_REQUIRED
|
||||||
},
|
},
|
||||||
shopListButton: shallowRef(shopListButton)
|
tpaShopListButton: shallowRef(tpaShopListButton)
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
filterOptions() {
|
radiusFilterOptions() {
|
||||||
const filterByAnswers =
|
const radiusFilterOptions = this.getCmsContent(
|
||||||
this.getCmsContent(
|
|
||||||
this.widget.filterByQuestion,
|
this.widget.filterByQuestion,
|
||||||
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
|
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
|
||||||
) ?? [];
|
) ?? [];
|
||||||
const filterByAnswersObj = {};
|
const options = {};
|
||||||
[...filterByAnswers].forEach((answer) => {
|
for (const option of radiusFilterOptions) {
|
||||||
filterByAnswersObj[answer.Name] = answer.Name;
|
options[option.Name] = option.Text;
|
||||||
});
|
}
|
||||||
return filterByAnswersObj;
|
return options;
|
||||||
},
|
},
|
||||||
tpaSearchQuestionLabel() {
|
tpaSearchQuestionLabel() {
|
||||||
return this.getCmsContent(
|
return this.getCmsContent(
|
||||||
|
|
@ -257,6 +241,9 @@ export default {
|
||||||
widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT
|
widgetFields.INPUT_QUESTION_WIDGET.QUESTION_TEXT
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
needHelpLinkText() {
|
||||||
|
return this.getCmsContent(this.widget.needHelpLink, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
|
},
|
||||||
searchInstructionsText() {
|
searchInstructionsText() {
|
||||||
return this.getCmsContent(
|
return this.getCmsContent(
|
||||||
this.widget.searchInstructions,
|
this.widget.searchInstructions,
|
||||||
|
|
@ -269,25 +256,25 @@ export default {
|
||||||
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
radiusInMiles() {
|
|
||||||
return convertRadiusFilterToInteger(this.filter);
|
|
||||||
},
|
|
||||||
noNetworkShopsAlertHeaderText() {
|
noNetworkShopsAlertHeaderText() {
|
||||||
return this.getCmsContent(
|
return this.getCmsContent(
|
||||||
this.widget.noNetworkShopsAlert,
|
this.widget.noNetworkShopsAlert,
|
||||||
widgetFields.ALERT_WIDGET.HEADLINE_TEXT
|
widgetFields.ALERT_WIDGET.HEADLINE_TEXT
|
||||||
)?.replaceAll('{custom:radiusInMiles}', this.radiusInMiles);
|
)?.replaceAll('{custom:radiusInMiles}', this.radiusFilter + " miles");
|
||||||
|
},
|
||||||
|
radiusFilteredAndCappedProviders() {
|
||||||
|
return this.providers.filter((provider) => provider.distanceInMiles <= this.radiusFilter).slice(0, 5);
|
||||||
},
|
},
|
||||||
providerAddresses() {
|
providerAddresses() {
|
||||||
return this.providers?.map((provider) => ({
|
return this.radiusFilteredAndCappedProviders?.map((provider) => ({
|
||||||
title: provider.companyName,
|
title: provider.companyName.toLowerCase(),
|
||||||
fullAddress: this.getFullProviderAddress(provider),
|
fullAddress: this.getFullProviderAddress(provider),
|
||||||
addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
|
addressLines: [this.getProviderAddress(provider), this.getProviderCityZipState(provider)]
|
||||||
})) ?? [];
|
})) ?? [];
|
||||||
},
|
},
|
||||||
providerButtonData() {
|
providerButtonData() {
|
||||||
return (
|
return (
|
||||||
this.providers?.map((provider) =>
|
this.radiusFilteredAndCappedProviders?.map((provider) =>
|
||||||
this.getShopButtonDataFromProvider(provider)) ?? []
|
this.getShopButtonDataFromProvider(provider)) ?? []
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -298,14 +285,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
async filter() {
|
|
||||||
if (this.dataLoaded) {
|
|
||||||
await this.getProviderButtonData().then((providers) => {
|
|
||||||
this.providers = providers;
|
|
||||||
});
|
|
||||||
this.mapZipCode = this.zipCode;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
providers(newProviders) {
|
providers(newProviders) {
|
||||||
if (this.dataLoaded) {
|
if (this.dataLoaded) {
|
||||||
this.selectedProviderNumber =
|
this.selectedProviderNumber =
|
||||||
|
|
@ -318,7 +297,6 @@ export default {
|
||||||
const provider = this.providers?.find((p) => p.providerNumber === newNumber);
|
const provider = this.providers?.find((p) => p.providerNumber === newNumber);
|
||||||
if (provider && this.dataLoaded) {
|
if (provider && this.dataLoaded) {
|
||||||
useMainStore().updateServiceLocation({
|
useMainStore().updateServiceLocation({
|
||||||
searchFilter: this.filter,
|
|
||||||
zipCode: this.zipCode,
|
zipCode: this.zipCode,
|
||||||
provider: {
|
provider: {
|
||||||
providerNumber: provider?.providerNumber,
|
providerNumber: provider?.providerNumber,
|
||||||
|
|
@ -342,13 +320,6 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setInitialSearchData(zipCode, filter, providers, providerNumber) {
|
|
||||||
this.zipCode = zipCode;
|
|
||||||
this.mapZipCode = zipCode;
|
|
||||||
this.filter = filter;
|
|
||||||
this.providers = providers;
|
|
||||||
this.selectedProviderNumber = providerNumber;
|
|
||||||
},
|
|
||||||
getFullProviderAddress(provider) {
|
getFullProviderAddress(provider) {
|
||||||
const addressLine1 = this.getProviderAddress(provider);
|
const addressLine1 = this.getProviderAddress(provider);
|
||||||
const addressLine2 = this.getProviderCityZipState(provider);
|
const addressLine2 = this.getProviderCityZipState(provider);
|
||||||
|
|
@ -379,16 +350,16 @@ export default {
|
||||||
}
|
}
|
||||||
return addressLine2;
|
return addressLine2;
|
||||||
},
|
},
|
||||||
async getProviderButtonData() {
|
async getProviderButtonData(shopName = "") {
|
||||||
this.reloadingProviders = true;
|
this.reloadingProviders = true;
|
||||||
const getTpaProvidersResult = await useMainStore().getTpaProviders(
|
const getTpaProvidersResult = await useMainStore().getTpaAndSafeliteProviders(
|
||||||
this.zipCode,
|
this.mapZipCode,
|
||||||
this.radiusInMiles
|
shopName
|
||||||
);
|
);
|
||||||
this.reloadingProviders = false;
|
this.reloadingProviders = false;
|
||||||
return getTpaProvidersResult?.data?.shopProviders ?? [];
|
return getTpaProvidersResult?.data ?? [];
|
||||||
},
|
},
|
||||||
doNotSeeMyShopLinkClick() {
|
needHelpLinkClick() {
|
||||||
this.mainStore.setBailout(bailoutMessage.RequestCallback());
|
this.mainStore.setBailout(bailoutMessage.RequestCallback());
|
||||||
this.$router.navigate(
|
this.$router.navigate(
|
||||||
this.navigationScenarios.CLICKED_NEED_HELP,
|
this.navigationScenarios.CLICKED_NEED_HELP,
|
||||||
|
|
@ -396,8 +367,12 @@ export default {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
async searchClick() {
|
async searchClick() {
|
||||||
this.providers = await this.getProviderButtonData();
|
if (isNaN(this.tpaSearchValue)) {
|
||||||
this.mapZipCode = this.zipCode;
|
this.providers = await this.getProviderButtonData(this.tpaSearchValue);
|
||||||
|
} else {
|
||||||
|
this.mapZipCode = this.tpaSearchValue;
|
||||||
|
this.providers = await this.getProviderButtonData();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
forwardButtonAction() {
|
forwardButtonAction() {
|
||||||
if (this.selectedProviderIsSafeliteShop) {
|
if (this.selectedProviderIsSafeliteShop) {
|
||||||
|
|
@ -407,16 +382,12 @@ export default {
|
||||||
? this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP
|
? this.navigationScenarios.CLICKED_FORWARD_WITH_SAFELITE_SHOP
|
||||||
: this.navigationScenarios
|
: this.navigationScenarios
|
||||||
.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP;
|
.CLICKED_FORWARD_WITH_NON_SAFELITE_SHOP;
|
||||||
|
// Do not save the zip code as the tpa search value, prevents an outdated zipcode from being used
|
||||||
|
// as the default search value if customer goes back and changes zip earlier in the flow
|
||||||
|
const tpaSearchValueToSave = this.tpaSearchValue === this.mapZipCode ? '' : this.tpaSearchValue;
|
||||||
|
this.savePageDataToStore(issPageValues.TPA_SEARCH, {tpaSearchValue: tpaSearchValueToSave, radiusFilter: this.radiusFilter});
|
||||||
this.$router.navigate(scenario, this.$route);
|
this.$router.navigate(scenario, this.$route);
|
||||||
},
|
},
|
||||||
getCustomValueFromString(str) {
|
|
||||||
switch (str) {
|
|
||||||
case 'radiusInMiles':
|
|
||||||
return this.radiusInMiles;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getShopButtonDataFromProvider(provider) {
|
getShopButtonDataFromProvider(provider) {
|
||||||
const cellNumber = toDisplayPhoneNumber(provider?.phoneNumber);
|
const cellNumber = toDisplayPhoneNumber(provider?.phoneNumber);
|
||||||
const distance =
|
const distance =
|
||||||
|
|
@ -426,7 +397,7 @@ export default {
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
buttonLabel: provider?.companyName ?? '',
|
buttonLabel: provider?.companyName.toLowerCase() ?? '',
|
||||||
buttonLabelSubCopy: distance === null ? '' : `${distance} mi`,
|
buttonLabelSubCopy: distance === null ? '' : `${distance} mi`,
|
||||||
buttonBodyCopy: `${this.getFullProviderAddress(provider)}<br>${
|
buttonBodyCopy: `${this.getFullProviderAddress(provider)}<br>${
|
||||||
cellNumber ?? ''
|
cellNumber ?? ''
|
||||||
|
|
@ -442,4 +413,30 @@ export default {
|
||||||
.darker-gray {
|
.darker-gray {
|
||||||
color: map-get($colors, 'darker-gray');
|
color: map-get($colors, 'darker-gray');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tpaSearchQuestionLabel {
|
||||||
|
margin-bottom: .625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
height: 27.1875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#providerSelectionForm {
|
||||||
|
#alertNoNetworkProviders {
|
||||||
|
:deep(.alert) {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 1.375rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.need-help-link-container {
|
||||||
|
margin-top:1.875rem;
|
||||||
|
margin-bottom: 2.1875rem;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -41,13 +41,14 @@ function setupMocks({ glassNameProp, glassLocationProp, colorAnswersProp, modelV
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const wrapper = shallowMount(glassPartQuestion, mountOptions);
|
|
||||||
|
|
||||||
// Mock store
|
// Mock store
|
||||||
const partsOrQuestions = pageData ?? { partsOrQuestions: [{ glassName: 'Stationary', glassLocation: 'Rear', parts: [] }] };
|
const partsOrQuestions = pageData ?? { partsOrQuestions: [{ glassName: 'Stationary', glassLocation: 'Rear', parts: [] }] };
|
||||||
useMainStore().pageData = jest.fn();
|
useMainStore().pageData = jest.fn();
|
||||||
useMainStore().pageData.mockReturnValue(partsOrQuestions);
|
useMainStore().pageData.mockReturnValue(partsOrQuestions);
|
||||||
document.querySelector = jest.fn().mockReturnValue({ clicked: false, click: jest.fn() });
|
document.querySelector = jest.fn().mockReturnValue({ clicked: false, click: jest.fn() });
|
||||||
|
|
||||||
|
const wrapper = shallowMount(glassPartQuestion, mountOptions);
|
||||||
|
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,36 +63,23 @@ describe('glass-part-question.vue', () => {
|
||||||
window.console.log(wrapper.vm.featureListData['Green Tint'][0].Text);
|
window.console.log(wrapper.vm.featureListData['Green Tint'][0].Text);
|
||||||
// Assert
|
// Assert
|
||||||
expect(Object.keys(wrapper.vm.featureListData).length).toBe(2);
|
expect(Object.keys(wrapper.vm.featureListData).length).toBe(2);
|
||||||
expect(wrapper.vm.featureListData['Green Tint'][0].Text).toBe('heated glass, solar, 1 hole');
|
expect(wrapper.vm.featureListData['Green Tint'][0].Text).toBe('Heated glass, Solar, 1 Hole');
|
||||||
expect(wrapper.vm.featureListData['Green Tint'][0].Name).toBe('DB12209GTYN');
|
expect(wrapper.vm.featureListData['Green Tint'][0].Name).toBe('DB12209GTYN');
|
||||||
expect(wrapper.vm.featureListData['Gray Tint Privacy'][0].Text).toBe('heated glass, solar, 1 hole');
|
expect(wrapper.vm.featureListData['Gray Tint Privacy'][0].Text).toBe('Heated glass, Solar, 1 Hole');
|
||||||
expect(wrapper.vm.featureListData['Gray Tint Privacy'][0].Name).toBe('DB12209YPYN');
|
expect(wrapper.vm.featureListData['Gray Tint Privacy'][0].Name).toBe('DB12209YPYN');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Tint mapper, should get tint image by glassLocation and tintColor', async () => {
|
test('Tint mapper, should get return css class based on tint color', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
||||||
const { wrapper } = setupMocks(featureListData);
|
const { wrapper } = setupMocks(featureListData);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
const tintSourceImage = wrapper.vm.getTintSourceImage('Rear', 'Green Tint');
|
const tintClass = wrapper.vm.convertTintToCSSClass('Green Tint');
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(tintSourceImage).toBe('Glass-NoShade-GreenTint.svg');
|
expect(tintClass).toBe('green-tint');
|
||||||
});
|
|
||||||
|
|
||||||
test('Tint mapper, should return empty string if no tint map found', async () => {
|
|
||||||
// Arrange
|
|
||||||
|
|
||||||
const { wrapper } = setupMocks(featureListData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.$nextTick();
|
|
||||||
const tintSourceImage = wrapper.vm.getTintSourceImage('Rear', 'Crazy Rainbow Tint');
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(tintSourceImage).toBe('');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should emit updateModelValue, and have correct attributes', async () => {
|
test('Should emit updateModelValue, and have correct attributes', async () => {
|
||||||
|
|
@ -122,7 +110,7 @@ describe('glass-part-question.vue', () => {
|
||||||
{ partNumber: 'DB12209GTYN', color: 'Green Tint' }
|
{ partNumber: 'DB12209GTYN', color: 'Green Tint' }
|
||||||
]);
|
]);
|
||||||
expect(listCard.attributes('groupname')).toBe('Rear-Stationary');
|
expect(listCard.attributes('groupname')).toBe('Rear-Stationary');
|
||||||
expect(listCard.attributes('validationrules')).toBe('Rear-Stationary-tint-required');
|
expect(listCard.attributes('validationrules')).toBe('Rear-Stationary-part-required');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('default is selected if only one option', async () => {
|
test('default is selected if only one option', async () => {
|
||||||
|
|
@ -136,58 +124,42 @@ describe('glass-part-question.vue', () => {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
const updateSpy = jest.spyOn(glassPartQuestion.methods, 'updateSelectedPartNumber');
|
||||||
const { wrapper } = setupMocks(featureListData);
|
const { wrapper } = setupMocks(featureListData);
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.vm.$nextTick();
|
|
||||||
await wrapper.setData({ selectedTint: 'Green Tint' });
|
|
||||||
// take emitted value, pass down as modelValue
|
|
||||||
// yes, yes, it's not ideal
|
|
||||||
await wrapper.setProps({ modelValue: wrapper.emitted()['update:modelValue'][0][0] });
|
|
||||||
await wrapper.vm.$nextTick();
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.selectedPartNumber).toBe('DB12209GTYN');
|
expect(updateSpy).toHaveBeenCalledWith('DB12209GTYN');
|
||||||
});
|
});
|
||||||
|
|
||||||
const partsForSelectedTintTestCases = [
|
const partsForLocationTestCases = [
|
||||||
[
|
[
|
||||||
'Rear',
|
'Rear',
|
||||||
'Stationary',
|
'Stationary',
|
||||||
'Green Tint',
|
|
||||||
[
|
[
|
||||||
{ partNumber: 'Glass1', color: 'Green Tint' },
|
{ partNumber: 'Glass1', color: 'Green Tint' },
|
||||||
|
{ partNumber: 'Glass2', color: 'Blue Tint' },
|
||||||
{ partNumber: 'Glass3', color: 'Green Tint' },
|
{ partNumber: 'Glass3', color: 'Green Tint' },
|
||||||
{ partNumber: 'Glass4', color: 'Green Tint' },
|
{ partNumber: 'Glass4', color: 'Green Tint' },
|
||||||
{ partNumber: 'Glass6', color: 'Green Tint' }
|
{ partNumber: 'Glass5', color: 'Blue Tint' },
|
||||||
|
{ partNumber: 'Glass6', color: 'Green Tint' },
|
||||||
|
{ partNumber: 'Glass7', color: 'Red Tint' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'Rear',
|
|
||||||
'Stationary',
|
|
||||||
'Blue Tint',
|
|
||||||
[
|
|
||||||
{ partNumber: 'Glass2', color: 'Blue Tint' },
|
|
||||||
{ partNumber: 'Glass5', color: 'Blue Tint' }
|
|
||||||
]
|
|
||||||
],
|
|
||||||
['Rear', 'Stationary', 'Red Tint', [{ partNumber: 'Glass7', color: 'Red Tint' }]],
|
|
||||||
[
|
[
|
||||||
'Windshield',
|
'Windshield',
|
||||||
'Single',
|
'Single',
|
||||||
'Green Tint',
|
|
||||||
[
|
[
|
||||||
{ partNumber: 'Windshield1', color: 'Green Tint' },
|
{ partNumber: 'Windshield1', color: 'Green Tint' },
|
||||||
{ partNumber: 'Windshield2', color: 'Green Tint' }
|
{ partNumber: 'Windshield2', color: 'Green Tint' }
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
['Windshield', 'Single', 'Blue Tint', []],
|
['Driver', 'Quarter', []]
|
||||||
['Driver', 'Quarter', 'Green Tint', []]
|
|
||||||
];
|
];
|
||||||
|
|
||||||
test.each(partsForSelectedTintTestCases)(
|
test.each(partsForLocationTestCases)(
|
||||||
'partsForSelectedTint returns correct parts',
|
'partsForLocation returns correct parts',
|
||||||
async (glassLocation, glassName, selectedTint, expectedResults) => {
|
async (glassLocation, glassName, expectedResults) => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const pageData = { partsOrQuestions: [
|
const pageData = { partsOrQuestions: [
|
||||||
{
|
{
|
||||||
|
|
@ -219,11 +191,8 @@ describe('glass-part-question.vue', () => {
|
||||||
pageData
|
pageData
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act
|
|
||||||
await wrapper.setData({ selectedTint });
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(expectedResults).toEqual(wrapper.vm.partsForSelectedTint);
|
expect(wrapper.vm.partsForLocation).toEqual(expectedResults);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,27 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<p class="mb-0 color-question-text">
|
<span class="glass-location-text">
|
||||||
{{ colorQuestionText }}
|
{{ partType }}
|
||||||
</p>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="nested-radio">
|
<template
|
||||||
<div class="row my-2">
|
v-for="(tint, index) in tintSelectionOptions"
|
||||||
<div class="col">
|
:key="index">
|
||||||
<buttonQuestion
|
<div class="tint-option">
|
||||||
v-model="selectedTint"
|
<span>{{ `${partType} - ${tint}` }}</span>
|
||||||
:answers="tintSelectionOptions"
|
<span :class="`tint-image ${convertTintToCSSClass(tint)}`"></span>
|
||||||
buttonTypeString="listCard"
|
|
||||||
:isWide="true"
|
|
||||||
altText=""
|
|
||||||
isRequired
|
|
||||||
:groupName="replaceAllSpaceWithDash(`${glassLocation}-${glassName}`)"
|
|
||||||
:validationRules="tintValidationRules">
|
|
||||||
<div
|
|
||||||
class="row my-2"
|
|
||||||
aria-live="polite">
|
|
||||||
<div class="col">
|
|
||||||
<buttonQuestion
|
|
||||||
id="glass-part-question"
|
|
||||||
v-model="selectedPartNumber"
|
|
||||||
buttonTypeString="radio"
|
|
||||||
class="radioQuestion"
|
|
||||||
:questionText="glassFeatureQuestion"
|
|
||||||
:answers="featureListData[selectedTint]"
|
|
||||||
textPosition="text-start"
|
|
||||||
:loaderEnabled="false"
|
|
||||||
isRequired
|
|
||||||
isSmallQuestionText
|
|
||||||
:groupName="replaceAllSpaceWithDash(`${glassLocation}-${glassName}-${selectedTint}`)"
|
|
||||||
:validationRules="partValidationRules" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</buttonQuestion>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<buttonQuestion
|
||||||
|
id="glass-part-question"
|
||||||
|
v-model="selectedPartNumber"
|
||||||
|
buttonTypeString="list-button"
|
||||||
|
class="radioQuestion"
|
||||||
|
:answers="featureListData[tint]"
|
||||||
|
:loaderEnabled="false"
|
||||||
|
isRequired
|
||||||
|
:groupName="replaceAllSpaceWithDash(`${glassLocation}-${glassName}`)"
|
||||||
|
:validationRules="partValidationRules" />
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -46,12 +29,10 @@
|
||||||
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
||||||
|
|
||||||
// Supporting files
|
// Supporting files
|
||||||
import getTintImage from '@/constants/tint-mapper';
|
|
||||||
import getCustomTransformValue from '@/constants/dynamictext-mapper';
|
|
||||||
import { defineRule } from 'vee-validate';
|
import { defineRule } from 'vee-validate';
|
||||||
import { required } from '@/helpers/validation-rules';
|
import { required } from '@/helpers/validation-rules';
|
||||||
import errorMessages from '@/constants/error-messages';
|
import errorMessages from '@/constants/error-messages';
|
||||||
import { useMainStore } from '@/store';
|
import { toTitleCase } from '@/helpers/text-helper';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'glass-part-question',
|
name: 'glass-part-question',
|
||||||
|
|
@ -72,42 +53,21 @@ export default {
|
||||||
emits: ['update:modelValue'],
|
emits: ['update:modelValue'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
glassColorQuestion: '',
|
|
||||||
glassFeatureQuestion: '',
|
|
||||||
selectedTint: ''
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
tintValidationRules() {
|
|
||||||
const validationRuleName = `${this.glassLocation}-${this.glassName}-tint-required`;
|
|
||||||
|
|
||||||
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
|
|
||||||
|
|
||||||
return validationRuleName;
|
|
||||||
},
|
|
||||||
partValidationRules() {
|
partValidationRules() {
|
||||||
const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`;
|
const validationRuleName = `${this.glassLocation}-${this.glassName}-part-required`;
|
||||||
|
|
||||||
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
|
defineRule(validationRuleName, required(errorMessages.OPTION_REQUIRED));
|
||||||
return validationRuleName;
|
return validationRuleName;
|
||||||
},
|
},
|
||||||
colorQuestionText() {
|
|
||||||
return getCustomTransformValue(
|
|
||||||
this.glassColorQuestion,
|
|
||||||
`${this.glassLocation} ${this.glassName}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
tintSelectionOptions() {
|
tintSelectionOptions() {
|
||||||
const tintOptions = [];
|
const tintOptions = [];
|
||||||
|
|
||||||
Object.keys(this.featureListData).forEach((tintOption) => {
|
Object.keys(this.featureListData).forEach((tintOption) => {
|
||||||
const buttonImage = this.getTintSourceImage(this.glassLocation, tintOption);
|
tintOptions.push(tintOption);
|
||||||
tintOptions.push({
|
|
||||||
value: tintOption,
|
|
||||||
buttonLabel: tintOption,
|
|
||||||
buttonImage: buttonImage ? require(`@/assets/img/tints/${buttonImage}`) : null
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return tintOptions;
|
return tintOptions;
|
||||||
|
|
@ -115,21 +75,21 @@ export default {
|
||||||
|
|
||||||
selectedPartNumber: {
|
selectedPartNumber: {
|
||||||
get() {
|
get() {
|
||||||
return this.modelValue?.partNumber;
|
return this.modelValue?.partNumber ?? '';
|
||||||
},
|
},
|
||||||
set(newValue) {
|
set(newValue) {
|
||||||
const part = this.partsForSelectedTint
|
const part = this.partsForLocation
|
||||||
.filter((partItem) => partItem.partNumber === newValue?.value)[0];
|
.filter((partItem) => partItem.partNumber === newValue)[0];
|
||||||
this.$emit('update:modelValue', part);
|
this.$emit('update:modelValue', part);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
partsForSelectedTint() {
|
partsForLocation() {
|
||||||
const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter((dataForGlassLocationAndName) =>
|
const matchingGlass = this.PartDataFromApi.partsOrQuestions?.filter((dataForGlassLocationAndName) =>
|
||||||
dataForGlassLocationAndName.glassName === this.glassName
|
dataForGlassLocationAndName.glassName === this.glassName
|
||||||
&& dataForGlassLocationAndName.glassLocation === this.glassLocation);
|
&& dataForGlassLocationAndName.glassLocation === this.glassLocation);
|
||||||
const matchingGlassParts = matchingGlass?.length === 1 ? matchingGlass[0].parts : [];
|
const matchingGlassParts = matchingGlass?.length === 1 ? matchingGlass[0].parts : [];
|
||||||
return matchingGlassParts.filter((part) => part.color === this.selectedTint) ?? [];
|
return matchingGlassParts;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Creates a map of the feature list data in the correct Name/Value
|
// Creates a map of the feature list data in the correct Name/Value
|
||||||
|
|
@ -142,7 +102,7 @@ export default {
|
||||||
|
|
||||||
// Map the data to Name/Text object for ButtonQuestion
|
// Map the data to Name/Text object for ButtonQuestion
|
||||||
const mappedItem = item.FeatureAnswers.reduce((featureArr, it) => {
|
const mappedItem = item.FeatureAnswers.reduce((featureArr, it) => {
|
||||||
featureArr.Text = it.FeatureAnswerText; // Display to User
|
featureArr.Text = this.toTitleCaseWithExceptions(it.FeatureAnswerText); // Display to User
|
||||||
featureArr.Name = it.PartNumber; // Backing Value
|
featureArr.Name = it.PartNumber; // Backing Value
|
||||||
|
|
||||||
return featureArr;
|
return featureArr;
|
||||||
|
|
@ -158,72 +118,19 @@ export default {
|
||||||
|
|
||||||
PartDataFromApi() {
|
PartDataFromApi() {
|
||||||
return this.mainStore.pageData(this.$route.query.issPage) ?? {};
|
return this.mainStore.pageData(this.$route.query.issPage) ?? {};
|
||||||
}
|
},
|
||||||
},
|
|
||||||
watch: {
|
partType() {
|
||||||
selectedTint() {
|
const type = this.partsForLocation?.[0]?.partType ?? '';
|
||||||
this.AutoSelectIfSinglePart();
|
return toTitleCase(type);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.LoadPreselectedValues();
|
this.AutoSelectIfSinglePart();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// Initialize the component data
|
|
||||||
initializeComponent(cmsContent) {
|
|
||||||
this.glassColorQuestion = cmsContent.ColorQuestionWidget.QuestionText;
|
|
||||||
this.glassFeatureQuestion = cmsContent.FeatureQuestionWidget.QuestionText;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Gets tint images based on the glass type, and tint name.
|
|
||||||
// Returns an empty string if the src or object is undefined.
|
|
||||||
getTintSourceImage(glassLocation, tintColor) {
|
|
||||||
const tintSourceObject = getTintImage(glassLocation, tintColor);
|
|
||||||
|
|
||||||
if (tintSourceObject === undefined || !tintSourceObject.src) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return tintSourceObject.src;
|
|
||||||
},
|
|
||||||
|
|
||||||
AutoSelectIfSinglePart() {
|
|
||||||
if (this.partsForSelectedTint?.length > 0) {
|
|
||||||
// Check if only a single part is present for the tint and set the v-model if it is.
|
|
||||||
if (this.partsForSelectedTint?.length === 1) {
|
|
||||||
// select element with matching partNumber
|
|
||||||
this.updateSelectedPartNumber(this.partsForSelectedTint[0].partNumber);
|
|
||||||
} else {
|
|
||||||
this.selectedPartNumber = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Loads the preselected values from the store.
|
|
||||||
LoadPreselectedValues() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
// Populate button-question model-value if parts data already exists in store
|
|
||||||
if (this.modelValue !== undefined) {
|
|
||||||
this.selectedTint = this.modelValue.color;
|
|
||||||
const { glassParts } = useMainStore().order.lineItems;
|
|
||||||
if (glassParts) {
|
|
||||||
for (const tintPart of this.partsForSelectedTint) {
|
|
||||||
for (const glassPart of glassParts) {
|
|
||||||
if (tintPart.partNumber === glassPart.partNumber) {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.updateSelectedPartNumber(tintPart.partNumber);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
updateSelectedPartNumber(partNumber) {
|
updateSelectedPartNumber(partNumber) {
|
||||||
this.selectedPartNumber = { value: partNumber };
|
this.selectedPartNumber = partNumber;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const radioInput = document.querySelector(`input[value=${this.selectedPartNumber}]`);
|
const radioInput = document.querySelector(`input[value=${this.selectedPartNumber}]`);
|
||||||
// Fire a click event on the input so the field is updated
|
// Fire a click event on the input so the field is updated
|
||||||
|
|
@ -231,37 +138,128 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
AutoSelectIfSinglePart() {
|
||||||
|
if (this.partsForLocation?.length > 0) {
|
||||||
|
// Check if only a single part is present for the tint and set the v-model if it is.
|
||||||
|
if (this.partsForLocation?.length === 1) {
|
||||||
|
// select element with matching partNumber
|
||||||
|
this.updateSelectedPartNumber(this.partsForLocation[0].partNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
replaceAllSpaceWithDash(str) {
|
replaceAllSpaceWithDash(str) {
|
||||||
return String(str).replaceAll(' ', '-');
|
return String(str).replaceAll(' ', '-');
|
||||||
|
},
|
||||||
|
convertTintToCSSClass(tint) {
|
||||||
|
return tint.toLowerCase().replaceAll(' ', '-').replaceAll(',', '');
|
||||||
|
},
|
||||||
|
toTitleCaseWithExceptions(text) {
|
||||||
|
const exceptions = ['side', 'glass', 'dimming'];
|
||||||
|
let temp = toTitleCase(text);
|
||||||
|
exceptions.forEach((exception) => {
|
||||||
|
const regEx = new RegExp(exception, 'ig');
|
||||||
|
temp = temp.replace(regEx, exception);
|
||||||
|
});
|
||||||
|
return temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.nested-radio {
|
.glass-location-text {
|
||||||
:deep(.ui-radio) {
|
|
||||||
flex-direction: column;
|
|
||||||
margin: 0.25rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 0.875rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-question-text {
|
|
||||||
color: $black;
|
|
||||||
font-weight: $font-weight-bold;
|
font-weight: $font-weight-bold;
|
||||||
|
color: $black;
|
||||||
}
|
}
|
||||||
|
.tint-option {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 2rem;
|
||||||
|
margin-top: .5rem;
|
||||||
|
margin-bottom: .25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $black;
|
||||||
|
|
||||||
#glass-part-question {
|
@include media-breakpoint-up(md) {
|
||||||
span.fw-bold.w-100 {
|
justify-content: flex-start;
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
}
|
||||||
div.col.radio-button-container {
|
}
|
||||||
padding-bottom: 0;
|
.radioQuestion {
|
||||||
|
:deep(.list-button) {
|
||||||
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tint-image {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
margin-left: 1rem;
|
||||||
|
margin-top: -.25rem;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-image: url(~@/assets/img/tints/GlassTint.png);
|
||||||
|
}
|
||||||
|
.blue-tint-green-shade {
|
||||||
|
background-position: -53px -53px;
|
||||||
|
}
|
||||||
|
.blue-tint-blue-shade {
|
||||||
|
background-position: -160px -53px;
|
||||||
|
}
|
||||||
|
.gray-tint-gray-shade {
|
||||||
|
background-position: -267px -53px;
|
||||||
|
}
|
||||||
|
.blue-tint {
|
||||||
|
background-position: -373px -53px;
|
||||||
|
}
|
||||||
|
.gray-tint {
|
||||||
|
background-position: -480px -53px;
|
||||||
|
}
|
||||||
|
.green-tint-green-shade {
|
||||||
|
background-position: -53px -160px;
|
||||||
|
}
|
||||||
|
.green-tint-blue-shade {
|
||||||
|
background-position: -160px -160px;
|
||||||
|
}
|
||||||
|
.green-tint-gray-shade {
|
||||||
|
background-position: -267px -160px;
|
||||||
|
}
|
||||||
|
.green-tint {
|
||||||
|
background-position: -373px -160px;
|
||||||
|
}
|
||||||
|
.clear {
|
||||||
|
background-position: -480px -160px;
|
||||||
|
}
|
||||||
|
.bronze-tint-green-shade {
|
||||||
|
background-position: -53px -266px;
|
||||||
|
}
|
||||||
|
.bronze-tint-blue-shade {
|
||||||
|
background-position: -160px -266px;
|
||||||
|
}
|
||||||
|
.bronze-tint-gray-shade {
|
||||||
|
background-position: -267px -266px;
|
||||||
|
}
|
||||||
|
.bronze-tint-bronze-shade {
|
||||||
|
background-position: -373px -266px;
|
||||||
|
}
|
||||||
|
.bronze-tint {
|
||||||
|
background-position: -480px -266px;
|
||||||
|
}
|
||||||
|
.bronze-tint-privacy {
|
||||||
|
background-position: -587px -266px;
|
||||||
|
}
|
||||||
|
.clear-blue-shade {
|
||||||
|
background-position: -53px -373px;
|
||||||
|
}
|
||||||
|
.gray-tint-blue-shade {
|
||||||
|
background-position: -160px -373px;
|
||||||
|
}
|
||||||
|
.blue-tint-gray-shade {
|
||||||
|
background-position: -267px -373px;
|
||||||
|
}
|
||||||
|
.gray-tint-privacy {
|
||||||
|
background-position: -373px -373px;
|
||||||
|
}
|
||||||
|
.tinted {
|
||||||
|
background-position: -480px -373px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -11,34 +11,36 @@
|
||||||
<div class="vehicle-parts-container iss-heritage-content-container-width">
|
<div class="vehicle-parts-container iss-heritage-content-container-width">
|
||||||
<siteSubHeader
|
<siteSubHeader
|
||||||
ref="siteSubHeader"
|
ref="siteSubHeader"
|
||||||
class="mt-4"
|
class="mt-4 subheader"
|
||||||
cmsWidgetName="SiteSubHeaderWidget" />
|
cmsWidgetName="SiteSubHeaderWidget" />
|
||||||
<alert
|
<div class="body-container">
|
||||||
id="vehicle-parts-alert"
|
<div
|
||||||
class="mt-3 mb-3"
|
v-for="(item, i) in PartsOrQuestions"
|
||||||
alertClass="alert-warning"
|
:key="i"
|
||||||
cmsWidgetName="AlertWidget"
|
class="glass-question-container">
|
||||||
:isDismissible="false" />
|
<glassPartQuestion
|
||||||
<div
|
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
|
||||||
v-for="(item, i) in PartsOrQuestions"
|
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]"
|
||||||
:key="i">
|
:glassLocation="item.glassLocation"
|
||||||
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
|
:glassName="item.glassName"
|
||||||
<hr v-if="i > 0" />
|
:colorAnswers="item.colorAnswers"
|
||||||
<glassPartQuestion
|
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
|
||||||
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
|
</div>
|
||||||
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]"
|
|
||||||
:glassLocation="item.glassLocation"
|
|
||||||
:glassName="item.glassName"
|
|
||||||
:colorAnswers="item.colorAnswers"
|
|
||||||
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
|
|
||||||
</div>
|
</div>
|
||||||
<siteFooter
|
<siteFooter
|
||||||
ref="siteFooter"
|
ref="siteFooter"
|
||||||
class="mt-5"
|
|
||||||
cmsWidgetName="SiteFooterWidget"
|
cmsWidgetName="SiteFooterWidget"
|
||||||
:isForwardActionDisabled="isForwardActionDisabled"
|
:isForwardActionDisabled="isForwardActionDisabled"
|
||||||
@backClicked="navigateBackByVehicleQuestions"
|
@backClicked="navigateBackByVehicleQuestions"
|
||||||
@ForwardClicked="forwardButtonAction" />
|
@ForwardClicked="forwardButtonAction" />
|
||||||
|
<div class="need-help-link-container">
|
||||||
|
<textLink
|
||||||
|
v-if="needHelpLinkText"
|
||||||
|
linkType="navigation"
|
||||||
|
:text="needHelpLinkText"
|
||||||
|
href="#"
|
||||||
|
@clickEvent="requestCallbackBailout" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -51,7 +53,7 @@ import glassPartQuestion from '@/layouts/vehicle-parts/glass-part-question/glass
|
||||||
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
||||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
|
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
|
||||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||||
import alert from '@/ux-components/alert/alert.vue';
|
import textLink from '@/ux-components/text-link/text-link.vue';
|
||||||
|
|
||||||
// Supporting Files
|
// Supporting Files
|
||||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||||
|
|
@ -61,6 +63,7 @@ import { Form } from 'vee-validate';
|
||||||
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
|
import vehicleQuestionsMixin from '@/mixins/vehicle-questions-mixin';
|
||||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
|
import widgetFields from '@/constants/cms-widget-fields';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'vehicle-parts',
|
name: 'vehicle-parts',
|
||||||
|
|
@ -71,7 +74,7 @@ export default {
|
||||||
siteHeader,
|
siteHeader,
|
||||||
siteSubHeader,
|
siteSubHeader,
|
||||||
siteFooter,
|
siteFooter,
|
||||||
alert
|
textLink
|
||||||
},
|
},
|
||||||
mixins: [BaseFormMixin, vehicleQuestionsMixin],
|
mixins: [BaseFormMixin, vehicleQuestionsMixin],
|
||||||
async beforeRouteEnter(to, from, next) {
|
async beforeRouteEnter(to, from, next) {
|
||||||
|
|
@ -88,17 +91,6 @@ export default {
|
||||||
// Call the "next" function to complete the transition to this page.
|
// Call the "next" function to complete the transition to this page.
|
||||||
next((vm) => {
|
next((vm) => {
|
||||||
vm.setCmsContent(resultMap.cmsContent);
|
vm.setCmsContent(resultMap.cmsContent);
|
||||||
|
|
||||||
// Glass Part Question dynamic component
|
|
||||||
Object.keys(vm.$refs)
|
|
||||||
.filter((r) => r.includes(vm.RefPrefix) && vm.$refs[r][0] !== undefined)
|
|
||||||
.forEach((c) =>
|
|
||||||
vm.$refs[c][0].initializeComponent({
|
|
||||||
ColorQuestionWidget:
|
|
||||||
resultMap.cmsContent.ColorQuestionWidget,
|
|
||||||
FeatureQuestionWidget:
|
|
||||||
resultMap.cmsContent.FeatureQuestionWidget
|
|
||||||
}));
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -156,6 +148,9 @@ export default {
|
||||||
|
|
||||||
RefPrefix() {
|
RefPrefix() {
|
||||||
return 'partQuestion';
|
return 'partQuestion';
|
||||||
|
},
|
||||||
|
needHelpLinkText() {
|
||||||
|
return this.getCmsContent('NeedHelpLinkWidget', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -220,23 +215,47 @@ export default {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
requestCallbackBailout() {
|
||||||
|
this.mainStore.setBailout(bailoutMessage.RequestCallback());
|
||||||
|
this.$router.navigate(navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT, this.$route);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.iss-heritage-container-width {
|
#app .iss-heritage-container-width {
|
||||||
|
.iss-heritage-content-container-width {
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
width: 58.33333333%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.vehicle-parts-container {
|
.vehicle-parts-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 1px;
|
min-height: 1px;
|
||||||
padding-left: .9375rem;
|
padding-left: .9375rem;
|
||||||
padding-right: .9375rem;
|
padding-right: .9375rem;
|
||||||
|
|
||||||
#vehicle-parts-alert {
|
.subheader {
|
||||||
.alert-heading {
|
:deep(strong) {
|
||||||
margin-top: 0.25rem !important;
|
text-transform: uppercase;
|
||||||
|
color: $black;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.glass-question-container {
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body-container {
|
||||||
|
margin-bottom: 1.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.need-help-link-container {
|
||||||
|
margin-bottom: 2.25rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,10 @@ const routingTable = () => [
|
||||||
{
|
{
|
||||||
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
scenario: navigationScenarios.CLICKED_FORWARD_WITH_NO_MORE_QUESTIONS,
|
||||||
destinationIssPageValue: issPageValues.COVERAGE_STATEMENT
|
destinationIssPageValue: issPageValues.COVERAGE_STATEMENT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: navigationScenarios.CLICKED_NEED_HELP_WITH_BAILOUT,
|
||||||
|
destinationIssPageValue: issPageValues.BAILOUT_PAGE
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ export const getDefaultState = () => ({
|
||||||
appointmentType: null,
|
appointmentType: null,
|
||||||
isVehicleProtected: null,
|
isVehicleProtected: null,
|
||||||
IsSafeliteProvider: null,
|
IsSafeliteProvider: null,
|
||||||
searchFilter: null,
|
tpaSearchRadius: null,
|
||||||
provider: {
|
provider: {
|
||||||
providerNumber: null,
|
providerNumber: null,
|
||||||
address: {
|
address: {
|
||||||
|
|
@ -1038,8 +1038,24 @@ export const useMainStore = defineStore({
|
||||||
return this.getProviders(zipCode, radius, true)
|
return this.getProviders(zipCode, radius, true)
|
||||||
},
|
},
|
||||||
|
|
||||||
getTpaProviders(zipCode, radius) {
|
getTpaAndSafeliteProviders(zipCode, provderNameSearchString = "") {
|
||||||
return this.getProviders(zipCode, radius, false)
|
const { parentAccountNumber } = this.order;
|
||||||
|
const carId = this.order.vehicle.carId;
|
||||||
|
const damageType = this.damage.isRepair ? 'Repair' : 'Install';
|
||||||
|
|
||||||
|
const parts = getLineItemsFlattened(this.order.lineItems.glassParts);
|
||||||
|
const partNumbers = parts.map((part) => part.partNumber).join(',');
|
||||||
|
|
||||||
|
let url = `${endpoints.GetTpaAndSafeliteProviders.url}/${zipCode}?accountNumber=${parentAccountNumber}&carId=${carId}&damageType=${damageType}&partNumbers=${partNumbers}`;
|
||||||
|
if (provderNameSearchString) {
|
||||||
|
url += `&providerNameSearchString=${provderNameSearchString}`;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
globalMethods.callHttpClient({
|
||||||
|
method: endpoints.GetTpaAndSafeliteProviders.method,
|
||||||
|
endpoint: url
|
||||||
|
}).then((response) => resolve(response), (error) => reject(error));
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
getProviders(zipcode, radius, safeliteOnly) {
|
getProviders(zipcode, radius, safeliteOnly) {
|
||||||
|
|
@ -1844,7 +1860,7 @@ export const useMainStore = defineStore({
|
||||||
phoneNumber: serviceLocationInfo.provider?.phoneNumber
|
phoneNumber: serviceLocationInfo.provider?.phoneNumber
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
this.order.serviceLocation.searchFilter = serviceLocationInfo.searchFilter;
|
this.order.serviceLocation.tpaSearchRadius = serviceLocationInfo.tpaSearchRadius;
|
||||||
},
|
},
|
||||||
|
|
||||||
resetState() {
|
resetState() {
|
||||||
|
|
|
||||||
|
|
@ -1966,53 +1966,65 @@ describe('Store', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getTpaProviders method', () => {
|
describe('getTpaAndSafeliteProviders method', () => {
|
||||||
describe('successful method call', () => {
|
describe('successful method call', () => {
|
||||||
it.each([[true, 'Repair'], [false, 'Replace']])(
|
it.each([[true, 'Repair'], [false, 'Install']])(
|
||||||
'calls getProviders api endpoint',
|
'calls getProviders api endpoint with damageType %s',
|
||||||
async (isRepair, damageType) => {
|
async (isRepair, damageType) => {
|
||||||
// Arrange
|
// Arrange
|
||||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({}));
|
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({}));
|
||||||
|
|
||||||
const carId = getRandomString(10, 14);
|
const carId = getRandomString(10, 14);
|
||||||
const parentAccountNumber = getRandomString(6, 6);
|
const parentAccountNumber = getRandomString(6, 6);
|
||||||
|
const partNumber = getRandomString(6, 6);
|
||||||
store.order.parentAccountNumber = parentAccountNumber;
|
store.order.parentAccountNumber = parentAccountNumber;
|
||||||
store.order.damage.isRepair = isRepair;
|
store.order.damage.isRepair = isRepair;
|
||||||
store.order.vehicle.carId = carId;
|
store.order.vehicle.carId = carId;
|
||||||
const zipCode = getRandomString(6, 6);
|
store.order.lineItems.glassParts = [{ partNumber }];
|
||||||
const radius = getRandomInt(5, 100);
|
const zipCode = getRandomString(5, 5);
|
||||||
const isBigTruck = false;
|
|
||||||
store.order.vehicle.isBigTruck = isBigTruck;
|
const expectedEndpoint = `${endpoints.GetTpaAndSafeliteProviders.url}/${zipCode}?accountNumber=${parentAccountNumber}&carId=${carId}&damageType=${damageType}&partNumbers=${partNumber}`;
|
||||||
const expectedEndpoint = endpoints.GetProviders.url(
|
|
||||||
zipCode,
|
|
||||||
damageType,
|
|
||||||
radius,
|
|
||||||
parentAccountNumber,
|
|
||||||
'false',
|
|
||||||
carId,
|
|
||||||
null,
|
|
||||||
isBigTruck
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await store.getTpaProviders(zipCode, radius);
|
await store.getTpaAndSafeliteProviders(zipCode);
|
||||||
|
|
||||||
// Asserts
|
// Asserts
|
||||||
expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({
|
expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
method: endpoints.GetProviders.method,
|
method: endpoints.GetTpaAndSafeliteProviders.method,
|
||||||
endpoint: expectedEndpoint
|
endpoint: expectedEndpoint
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
it('includes providerNameSearchString in endpoint when provided', async () => {
|
||||||
|
// Arrange
|
||||||
|
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve({}));
|
||||||
|
|
||||||
|
const carId = getRandomString(10, 14);
|
||||||
|
const parentAccountNumber = getRandomString(6, 6);
|
||||||
|
const partNumber = getRandomString(6, 6);
|
||||||
|
store.order.parentAccountNumber = parentAccountNumber;
|
||||||
|
store.order.damage.isRepair = true;
|
||||||
|
store.order.vehicle.carId = carId;
|
||||||
|
store.order.lineItems.glassParts = [{ partNumber }];
|
||||||
|
const zipCode = getRandomString(5, 5);
|
||||||
|
const providerNameSearchString = 'Test Shop';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await store.getTpaAndSafeliteProviders(zipCode, providerNameSearchString);
|
||||||
|
|
||||||
|
// Asserts
|
||||||
|
expect(globalMethods.callHttpClient).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
|
endpoint: expect.stringContaining(`&providerNameSearchString=${providerNameSearchString}`)
|
||||||
|
}));
|
||||||
|
});
|
||||||
it('Returns expected response object', async () => {
|
it('Returns expected response object', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const response = { ReferralNumber: getRandomString(6, 6) };
|
const response = { ReferralNumber: getRandomString(6, 6) };
|
||||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
|
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(response));
|
||||||
const zipCode = getRandomString(6, 6);
|
const zipCode = getRandomString(5, 5);
|
||||||
const radius = getRandomInt(5, 100);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = store.getTpaProviders(zipCode, radius);
|
const result = store.getTpaAndSafeliteProviders(zipCode);
|
||||||
|
|
||||||
// Asserts
|
// Asserts
|
||||||
await expect(result).resolves.toBe(response);
|
await expect(result).resolves.toBe(response);
|
||||||
|
|
@ -2020,11 +2032,10 @@ describe('Store', () => {
|
||||||
it('null response by api => no exceptions thrown', async () => {
|
it('null response by api => no exceptions thrown', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(null));
|
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
const zipCode = getRandomString(6, 6);
|
const zipCode = getRandomString(5, 5);
|
||||||
const radius = getRandomInt(5, 100);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await store.getTpaProviders(zipCode, radius);
|
await store.getTpaAndSafeliteProviders(zipCode);
|
||||||
});
|
});
|
||||||
it('no providers returned by api => promise resolves to empty list', async () => {
|
it('no providers returned by api => promise resolves to empty list', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -2034,11 +2045,10 @@ describe('Store', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(responseNoProviders));
|
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(responseNoProviders));
|
||||||
const zipCode = getRandomString(6, 6);
|
const zipCode = getRandomString(5, 5);
|
||||||
const radius = getRandomInt(5, 100);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await store.getTpaProviders(zipCode, radius);
|
const result = await store.getTpaAndSafeliteProviders(zipCode);
|
||||||
|
|
||||||
// Asserts
|
// Asserts
|
||||||
expect(result.data.shopProviders).toHaveLength(0);
|
expect(result.data.shopProviders).toHaveLength(0);
|
||||||
|
|
@ -2060,7 +2070,7 @@ describe('Store', () => {
|
||||||
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(responseProviders));
|
globalMethods.callHttpClient = jest.fn().mockReturnValue(Promise.resolve(responseProviders));
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const result = await store.getTpaProviders();
|
const result = await store.getTpaAndSafeliteProviders();
|
||||||
|
|
||||||
// Asserts
|
// Asserts
|
||||||
expect(result.data.shopProviders).toHaveLength(2);
|
expect(result.data.shopProviders).toHaveLength(2);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue