Merge pull request #2752 from Safelite/rlsmerge/2025.08.21-to-dev

Rlsmerge/2025.08.21 to dev
This commit is contained in:
CarlNation 2025-08-12 07:58:01 -04:00 committed by GitHub
commit ce03ee8fb4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 597 additions and 334 deletions

View file

@ -27,4 +27,3 @@ ADMIN_SERVICE_API_URL="https://issadminapi.dev.sagaws.net/iss-admin/api/v1/"
# API authentication (replace with actual value when running tests) # API authentication (replace with actual value when running tests)
CCIS_API_AUTH="undefined" CCIS_API_AUTH="undefined"

View file

@ -131,24 +131,24 @@ export class BasePage {
} }
async validateProgressBar(progressPercentage: string, timeout: number = 60000) { async validateProgressBar(progressPercentage: string, timeout: number = 60000) {
// This section has been commented out until progress bar work is completed for parity.
// await waitUntil(async () => {
// let loaderElements = await this.page.locator('button .loader, .buy-loader, timeout, .modal-loader').all();
// return !(await Promise.any(loaderElements.map(el => el.isVisible())).catch(() => false));
// });
await waitUntil(async () => { // // Take a screenshot of the page before validating the progress bar
let loaderElements = await this.page.locator('button .loader, .buy-loader, timeout, .modal-loader').all(); // await this.page.screenshot({ path: `test-results\\ortoni-data\\progress-bar-${Date.now()}.png`, fullPage: true });
return !(await Promise.any(loaderElements.map(el => el.isVisible())).catch(() => false)); // // Wait until the progress bar element is attached and visible
});
// Take a screenshot of the page before validating the progress bar // const actualProgressPercentage = await this.progressBar.evaluate(
await this.page.screenshot({ path: `test-results\\ortoni-data\\progress-bar-${Date.now()}.png`, fullPage: true }); // async (element) => {
// Wait until the progress bar element is attached and visible // await new Promise(resolve => setTimeout(resolve, 200));
// return element.style.width || "Not Found";
const actualProgressPercentage = await this.progressBar.evaluate( // }
async (element) => { // );
await new Promise(resolve => setTimeout(resolve, 200)); // Soft.expect(actualProgressPercentage).toBe(progressPercentage);
return element.style.width || "Not Found"; // console.log(`Progress Bar Percentage: Actual - ${actualProgressPercentage} vs Expected - ${progressPercentage}`);
}
);
Soft.expect(actualProgressPercentage).toBe(progressPercentage);
console.log(`Progress Bar Percentage: Actual - ${actualProgressPercentage} vs Expected - ${progressPercentage}`);
} }
} }

View file

@ -17,7 +17,7 @@ export class SchedulePage extends BasePage {
readonly militaryWarningMessage: Locator; readonly militaryWarningMessage: Locator;
readonly changeZipButton: Locator; readonly changeZipButton: Locator;
readonly updateZipTextBox: Locator; readonly updateZipTextBox: Locator;
readonly saveZipButton: Locator; readonly saveLocationButton: Locator;
readonly changeShopLocationLink: Locator; readonly changeShopLocationLink: Locator;
readonly selectAShopOptions: Locator; readonly selectAShopOptions: Locator;
readonly yourSafeliteShop: Locator; readonly yourSafeliteShop: Locator;
@ -37,14 +37,14 @@ export class SchedulePage extends BasePage {
super(page); super(page);
this.page = page; this.page = page;
this.inShopButton = this.page.getByText(/In-shop/); this.inShopButton = this.page.locator('label[buttonlabel="You come to our store"]');
this.mobileButton = this.page.locator('label[buttonlabel="Mobile"]'); this.mobileButton = this.page.locator('label[buttonlabel="Our mobile shop comes to you"]');
this.RecalWarningMessage1 = this.page.getByText(/We're not able to provide mobile service/); this.RecalWarningMessage1 = this.page.getByText(/We're not able to provide mobile service/);
this.RecalWarningMessage2 = this.page.getByText(/advanced safety system recalibration needs to be done in our shop./); this.RecalWarningMessage2 = this.page.getByText(/advanced safety system recalibration needs to be done in our shop./);
this.militaryWarningMessage = this.page.locator('[class*="widget-name-AlertMilitaryBaseZipWidget"]'); this.militaryWarningMessage = this.page.locator('[class*="widget-name-AlertMilitaryBaseZipWidget"]');
this.changeZipButton = this.page.locator('a:has(span.sr-only:has-text("edit zip code"))'); this.changeZipButton = this.page.locator('a:has(span.sr-only:has-text("edit zip code"))');
this.updateZipTextBox = this.page.locator('#serviceZipCode').filter({ visible: true }); this.updateZipTextBox = this.page.locator('#serviceZipCode').filter({ visible: true });
this.saveZipButton = this.page.getByText('Save ZIP code', { exact: true }); this.saveLocationButton = this.page.getByText('Save location', { exact: true });
this.changeShopLocationLink = this.page.locator(".shop-question a").filter({ hasText: "Change shop location " }); this.changeShopLocationLink = this.page.locator(".shop-question a").filter({ hasText: "Change shop location " });
this.selectAShopOptions = this.page.locator('[class="shop-question"]'); this.selectAShopOptions = this.page.locator('[class="shop-question"]');
this.yourSafeliteShop = this.page.locator("fieldset:has(#chooseShop) label"); this.yourSafeliteShop = this.page.locator("fieldset:has(#chooseShop) label");
@ -82,10 +82,11 @@ export class SchedulePage extends BasePage {
if (zipCodeMatch) { if (zipCodeMatch) {
const zipCode = zipCodeMatch[0]; const zipCode = zipCodeMatch[0];
// Enter the ZIP code into the updateZipTextBox // Enter the ZIP code into the updateZipTextBox
await this.changeZipButton.click(); await this.changeShopLocationLink.click();
await this.page.waitForTimeout(500); await this.page.waitForTimeout(500);
await this.updateZipTextBox.fill(zipCode); await this.updateZipTextBox.fill(zipCode);
await this.saveZipButton.click(); // Click the save location button
await this.saveLocationButton.click();
} }
await this.inShopButton.click(); await this.inShopButton.click();

View file

@ -60,7 +60,7 @@ const cashReplaceGlassPromoInshopTests: ITestCase[] = [];
const tc = { const tc = {
name: `CashReplaceGlassPromoInshop`, name: `CashReplaceGlassPromoInshop`,
tags: ['@E2E','@CashReplaceGlassPromoInshop', '@test_report', '@CASH'], tags: ['@E2E','@CashReplaceGlassPromoInshop', '@test_report', '@CASH', '@CASH-1182'],
testData: cashReplaceGlassPromoInshopData testData: cashReplaceGlassPromoInshopData
}; };
cashReplaceGlassPromoInshopTests.push(tc); cashReplaceGlassPromoInshopTests.push(tc);

View file

@ -95,7 +95,7 @@ const cashReplaceMultiGlassMobileTests: ITestCase[] = [];
const tc = { const tc = {
name: `CashReplaceMultiGlassMobile`, name: `CashReplaceMultiGlassMobile`,
tags: ['@E2E','@CashReplaceMultiGlassMobile', '@test_report', '@CASH'], tags: ['@E2E','@CashReplaceMultiGlassMobile', '@test_report', '@CASH', '@CASH-1182'],
testData: cashReplaceMultiGlassMobileData testData: cashReplaceMultiGlassMobileData
}; };
cashReplaceMultiGlassMobileTests.push(tc); cashReplaceMultiGlassMobileTests.push(tc);

View file

@ -101,7 +101,7 @@ const cashReplaceMultiGlassPromoInshopTests: ITestCase[] = [];
const tc = { const tc = {
name: `CashReplaceMultiGlassPromoInshop`, name: `CashReplaceMultiGlassPromoInshop`,
tags: ['@E2E','@CashReplaceMultiGlassPromoInshop', '@test_report', '@CASH', '@CASH-848'], tags: ['@E2E','@CashReplaceMultiGlassPromoInshop', '@test_report', '@CASH', '@CASH-1182'],
testData: cashReplaceMultiGlassPromoInshopData testData: cashReplaceMultiGlassPromoInshopData
}; };
cashReplaceMultiGlassPromoInshopTests.push(tc); cashReplaceMultiGlassPromoInshopTests.push(tc);

View file

@ -77,7 +77,7 @@ const cashReplaceSafeliteCanNotRecalMobileTests: ITestCase[] = [];
const tc = { const tc = {
name: `CashReplaceSafeliteCanNotRecalMobile`, name: `CashReplaceSafeliteCanNotRecalMobile`,
tags: ['@E2E','@CashReplaceSafeliteCanNotRecalMobile', '@test_report', '@CASH'], tags: ['@E2E','@CashReplaceSafeliteCanNotRecalMobile', '@test_report', '@CASH', '@CASH-1182'],
testData: cashReplaceSafeliteCanNotRecalMobileData testData: cashReplaceSafeliteCanNotRecalMobileData
}; };
cashReplaceSafeliteCanNotRecalMobileTests.push(tc); cashReplaceSafeliteCanNotRecalMobileTests.push(tc);

View file

@ -66,7 +66,7 @@ const cashReplaceVinMobileTests: ITestCase[] = [];
const tc = { const tc = {
name: `CashReplaceVinMobile`, name: `CashReplaceVinMobile`,
tags: ['@E2E','@CashReplaceVinMobile', '@test_report', '@CASH'], tags: ['@E2E','@CashReplaceVinMobile', '@test_report', '@CASH', '@CASH-1182'],
testData: cashReplaceVinMobileData testData: cashReplaceVinMobileData
}; };
cashReplaceVinMobileTests.push(tc); cashReplaceVinMobileTests.push(tc);

View file

@ -37,7 +37,7 @@ body .headerlinecontainer .headerline1 {
line-height: 32px; line-height: 32px;
font-weight: 400; font-weight: 400;
margin: 24px 0; margin: 24px 0;
text-align: center; text-align: left;
} }
body input, body input,
body select { body select {
@ -137,9 +137,9 @@ body .buttonContainer {
} }
body .buttonContainer button { body .buttonContainer button {
position: relative; position: relative;
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%); background: #db0020;
border: none; border: none;
border-radius: 8px; border-radius: 50rem;
color: #fff; color: #fff;
justify-content: center; justify-content: center;
font-family: Urbanist, Arial, Helvetica, sans-serif; font-family: Urbanist, Arial, Helvetica, sans-serif;
@ -149,7 +149,6 @@ body .buttonContainer button {
} }
@media (hover: hover) { @media (hover: hover) {
body .buttonContainer button { body .buttonContainer button {
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
cursor: pointer; cursor: pointer;
} }
} }

View file

@ -44,7 +44,7 @@ body {
line-height: 32px; line-height: 32px;
font-weight: 400; font-weight: 400;
margin: 24px 0; margin: 24px 0;
text-align: center; text-align: left;
} }
} }
@ -148,9 +148,9 @@ body {
height: 48px; height: 48px;
button { button {
position: relative; position: relative;
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%); background: #db0020;
border: none; border: none;
border-radius: 8px; border-radius: 50rem;
color: #fff; color: #fff;
justify-content: center; justify-content: center;
font-family: Urbanist, Arial, Helvetica, sans-serif; font-family: Urbanist, Arial, Helvetica, sans-serif;
@ -158,7 +158,6 @@ body {
font-size: 16px; font-size: 16px;
height: 48px; height: 48px;
@media (hover: hover) { @media (hover: hover) {
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
cursor: pointer; cursor: pointer;
} }
&:focus { &:focus {

View file

@ -73,11 +73,11 @@ export const pageProgressMapper = {
step: 3, step: 3,
}, },
"payment-method": { "payment-method": {
percent: 92, //The first Step 4 must be 92 so the animated bar lines up with the dot percent: 97, //The first Step 4 must be 97 so the animated bar lines up with the dot
step: 3, step: 4,
}, },
payment: { payment: {
percent: 96, percent: 98.5,
step: 4, step: 4,
}, },
confirmation: { confirmation: {

View file

@ -12,6 +12,10 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
<span class="fw-bold w-100" :class="[labelBold ? 'span-bold' : '']"> <span class="fw-bold w-100" :class="[labelBold ? 'span-bold' : '']">
{{ questionText }} {{ questionText }}
</span> </span>
<p
v-if="questionTextDescription"
class="question-text-description"
v-html="questionTextDescription"></p>
</div> </div>
<div class="w-100 d-flex justify-content-center"> <div class="w-100 d-flex justify-content-center">
@ -60,6 +64,7 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
:isInsuranceSelected="isInsuranceSelected" :isInsuranceSelected="isInsuranceSelected"
:suppressError="suppressError" :suppressError="suppressError"
:labelBold="labelBold" :labelBold="labelBold"
:isHidden="setIsHidden(index)"
@buttonEvent="handleButtonEvent" @buttonEvent="handleButtonEvent"
v-model="selectedValues" /> v-model="selectedValues" />
<!-- For nested questions --> <!-- For nested questions -->
@ -92,6 +97,11 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
:name="formatString(groupName)" :name="formatString(groupName)"
v-if="!suppressError"></error-message> v-if="!suppressError"></error-message>
</div> </div>
<div v-if="lazyLoad.isLazyLoad && !showAllButtons" id="show-more-button">
<button class="btn btn-link" type="button" @click="toggleShowAllButtons">
View more times
</button>
</div>
</div> </div>
</template> </template>
@ -118,6 +128,7 @@ export default {
isMultiSelect: Boolean, isMultiSelect: Boolean,
groupName: String, groupName: String,
questionText: String, questionText: String,
questionTextDescription: String,
answers: Array, answers: Array,
textPosition: { textPosition: {
type: String, type: String,
@ -158,6 +169,13 @@ export default {
required: false, required: false,
default: false, default: false,
}, },
lazyLoad: {
type: Object,
default: () => ({
isLazyLoad: false,
amountToLoad: null,
}),
},
}, },
setup(props) { setup(props) {
const propsClone = Object.assign({}, props); const propsClone = Object.assign({}, props);
@ -189,6 +207,7 @@ export default {
data() { data() {
return { return {
lastValuePushedToGa: null, lastValuePushedToGa: null,
showAllButtons: false,
}; };
}, },
computed: { computed: {
@ -284,6 +303,15 @@ export default {
this.$emit("update:modelValue", selectedAnswers); this.$emit("update:modelValue", selectedAnswers);
}, },
}, },
setIsHidden() {
return (index) => {
return (
this.lazyLoad.isLazyLoad &&
index >= this.lazyLoad.amountToLoad &&
!this.showAllButtons
);
};
},
}, },
methods: { methods: {
formatString(str) { formatString(str) {
@ -296,6 +324,9 @@ export default {
const eventName = event.eventName; const eventName = event.eventName;
this.$emit(`buttonEvent.${eventName}`, event.args); this.$emit(`buttonEvent.${eventName}`, event.args);
}, },
toggleShowAllButtons() {
this.showAllButtons = true;
},
}, },
watch: { watch: {
modelValue(newValue, oldValue) { modelValue(newValue, oldValue) {
@ -357,6 +388,28 @@ export default {
font-family: UrbanistSemibold; font-family: UrbanistSemibold;
color: $black; color: $black;
&.timeslots {
.col {
& > label[isHidden="true"] {
display: none;
}
}
#show-more-button {
width: 100%;
text-align: center;
margin-top: 0.5rem;
button {
color: $blue;
text-underline-offset: 4px;
&:active {
background: unset;
}
}
}
}
.radio-button-container { .radio-button-container {
&:not(:last-child) { &:not(:last-child) {
padding-bottom: map-get($spacers, 2); padding-bottom: map-get($spacers, 2);
@ -376,6 +429,13 @@ export default {
font-weight: 600; font-weight: 600;
} }
} }
.question-text-description {
font-family: UrbanistRegular;
& > sup {
font-size: 0.5rem;
top: -0.4rem;
}
}
.small-question-text { .small-question-text {
&.question-text { &.question-text {
span { span {

View file

@ -336,7 +336,7 @@ export default {
); );
if (this.estimatedServiceMinutesMinimum && this.estimatedServiceMinutesMaximum) { if (this.estimatedServiceMinutesMinimum && this.estimatedServiceMinutesMaximum) {
return `${inshopDurationTextWithoutTime} ${inshopDurationTime}`; return `${inshopDurationTextWithoutTime} <b>${inshopDurationTime}</b>`;
} }
return null; return null;
@ -353,7 +353,7 @@ export default {
); );
if (this.estimatedServiceMinutesMinimum && this.estimatedServiceMinutesMaximum) { if (this.estimatedServiceMinutesMinimum && this.estimatedServiceMinutesMaximum) {
return `${mobileDurationTextWithoutTime} ${mobileDurationTime}`; return `${mobileDurationTextWithoutTime} <b>${mobileDurationTime}</b>`;
} }
return null; return null;
@ -1025,6 +1025,8 @@ export default {
flex-grow: 0; flex-grow: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start;
text-align: left;
.duration-text-block { .duration-text-block {
text-align: left; text-align: left;
@ -1040,6 +1042,7 @@ export default {
.view-more-dates { .view-more-dates {
color: $blue; color: $blue;
font-family: UrbanistSemiBold;
} }
} }
.loader { .loader {
@ -1106,10 +1109,11 @@ export default {
.month-year { .month-year {
grid-area: 1 / 1 / 2 / 5; grid-area: 1 / 1 / 2 / 5;
font-family: UrbanistBold; font-family: UrbanistSemiBold;
color: $black; color: $black;
justify-content: center; justify-content: left;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
font-weight: 500;
} }
.legend { .legend {
grid-area: 1 / 5 / 2 / 8; grid-area: 1 / 5 / 2 / 8;
@ -1468,19 +1472,8 @@ export default {
display: flex; display: flex;
max-width: 100%; max-width: 100%;
flex-wrap: wrap; flex-wrap: wrap;
gap: 0 0.5rem;
& > div { & > div {
flex: 0 0 calc(50% - 0.25rem);
}
}
:deep(.button-question.is-mobile-appointment) {
.button-inner-wrapper > div {
flex: 0 0 100%;
}
}
:deep(.button-question.is-drop-off-appointment) {
.button-inner-wrapper > div {
flex: 0 0 100%; flex: 0 0 100%;
} }
} }
@ -1490,6 +1483,8 @@ export default {
display: block; display: block;
position: relative; position: relative;
height: 2rem; height: 2rem;
font-size: 0.875rem;
padding-top: 0;
width: 100%; width: 100%;
justify-content: center; justify-content: center;
background: transparent; background: transparent;

View file

@ -19,7 +19,9 @@
:validationRules="validationRules" :validationRules="validationRules"
:placeHolderText="placeHolderText" :placeHolderText="placeHolderText"
:valueAsKey="valueAsKey"> :valueAsKey="valueAsKey">
<option v-if="placeHolderText" value="" selected>{{ placeHolderText }}</option> <option v-if="placeHolderText && !isDisabled" value="" selected>
{{ placeHolderText }}
</option>
<option <option
v-for="(value, name, index) in options" v-for="(value, name, index) in options"
:value="valueAsKey == true ? value : name" :value="valueAsKey == true ? value : name"
@ -152,7 +154,7 @@ export default {
border: 1px solid $gray-500; border: 1px solid $gray-500;
border-radius: 0.5rem; border-radius: 0.5rem;
min-height: 3rem; min-height: 3rem;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
min-height: 3.5rem; min-height: 3.5rem;
} }

View file

@ -9,7 +9,9 @@
tabindex="-1" tabindex="-1"
aria-labelledby="ModalComponentLabel" aria-labelledby="ModalComponentLabel"
@keypress.enter="onEnter" @keypress.enter="onEnter"
aria-hidden="true"> aria-hidden="true"
@click.self="closeModal">
<!--Close modal when clicking other than close button-->
<div class="modal-dialog modal-dialog-centered"> <div class="modal-dialog modal-dialog-centered">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header mb-0 mt-6"> <div class="modal-header mb-0 mt-6">
@ -248,6 +250,7 @@ export default {
button { button {
margin: 0; margin: 0;
border-radius: 50rem;
} }
} }
} }

View file

@ -337,7 +337,7 @@ export default {
border-radius: 0.5rem; border-radius: 0.5rem;
min-height: 3rem; min-height: 3rem;
padding: 0.75rem 1rem; padding: 0.75rem 1rem;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
padding: 1rem; padding: 1rem;
min-height: 3.5rem; min-height: 3.5rem;

View file

@ -227,9 +227,14 @@ export default {
} }
} }
&.has-package-discount { //Package container height with package discount AND "most popular" label
&.has-package-discount.has-subheader {
min-height: 170px; min-height: 170px;
} }
//Package container height with package discount only
&.has-package-discount {
min-height: 136px;
}
&:before { &:before {
content: ""; content: "";

View file

@ -15,7 +15,9 @@
v-show="shouldShowWebchatButton" v-show="shouldShowWebchatButton"
v-on:click="webchatClicked" v-on:click="webchatClicked"
type="button" type="button"
class="chat-button"></button> class="chat-button">
<span>Chat Now</span>
</button>
</span> </span>
</div> </div>
<div class="button-container"> <div class="button-container">
@ -206,14 +208,11 @@ export default {
} }
} }
position: relative; position: relative;
padding: 0 0 1rem 0; padding: 0;
.button-container { .button-container {
&.webchat { &.webchat {
margin-right: 1rem; margin-right: 0.875rem;
@include media-breakpoint-up(md) {
margin-right: 2rem;
}
} }
} }
@ -232,14 +231,29 @@ export default {
.webchat { .webchat {
.chat-button { .chat-button {
width: 1.5rem; text-transform: uppercase;
height: 1.5rem; width: 7.5rem;
height: 2rem;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xml:space='preserve' id='Layer_2' x='0' y='0' style='enable-background:new 0 0 24 24' version='1.1' viewBox='0 0 24 24'%3E%3Cstyle%3E .st0%7Bfill:%232e6fb6%7D %3C/style%3E%3Ccircle cx='12' cy='12' r='12' class='st0'/%3E%3Cpath d='M18.3 12c0 3.5-2.8 6.3-6.3 6.3-1.2 0-2.4-.4-3.4-1l-2.3.7s-.5.1-.3-.4.5-1.7.7-2.2c-.6-1-1-2.1-1-3.3 0-3.5 2.8-6.3 6.3-6.3 3.5-.1 6.3 2.7 6.3 6.2z' style='fill:%23fff'/%3E%3Ccircle cx='10.2' cy='12' r='.6' class='st0'/%3E%3Ccircle cx='12' cy='12' r='.6' class='st0'/%3E%3Ccircle cx='13.8' cy='12' r='.6' class='st0'/%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xml:space='preserve' id='Layer_2' x='0' y='0' style='enable-background:new 0 0 24 24' version='1.1' viewBox='0 0 24 24'%3E%3Cstyle%3E .st0%7Bfill:%232e6fb6%7D %3C/style%3E%3Ccircle cx='12' cy='12' r='12' class='st0'/%3E%3Cpath d='M18.3 12c0 3.5-2.8 6.3-6.3 6.3-1.2 0-2.4-.4-3.4-1l-2.3.7s-.5.1-.3-.4.5-1.7.7-2.2c-.6-1-1-2.1-1-3.3 0-3.5 2.8-6.3 6.3-6.3 3.5-.1 6.3 2.7 6.3 6.2z' style='fill:%23fff'/%3E%3Ccircle cx='10.2' cy='12' r='.6' class='st0'/%3E%3Ccircle cx='12' cy='12' r='.6' class='st0'/%3E%3Ccircle cx='13.8' cy='12' r='.6' class='st0'/%3E%3C/svg%3E");
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 1.5rem 1.5rem; background-size: 2rem 2rem;
background-position: center; background-position: right;
border: none; border: none;
background-color: transparent; background-color: transparent;
padding-right: 2rem;
font-size: 0.875rem;
font-weight: 600;
font-family: "UrbanistSemibold";
color: $blue;
@include media-breakpoint-down(md) {
width: 2rem;
padding-right: 0;
}
span {
@include media-breakpoint-down(md) {
display: none;
}
}
} }
} }
} }

View file

@ -39,25 +39,14 @@
<span class="dot4"></span> <span class="dot4"></span>
</div> </div>
<div class="d-flex flex-column justify-content-between"> <div class="d-flex flex-column justify-content-between">
<div class="step-containers"> <div class="step-containers" v-for="step in steps" :key="step.number">
<span class="step-number">Step 1 of 4</span> <span class="step-number">Step {{ step.number }} of 4</span>
<br /> <br />
<span class="step-name">Vehicle</span> <span
</div> class="step-name"
<div class="step-containers"> :class="{ 'active-step': step.number === currentStepNumber }">
<span class="step-number">Step 2 of 4</span> {{ step.name }}
<br /> </span>
<span class="step-name">Quote</span>
</div>
<div class="step-containers">
<span class="step-number">Step 3 of 4</span>
<br />
<span class="step-name">Schedule</span>
</div>
<div class="step-containers">
<span class="step-number">Step 4 of 4</span>
<br />
<span class="step-name">Review</span>
</div> </div>
</div> </div>
</div> </div>
@ -107,6 +96,14 @@ export default {
currentStepNumber() { currentStepNumber() {
return getProgressBarStep(this.$route.name); return getProgressBarStep(this.$route.name);
}, },
steps() {
return [
{ number: 1, name: "Vehicle" },
{ number: 2, name: "Quote" },
{ number: 3, name: "Schedule" },
{ number: 4, name: "Review" },
];
},
}, },
components: { components: {
progressBar, progressBar,
@ -118,11 +115,15 @@ export default {
.menu-modal-container { .menu-modal-container {
button { button {
border: none; border: none;
color: $blue;
font-family: UrbanistSemibold, Arial, Helvetica, sans-serif;
font-weight: 600;
font-size: 0.875rem;
&.menu-button { &.menu-button {
width: auto; width: auto;
height: auto; height: auto;
border-radius: 1.5rem; border-radius: 1.5rem;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
background-color: $white; background-color: $white;
position: relative; position: relative;
display: flex; display: flex;
@ -254,6 +255,10 @@ export default {
.step-name { .step-name {
font-size: 1.25rem; font-size: 1.25rem;
} }
.active-step {
font-family: UrbanistSemibold, Arial, Helvetica, sans-serif;
font-weight: 600;
}
} }
} }
.modal-fullscreen { .modal-fullscreen {

View file

@ -125,7 +125,7 @@ export default {
align-items: center; align-items: center;
height: 3rem; height: 3rem;
border-radius: 0.5rem; border-radius: 0.5rem;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
&.progress-saved { &.progress-saved {
background: none; background: none;

View file

@ -9,79 +9,11 @@
<img :src="ScheduleConfirmationImage" /> <img :src="ScheduleConfirmationImage" />
<span v-html="ScheduleConfirmationText"></span> <span v-html="ScheduleConfirmationText"></span>
</div> </div>
<div class="row justify-content-center"> <div class="emailtext" v-html="ConfirmationEmailText"></div>
<div class="col-md-6 col-xl-4"> <div class="main">
<div class="header-container"> <div class="scheduleText">
<img :src="ScheduleConfirmationImage" /> <p>{{ ScheduleDateFormatted }}</p>
<span v-html="ScheduleConfirmationText"></span> <p>{{ ScheduleTimeFormatted }}</p>
</div>
<div class="emailtext" v-html="ConfirmationEmailText"></div>
<div class="main">
<div></div>
<div class="scheduleText">
<p>{{ ScheduleDateFormatted }}</p>
<p>{{ ScheduleTimeFormatted }}</p>
</div>
<addToCalendar
mobileWidgetName="AddToCalendar_Mobile"
inShopWidgetName="AddToCalendar_InShop"
dropOffWidgetName="AddToCalendar_DropOff"
overnightDropOffWidgetName="AddToCalendar_OvernightDropOff"
allDayDropOffWidgetName="AddToCalendar_AllDayDropOff"
sameDayDropOffWidgetName="AddToCalendar_SameDayDropOff"
:serviceLocationFullAddress="ServiceLocationFullAddress"
:providerFullAddress="ProviderFullAddress"
:appointmentType="AppointmentType"
:scheduleDate="ScheduleDate"
:scheduleStartTime="ScheduleStartTime"
:scheduleEndTime="ScheduleEndTime" />
<div class="appointment-text" v-html="AppointmentWordingText"></div>
<textBlock
:customText="AppointmentDuration"
justifyText="center"
typeStyle="medium"
class="duration-text-block" />
</div>
<div class="mt-3" v-if="shouldDisplayFosterLove">
<donationBlock
cmsWidgetName="DonationWidget"
v-model="donationAmount"
:donationValues="donationValues"
:showDonationSuccess="showDonationSuccess"
:showDonationError="showDonationError"
@DonationAddedEvent="addDonationToOrder"
ref="donationBlock" />
</div>
<hr class="mt-4 mb-0" />
<cart
v-if="ShowCart"
:damage="damageInfo"
:availableVaps="vaps"
:allowItemRemoval="false"
v-model="lineItemsWithoutDonation"
:donationCartItem="donationLineItem"
:showAsPaid="isPia"
servicePackageOptionsCmsName="ServicePackageTitle"
:isInsurance="isInsurance"
:insuranceDeductible="currentDeductible"
:insuranceCompanyName="insuranceCompanyName"
:showInsuranceCoverageAs="showInsuranceCoverageAs"
:shouldHideRecalibration="shouldHideRecalibration"
:isExpandedOnLoad="false"
:isItac="isItac"
:isNoComp="isNoComp"
:isMSRFeeApplicable="isMSRFeeApplicable" />
<hr class="mb-5" />
</div> </div>
<addToCalendar <addToCalendar
@ -118,7 +50,7 @@
ref="donationBlock" /> ref="donationBlock" />
</div> </div>
<hr class="mt-5 mb-0" /> <hr class="mt-4 mb-0" />
<cart <cart
v-if="ShowCart" v-if="ShowCart"
@ -139,7 +71,7 @@
:isNoComp="isNoComp" :isNoComp="isNoComp"
:isMSRFeeApplicable="isMSRFeeApplicable" /> :isMSRFeeApplicable="isMSRFeeApplicable" />
<hr class="mt-4 mb-5" /> <hr class="mb-5" />
</div> </div>
</div> </div>
</div> </div>

View file

@ -108,11 +108,11 @@ export default {
position: relative; position: relative;
background: $white; background: $white;
transition: all 150ms linear; transition: all 150ms linear;
border-radius: $border-radius-lg; border-radius: 50rem;
border: 1px solid $gray-500; border: 1px solid $gray-500;
width: 100%; width: 100%;
outline: none; outline: none;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
span { span {
&.small { &.small {

View file

@ -57,7 +57,7 @@
alertClass="alert-info" /> alertClass="alert-info" />
<promoModalQuestion <promoModalQuestion
class="mt-6 d-flex justify-content-center" class="mt-6 d-flex"
v-model="lineItems" v-model="lineItems"
:addableVaps="addableVaps" :addableVaps="addableVaps"
pageName="quote" pageName="quote"
@ -624,7 +624,7 @@ export default {
if (this.packageNumber > 2) { if (this.packageNumber > 2) {
return "col-xl-12"; return "col-xl-12";
} else { } else {
return "col-xl-6"; return "col-xl-10";
} }
}, },
currentNumberOfPackagesAction(packageNumber) { currentNumberOfPackagesAction(packageNumber) {
@ -922,6 +922,60 @@ export default {
width: -moz-available; width: -moz-available;
} }
} }
.promo-modal-question {
@include media-breakpoint-up(md) {
justify-content: center;
}
}
//Save email modal ONLY centered on screen for quote page only
.save-progress-popup-question {
:deep(.modal-component) {
.modal-dialog {
max-width: 767px;
margin: 0 0.5rem;
top: 0;
@include media-breakpoint-up(md) {
width: 50%;
max-width: 600px;
right: 0;
left: 0;
transform: none;
margin: 0 auto;
}
.modal-content {
border-radius: 0.5rem;
margin: 0.5rem 0 0 0;
@include media-breakpoint-up(md) {
box-shadow: none;
border-radius: 0;
height: auto;
border-radius: 0.5rem;
}
}
&.modal-dialog-centered {
height: auto;
min-height: auto;
}
}
.modal-footer {
button {
&.btn {
border-radius: 50rem;
}
}
button {
&.btn {
&.skip-button {
margin: 0 auto 1rem;
color: $blue;
font-family: UrbanistSemibold, Arial, Helvetica, sans-serif;
text-decoration: none;
}
}
}
}
}
}
} }
.quote-page.show-save-progress-popup .row.justify-content-center { .quote-page.show-save-progress-popup .row.justify-content-center {
display: none; display: none;

View file

@ -5,56 +5,9 @@
<div class="container page-container-grouped-styles"> <div class="container page-container-grouped-styles">
<div class="row"> <div class="row">
<div class="col-12 col-md-10 col-lg-8 col-xl-7"> <div class="col-12 col-md-10 col-lg-8 col-xl-7">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-4" />
<serviceZipModalQuestion
editScreenReaderTextCmsWidgetName="ScreenReaderZipEditWidget"
v-model="serviceZipCodeQuestion"
ref="serviceZipCodeQuestion"
:carId="carId"
:isVehicleHeavyTruck="isVehicleHeavyTruck"
:mobileFeePart="mobileFeePart"
@updated-mobile-fee-part="setMobileFeePart"
@updated-recycle-fee-part="setRecycleFeePart"
@updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase"
@updated-bill-to-account-number="setBillToAccountNumber"
@service-zip-changed-from-modal="onServiceZipChanged"
linkWidgetName="ServiceZipLinkWidget"
modalWidgetName="ServiceZipModalWidget" />
<alert
ref="alertMilitaryBaseZip"
class="my-5"
cmsWidgetName="AlertMilitaryBaseZipWidget"
v-if="displayMilitaryZipAlert"
alertClass="alert-warning" />
<alert
ref="alertMobileOnly"
class="my-5"
cmsWidgetName="AlertMobileOnlyWidget"
v-if="displayServiceableMobileOnly"
alertClass="alert-warning" />
<alert
ref="alertRecalNoMobile"
class="my-5"
cmsWidgetName="AlertRecalNoMobileWidget"
v-if="displayRecalibrationWarning"
@text-link-clicked="openModalAction"
alertClass="alert-warning" />
<alert
ref="alertInshopOnly"
class="my-5"
cmsWidgetName="AlertInshopOnlyWidget"
v-if="displayServiceableInshopOnly"
alertClass="alert-warning" />
<alert
ref="alertNoShops"
class="my-5"
cmsWidgetName="AlertNoShopsWidget"
v-if="displayNoShopsAlert"
alertClass="alert-warning" />
<alert <alert
ref="alertMobileFeeFree" ref="alertMobileFeeFree"
class="my-5" class="mb-5"
cmsWidgetName="AlertMobileFeeFreeWidget" cmsWidgetName="AlertMobileFeeFreeWidget"
v-if="showMobileFreeAlert" v-if="showMobileFreeAlert"
alertClass="alert-success" /> alertClass="alert-success" />
@ -62,6 +15,7 @@
</div> </div>
<div class="row appointment-type"> <div class="row appointment-type">
<div class="col-12 col-md-10 col-lg-8 col-xl-7"> <div class="col-12 col-md-10 col-lg-8 col-xl-7">
<funnelSubHeader cmsWidgetName="ScheduleYourServiceWidget" class="mb-5" />
<appointmentTypeQuestion <appointmentTypeQuestion
v-model="appointmentTypeFromAppointmentTypeQuestion" v-model="appointmentTypeFromAppointmentTypeQuestion"
v-show="isAppointmentTypeDisplayed" v-show="isAppointmentTypeDisplayed"
@ -77,21 +31,78 @@
labelBold="true" /> labelBold="true" />
</div> </div>
</div> </div>
<div class="row">
<div class="col-12 col-md-10 col-lg-8 col-xl-7">
<alert
ref="alertMobileOnly"
class="mt-5 mb-5"
cmsWidgetName="AlertMobileOnlyWidget"
v-if="displayServiceableMobileOnly"
alertClass="alert-warning" />
<alert
ref="alertRecalNoMobile"
class="mt-5 mb-5"
cmsWidgetName="AlertRecalNoMobileWidget"
v-if="displayRecalibrationWarning"
@text-link-clicked="openModalAction"
alertClass="alert-warning" />
<alert
ref="alertInshopOnly"
class="mt-5 mb-5"
cmsWidgetName="AlertInshopOnlyWidget"
v-if="displayServiceableInshopOnly"
alertClass="alert-warning" />
<alert
ref="alertMilitaryBaseZip"
class="mt-5 mb-5"
cmsWidgetName="AlertMilitaryBaseZipWidget"
v-if="displayMilitaryZipAlert"
alertClass="alert-warning" />
<alert
ref="alertNoShops"
class="mt-5 mb-5"
cmsWidgetName="AlertNoShopsWidget"
v-if="displayNoShopsAlert"
alertClass="alert-warning" />
</div>
</div>
<div
v-if="appointmentType && appointmentType === appointmentTypeStrings.MOBILE"
class="col-12 col-md-10 col-lg-8 col-xl-7">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-4" />
<serviceZipModalQuestion
editScreenReaderTextCmsWidgetName="ScreenReaderZipEditWidget"
v-model="serviceZipCodeQuestion"
ref="serviceZipCodeQuestion"
:carId="carId"
:isVehicleHeavyTruck="isVehicleHeavyTruck"
:mobileFeePart="mobileFeePart"
@updated-mobile-fee-part="setMobileFeePart"
@updated-recycle-fee-part="setRecycleFeePart"
@updated-serviceability="setServiceabilityDetails"
@updated-contains-military-base="setContainsMilitaryBase"
@updated-bill-to-account-number="setBillToAccountNumber"
@service-zip-changed-from-modal="onServiceZipChanged"
linkWidgetName="ServiceZipLinkWidget"
modalWidgetName="ServiceZipModalWidget" />
</div>
<div <div
class="row your-shop-location" class="row your-shop-location"
v-if="appointmentType && appointmentType !== appointmentTypeStrings.MOBILE"> v-if="appointmentType && appointmentType !== appointmentTypeStrings.MOBILE">
<div class="col-12 col-md-10 col-lg-8 col-xl-7"> <div class="col-12 col-md-10 col-lg-8 col-xl-7">
<button-question <div>
class="shop-question-button" <shopLocation
ref="buttonQuestion" v-if="
:answers="selectedShopAnswer" appointmentType && appointmentType !== appointmentTypeStrings.MOBILE
:modelValue="selectedProvider?.providerNumber" "
:isMultiSelect="false" :selectedShop="selectedShopAnswer"
:readonly="true" :selectedProviderNumberFromParent="selectedProvider?.providerNumber"
:questionText="questionText" :shopProviderDataFromParent="shopProviderData"
buttonTypeString="shopListButton" :zipCodeFromParent="zipCode"
:buttonTypeObject="shopListButton" :isShopQuestionDisplayed="isShopQuestionDisplayed"
groupName="chooseShop" /> @shop-selected="onShopSelected"
@updated-serviceability="setServiceabilityDetails" />
</div>
<div> <div>
<textBlock <textBlock
v-if="mobileFeeApplies && isMobileSelected" v-if="mobileFeeApplies && isMobileSelected"
@ -100,14 +111,6 @@
typeStyle="caption" typeStyle="caption"
class="ps-4 pe-4 mt-4" /> class="ps-4 pe-4 mt-4" />
</div> </div>
<shopQuestionPopup
v-if="isShopQuestionDisplayed"
:selectedProviderNumberFromParent="selectedProvider?.providerNumber"
:shopProviderDataFromParent="shopProviderData"
@shop-selected="onShopSelected"
@updated-serviceability="setServiceabilityDetails"
:zipCodeFromParent="zipCode"
cmsWidgetName="YourSafeliteShopWidget" />
<contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" /> <contentGroupModal ref="RecalModal" cmsWidgetName="RecalModal" />
</div> </div>
@ -158,9 +161,8 @@ import alert from "@/ux-components/alert/alert";
import serviceZipModalQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-modal-question"; import serviceZipModalQuestion from "@/layouts/service-location/service-zip-modal-question/service-zip-modal-question";
import appointmentTypeQuestion from "@/layouts/service-location/appointment-type-question/appointment-type-question"; import appointmentTypeQuestion from "@/layouts/service-location/appointment-type-question/appointment-type-question";
import shopQuestion from "@/layouts/service-location/shop-question/shop-question"; import shopQuestion from "@/layouts/service-location/shop-question/shop-question";
import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-question-popup";
import buttonQuestion from "@/digital-components/button-question/button-question.vue";
import shopListButton from "@/layouts/service-location/shop-question/shop-list-button/shop-list-button"; import shopListButton from "@/layouts/service-location/shop-question/shop-list-button/shop-list-button";
import shopLocation from "@/layouts/schedule/shop-location/shop-location";
import funnelHeader from "@/fmg-components/funnel-header/funnel-header"; import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
import navbar from "@/fmg-components/nav-bar/nav-bar"; import navbar from "@/fmg-components/nav-bar/nav-bar";
@ -697,7 +699,12 @@ export default {
); );
}, },
isAppointmentTypeDisplayed() { isAppointmentTypeDisplayed() {
return this.zipCode && !this.displayNoShopsAlert; return (
this.zipCode &&
!this.displayNoShopsAlert &&
this.isServiceableMobile &&
this.isServiceableInshop
);
}, },
requiresInshopRecalibration() { requiresInshopRecalibration() {
// Specifically check for isRecalibrationServiceableMobile === false, not null or true. // Specifically check for isRecalibrationServiceableMobile === false, not null or true.
@ -769,21 +776,15 @@ export default {
const zipCode = this.selectedProvider.address.zipCode; const zipCode = this.selectedProvider.address.zipCode;
const distanceInMiles = provider ? Math.round(provider.distanceInMiles * 2) / 2 : 0; const distanceInMiles = provider ? Math.round(provider.distanceInMiles * 2) / 2 : 0;
return [ return {
{ city: `${city}`,
buttonLabel: `${city}`, distance: `${distanceInMiles} mi`,
buttonLabelSubCopy: `${distanceInMiles} mi`, address1: `${streetAddress}`,
buttonBodyCopy: `${streetAddress}, ${city}, ${state} ${zipCode}`, address2: `${city}, ${state} ${zipCode}`,
additionalButtonData: this.additionalButtonData, };
value: this.selectedProvider.providerNumber,
},
];
} }
return []; return [];
}, },
questionText() {
return this.getCmsContent("YourSafeliteShopWidget", "QuestionText");
},
appointmentTypeStrings() { appointmentTypeStrings() {
return AppointmentTypeStrings; return AppointmentTypeStrings;
}, },
@ -1554,6 +1555,7 @@ export default {
} }
}, },
updateTimeSlot(timeSlotObj) { updateTimeSlot(timeSlotObj) {
if (this.preSelectedDate && !timeSlotObj?.timeSlot?.date) return;
this.selectedTimeSlotInfo = timeSlotObj; this.selectedTimeSlotInfo = timeSlotObj;
if ( if (
this.appointmentType !== AppointmentTypeStrings.MOBILE && this.appointmentType !== AppointmentTypeStrings.MOBILE &&
@ -1740,57 +1742,75 @@ export default {
serviceZipModalQuestion, serviceZipModalQuestion,
appointmentTypeQuestion, appointmentTypeQuestion,
contentGroupModal, contentGroupModal,
shopQuestionPopup, shopLocation,
buttonQuestion,
}, },
}; };
</script> </script>
<style lang="scss"> <style lang="scss" scoped>
.container { .container {
&.page-schedule { .question-text {
padding: 0 1rem; margin-bottom: 1.5rem;
.text-link-small {
a, & > span {
.btn-link { display: flex;
width: auto; justify-content: flex-start;
margin: 0 auto; margin-bottom: 0.25rem;
height: auto;
font-size: 0.875rem;
line-height: 1.75;
padding: 0;
border-radius: 0;
&:focus {
outline: 1px solid $blue;
}
@include media-breakpoint-up(md) {
font-size: 1rem;
}
}
} }
.funnel-sub-header {
h5.dark-header {
margin-bottom: 0.25rem;
}
}
.change-location a {
font-family: UrbanistSemibold;
}
.date-picker {
border-top: 1px solid $gray-500;
margin-top: 1.5rem;
}
.time-slots-question {
padding: 0 0.75rem;
}
}
.question-text > span {
display: flex;
justify-content: flex-start;
} }
} }
.alert.alert-warning {
.alert-heading {
color: $black;
font-family: UrbanistSemibold;
font-size: 1rem;
}
}
.shop-question-button .list-button-content { .shop-question-button .list-button-content {
background: $blue-100; background: $blue-100;
box-shadow: 0 0 0 1px $primary; box-shadow: 0 0 0 1px $primary;
} }
.container .row .col-12 .alert-success .alert-heading {
color: $black;
font-weight: 600;
}
.funnel-sub-header h5 {
font-weight: 500;
font-size: 1rem;
font-family: UrbanistSemibold;
span {
letter-spacing: 0;
}
}
.appointment-type .funnel-sub-header h5 {
font-family: UrbanistRegular;
font-size: 1.25rem;
}
.funnel-sub-header.my-5 h5 {
font-weight: 400;
font-size: 1.25rem;
}
:deep(.funnel-sub-header:not(.mb-5)) {
h5.dark-header {
font-weight: 600;
font-size: 1rem;
}
}
.col-12 a {
font-family: UrbanistSemibold;
font-weight: 500;
line-height: 26px;
text-underline-offset: 4px;
}
.text-block.duration-text-block b {
font-family: UrbanistSemibold;
}
</style> </style>

View file

@ -0,0 +1,121 @@
<template>
<div id="shop-location">
<textBlock :customText="questionText" typeStyle="button-question" class="mb-2" />
<div>
<div>
<label v-for="addressItem in addressDetails" :key="addressItem">
{{ addressItem }}
</label>
</div>
<div>
<label>{{ selectedShop.distance }}</label>
</div>
</div>
<shopQuestionPopup
v-if="isShopQuestionDisplayed"
:selectedProviderNumberFromParent="selectedProviderNumberFromParent"
:shopProviderDataFromParent="shopProviderDataFromParent"
:zipCodeFromParent="zipCodeFromParent"
@shop-selected="onShopSelected"
@updated-serviceability="setServiceabilityDetails"
cmsWidgetName="YourSafeliteShopWidget" />
</div>
</template>
<script>
import textBlock from "@/digital-components/text-block/text-block";
import shopQuestionPopup from "@/layouts/service-location/shop-question/shop-question-popup";
export default {
name: "shopLocation",
props: {
selectedShop: {
type: Object,
default: () => ({
city: null,
distance: null,
address1: null,
address2: null,
}),
},
isShopQuestionDisplayed: {
type: Boolean,
default: false,
},
selectedProviderNumberFromParent: {
type: String,
default: null,
},
shopProviderDataFromParent: {
type: Object,
default: () => ({}),
},
zipCodeFromParent: {
type: String,
default: null,
},
},
computed: {
questionText() {
return this.getCmsContent("YourSafeliteShopWidget", "QuestionText");
},
addressDetails() {
const { distance, ...addressDetails } = this.selectedShop;
return addressDetails;
},
},
components: {
textBlock,
shopQuestionPopup,
},
methods: {
onShopSelected(shopQuestionPopUpData) {
this.$emit("shop-selected", shopQuestionPopUpData);
},
setServiceabilityDetails(serviceabilityDetails) {
this.$emit("updated-serviceability", serviceabilityDetails);
},
},
};
</script>
<style lang="scss" scoped>
#shop-location {
& > div {
display: flex;
justify-content: space-between;
& > div {
display: flex;
flex-direction: column;
label {
font-size: 0.875rem;
}
}
}
& > div.shop-question {
width: 172px;
}
}
</style>
<style lang="scss">
#shop-location {
& > div.shop-question {
width: fit-content;
background-color: $blue;
border-radius: $border-radius-pill;
a {
display: inline-block;
text-decoration: none;
color: $white;
font-weight: $font-weight-600;
line-height: 1.5rem;
padding: 0.75rem 3rem;
}
}
}
</style>

View file

@ -90,11 +90,11 @@ export default {
position: relative; position: relative;
background: $white; background: $white;
transition: all 150ms linear; transition: all 150ms linear;
border-radius: $border-radius-lg; border-radius: $border-radius-pill;
border: 1px solid $gray-500; border: 1px solid $gray-500;
width: 100%; width: 100%;
outline: none; outline: none;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
span.premium-appointment-price { span.premium-appointment-price {
position: absolute; position: absolute;

View file

@ -601,7 +601,7 @@ export default {
} }
} }
.waitlist { .waitlist {
box-shadow: 0px 1px 4px 0px #00000033; box-shadow: 0 1px 5px 0 #00000033;
border-radius: 8px; border-radius: 8px;
font-size: $h6-font-size; font-size: $h6-font-size;
padding: 16px; padding: 16px;
@ -611,7 +611,7 @@ export default {
padding-left: 0px; padding-left: 0px;
input { input {
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 1px 4px 0px #00000033; box-shadow: 0 1px 5px 0 #00000033;
} }
} }
.form-check-input { .form-check-input {

View file

@ -4,10 +4,12 @@
v-if="isDropOffAppointmentAvailable" v-if="isDropOffAppointmentAvailable"
v-model="selectedAnswerForDropOffOrInshop" v-model="selectedAnswerForDropOffOrInshop"
:questionText="dropOffOrPickATimeQuestionLabelText" :questionText="dropOffOrPickATimeQuestionLabelText"
:questionTextDescription="dropOffOrPickATimeQuestionDescription"
:answers="answersForDropOffQuestion" :answers="answersForDropOffQuestion"
isRequired isRequired
insertOrLabelBeforeFinalOption insertOrLabelBeforeFinalOption
groupName="chooseDropOffOrInshop" groupName="chooseDropOffOrInshop"
class="choose-dropoff-or-inshop"
validationRules="time-slot-required"> validationRules="time-slot-required">
<div> <div>
<alert <alert
@ -30,6 +32,7 @@
isInshopOrDropOffAppointment ? 'is-inshop-or-drop-off-appointment' : '', isInshopOrDropOffAppointment ? 'is-inshop-or-drop-off-appointment' : '',
]" ]"
:answers="availableTimeSlots" :answers="availableTimeSlots"
:lazyLoad="{ isLazyLoad: !isMobileAppointment, amountToLoad: 10 }"
groupName="chooseTimeSlot" groupName="chooseTimeSlot"
textPosition="text-center" textPosition="text-center"
v-model="selectedAnswerForTimeSlots" v-model="selectedAnswerForTimeSlots"
@ -47,6 +50,7 @@
cmsWidgetName="WaitListLabelWidget" cmsWidgetName="WaitListLabelWidget"
typeStyle="medium" typeStyle="medium"
fontWeight="600" fontWeight="600"
class="waitlist-label"
marginTopSizeOverride="0" /> marginTopSizeOverride="0" />
<checkboxQuestion <checkboxQuestion
class="mt-3" class="mt-3"
@ -190,7 +194,8 @@ export default {
this.selectedDate == null || this.selectedDate == null ||
this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF || this.appointmentType === AppointmentTypeStrings.IN_SHOP_OR_DROP_OFF ||
this.appointmentType === AppointmentTypeStrings.IN_SHOP || this.appointmentType === AppointmentTypeStrings.IN_SHOP ||
this.appointmentType === AppointmentTypeStrings.DROP_OFF this.appointmentType === AppointmentTypeStrings.DROP_OFF ||
!this.availableTimeSlots
) { ) {
if (!this.selectedAnswerForTimeSlots && !this.selectedAnswerForDropOffOrInshop) { if (!this.selectedAnswerForTimeSlots && !this.selectedAnswerForDropOffOrInshop) {
this.autoSelectTimeSlotIfOnlyOneIsAvailable(); this.autoSelectTimeSlotIfOnlyOneIsAvailable();
@ -228,6 +233,10 @@ export default {
dropOffOrPickATimeQuestionLabelText() { dropOffOrPickATimeQuestionLabelText() {
return this.getCmsContent(this.dropOffOrPickATimeQuestionCmsWidgetName, "QuestionText"); return this.getCmsContent(this.dropOffOrPickATimeQuestionCmsWidgetName, "QuestionText");
}, },
dropOffOrPickATimeQuestionDescription() {
// This is hardcoded because Input Question Widget doesn't currently have a place to add additional text
return "You can drop off your vehicle in the morning and pick it up later in the day with Drop & Go<sup>&#8482</sup> or pick an appointment time.";
},
pickATimeButtonLabelText() { pickATimeButtonLabelText() {
return this.getCmsContent(this.dropOffOrPickATimeQuestionCmsWidgetName, "Answers")[0] return this.getCmsContent(this.dropOffOrPickATimeQuestionCmsWidgetName, "Answers")[0]
.Text; .Text;
@ -644,18 +653,31 @@ export default {
margin-bottom: 8px; margin-bottom: 8px;
} }
} }
.button-question.choose-dropoff-or-inshop
.button-inner-wrapper
.col:first-child
.button-content.list-button-content
> span::after {
content: "TM";
vertical-align: super;
font-size: 50%;
}
.waitlist { .waitlist {
box-shadow: 0px 1px 4px 0px #00000033; box-shadow: 0 1px 5px 0 #00000033;
border-radius: 8px; border-radius: 8px;
font-size: 1rem; font-size: 1rem;
padding: 16px; padding: 16px;
text-align: left; text-align: left;
.waitlist-label {
font-family: UrbanistSemibold;
}
.ui-checkbox { .ui-checkbox {
padding-left: 0px; padding-left: 0px;
input { input {
border-radius: 4px; border-radius: 4px;
box-shadow: 0px 1px 4px 0px #00000033; box-shadow: 0 1px 5px 0 #00000033;
} }
} }
.form-check-input { .form-check-input {

View file

@ -7,7 +7,6 @@
:questionText="questionText" :questionText="questionText"
:answers="answersToDisplay" :answers="answersToDisplay"
:groupName="groupName" :groupName="groupName"
buttonTypeString="listCard"
v-model="selectedValue" v-model="selectedValue"
:suppressError="suppressError" :suppressError="suppressError"
:validationRules="validationRules" :validationRules="validationRules"
@ -134,4 +133,11 @@ export default {
width: auto; width: auto;
} }
} }
div.appointment-type-question div.button-question div.col div.button-content {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
div.appointment-type-question div.button-question div.question-text span {
font-weight: 500;
}
</style> </style>

View file

@ -214,14 +214,19 @@ export default {
); );
// update content related to service zip code // update content related to service zip code
this.$emit("updated-mobile-fee-part", mobileFeePart); if (this.internalModel.zipCode !== this.modelValue.zipCode) {
this.$emit("updated-recycle-fee-part", recycleFeePart); this.$emit("updated-mobile-fee-part", mobileFeePart);
this.$emit("updated-serviceability", serviceabilityDetails.data); this.$emit("updated-recycle-fee-part", recycleFeePart);
this.$emit("updated-contains-military-base", zipCodeData.containsMilitaryBase); this.$emit("updated-serviceability", serviceabilityDetails.data);
this.$emit("updated-bill-to-account-number", billToAccountNumber); this.$emit(
this.$emit("service-zip-changed-from-modal"); "updated-contains-military-base",
// update the page level model zipCodeData.containsMilitaryBase
this.$emit("update:modelValue", this.internalModel); );
this.$emit("updated-bill-to-account-number", billToAccountNumber);
this.$emit("service-zip-changed-from-modal");
// update the page level model
this.$emit("update:modelValue", this.internalModel);
}
this.closeModal(); this.closeModal();
} }

View file

@ -177,7 +177,7 @@ export default {
border: 1px solid $gray-500; border: 1px solid $gray-500;
width: 100%; width: 100%;
outline: none; outline: none;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
span { span {
&.small { &.small {

View file

@ -1,10 +1,10 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
<div class="container"> <div class="container vehicle-damage">
<div class="row"> <div class="row">
<div class="col-12 col-md-10 col-lg-8 col-xl-7"> <div class="col-12 col-md-10 col-lg-8 col-xl-7">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mb-7" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mb-4" />
<alert <alert
ref="vehicleChangeAlert" ref="vehicleChangeAlert"
v-if="shouldDisplayVehicleChangeAlert" v-if="shouldDisplayVehicleChangeAlert"
@ -755,11 +755,31 @@ export default {
</script> </script>
<style lang="scss"> <style lang="scss">
.replace-options-question { .vehicle-damage {
.base-input-button:not(.has-error):hover.list-card:not(.selected) {
border-radius: 0.5rem;
}
.question-text { .question-text {
margin: 1rem 0 0 0; margin: 1.5rem 0 0.5rem 0;
}
}
.replace-options-question {
.base-input-button:not(.has-error):hover.list-card:not(.selected) {
border-radius: 50rem;
}
.button-question {
label {
&.list-card,
&.list-card input[type="checkbox"]:checked + .list-card-content,
&.list-card input[type="radio"]:checked + .list-card-content {
border-radius: 50rem;
}
}
}
.question-text {
margin: 1.5rem 0 0.5rem 0;
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
margin: 1rem 0; margin: 1.5rem 0 0.5rem 0;
} }
} }
.two-list-card-width { .two-list-card-width {

View file

@ -27,17 +27,17 @@
:colorAnswers="item.colorAnswers" :colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" /> :alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div> </div>
<hr class="mt-7 mb-0" />
<saveProgressModalQuestion
modalWidgetName="SaveProgressModalWidget"
pageName="vehicle-parts"
v-if="showSaveProgressModal" />
<navbar <navbar
cmsWidgetName="FunnelFooterWidget" cmsWidgetName="FunnelFooterWidget"
ref="navbar" ref="navbar"
:isForwardActionDisabled="isForwardActionDisabled" :isForwardActionDisabled="isForwardActionDisabled"
@back-clicked="navigateBack" @back-clicked="navigateBack"
@ForwardClicked="forwardButtonAction" /> @ForwardClicked="forwardButtonAction" />
<saveProgressModalQuestion
modalWidgetName="SaveProgressModalWidget"
pageName="vehicle-parts"
v-if="showSaveProgressModal" />
</div> </div>
</div> </div>
</div> </div>
@ -242,10 +242,17 @@ export default {
label { label {
&.list-card { &.list-card {
height: auto; height: auto;
border-radius: 50rem;
input[type="radio"]:checked + .list-card-content {
border-radius: 50rem;
}
} }
} }
.two-list-card-width { .two-list-card-width {
width: 100%; width: 100%;
} }
.save-progress-modal-question {
margin: 1rem 0;
}
} }
</style> </style>

View file

@ -1,7 +1,7 @@
<template> <template>
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }"> <Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
<funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" /> <funnelHeader cmsWidgetName="FunnelHeaderWidget" ref="funnelHeader" />
<div class="container"> <div class="container vehicle">
<div class="row"> <div class="row">
<div class="col-12 col-md-10 col-lg-8 col-xl-7"> <div class="col-12 col-md-10 col-lg-8 col-xl-7">
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="siteSubHeader" /> <funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="siteSubHeader" />
@ -631,8 +631,7 @@ export default {
margin-bottom: 0; margin-bottom: 0;
} }
.siteSubHeader { .siteSubHeader {
margin-top: 1.5rem; margin: 0;
margin-bottom: 0;
} }
.separator-line { .separator-line {
grid-area: 2/1/2/8; grid-area: 2/1/2/8;

View file

@ -80,6 +80,10 @@ export default {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
a {
text-decoration: none;
font-family: UrbanistSemibold, Arial, Helvetica, sans-serif;
}
} }
.vin-info { .vin-info {
max-height: 0; max-height: 0;

View file

@ -133,15 +133,6 @@ export default {
const currentPageName = getPageNameFromRouter(); const currentPageName = getPageNameFromRouter();
const universes = store.getters.applicationUser.experiments; const universes = store.getters.applicationUser.experiments;
let hasDynamoLogging = experimentMixin.methods.hasSettingEqualTo(
experimentSettings.DYNAMO_LOGGING,
"true",
universes
);
if (!hasDynamoLogging) {
return;
}
const variationNames = universes const variationNames = universes
.filter((item) => item.universeName === experimentUniverses.CONCEPT_FUNNEL) .filter((item) => item.universeName === experimentUniverses.CONCEPT_FUNNEL)
.map((item) => item.variationName) .map((item) => item.variationName)

View file

@ -28,7 +28,7 @@
position: relative; position: relative;
z-index: 5; z-index: 5;
@include box-shadow-hover($blue-300); @include box-shadow-hover($blue-300);
border-radius: 0.5rem; border-radius: $border-radius-pill;
} }
} }
} }

View file

@ -43,7 +43,7 @@ export default {
<style lang="scss"> <style lang="scss">
.list-button-horizontal { .list-button-horizontal {
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
input[type="radio"], input[type="radio"],
input[type="checkbox"] { input[type="checkbox"] {
position: absolute; position: absolute;

View file

@ -106,7 +106,7 @@ export default {
width: 100%; width: 100%;
outline: none; outline: none;
border-radius: 50rem; border-radius: 50rem;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
span { span {
&.small { &.small {

View file

@ -76,7 +76,7 @@ export default {
} }
.list-card { .list-card {
border: 1px solid $gray-500; border: 1px solid $gray-500;
box-shadow: 0px 1px 4px 0px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
&.has-error { &.has-error {
input[type="checkbox"], input[type="checkbox"],