Merge branch 'develop' into feature/INSR-2206

This commit is contained in:
Katie Kroell 2025-12-11 09:26:17 -05:00
commit 37410041bf
84 changed files with 1583 additions and 2007 deletions

View file

@ -23,7 +23,7 @@ module.exports = {
'implicit-arrow-linebreak': ['off'],
'comma-dangle': ['error', 'never'],
indent: ['error', 4, { SwitchCase: 1 }],
'max-len': ['error', { code: 140 }],
'max-len': ['error', { code: 160 }],
'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
'vue/html-indent': 'off',
'vue/html-closing-bracket-newline': ['error', {

260
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -33,7 +33,7 @@
"devDependencies": {
"@faker-js/faker": "^9.0.3",
"@pinia/testing": "0.1.2",
"@playwright/test": "^1.48.0",
"@playwright/test": "^1.56.1",
"@rushstack/eslint-patch": "^1.3.2",
"@saucelabs/playwright-reporter": "^1.5.0",
"@testing-library/jest-dom": "5.16.5",
@ -74,7 +74,7 @@
"sass-loader": "^12.0.0",
"saucectl": "^0.188.0",
"typescript-eslint": "^8.11.0",
"vite": "^6.3.6",
"vite": "^6.4.1",
"vitest": "^3.2.4",
"volar-service-vetur": "latest",
"wait-on": "^8.0.2"

View file

@ -19,7 +19,7 @@
"location/api/v1/location/providers/75023/Replace/100/550036/true/CR00056707/DW01571GTNNOEM": "0002a_Advanced_Replace_Deductible_Client/location/api/v1/location/providers/75023/Replace/100/550036/true/CR00056707/DW01571GTNNOEM.json",
"schedule/api/v1/schedule/shop-time-slots": "0002a_Advanced_Replace_Deductible_Client/schedule/api/v1/schedule/shop-time-slots.json",
"location/api/v1/location/alert-reasons/01813": "0002a_Advanced_Replace_Deductible_Client/location/api/v1/location/alert-reasons/01813.json",
"parts/api/v1/parts/rain-defense": "0002a_Advanced_Replace_Deductible_Client/parts/api/v1/parts/rain-defense.json",
"parts/api/v1/parts/rain-repel": "0002a_Advanced_Replace_Deductible_Client/parts/api/v1/parts/rain-repel.json",
"price/api/v1/price/combined-quote": "0002a_Advanced_Replace_Deductible_Client/price/api/v1/price/combined-quote.json"
}
}

View file

@ -7,6 +7,7 @@
<!-- The above durations should be kept in sync with the global css class "fade-on-route-transition" -->
<component :is="Component" />
</transition>
<footerMenu />
</router-view>
<loadingModal
:showLoader="shouldShowLoader"
@ -17,10 +18,12 @@
<script>
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
import showIssLoadingModal from '@/helpers/loading-modal-helper.js';
import footerMenu from '@/iss-components/footer-menu/footer-menu.vue';
export default {
name: 'app',
components: {
footerMenu,
loadingModal
},
setup() {
@ -45,15 +48,15 @@ window.onerror = (msg, url, line, col, error) => {
// Note that col & error are new to the HTML 5 spec and may not be
// supported in every browser. It worked for me in Chrome.
global.$logger.logError(msg, {
url: url,
line: line,
column: col ?? "",
error: error ?? "",
url,
line,
column: col ?? '',
error: error ?? ''
});
// If you return true, then error alerts (like in older versions of
// Internet Explorer) will be suppressed.
var suppressErrorAlert = true;
const suppressErrorAlert = true;
return suppressErrorAlert;
};
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -0,0 +1,26 @@
<svg width="165" height="15" viewBox="0 0 165 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4668_1909)">
<path d="M9.45033 4.77209C9.29949 4.77209 9.17707 4.64967 9.17707 4.49883V4.20808C9.17707 3.42765 8.68083 2.77839 7.62933 2.77839C6.46196 2.77839 5.93512 3.60473 5.93512 4.19934C5.93512 6.81826 14.815 5.53722 14.815 10.3837C14.815 13.206 12.2135 14.4695 7.42383 14.4695C2.92489 14.4695 0.413086 13.4858 0.413086 10.7379V10.5477C0.413086 10.3969 0.535507 10.2744 0.686346 10.2744H5.39515C5.54599 10.2744 5.66841 10.3969 5.66841 10.5477V10.8406C5.66841 11.973 6.39856 12.3818 7.45007 12.3818C8.56059 12.3818 9.2033 11.5752 9.2033 10.8494C9.2033 8.23046 0.67323 9.53118 0.675416 4.8333C0.675416 2.15973 2.92489 0.692871 7.51128 0.692871C12.0758 0.692871 14.1132 1.85149 14.251 4.48353C14.2597 4.64311 14.1351 4.77646 13.9777 4.77646L9.45033 4.77209Z" fill="#DB0020"/>
<path d="M29.8398 3.41653C29.8398 1.54088 30.9875 0.845703 34.4044 0.845703C35.0383 0.845703 35.8013 0.874122 36.503 0.928774C36.6451 0.939705 36.7544 1.05994 36.7544 1.20203V2.35628C36.7544 2.51805 36.6167 2.64266 36.4549 2.62954C36.3063 2.61643 36.1445 2.61205 35.9324 2.61205C35.3313 2.61205 34.7585 2.80224 34.7585 3.27225V4.60138C34.7585 4.75222 34.8809 4.87464 35.0318 4.87464H36.479C36.6298 4.87464 36.7522 4.99706 36.7522 5.1479V6.7022C36.7522 6.85304 36.6298 6.97546 36.479 6.97546H35.0318C34.8809 6.97546 34.7585 7.09788 34.7585 7.24872V13.9971C34.7585 14.148 34.6361 14.2704 34.4853 14.2704H30.1153C29.9644 14.2704 29.842 14.148 29.842 13.9971L29.8398 3.41653Z" fill="#DB0020"/>
<path d="M42.1607 10.1038C42.0098 10.1038 41.8874 10.2262 41.8874 10.3771V11.586C41.8874 12.5938 42.5432 12.8539 43.2275 12.8539C44.0407 12.8539 44.5479 12.3358 44.6135 11.2275C44.6222 11.0832 44.7424 10.9717 44.8867 10.9717H48.7561C48.92 10.9717 49.0446 11.1138 49.0293 11.2756C48.8348 13.3589 47.1406 14.5153 43.2537 14.5153C38.499 14.5153 36.9688 13.16 36.9688 9.58135C36.9688 5.98525 38.8269 4.62988 43.2537 4.62988C47.1887 4.62988 49.1824 5.74041 49.1824 9.14632V9.82837C49.1824 9.97921 49.0599 10.1016 48.9091 10.1016L42.1607 10.1038ZM44.5916 7.73193C44.5916 6.74163 44.2637 6.2913 43.2253 6.2913C42.2131 6.2913 41.8852 6.74163 41.8852 7.73193V8.12542C41.8852 8.27626 42.0077 8.39868 42.1585 8.39868H44.3162C44.467 8.39868 44.5894 8.27626 44.5894 8.12542L44.5916 7.73193Z" fill="#DB0020"/>
<path d="M51.2066 0.413086H55.5766C55.7274 0.413086 55.8498 0.535507 55.8498 0.686346L55.8476 13.9974C55.8476 14.1482 55.7252 14.2706 55.5744 14.2706H51.2044C51.0536 14.2706 50.9312 14.1482 50.9312 13.9974L50.9333 0.686346C50.9312 0.535507 51.0558 0.413086 51.2066 0.413086Z" fill="#DB0020"/>
<path d="M58.2503 4.85082H62.6203C62.7711 4.85082 62.8935 4.97324 62.8935 5.12408V13.9952C62.8935 14.146 62.7711 14.2684 62.6203 14.2684H58.2503C58.0995 14.2684 57.9771 14.146 57.9771 13.9952V5.12408C57.9771 4.97324 58.0995 4.85082 58.2503 4.85082ZM58.2503 0.413086H62.6203C62.7711 0.413086 62.8935 0.535507 62.8935 0.686346V3.0014C62.8935 3.15224 62.7711 3.27466 62.6203 3.27466H58.2503C58.0995 3.27466 57.9771 3.15224 57.9771 3.0014V0.686346C57.9771 0.535507 58.0995 0.413086 58.2503 0.413086Z" fill="#DB0020"/>
<path d="M77.6363 10.1038C77.4854 10.1038 77.363 10.2262 77.363 10.3771V11.586C77.363 12.5938 78.0188 12.8539 78.7031 12.8539C79.5163 12.8539 80.0235 12.3358 80.089 11.2275C80.0978 11.0832 80.218 10.9717 80.3623 10.9717H84.2317C84.3934 10.9717 84.5202 11.1138 84.5049 11.2756C84.3104 13.3589 82.6162 14.5153 78.7293 14.5153C73.9746 14.5153 72.4443 13.16 72.4443 9.58135C72.4443 5.98525 74.3025 4.62988 78.7293 4.62988C82.6642 4.62988 84.6579 5.74041 84.6579 9.14632V9.82837C84.6579 9.97921 84.5355 10.1016 84.3847 10.1016L77.6363 10.1038ZM80.0672 7.73193C80.0672 6.74163 79.7393 6.2913 78.7009 6.2913C77.6909 6.2913 77.363 6.74163 77.363 7.73193V8.12542C77.363 8.27626 77.4854 8.39868 77.6363 8.39868H79.7939C79.9448 8.39868 80.0672 8.27626 80.0672 8.12542V7.73193Z" fill="#DB0020"/>
<path d="M28.0737 7.63574C28.0627 5.20045 25.6624 4.62988 22.2259 4.62988C20.0726 4.62988 16.8329 5.06273 16.5837 7.48927C16.5662 7.65104 16.6951 7.79095 16.8569 7.79095H20.5754C20.7153 7.79095 20.8312 7.68383 20.8465 7.54392C20.9361 6.7154 21.3755 6.28912 22.2237 6.28912C23.0697 6.28912 23.4698 6.58424 23.4698 7.15699V7.99863C23.4698 8.13635 23.3692 8.25221 23.2337 8.2697C23.0107 8.30031 22.6784 8.33966 22.0335 8.43366L20.0945 8.72878C16.9509 9.19878 15.9956 10.0142 15.9956 11.7499C15.9956 13.3654 17.1433 14.5131 20.0945 14.5131C21.5001 14.5131 22.7571 14.0869 23.3452 13.3261C23.3802 13.2802 23.4523 13.2911 23.4676 13.3458C23.5245 13.5403 23.6316 13.8945 23.7037 14.089C23.7452 14.1962 23.848 14.2683 23.9617 14.2683H27.7982C27.9491 14.2683 28.0715 14.1459 28.0715 13.995L28.0737 7.63574ZM21.9527 12.6637C21.216 12.6637 20.7503 12.0145 20.7503 11.3892C20.7503 10.764 21.0433 10.3661 21.7625 10.1738C22.2303 10.0492 22.8184 9.95517 23.1725 9.90707C23.3365 9.88303 23.4851 10.012 23.4851 10.1781V11.1203C23.4829 12.1434 23.0435 12.6637 21.9527 12.6637Z" fill="#DB0020"/>
<path d="M70.1795 6.97546H71.572C71.7229 6.97546 71.8453 6.85304 71.8453 6.7022V5.1479C71.8453 4.99706 71.7229 4.87464 71.572 4.87464H70.1773C70.0265 4.87464 69.904 4.75222 69.904 4.60138L69.8844 0.694857V0.620531C69.8844 0.506855 69.7926 0.415039 69.6789 0.415039C69.6483 0.415039 69.622 0.421597 69.5958 0.432528C69.5914 0.434714 69.5849 0.4369 69.5849 0.4369L65.2608 3.00335C65.0662 3.10829 64.9875 3.13233 64.9875 3.27661V11.9772C64.9875 14.0605 66.1615 14.3753 69.1673 14.3753C69.9106 14.3753 70.7654 14.3469 71.5917 14.2901C71.736 14.2791 71.8453 14.1589 71.8453 14.0168V12.7117C71.8453 12.5609 71.7229 12.4385 71.572 12.4385H71.0802C70.2888 12.4385 69.9062 12.2483 69.9062 11.7083V7.24872C69.904 7.09788 70.0265 6.97546 70.1795 6.97546Z" fill="#DB0020"/>
<path d="M90.1211 12.8885L91.4218 11.3101C92.1388 12.0927 93.0002 12.425 93.6494 12.425C94.3927 12.425 94.7097 12.0534 94.7097 11.6293C94.7097 11.1112 94.3774 10.886 93.3171 10.5275C91.8853 10.0356 90.4512 9.36014 90.4512 7.50198C90.4512 5.93675 91.7913 4.75627 93.5423 4.73003C94.7753 4.7038 95.9033 5.18037 96.8061 5.94986L95.5601 7.56756C94.7512 6.93141 94.1675 6.67783 93.6363 6.67783C93.092 6.67783 92.7597 6.95546 92.7597 7.40798C92.7466 7.85831 93.092 8.09878 94.1129 8.49664C95.7721 9.13279 97.0444 9.55689 97.0444 11.3757C97.0444 13.5902 95.1469 14.3859 93.5817 14.3859C92.3749 14.3881 91.1289 13.9225 90.1211 12.8885Z" fill="black"/>
<path d="M97.9341 9.55945C97.9341 6.71973 99.9234 4.71729 102.789 4.71729C105.601 4.71729 107.632 6.66727 107.632 9.55945C107.632 12.4385 105.603 14.3885 102.789 14.3885C99.9234 14.3885 97.9341 12.3992 97.9341 9.55945ZM105.31 9.55945C105.31 7.99421 104.25 6.7875 102.789 6.7875C101.303 6.7875 100.256 8.02045 100.256 9.55945C100.256 11.0984 101.303 12.3314 102.789 12.3314C104.247 12.3314 105.31 11.1247 105.31 9.55945Z" fill="black"/>
<path d="M108.996 4.8501H111.265V12.2915H115.178V14.2677H108.996V4.8501Z" fill="black"/>
<path d="M115.788 10.3415V4.8501H118.015V10.2104C118.015 11.3646 118.573 12.3199 119.674 12.3199C120.656 12.3199 121.373 11.5504 121.373 10.2104V4.8501H123.588V10.3415C123.588 12.7965 122.182 14.388 119.674 14.388C117.353 14.388 115.788 12.9539 115.788 10.3415Z" fill="black"/>
<path d="M127.354 6.82631H124.899V4.8501H132.076V6.82631H129.608V14.2677H127.352V6.82631H127.354Z" fill="black"/>
<path d="M133.537 4.8501H135.806V14.2677H133.537V4.8501Z" fill="black"/>
<path d="M137.225 9.55945C137.225 6.71973 139.214 4.71729 142.08 4.71729C144.891 4.71729 146.922 6.66727 146.922 9.55945C146.922 12.4385 144.893 14.3885 142.08 14.3885C139.214 14.3885 137.225 12.3992 137.225 9.55945ZM144.6 9.55945C144.6 7.99421 143.54 6.7875 142.08 6.7875C140.593 6.7875 139.546 8.02045 139.546 9.55945C139.546 11.0984 140.593 12.3314 142.08 12.3314C143.538 12.3314 144.6 11.1247 144.6 9.55945Z" fill="black"/>
<path d="M148.288 4.8501H150.424L154.178 10.6607L154.204 10.6476V4.8501H156.392V14.2677H154.191L150.503 8.61671H150.477V14.2677H148.288V4.8501Z" fill="black"/>
<path d="M157.494 12.8885L158.795 11.3101C159.512 12.0927 160.373 12.425 161.022 12.425C161.765 12.425 162.082 12.0534 162.082 11.6293C162.082 11.1112 161.75 10.886 160.69 10.5275C159.258 10.0356 157.824 9.36014 157.824 7.50198C157.824 5.93675 159.164 4.75627 160.915 4.73003C162.148 4.7038 163.276 5.18037 164.179 5.94986L162.933 7.56756C162.124 6.93141 161.54 6.67783 161.009 6.67783C160.465 6.67783 160.135 6.95546 160.135 7.40798C160.122 7.85831 160.467 8.09878 161.488 8.49664C163.147 9.13279 164.419 9.55689 164.419 11.3757C164.419 13.5902 162.522 14.3859 160.957 14.3859C159.748 14.3881 158.502 13.9225 157.494 12.8885Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_4668_1909">
<rect width="165" height="14.9096" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.6 KiB

View file

@ -97,7 +97,7 @@ const endpoints = Object.freeze({
method: 'GET'
},
GetRainDefense: {
url: `${PARTS_BASE_URL}/rain-defense`,
url: `${PARTS_BASE_URL}/rain-repel`,
method: 'GET'
},
GetRecalParts: {

View file

@ -0,0 +1,82 @@
export const pageProgressMapper = {
'duplicate-check': {
percent: 10
},
'policy-holder-details': {
percent: 15
},
'policy-vehicles': {
percent: 15
},
'policy-endorsements': {
percent: 15
},
'vehicle-selection': {
percent: 20
},
'vehicle-damage': {
percent: 30
},
'part-questions': {
percent: 35
},
'molding-questions': {
percent: 40
},
'vehicle-parts': {
percent: 40
},
'capability-questions': {
percent: 40
},
'vehicle-lookup': {
percent: 45
},
'vin-lookup': {
percent: 50
},
'license-plate-lookup': {
percent: 50
},
'address-lookup': {
percent: 50
},
'address-vehicles': {
percent: 50
},
'coverage-statement': {
percent: 55
},
'provider-preference': {
percent: 60
},
'service-location': {
percent: 65
},
'schedule-page': {
percent: 70
},
'contact-details': {
percent: 80
},
'service-packages': {
percent: 85
},
'payment-method': {
percent: 90
},
'payment-page': {
percent: 95
},
'tpa-search': {
percent: 85
},
'tpa-confirmation': {
percent: 100
},
'order-confirmation': {
percent: 100
}
};
export const getProgressBarPercentage = (page) => pageProgressMapper[page]?.percent || 0;

View file

@ -2,8 +2,12 @@
<div
class="date-picker text-center"
:class="[calendarViewDirection, { 'has-error': errors.length > 0 }]">
<fieldset id="date-picker-fieldset" ref="datePickerFieldset">
<legend class="sr-only">Select a day and time</legend>
<fieldset
id="date-picker-fieldset"
ref="datePickerFieldset">
<legend class="sr-only">
Select a day and time
</legend>
<div
v-for="month in months"
:id="`${month.monthLabel}-${month.yearNum?.toString()}`"
@ -80,12 +84,12 @@
</label>
</div>
</div>
<loader
:class="[!isLoading ? 'date-picker-hidden' : '']"
loaderColor="blue"
loaderPosition="center" />
<div id="date-of-month-error" class="row form-test-error">
<ErrorMessage :name="customComponentId" class="small mt-1">
<div
id="date-of-month-error"
class="row form-test-error">
<ErrorMessage
:name="customComponentId"
class="small mt-1">
</ErrorMessage>
</div>
<button
@ -106,7 +110,6 @@
<script>
// Supporting files
import loader from '@/ux-components/loader/loader.vue';
import { useMainStore } from '@/store';
import { useField, ErrorMessage } from 'vee-validate';
import { deepClone } from '@/helpers/object-helper';
@ -124,7 +127,6 @@ import { selectableDaysOptions, requiredParameter } from './mixins/helpers';
export default {
name: 'date-picker',
components: {
loader,
ErrorMessage
},
props: {
@ -206,8 +208,8 @@ export default {
computed: {
todayString() {
return (
this.todayOverrideDateString ||
convertDateToDateString(new Date())
this.todayOverrideDateString
|| convertDateToDateString(new Date())
);
},
todayDayIndex() {
@ -307,9 +309,7 @@ export default {
let weekEndDate = this.getWeekEndDate(todayString);
if (preSelectedDateString) {
const preSelectedDateMonthEnd = this.getMonthEnd(
preSelectedDateString
);
const preSelectedDateMonthEnd = this.getMonthEnd(preSelectedDateString);
let weekIncludesPreSelectedMonthEnd = false;
let i = 0;
while (!weekIncludesPreSelectedMonthEnd) {
@ -318,10 +318,10 @@ export default {
weekEndDate = this.getWeekEndDate(weekStartDate);
if (
(preSelectedDateMonthEnd > weekStartDate &&
preSelectedDateMonthEnd < weekEndDate) ||
preSelectedDateMonthEnd === weekStartDate ||
preSelectedDateMonthEnd === weekEndDate
(preSelectedDateMonthEnd > weekStartDate
&& preSelectedDateMonthEnd < weekEndDate)
|| preSelectedDateMonthEnd === weekStartDate
|| preSelectedDateMonthEnd === weekEndDate
) {
weekEndDate = preSelectedDateMonthEnd;
weekIncludesPreSelectedMonthEnd = true;
@ -349,8 +349,8 @@ export default {
// If any of these weeks is split between two months, then make them 2 separate "weeks"
// (a week split between two months is considered 2 weeks per business requirements)
const hasSplitWeek = (week) =>
week.weekStartDate.split('-')[1] !==
week.weekEndDate.split('-')[1];
week.weekStartDate.split('-')[1]
!== week.weekEndDate.split('-')[1];
const splitWeekIndex = weeks.findIndex(hasSplitWeek);
if (splitWeekIndex > -1) {
@ -359,9 +359,7 @@ export default {
let switchToWeek2 = false;
for (let j = 0; j < 7; j++) {
const newDate = convertDateStringToDate(
weeks[splitWeekIndex].weekStartDate
);
const newDate = convertDateStringToDate(weeks[splitWeekIndex].weekStartDate);
newDate.setDate(newDate.getDate() + j);
if (newDate.getDate() === 1) switchToWeek2 = true;
if (switchToWeek2) {
@ -412,10 +410,8 @@ export default {
} else {
todayDateString = convertDateToDateString(new Date());
}
if (config.selectableDatesSetting === 'past')
calendarViewDirection = 'past';
if (config.selectableDatesSetting === 'custom')
calendarViewDirection = 'future';
if (config.selectableDatesSetting === 'past') calendarViewDirection = 'past';
if (config.selectableDatesSetting === 'custom') calendarViewDirection = 'future';
const currentMonthEnd = this.getMonthEnd(todayDateString);
// TODO - set up currentMonthStart if direction is PAST:
@ -484,11 +480,9 @@ export default {
const direction = config.calendarViewDirection;
const monthsAfterToLoadOffset = 6;
const monthsBeforeToLoadOffset = 36;
config.initialShopTimeSlotsResponse.days.forEach(
(selectableDate) => {
this.selectableDatesData.push(selectableDate);
}
);
config.initialShopTimeSlotsResponse.days.forEach((selectableDate) => {
this.selectableDatesData.push(selectableDate);
});
// GENERATE MONTHS AND PUSH THEM INTO ARRAY
const months = [];
@ -524,11 +518,10 @@ export default {
this.$nextTick(() => {
// Advance to month
const monthToShow = this.months.find((month) =>
month.monthClass.includes('month-preselected')
);
month.monthClass.includes('month-preselected'));
if (
monthToShow.monthClass.includes('month-preselected') &&
monthToShow.monthClass.includes('last-available-month')
monthToShow.monthClass.includes('month-preselected')
&& monthToShow.monthClass.includes('last-available-month')
) {
// disable View More dates button if the preSelectedDate in the last available month
this.disableViewMoreDatesButton = true;
@ -553,12 +546,10 @@ export default {
*/
let monthNum =
convertDateStringToDate(this.todayString).getMonth() +
offset +
1;
let yearNum = convertDateStringToDate(
this.todayString
).getFullYear();
convertDateStringToDate(this.todayString).getMonth()
+ offset
+ 1;
let yearNum = convertDateStringToDate(this.todayString).getFullYear();
const { calendarViewDirection } = options;
if (calendarViewDirection === 'future' && offset > 0) {
while (monthNum > 12) {
@ -595,18 +586,18 @@ export default {
let monthEndDateNum = monthEndDate.getDate();
if (
offset === 0 &&
calendarViewDirection === 'past' &&
monthEndDateNum > this.currentWeekEndDateNum
offset === 0
&& calendarViewDirection === 'past'
&& monthEndDateNum > this.currentWeekEndDateNum
) {
monthEndDateNum = this.currentWeekEndDateNum;
}
if (options.preSelectedDate) {
if (
monthStartDate.getFullYear() ===
preSelectedDateObj.getFullYear() &&
monthStartDate.getMonth() === preSelectedDateObj.getMonth()
monthStartDate.getFullYear()
=== preSelectedDateObj.getFullYear()
&& monthStartDate.getMonth() === preSelectedDateObj.getMonth()
) {
monthClass += ' month-preselected';
} else if (monthStartDate > preSelectedDateObj) {
@ -619,14 +610,14 @@ export default {
}
if (
Math.abs(offset) === options.monthsAfterToLoadOffset &&
calendarViewDirection === 'future'
Math.abs(offset) === options.monthsAfterToLoadOffset
&& calendarViewDirection === 'future'
) {
monthClass += ' last-available-month';
}
if (
Math.abs(offset) === options.monthsBeforeToLoadOffset &&
calendarViewDirection === 'past'
Math.abs(offset) === options.monthsBeforeToLoadOffset
&& calendarViewDirection === 'past'
) {
// TODO - re-check this logic if past direction
monthClass += ' last-available-month';
@ -635,24 +626,22 @@ export default {
// populate dates array
for (let i = monthStartDateNum; i <= monthEndDateNum; i++) {
let dayClasses = '';
const dateString = `${yearNum.toString()}-${`0${monthNum}`.slice(
-2
)}-${`0${i}`.slice(-2)}`;
const dateString = `${yearNum.toString()}-${`0${monthNum}`.slice(-2)}-${`0${i}`.slice(-2)}`;
if (offset === 0 && i === this.todayDateNum) {
dayClasses += ' current-day';
}
if (
offset === 0 &&
i < this.todayDateNum &&
calendarViewDirection === 'future'
offset === 0
&& i < this.todayDateNum
&& calendarViewDirection === 'future'
) {
dayClasses += ' unavailable-day';
}
if (
offset === 0 &&
i > this.todayDateNum &&
calendarViewDirection === 'past'
offset === 0
&& i > this.todayDateNum
&& calendarViewDirection === 'past'
) {
dayClasses += ' unavailable-day';
}
@ -660,11 +649,11 @@ export default {
dayClasses += ' sunday';
}
if (
this.hideSomeDaysForInitialView &&
convertDateStringToDate(initialViewEndDate).getMonth() +
1 ===
monthNum &&
convertDateStringToDate(initialViewEndDate).getDate() < i
this.hideSomeDaysForInitialView
&& convertDateStringToDate(initialViewEndDate).getMonth()
+ 1
=== monthNum
&& convertDateStringToDate(initialViewEndDate).getDate() < i
) {
dayClasses += ' day-hidden';
isMonthThatHidesSomeDaysForInitialView = true;
@ -674,9 +663,7 @@ export default {
dayClasses,
inputValue: dateString,
isSelectable:
this.selectableDatesData.findIndex(
(date) => date.date === dateString
) > -1
this.selectableDatesData.findIndex((date) => date.date === dateString) > -1
};
dates.push(dateObject);
}
@ -701,26 +688,21 @@ export default {
let monthStartDateNum = 0;
if (this.hideSomeDaysForInitialView) {
monthToShow = this.months.find(
({ isMonthThatHidesSomeDaysForInitialView }) =>
isMonthThatHidesSomeDaysForInitialView
);
monthToShow = this.months.find(({ isMonthThatHidesSomeDaysForInitialView }) =>
isMonthThatHidesSomeDaysForInitialView);
// find the first day-hidden to become the next api call start date
monthStartDateNum =
monthToShow.dates.find(({ dayClasses }) =>
dayClasses.includes('day-hidden')
).dateNum - 1;
dayClasses.includes('day-hidden')).dateNum - 1;
} else {
if (this.calendarViewDirection === 'future') {
monthToShow = this.months.find((month) =>
month.monthClass.includes('month-hidden')
);
month.monthClass.includes('month-hidden'));
}
if (this.calendarViewDirection === 'past') {
// TODO: UPDATE THIS WITH CORRECT PAST LOOKING LOGIC
monthToShow = this.months.find((month) =>
month.monthClass.includes('month-hidden')
);
month.monthClass.includes('month-hidden'));
}
}
if (monthToShow) {
@ -737,8 +719,7 @@ export default {
);
this.scrollToElement(monthToShow.monthString);
if (monthToShow.monthClass.includes('last-available-month'))
this.disableViewMoreDatesButton = true;
if (monthToShow.monthClass.includes('last-available-month')) this.disableViewMoreDatesButton = true;
}
},
async updateSelectableDates(monthStart, monthEnd) {
@ -751,9 +732,7 @@ export default {
);
moreSelectableDates.days.forEach((selectableDate) => {
const index = this.selectableDatesData.findIndex(
(dateObj) => dateObj.date === selectableDate.date
);
const index = this.selectableDatesData.findIndex((dateObj) => dateObj.date === selectableDate.date);
if (index === -1) this.selectableDatesData.push(selectableDate);
this.months.forEach((month) => {
// TODO: avoid checking all calendar dates; maybe only ones between monthStart and monthEnd as defined above?
@ -821,19 +800,6 @@ export default {
flex-grow: 1;
position: relative;
}
.loader {
height: 2rem;
width: 100%;
display: flex;
justify-content: center;
transform: unset;
right: unset;
&::after {
width: 1.5rem;
height: 1.5rem;
}
}
.calendar-grid-container {
margin: 0 auto 2rem auto;
max-width: 414px;

View file

@ -132,29 +132,23 @@ export default {
margin-bottom: 0.25rem;
}
.form-select {
border: 1px solid $gray-500;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%231474a2'/%3e%3c/svg%3e");
border: $border-input;
background-image: url(~@/assets/img/icons/select.png);
background-size: 0.625rem 1rem;
color: $gray-600;
border-radius: 0.5rem;
border-radius: $border-radius;
min-height: 3rem;
letter-spacing: inherit;
box-shadow: $box-shadow-input;
&:focus,
&:focus-visible {
box-shadow: 0 0 0 2.5px $blue;
border: $border-input-focus;
}
&:disabled,
&.disabled {
background-color: $gray-100;
color: $gray-500;
filter: grayscale(100%);
&:hover {
box-shadow: 0 0 0 4px transparent;
border: 1px solid $gray-500;
}
}
&:hover {
border: 1px solid $gray-500;
box-shadow: 0 0 0 4px $blue-300;
}
}
}

View file

@ -153,27 +153,20 @@ export default {
.form-control {
max-height: 30rem;
border: 1px solid $gray-500;
border-radius: 0.5rem;
border: $border-input;
border-radius: $border-radius;
padding: 12px 16px;
letter-spacing: inherit;
box-shadow: $box-shadow-input;
&::placeholder {
color: $gray-500;
}
&:focus {
box-shadow: 0 0 0 2.5px $blue;
border: $border-input-focus;
}
&:disabled,
&.disabled {
background-color: $gray-100;
&:hover {
box-shadow: 0 0 0 4px transparent;
border: 1px solid $gray-500;
}
}
&:hover {
border: 1px solid $gray-500;
box-shadow: 0 0 0 4px $blue-300;
}
}
}

View file

@ -275,7 +275,7 @@ input::-webkit-date-and-time-value {
position: relative;
&.has-search-icon {
input[type='text'] {
border-radius: $border-radius-lg;
border-radius: $border-radius;
}
button[type='submit'] {
position: absolute;
@ -329,29 +329,22 @@ input::-webkit-date-and-time-value {
margin-bottom: 0.25rem;
}
.form-control {
border: 1px solid $gray-500;
border-radius: 0.5rem;
border: $border-input;
border-radius: $border-radius;
min-height: 3rem;
max-height: 3rem;
padding: 0.75rem 1rem;
letter-spacing: inherit;
box-shadow: $box-shadow-input;
&::placeholder {
color: $gray-500;
}
&:focus {
box-shadow: 0 0 0 2.5px $blue;
&:focus, &:focus-within {
border: $border-input-focus;
}
&:disabled,
&.disabled {
background-color: $gray-100;
&:hover {
box-shadow: 0 0 0 4px transparent;
border: 1px solid $gray-500;
}
}
&:hover {
border: 1px solid $gray-500;
box-shadow: 0 0 0 4px $blue-300;
}
}
p {

View file

@ -19,9 +19,6 @@
align-items-center justify-content-center d-inline-flex mt-2 py-3 px-4 delay w-100"
@click="continueReferral">
{{ modalBodyText }}
<loader
v-if="isLoaderDisplayed"
class="ms-2 button-loader" />
</button>
</modal>
</div>
@ -29,20 +26,17 @@
</template>
<script>
import loader from '@/ux-components/loader/loader.vue';
import modal from '@/digital-components/modal/modal.vue';
import { getISSCookie } from '@/helpers/cookie-helper.js';
export default {
name: 'continue-modal',
components: {
loader,
modal
},
emits: ['continue-previous-referral', 'start-new-referral'],
data() {
return {
isLoaderDisplayed: false,
isModalOpened: false
};
},
@ -69,9 +63,6 @@ export default {
openModal() {
this.$refs.continueModal.openModal();
},
removeLoader() {
this.isLoaderDisplayed = false;
},
setModalStatus(isOpened) {
this.isModalOpened = isOpened;
},
@ -79,7 +70,6 @@ export default {
this.$refs.continueModal.closeModal();
},
continueReferral() {
this.isLoaderDisplayed = true;
this.$emit('continue-previous-referral');
},
startNewReferral() {

View file

@ -0,0 +1,143 @@
<template>
<div class="footer-menu-container">
<div class="footer-menu-wrapper">
<div class="footer-menu-image-container">
<div class="footer-menu-image">
<img
:src="require('@/assets/img/powered-by-safelite-solutions.svg')"
alt="Powered by Safelite Solutions" />
</div>
</div>
<div class="footer-menu-items-container">
<!-- Footer menu items go here -->
<div class="footer-menu-item">
&copy; {{ new Date().getFullYear() }} Safelite Group
</div>
<div class="footer-menu-item">
<textLink
linkType="newWindowLink"
text="Terms of service"
href="//www.safelite.com/terms-of-use"
target="_blank" />
</div>
<div class="footer-menu-item">
<textLink
linkType="newWindowLink"
text="Your privacy choices"
href="//www.safelite.com/privacy-center"
target="_blank">
<template #after-text>
<img
class="ccpa-icon"
src="~@/assets/img/icons/ccpa-icon.svg"
alt="Your privacy choices" />
</template>
</textLink>
</div>
<div class="footer-menu-item">
Cookie Preferences
</div>
<div class="footer-menu-item">
<textLink
linkType="newWindowLink"
text="Notice at collection"
href="https://www.safelite.com/ccpa-privacy-policy"
target="_blank" />
</div>
</div>
</div>
</div>
</template>
<script>
import textLink from '@/ux-components/text-link/text-link.vue';
export default {
name: 'footer-menu',
components: {
textLink
}
};
</script>
<style lang="scss" scoped>
.footer-menu-container {
display: flex;
border-top: solid 0.125rem #d3d3d3;
@include media-breakpoint-up(xs) {
padding: 1rem 0 1.25rem 0; // Heritage 1.250rem 0
flex-direction: column;
justify-content: center;
align-items: center;
}
@include media-breakpoint-up(xl) {
padding: 3rem 0;
.footer-menu-wrapper {
display: flex;
flex-direction: row-reverse;
justify-content: space-between;
align-items: center;
}
}
.footer-menu-items-container {
@include media-breakpoint-up(xs) {
display: flex;
width: 100%;
flex-direction: column;
justify-content: center;
align-items: center;
margin-top: 1.25rem;
.footer-menu-item:not(:first-child) {
margin-top: 0.75rem;
}
}
@include media-breakpoint-up(xl) {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-top: 0;
.footer-menu-item {
margin-top: 0;
margin-right: 1.75rem;
&:not(:first-child) {
margin-top: 0;
}
&:last-child {
margin-right: 5rem;
}
}
}
.footer-menu-item {
display: flex;
text-align: center;
font-size: 0.875rem;
.ccpa-icon {
width: 2.0625rem;
height: 1rem;
margin-left: 0.5rem;
}
a {
color: #525656;
text-decoration: none;
line-height: 1.56;
font-weight: 400;
padding: 0;
&:hover {
text-decoration: underline;
}
}
}
}
}
</style>

View file

@ -19,60 +19,6 @@ jest.mock('@/helpers/cms-content-helper', () => ({
}));
function setupMocks() {
// TODO: Use or delete these
const unused1 = () => ({
partsOrQuestions: [
{
parts: null,
partQuestions: [
{
questionSequence: 1,
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
answers: [
{
answerResult: '',
answerText: 'Yes',
nextQuestionSequence: 2
},
{
answerResult: '',
answerText: 'No',
nextQuestionSequence: 3
}
]
}
],
glassLocation: 'Windshield',
glassName: 'Single',
answerKey: 'Windshield-Single',
answerData: null
}
]
});
const unused2 = () => ({
partsQuestionAnswers: [
{
glassLocation: 'Windshield',
glassName: 'Single',
result: 'FW04848',
answeredQuestions: [
{
questionText:
'Is your vehicle equipped with the Panoramic Sunroof which can be identified by having a glass panel over the rear seats?',
selectedAnswerText: 'Yes',
questionNum: 1
},
{
questionText:
'Is your vehicle equipped with a heated windshield that melts snow and ice from underneath the windshield wiper blades?',
selectedAnswerText: 'Yes',
questionNum: 2
}
]
}
]
});
const mountOptions = getMountOptions({
mixins: [baseMixin, vehicleQuestionsMixin]
});

View file

@ -1,18 +1,13 @@
<template>
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<loadingModal ref="loadingModal" :textSlides="loadingText" />
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="iss-heritage-container-width">
<div class="questions-page-layout-container iss-heritage-content-container-width">
<siteSubHeader
class="mt-4"
cmsWidgetName="SiteSubHeaderWidget" />
<alert
ref="alertFewMoreQuestions"
cmsWidgetName="alertWidget"
@ -48,23 +43,19 @@
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import alert from '@/ux-components/alert/alert.vue';
import questionChain from '@/digital-components/question-chain/question-chain.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
export default {
name: 'questions-page',
components: {
siteHeader,
vehicleBanner,
alert,
questionChain,
siteSubHeader,
siteFooter,
loadingModal,
siteFooter
},
props: {
isMetaValid: Boolean,
@ -74,7 +65,7 @@ export default {
validationRules: String,
modelValue: Object,
loadingText: Array,
index: Number,
index: Number
},
emits: ['update:modelValue', 'forwardButtonAction', 'back-click'],
computed: {
@ -84,16 +75,16 @@ export default {
},
set(newValue) {
this.$emit('update:modelValue', newValue);
},
},
}
}
},
methods: {
showThisQuestionChain(glass, i) {
// return false if no questions or if suppressed
if (
!glass.questions ||
glass.questions?.length < 1 ||
glass.isSuppressedPart
!glass.questions
|| glass.questions?.length < 1
|| glass.isSuppressedPart
) {
return false;
}
@ -106,15 +97,21 @@ export default {
},
handleBackButtonAction() {
this.$emit('back-click');
},
showLoadingModal() {
this.$refs.loadingModal.showModal();
},
},
}
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.questions-page-layout-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.questions-page {
.question-text {
margin-bottom: 0.5rem;

View file

@ -294,32 +294,6 @@ describe('Shop list button', () => {
expect(availabilityIndicatorBlock.classes()).toContain('availability-indicator');
expect(availabilityIndicatorBlock.classes()).toContain('rounded-pill');
});
test('availability indicator loader when displayAvailabilityIndicators', async () => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(null)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityIndicatorLoader = wrapper.findComponent(loaderReference);
// Assert
expect(availabilityIndicatorLoader.exists()).toBeTruthy();
expect(availabilityIndicatorLoader.props().loaderPosition).toBe('left');
expect(availabilityIndicatorLoader.props().allowPageInteraction).toBe(true);
});
describe('availability badge when displayAvailabilityIndicators true', () => {
test('and "availabilityRating" is "high"', async () => {
// Arrange
@ -437,60 +411,6 @@ describe('Shop list button', () => {
});
});
describe('should not render', () => {
test.each([false, null, undefined])(
'availability indicator block when displayAvailabilityIndicators falsy',
async (displayAvailabilityIndicators) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators,
availabilityRatingCallback: () => Promise.resolve({})
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityIndicatorBlock = wrapper.find(availabilityIndicatorBlockReference);
// Assert
expect(availabilityIndicatorBlock.exists()).toBeFalsy();
}
);
test.each([null, undefined])(
'availability badge when displayAvailabilityIndicators true and "availabilityRating" is null',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const availabilityBadge = wrapper.find(availabilityBadgeReference);
// Assert
expect(availabilityBadge.exists()).toBeFalsy();
}
);
test('button body copy when buttonBodyCopy not provided', async () => {
// Arrange
const additionalButtonData = {
@ -542,33 +462,6 @@ describe('Shop list button', () => {
});
describe('computed', () => {
describe('isLoaderDisplayed', () => {
test.each([null, undefined])(
'should return true when availabilityRating is null or undefined',
async (availabilityRating) => {
// Arrange
const additionalButtonData = {
displayAvailabilityIndicators: true,
availabilityRatingCallback: () => Promise.resolve(availabilityRating)
};
const wrapper = mount(shopListButton, {
propsData: {
value: 1234,
modelValue: 'value of modal',
groupName: 'name of group',
buttonLabel: 'label of button',
additionalButtonData
},
mixins: [inputButtonWrapperMixin]
});
await wrapper.vm.$nextTick();
// Act
const result = wrapper.vm.isLoaderDisplayed;
// Assert
expect(result).toBeTruthy();
}
);
test('should return false when availabilityRating is empty string', async () => {
// Arrange
const availabilityRating = '';

View file

@ -25,13 +25,7 @@
id="availabilityIndicatorBlock"
class="availability-indicator rounded-pill"
:class="availabilityRatingClass">
<loader
v-if="isLoaderDisplayed"
ref="availabilityIndicatorLoader"
loaderPosition="left"
:allowPageInteraction="true" />
<div
v-else
id="availabilityIndicator"
class="d-flex align-items-center">
<div
@ -64,13 +58,11 @@
<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: 'shop-list-button',
components: {
baseInputButton,
loader
baseInputButton
},
mixins: [inputButtonWrapperMixin],
data() {
@ -80,9 +72,6 @@ export default {
};
},
computed: {
isLoaderDisplayed() {
return this.availabilityRating == null;
},
availabilityRatingClass() {
if (this.availabilityRating != null) {
return this.availabilityRating === 'high' ? 'green' : 'orange';
@ -203,18 +192,6 @@ export default {
align-items: center;
}
.loader {
padding: 0 0.25rem 0 0.25rem;
padding-top: 0.125rem;
padding-bottom: 0.125rem;
}
.loader:after {
background-color: $gray-550;
height: 1rem;
width: 1rem;
}
&.green {
color: $green-700;
background-color: $green-100;

View file

@ -1,40 +0,0 @@
<template>
<div class="footerImage">
<img
:src="footerImageURL"
alt="" />
</div>
</template>
<script>
import widgetFields from '@/constants/cms-widget-fields.js';
export default {
name: 'footer-image',
data() {
return {
widget: {
footer: 'SiteFooterWidget'
}
};
},
computed: {
footerImageURL() {
return this.getCmsContent(
this.widget.footer,
widgetFields.FOOTER_WIDGET.FOOTER_IMAGE_URL
);
}
}
};
</script>
<style lang="scss" scoped>
.footerImage {
display: flex;
justify-content: center;
margin-top: auto;
img {
max-width: 23.4375rem;
}
}
</style>

View file

@ -49,7 +49,6 @@
<script>
import textLink from '@/ux-components/text-link/text-link.vue';
import buttonMain from '@/ux-components/button-main/button-main.vue';
import issPageValues from '@/router/router-constants/issPage-values';
export default {
name: 'site-footer',
@ -80,29 +79,10 @@ export default {
return this.customButtontext
? this.customButtontext
: this.getCmsContent(this.cmsWidgetName, 'ForwardButtonText');
},
footerImageURL() {
const output = this.getCmsContent(
this.cmsWidgetName,
'FooterImageURL'
);
return output;
},
includeFooterImage() {
const currentPageName = this.getPageNameByQueryString();
return currentPageName.toLowerCase() === issPageValues.WELCOME_PAGE;
}
},
mounted() {
this.paddingHeight = this.includeFooterImage
? this.getFooterInfoBoxHeight() + 16
: this.getFooterInfoBoxHeight() + 24;
this.$nextTick(() => {
window.addEventListener('resize', this.onResize);
});
},
beforeUnmount() {
window.removeEventListener('resize', this.onResize);
this.paddingHeight = this.getFooterInfoBoxHeight() + 24;
},
unmounted() {
document.onkeydown = null;
@ -114,10 +94,6 @@ export default {
updateButtonText(newText) {
this.customButtontext = newText;
},
removeLoader() {
this.$refs.buttonMain.removeLoader();
document.onkeydown = () => true;
},
buttonClick() {
// prevent keyboard input after button click
document.onkeydown = () => false;
@ -145,14 +121,12 @@ export default {
justify-content: center;
}
.col,
.col-auto,
.col button {
.col-auto {
width: 100%;
}
@media only screen and (min-width: 340px) {
.col,
.col-auto,
.col button {
.col-auto {
width: auto;
justify-content: flex-end;
}
@ -180,18 +154,4 @@ export default {
}
}
}
.footerImage {
text-align: center;
position: sticky;
}
@media only screen and (max-width: 340px) {
.footerImage {
bottom: 78px;
}
}
#siteFooterImage {
width: 100%;
}
</style>

View file

@ -0,0 +1,87 @@
<template>
<div
v-if="progress > 0"
class="progress-bar-container">
<div class="progress-bar-header">
<span aria-hidden="true">{{ progress }}%</span>
</div>
<div class="progress">
<div
class="progress-bar progress-bar-success"
role="progressbar"
:aria-valuetext="`Scheduling progress ${progress}%`"
aria-valuemin="0"
aria-valuemax="100"
:style="{ width: progress + '%' }">
<div class="progress-bar-middle"></div>
</div>
</div>
</div>
</template>
<script>
import { getProgressBarPercentage } from '@/constants/progress-bar-mapper';
import { useMainStore } from '@/store';
export default {
name: 'progress-bar',
data() {
return {
progress: this.getProgress()
};
},
methods: {
getProgress() {
const pageName = useMainStore().applicationUser.lastPageVisited;
return getProgressBarPercentage(pageName);
}
}
};
</script>
<style lang="scss">
.progress-bar-container {
display: flex;
.progress-bar-header {
padding-right: 0.3125rem;
color: $progress-bar-color;
font-weight: 600;
font-size: 0.875rem;
line-height: 0.9375rem;
text-align: right;
}
.progress {
@include media-breakpoint-up(xs) {
min-width: 5.9375rem;
}
@include media-breakpoint-up(md) {
min-width: 17.1875rem;
}
margin-left: 0;
border-radius: $border-radius-pill;
overflow: visible;
.progress-bar {
background-color: $progress-bar-color;
border-radius: $border-radius-pill 0 0 $border-radius-pill;
overflow: visible;
.progress-bar-middle {
width: 1.0625rem;
height: 1.0625rem;
position: relative;
margin-right: -8.5px;
margin-left: auto;
margin-top: -1px;
border: 0.125rem solid #ffffff;
border-radius: 50%;
background-color: $progress-bar-color;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
}
}
}
}
</style>

View file

@ -1,14 +1,18 @@
<template>
<div>
<div
class="site-header d-flex justify-content-center align-items-center flex-column py-2"
:style="logoBackgroundStyle">
<img
id="siteHeaderImage"
class="img-fluid"
:src="imageSrc"
:alt="altText" />
<menuModal />
<div
class="site-header-container"
:style="logoBackgroundStyle">
<div class="site-header iss-heritage-container-width">
<div class="header-logo-container">
<img
id="siteHeaderImage"
class="img-fluid"
:src="imageSrc"
:alt="altText" />
</div>
<div class="header-progress-bar-container">
<progressBar />
</div>
</div>
<alert
v-if="displayGlobalAlert"
@ -22,17 +26,16 @@
</template>
<script>
import menuModal from '@/iss-components/site-header/menu-modal/menu-modal.vue';
import alert from '@/ux-components/alert/alert.vue';
import { useMainStore } from '@/store';
import eventBus from '@/helpers/event-bus/event-bus';
import { globalEvents } from '@/constants/events';
import progressBar from '@/iss-components/site-header/progress-bar/progress-bar.vue';
export default {
name: 'site-header',
components: {
menuModal,
alert
alert, progressBar
},
props: {
cmsWidgetName: String
@ -130,15 +133,43 @@ export default {
</script>
<style lang="scss" scoped>
.site-header {
height: 56px;
position: relative;
@include media-breakpoint-down(md) {
margin: 0 -.75rem;
.site-header-container {
width: 100%;
margin: 0;
@include media-breakpoint-up(xs) {
padding: 0.750rem 0.9375rem 1rem 0.9375rem;
}
@include media-breakpoint-up(md) {
padding: 1rem 0 1.25rem 0;
}
.site-header {
display: flex;
@include media-breakpoint-down(md) {
margin: 0 -.75rem;
}
.header-logo-container {
flex: 1 1 auto;
}
.header-progress-bar-container {
flex: 0 1 auto;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
#siteHeaderImage {
width: auto;
height: 2.5rem;
@include media-breakpoint-up(xs) {
height: 2.625rem; // 42px no padding in image
}
@include media-breakpoint-up(md) {
height: 4rem; // 64px no padding in image
}
}
</style>

View file

@ -1,10 +1,10 @@
<template>
<div>
<div
class="subheader-primary d-flex align-items-center justify-content-center overflow-hidden">
class="subheader-primary d-flex overflow-hidden">
<h5
class="text-center fw-normal mb-0 subheader-primary"
:class="headerColor">
:class="[justifySubheaderSubText, headerColor]"
class="fw-normal mb-0 subheader-primary">
<span>
{{ content }}
</span>
@ -49,6 +49,7 @@ export default {
hasBackButton: Boolean,
issContainingPage: String,
justification: String,
justificationSubText: String,
stripRteStyle: Boolean,
subContentProperty: String,
subHeaderClasses: String,
@ -108,6 +109,11 @@ export default {
? 'justify-content-left'
: 'justify-content-center';
},
justifySubheaderSubText() {
return this.justificationSubText?.toLowerCase() === 'center'
? 'justify-content-center'
: 'justify-content-left';
},
alternateFormatting() {
// override for service-packages unique style
if (this.issContainingPage?.toLowerCase() === 'service-packages') {
@ -147,6 +153,12 @@ h5 {
span {
color: $black;
}
&.justify-content-center {
text-align: center;
}
&.justify-content-left {
text-align: left;
}
}
p {
margin: 0;
@ -167,7 +179,10 @@ p {
.subheader-secondary {
p {
font-size: .875rem;
margin-bottom: 1.25rem;
color: #525656;
font-size: 1rem;
line-height: 1.56;
&.justify-content-center {
text-align: center;
}

View file

@ -1,114 +0,0 @@
import { shallowMount } from '@vue/test-utils';
import vehicleCategories from '@/constants/vehicle-categories.js';
import { useMainStore } from '@/store';
import { createApp } from 'vue';
import { createPinia, mapStores } from 'pinia';
import App from '@/App.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
const cmsData = { VehicleBannerWidget:
{
GenericVehicleImage: 'blurred-image.jpg',
GenericVehicleImageFilePath: 'images/default-source/default-album/blurred-image.jpg',
CarUnmatchedVehicleIcon: 'car-placeholder.jpg',
TruckUnmatchedVehicleIcon: 'truck-placeholder.jpg',
VanUnmatchedVehicleIcon: 'van-placeholder.jpg',
CommercialVanUnmatchedVehicleIcon: 'commercial-placeholder.jpg',
SuvUnmatchedVehicleIcon: 'suv-placeholder.jpg'
} };
const vueApp = createApp(App);
const pinia = createPinia();
vueApp.use(pinia);
const store = useMainStore();
const mockMixin = {
methods: {
getCmsContent(widgetName, fieldName) {
return cmsData[widgetName][fieldName];
}
},
computed: {
...mapStores(useMainStore),
vehicleCategories() {
return vehicleCategories;
}
}
};
describe('vehicleBanner', () => {
test('renders the blurrycar image when displayGenericVehicleImage is true', async () => {
const wrapper = shallowMount(vehicleBanner, {
propsData: {
displayGenericVehicleImage: true,
cmsWidgetName: 'VehicleBannerWidget'
},
mixins: [mockMixin]
});
expect(wrapper.vm.vehicleImageToDisplay).toEqual(wrapper.vm.genericVehicleImage);
expect(wrapper.find('img').attributes('class')).toContain('vehicle-image');
wrapper.unmount();
});
test('renders expected vehicle image', async () => {
store.order.vehicle.imageUrl = 'url_to_vehicle_image';
const wrapper = shallowMount(vehicleBanner, {
propsData: {
displayGenericVehicleImage: false,
cmsWidgetName: 'VehicleBannerWidget'
},
mixins: [mockMixin]
});
expect(wrapper.vm.vehicleImageToDisplay).toEqual('url_to_vehicle_image');
expect(wrapper.find('img').attributes('class')).toContain('vehicle-image');
wrapper.unmount();
});
test('should render default car icon when imageUrl is null and category is default', async () => {
store.order.vehicle.imageUrl = null;
const wrapper = shallowMount(vehicleBanner, {
propsData: {
displayGenericVehicleImage: false,
cmsWidgetName: 'VehicleBannerWidget'
},
mixins: [mockMixin]
});
const iconUrl = wrapper.vm.vehicleImageToDisplay;
expect(iconUrl).toEqual('car-placeholder.jpg');
wrapper.unmount();
});
const params = [['CAR', 'car-placeholder.jpg'],
['TRUCK', 'truck-placeholder.jpg'],
['VAN', 'van-placeholder.jpg'],
['COMMERCIAL VAN', 'commercial-placeholder.jpg'],
['SUV', 'suv-placeholder.jpg'],
['OTHER', 'car-placeholder.jpg']];
test.each(params)('renders correct icon when imageUrl is not populated for %s and %s', async (category, expectedIcon) => {
store.order.vehicle.imageUrl = null;
store.order.vehicle.category = category;
const wrapper = shallowMount(vehicleBanner, {
propsData: {
displayGenericVehicleImage: false,
cmsWidgetName: 'VehicleBannerWidget'
},
mixins: [mockMixin]
});
const vehicleIcon = wrapper.vm.getUnmatchedVehicleIcon();
expect(vehicleIcon).toEqual(expectedIcon);
expect(wrapper.find('img').attributes('class')).toContain('vehicle-image');
wrapper.unmount();
});
});

View file

@ -1,84 +0,0 @@
<template>
<div class="vehicle_banner text-center">
<img
class="vehicle-image img-fluid"
:src="vehicleImageToDisplay"
alt="" />
</div>
</template>
<script>
export default {
name: 'vehicle-banner',
props: {
displayGenericVehicleImage: {
type: Boolean,
required: true
},
cmsWidgetName: String
},
computed: {
vehicleImageToDisplay() {
if (this.displayGenericVehicleImage) {
return this.genericVehicleImage;
}
const imageUrl = (this.mainStore.hasSubmittedOrder())
? this.mainStore.getSubmittedOrder().vehicle.imageUrl
: this.mainStore.order.vehicle.imageUrl;
if (!imageUrl || imageUrl === 'NULL') {
return this.getUnmatchedVehicleIcon();
}
return imageUrl;
},
genericVehicleImage() {
return this.getCmsContent(this.cmsWidgetName, 'GenericVehicleImage');
},
carUnmatchedVehicleIcon() {
return this.getCmsContent(this.cmsWidgetName, 'CarUnmatchedVehicleIcon');
},
truckUnmatchedVehicleIcon() {
return this.getCmsContent(this.cmsWidgetName, 'TruckUnmatchedVehicleIcon');
},
vanUnmatchedVehicleIcon() {
return this.getCmsContent(this.cmsWidgetName, 'VanUnmatchedVehicleIcon');
},
commercialUnmatchedVehicleIcon() {
return this.getCmsContent(this.cmsWidgetName, 'CommercialVanUnmatchedVehicleIcon');
},
suvUnmatchedVehicleIcon() {
return this.getCmsContent(this.cmsWidgetName, 'SuvUnmatchedVehicleIcon');
}
},
methods: {
getUnmatchedVehicleIcon() {
const category = this.mainStore.getSubmittedOrder()?.vehicle.category ?? this.mainStore.order.vehicle.category;
switch (category) {
case this.vehicleCategories.CAR:
return this.carUnmatchedVehicleIcon;
case this.vehicleCategories.SUV:
return this.suvUnmatchedVehicleIcon;
case this.vehicleCategories.TRUCK:
return this.truckUnmatchedVehicleIcon;
case this.vehicleCategories.VAN:
return this.vanUnmatchedVehicleIcon;
case this.vehicleCategories.COMMERCIALVAN:
return this.commercialUnmatchedVehicleIcon;
default:
return this.carUnmatchedVehicleIcon;
}
}
}
};
</script>
<style lang="scss" scoped>
.vehicle-image {
max-width: 290px;
object-fit: cover;
width: 100%;
height: 132px;
}
</style>

View file

@ -1,4 +1,5 @@
<template>
<form>
<div class="page-container-grouped-styles access-denied">
<div class="fade-on-route-transition position-relative">
<div class="container-fluid">
@ -10,6 +11,7 @@
</div>
</div>
</div>
</form>
</template>
<script>

View file

@ -88,7 +88,6 @@ function setupMocks({
wrapper.vm.$router.navigateWithSpinner = jest.fn();
wrapper.vm.navigateBack = baseMixin.methods.navigateBack;
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
wrapper.vm.$refs.siteFooter.disableForwardButton = jest.fn();
wrapper.vm.$refs.siteFooter.enableForwardAction = jest.fn();
@ -483,7 +482,7 @@ describe('address-lookup.vue', () => {
const { wrapper } = setupMocks({
vinVehicles: [
{
{
vehicle: {
carId: 'BIGTRUCKCARID',
isBigTruck: true,
@ -498,7 +497,7 @@ describe('address-lookup.vue', () => {
await wrapper.setData({
customerQuestions: {
addressQuestions: mockRegistrationAddress
},
}
});
// Act
@ -518,7 +517,7 @@ describe('address-lookup.vue', () => {
const { wrapper } = setupMocks({
vinVehicles: [
{
{
vehicle: {
carId: 'BIGTRUCKCARID2',
isBigTruck: true,
@ -533,7 +532,7 @@ describe('address-lookup.vue', () => {
await wrapper.setData({
customerQuestions: {
addressQuestions: mockRegistrationAddress
},
}
});
// Act

View file

@ -4,23 +4,16 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
ref="vehicleBanner"
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<div class="iss-heritage-container-width">
<div class="address-lookup-container iss-heritage-content-container-width">
<siteSubHeader
ref="siteSubHeader"
cmsWidgetName="SiteSubHeaderWidget"
class="mb-5" />
class="mt-4" />
<alert
v-if="displayVinNotFoundAlert"
ref="alertVinNotFound"
@ -82,7 +75,6 @@
import baseFormMixin from '@/mixins/base-form-mixin';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import customerQuestions from '@/layouts/address-lookup/customer-questions/customer-questions.vue';
import alert from '@/ux-components/alert/alert.vue';
@ -106,7 +98,6 @@ export default {
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
customerQuestions,
alert,
@ -259,8 +250,7 @@ export default {
if (!resultMap.vinLookupResponse.isStatePermissible) {
// State Restrictions forbid lookup by address
this.displayVinLookupByHomeAddressNotAllowedAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
return this.$refs.siteFooter.disableForwardButton();
}
const carsFound = resultMap.vinLookupResponse.vinVehicles;
@ -272,12 +262,10 @@ export default {
if (!carFound.canSafeliteService) {
this.displayNoServiceAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
return this.$refs.siteFooter.disableForwardButton();
}
this.isCarIdDifferent =
carFound.carId !== useMainStore().order.vehicle.carId;
this.isCarIdDifferent = carFound.carId !== useMainStore().order.vehicle.carId;
if (this.isCarIdDifferent && carFound.carId !== this.previouslyEnteredCarId) {
// Display Alert
this.previouslyEnteredCarId = carFound.carId;
@ -293,10 +281,9 @@ export default {
await isGlassAvailableForCarId(carFound.carId);
// Update button "Continue with..."
this.$refs.siteFooter
return this.$refs.siteFooter
// eslint-disable-next-line max-len
.updateButtonText(`Continue with ${carFound.year} ${carFound.make} ${carFound.model} ${this.forwardButtonCarStyle}`);
return this.$refs.siteFooter.removeLoader();
}
// update data
@ -319,8 +306,7 @@ export default {
} else {
// No VINS found.
this.displayVinNotFoundAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
return this.$refs.siteFooter.disableForwardButton();
}
// Save vehicle, customer, service and registration information
@ -390,3 +376,14 @@ export default {
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.address-lookup-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
</style>

View file

@ -119,7 +119,6 @@ function setupMocks({
wrapper.vm.$router.navigateWithSpinner = jest.fn();
wrapper.vm.navigateBack = baseMixin.methods.navigateBack;
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
wrapper.vm.$refs.siteFooter.disableForwardButton = jest.fn();
return { wrapper };
@ -147,7 +146,6 @@ describe('address-vehicles.vue', () => {
};
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
wrapper.vm.lookupVin = jest.fn(() => Promise.resolve(lookupVinResponse));
wrapper.vm.$router.navigate = jest.fn();
wrapper.vm.saveVin = jest.fn().mockImplementation(() => {});
@ -176,7 +174,6 @@ describe('address-vehicles.vue', () => {
};
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
wrapper.vm.lookupVin = jest.fn(() => Promise.reject(lookupVinResponse));
wrapper.vm.$router.navigate = jest.fn();
wrapper.vm.saveVin = jest.fn().mockImplementation(() => {});
@ -323,7 +320,7 @@ describe('address-vehicles.vue', () => {
selectedVehicleVin: 'BIGTRUCKVIN2',
previouslyEnteredCarId: 'BIGTRUCKCARID2'
});
2
wrapper.vm.selectedVehicle = {
vin: 'BIGTRUCKVIN2',
vehicle: {

View file

@ -4,19 +4,15 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="iss-heritage-container-width">
<div class="address-vehicles-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
<alert
id="multiple-vehicles-alert"
ref="alertFoundMultipleVehicles"
@ -27,8 +23,8 @@
manualCopy=""
:isDismissible="false" />
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
ref="AlertNoService"
class="mt-5"
cmsWidgetName="AlertVehicleSelection"
alertClass="alert-danger"
@ -110,7 +106,6 @@ import baseFormMixin from '@/mixins/base-form-mixin';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import alert from '@/ux-components/alert/alert.vue';
import addressVehiclesQuestion from '@/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue';
@ -125,7 +120,6 @@ export default {
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
vehicleBanner,
alert,
addressVehiclesQuestion
},
@ -265,16 +259,11 @@ export default {
return false;
},
async forwardButtonAction() {
const vinLookup = await useMainStore()
.lookupVehicleByVin(this.selectedVehicle.vin)
.catch(() => {
this.$refs.siteFooter.removeLoader();
});
const vinLookup = await useMainStore().lookupVehicleByVin(this.selectedVehicle.vin);
if (!vinLookup) {
return;
}
this.isSelectedGlassAvailableForVehicle =
await isGlassAvailableForCarId(vinLookup.data.carId);
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vinLookup.data.carId);
await useMainStore().saveVin(
{
vehicleInfo: Object.assign(this.selectedVehicle.vehicle, {
@ -313,8 +302,16 @@ export default {
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.address-vehicles-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.alert-provide-vin {
font-size: 0.75rem;
line-height: 1.4;

View file

@ -4,16 +4,14 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="bailout-page-container iss-heritage-content-container-width">
<siteSubHeader
ref="siteSubHeader"
:cmsWidgetName="subHeaderCmsWidgetName"
@ -225,4 +223,13 @@ export default {
<style lang="scss">
@import '@/styles/bailout-common.scss';
.iss-heritage-container-width {
.bailout-page-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
</style>

View file

@ -1,19 +1,19 @@
<template>
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<form>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="sub-header-content"
justification="left" />
<div class="iss-heritage-container-width">
<div class="contact-confirmation-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="sub-header-content mt-4"
justification="left" />
</div>
</div>
</div>
</div>
</form>
</template>
<script>
// Components
@ -64,9 +64,17 @@ export default {
</script>
<style lang="scss">
.sub-header-content {
h5 {
margin-bottom: 1rem;
}
.iss-heritage-container-width {
.contact-confirmation-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.sub-header-content {
h5 {
margin-bottom: 1rem;
}
}
</style>

View file

@ -4,16 +4,14 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="contact-details-container iss-heritage-content-container-width">
<siteSubHeader
id="sub-header"
ref="siteSubHeader"
@ -236,6 +234,15 @@ export default {
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.contact-details-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.dark-gray {
color: $darker-gray;
}

View file

@ -2,7 +2,6 @@
exports[`returns the initial data 1`] = `
Object {
"isLoaderDisplayed": false,
"isModalOpened": false,
}
`;

View file

@ -21,9 +21,6 @@
align-items-center justify-content-center d-inline-flex mt-4 py-3 px-4 delay w-100"
@click="returnToClaim">
{{ modalBodyText2 }}
<loader
v-if="isLoaderDisplayed"
class="ms-2 button-loader" />
</button>
</modal>
</div>
@ -31,19 +28,16 @@
</template>
<script>
import loader from '@/ux-components/loader/loader.vue';
import modal from '@/digital-components/modal/modal.vue';
export default {
name: 'cancel-claim-modal',
components: {
loader,
modal
},
emits: ['cancel-claim-confirmation', 'return-to-claim'],
data() {
return {
isLoaderDisplayed: false,
isModalOpened: false
};
},
@ -65,9 +59,6 @@ export default {
openModal() {
this.$refs.cancelClaimModal.openModal();
},
removeLoader() {
this.isLoaderDisplayed = false;
},
setModalStatus(isOpened) {
this.isModalOpened = isOpened;
},

View file

@ -5,27 +5,25 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition coverage-statement">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition coverage-statement">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center pt-5">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="coverage-statement-container iss-heritage-content-container-width">
<h5
ref="siteSubHeader"
class="sub-header text-center text-black"
class="sub-header text-black mt-4"
v-html="coverageStatementSubHeader"></h5>
<div
ref="explanatoryText"
class="body-text text-center mt-2"
class="body-text mt-2"
v-html="explanatoryText"></div>
<div
ref="secondaryText"
class="text-center mt-4 mb-1 fw-bold text-black"
class="mt-4 mb-1 fw-bold text-black"
v-html="secondaryText"></div>
<div
v-if="isDeductibleVisible"
@ -100,6 +98,7 @@
@returnToClaim="continueClaim" />
</Form>
</template>
<script>
// Import Component
import { Form } from 'vee-validate';
@ -498,6 +497,15 @@ export default {
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.coverage-statement-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.coverage-statement {
.cost {
color: $green;
@ -511,7 +519,7 @@ export default {
.sub-header {
line-height: 2rem;
}
:deep ol {
:deep(ol) {
padding: 0;
padding-left: 1.125rem;
padding-right: 1.125rem;
@ -522,7 +530,7 @@ export default {
margin-bottom: .5rem;
}
}
:deep p {
:deep(p) {
line-height: 1.5rem;
font-size: 0.875rem;
margin-bottom: 0.5rem;
@ -530,11 +538,11 @@ export default {
color: $black;
}
}
:deep .body-text {
:deep(.body-text) {
font-size: 0.875rem;
line-height: 1.5rem;
}
:deep .question-text {
:deep(.question-text) {
margin-top: 1.5rem;
margin-bottom: 0.5rem;
font-size: 1rem;
@ -554,7 +562,7 @@ export default {
}
}
:deep .deductible-modal {
:deep(.deductible-modal) {
p {
margin-bottom: 0 !important;
}

View file

@ -4,20 +4,18 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="duplicate-check-container iss-heritage-content-container-width">
<siteSubHeader
id="sub-header"
ref="siteSubHeader"
class="mt-5 duplicate-check-subheader"
class="mt-4 duplicate-check-subheader"
:cmsWidgetName="widget.siteSubHeader" />
<buttonQuestion
ref="buttonQuestion"
@ -56,7 +54,7 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper.js';
import BaseFormMixin from '@/mixins/base-form-mixin.js';
import { useMainStore } from '@/store/index.js';
import globalRules from '@/constants/global-rules.js';
import {formatDate, toTitleCase} from '@/helpers/text-helper.js';
import { formatDate, toTitleCase } from '@/helpers/text-helper.js';
const dupeCheckDateFormatter = new Intl.DateTimeFormat('en-US', { timeZone: 'UTC', month: '2-digit', day: '2-digit', year: 'numeric' });
@ -205,6 +203,15 @@ export default {
</script>
<style lang="scss">
.iss-heritage-container-width {
.duplicate-check-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.duplicate-check-subheader {
.subheader-secondary {
margin-top: map-get($spacers, 2);

View file

@ -76,7 +76,6 @@ function setupMocks({
wrapper.vm.$router.navigateWithSpinner = jest.fn();
wrapper.vm.navigateBack = baseMixin.methods.navigateBack;
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
wrapper.vm.$refs.siteFooter.disableForwardButton = jest.fn();
wrapper.vm.$refs.siteFooter.enableForwardAction = jest.fn();
@ -156,7 +155,7 @@ describe('license-plate-lookup.vue', () => {
// Arrange
const mockRegistrationLicensePlate = {
licensePlate: 'BIGTRUCKTEST'
};
};
const { wrapper } = setupMocks({
lookupVinByPlateResponse: {
@ -187,7 +186,7 @@ describe('license-plate-lookup.vue', () => {
// Arrange
const mockRegistrationLicensePlate = {
licensePlate: 'BIGTRUCKTEST2'
};
};
const { wrapper } = setupMocks({
lookupVinByPlateResponse: {

View file

@ -4,21 +4,15 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<div class="iss-heritage-container-width">
<div class="license-plate-lookup-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mb-5"
class="mt-4"
subHeaderMarginClasses="mt-1" />
<alert
v-if="displayVinNotFoundAlert"
@ -105,7 +99,6 @@ import vinPagesMixin from '@/mixins/vin-pages-mixin';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import textboxQuestion from '@/digital-components/textbox-question/textbox-question.vue';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
import alert from '@/ux-components/alert/alert.vue';
@ -125,7 +118,6 @@ export default {
siteFooter,
siteHeader,
siteSubHeader,
vehicleBanner,
textboxQuestion,
dropdownQuestion,
alert
@ -274,8 +266,7 @@ export default {
if (vinLookupResponse.error) {
this.displayVinNotFoundAlert = true;
this.previouslyEnteredCarId = null;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
return this.$refs.siteFooter.disableForwardButton();
}
// Vehicle found from VIN lookup
@ -283,8 +274,7 @@ export default {
if (!vehicleFromLookup.canSafeliteService) {
this.displayNoServiceAlert = true;
this.$refs.siteFooter.disableForwardButton();
return this.$refs.siteFooter.removeLoader();
return this.$refs.siteFooter.disableForwardButton();
}
// Check if the CarId has changed
@ -307,10 +297,9 @@ export default {
this.isSelectedGlassAvailableForVehicle = await isGlassAvailableForCarId(vehicleFromLookup.carId);
// Update button "Continue with..."
this.$refs.siteFooter
return this.$refs.siteFooter
// eslint-disable-next-line max-len
.updateButtonText(`Continue with ${vehicleFromLookup.year} ${vehicleFromLookup.make} ${vehicleFromLookup.model} ${this.forwardButtonCarStyle}`);
return this.$refs.siteFooter.removeLoader();
}
// Save vehicle, license plate, and registration information
@ -354,6 +343,15 @@ export default {
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.license-plate-lookup-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
#license-plate-question-wrapper .form-test-error {
/**
Override extra margin-bottom in the error message in TextboxQuestion

View file

@ -13,7 +13,7 @@ import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type';
import { deepClone } from '@/helpers/object-helper';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import { paymentMethods } from "@/constants/payment-method-constants";
import { paymentMethods } from '@/constants/payment-method-constants';
jest.mock('@/helpers/layout-helper.js', () => jest.fn());
@ -42,10 +42,6 @@ const headerStub = {
render: () => {}
};
const vehicleBannerStub = {
render: () => {}
};
const addToCalendarStub = {
render: () => {}
};
@ -148,7 +144,6 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
mountOptions.global.stubs = {
siteFooter: footerStub,
siteHeader: headerStub,
vehicleBanner: vehicleBannerStub,
addToCalendar: addToCalendarStub
};
@ -181,7 +176,7 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
describe('OrderConfirmation.vue', () => {
afterEach(() => {
jest.resetAllMocks();
})
});
describe('Page pre-requisites', () => {
test('If submitted order saved to store, page pre-reqs return true', async () => {
// Arrange
@ -204,7 +199,7 @@ describe('OrderConfirmation.vue', () => {
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => sessionStorage);
};
wrapper = getMountedComponent({}, {}, mockStoreActions).wrapper;
wrapper = getMountedComponent({}, {}, mockStoreActions).wrapper;
});
test('Should render Site Header', () => {
// Act
@ -213,13 +208,6 @@ describe('OrderConfirmation.vue', () => {
// Assert
expect(siteHeader.exists()).toBe(true);
});
test('Should render Vehicle Banner', () => {
// Act
const vehicleBanner = wrapper.findComponent(vehicleBannerStub);
// Assert
expect(vehicleBanner.exists()).toBe(true);
});
test('If Advanced flow, should display Site Footer', () => {
// Arrange
const mockStoreActions = () => {
@ -287,7 +275,7 @@ describe('OrderConfirmation.vue', () => {
});
});
describe('Computed properties', () => {
describe('customValueMap', () =>{
describe('customValueMap', () => {
test.each([
'inShopAppointment',
'dropOffAppointment',
@ -314,7 +302,7 @@ describe('OrderConfirmation.vue', () => {
});
test('returns expected vehicle info', () => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
const year = 1998;
const make = 'Toyota';
const model = 'Cruse';
@ -327,9 +315,9 @@ describe('OrderConfirmation.vue', () => {
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
// Act
const actualYear = wrapper.vm.customValueMap['vehicleYear'];
const actualMake = wrapper.vm.customValueMap['vehicleMake'];
const actualModel = wrapper.vm.customValueMap['vehicleModel'];
const actualYear = wrapper.vm.customValueMap.vehicleYear;
const actualMake = wrapper.vm.customValueMap.vehicleMake;
const actualModel = wrapper.vm.customValueMap.vehicleModel;
// Assert
expect(actualYear).toBe(year);
@ -338,7 +326,7 @@ describe('OrderConfirmation.vue', () => {
});
test('returns expected customer email', () => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
const emailAddress = 'email@google.com';
order.customer.emailAddress = emailAddress;
const mockStoreActions = () => {
@ -347,19 +335,15 @@ describe('OrderConfirmation.vue', () => {
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
// Act
const actualEmail = wrapper.vm.customValueMap['email'];
const actualEmail = wrapper.vm.customValueMap.email;
// Assert
expect(actualEmail).toBe(emailAddress);
});
})
});
describe('confirmationEmailText', () => {
const greaterId = "&gt;";
const lessId = "&lt;";
const mobileWording = "Mobile wording";
const nonMobileWording = "Non mobile wording";
const mobileWidget = "MobileWordingWidget";
const dropOffAndInShopWidget = "DropOffAndInShopWordingWidget"
const greaterId = '&gt;';
const lessId = '&lt;';
test.each([
['test', 'test'],
[`te${greaterId}st`, 'te>st'],
@ -394,7 +378,7 @@ describe('OrderConfirmation.vue', () => {
['Between 11 PM - 12 AM', '23:00', '00:00']
])('should return Mobile time in expected format "%p" when start time "%p" and end time "%p"', (expected, startTime, endTime) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.schedule.startTime = startTime;
order.schedule.endTime = endTime;
order.serviceLocation.appointmentType = AppointmentTypeStrings.MOBILE;
@ -416,7 +400,7 @@ describe('OrderConfirmation.vue', () => {
['01:00', '02:00']
])('should return Drop off time in same format regardless of start/end time', (startTime, endTime) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.schedule.startTime = startTime;
order.schedule.endTime = endTime;
order.serviceLocation.appointmentType = AppointmentTypeStrings.DROP_OFF;
@ -440,7 +424,7 @@ describe('OrderConfirmation.vue', () => {
['at 12:00 PM', '12:00', '02:00']
])('should return In Shop time in expected format "%p" when start time "%p"', (expected, startTime, endTime) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.schedule.startTime = startTime;
order.schedule.endTime = endTime;
order.serviceLocation.appointmentType = AppointmentTypeStrings.IN_SHOP;
@ -457,19 +441,19 @@ describe('OrderConfirmation.vue', () => {
});
});
describe('appointmentLocation', () => {
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.serviceLocation = {
address: "123 Service Rd.",
address2: "Box 4",
city: "Columbus",
state: "OH",
zipCode: "12345",
address: '123 Service Rd.',
address2: 'Box 4',
city: 'Columbus',
state: 'OH',
zipCode: '12345',
provider: {
address: {
streetAddress: "304 provider Ln.",
city: "pittsburg",
state: "PA",
zipCode: "16001"
streetAddress: '304 provider Ln.',
city: 'pittsburg',
state: 'PA',
zipCode: '16001'
}
}
};
@ -509,9 +493,7 @@ describe('OrderConfirmation.vue', () => {
// Assert
expect(text).toBe(expectedShopLocation);
});
test.each(
['turtle', undefined, null]
)('unknown appointment type %p returns null', (type) => {
test.each(['turtle', undefined, null])('unknown appointment type %p returns null', (type) => {
// Arrange
order.serviceLocation.appointmentType = type;
const mockStoreActions = () => {
@ -527,20 +509,20 @@ describe('OrderConfirmation.vue', () => {
});
});
describe('serviceLocationFullAddress', () => {
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
beforeEach(() => {
order.serviceLocation = {
address: "123 Service Rd.",
address2: "Box 4",
city: "Columbus",
state: "OH",
zipCode: "12345",
address: '123 Service Rd.',
address2: 'Box 4',
city: 'Columbus',
state: 'OH',
zipCode: '12345',
provider: {
address: {
streetAddress: "304 provider Ln.",
city: "pittsburg",
state: "PA",
zipCode: "16001"
streetAddress: '304 provider Ln.',
city: 'pittsburg',
state: 'PA',
zipCode: '16001'
}
}
};
@ -550,7 +532,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "123 Service Rd., Box 4,<br/> Columbus, OH 12345";
const expected = '123 Service Rd., Box 4,<br/> Columbus, OH 12345';
// Act
const text = wrapper.vm.serviceLocationFullAddress;
@ -564,7 +546,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = ", Box 4,<br/> Columbus, OH 12345";
const expected = ', Box 4,<br/> Columbus, OH 12345';
// Act
const text = wrapper.vm.serviceLocationFullAddress;
@ -578,7 +560,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "123 Service Rd., <br/> Columbus, OH 12345";
const expected = '123 Service Rd., <br/> Columbus, OH 12345';
// Act
const text = wrapper.vm.serviceLocationFullAddress;
@ -592,7 +574,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "123 Service Rd., Box 4,<br/> , OH 12345";
const expected = '123 Service Rd., Box 4,<br/> , OH 12345';
// Act
const text = wrapper.vm.serviceLocationFullAddress;
@ -606,7 +588,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "123 Service Rd., Box 4,<br/> Columbus, 12345";
const expected = '123 Service Rd., Box 4,<br/> Columbus, 12345';
// Act
const text = wrapper.vm.serviceLocationFullAddress;
@ -620,7 +602,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "123 Service Rd., Box 4,<br/> Columbus, OH ";
const expected = '123 Service Rd., Box 4,<br/> Columbus, OH ';
// Act
const text = wrapper.vm.serviceLocationFullAddress;
@ -638,7 +620,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = ", <br/> , ";
const expected = ', <br/> , ';
// Act
const text = wrapper.vm.serviceLocationFullAddress;
@ -648,20 +630,20 @@ describe('OrderConfirmation.vue', () => {
});
});
describe('providerFullAddress', () => {
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
beforeEach(() => {
order.serviceLocation = {
address: "123 Service Rd.",
address2: "Box 4",
city: "Columbus",
state: "OH",
zipCode: "12345",
address: '123 Service Rd.',
address2: 'Box 4',
city: 'Columbus',
state: 'OH',
zipCode: '12345',
provider: {
address: {
streetAddress: "304 provider Ln.",
city: "pittsburg",
state: "PA",
zipCode: "16001"
streetAddress: '304 provider Ln.',
city: 'pittsburg',
state: 'PA',
zipCode: '16001'
}
}
};
@ -671,7 +653,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "304 Provider Ln.,<br/> Pittsburg, PA 16001";
const expected = '304 Provider Ln.,<br/> Pittsburg, PA 16001';
// Act
const text = wrapper.vm.providerFullAddress;
@ -685,7 +667,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "";
const expected = '';
// Act
const text = wrapper.vm.providerFullAddress;
@ -699,7 +681,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "304 Provider Ln.,<br/> , PA 16001";
const expected = '304 Provider Ln.,<br/> , PA 16001';
// Act
const text = wrapper.vm.providerFullAddress;
@ -713,7 +695,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "304 Provider Ln.,<br/> Pittsburg, 16001";
const expected = '304 Provider Ln.,<br/> Pittsburg, 16001';
// Act
const text = wrapper.vm.providerFullAddress;
@ -727,7 +709,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "304 Provider Ln.,<br/> Pittsburg, PA ";
const expected = '304 Provider Ln.,<br/> Pittsburg, PA ';
// Act
const text = wrapper.vm.providerFullAddress;
@ -744,7 +726,7 @@ describe('OrderConfirmation.vue', () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
const expected = "";
const expected = '';
// Act
const text = wrapper.vm.providerFullAddress;
@ -754,10 +736,10 @@ describe('OrderConfirmation.vue', () => {
});
});
describe('appointmentWordingText', () => {
const mobileWording = "Mobile wording";
const nonMobileWording = "Non mobile wording";
const mobileWidget = "MobileWordingWidget";
const dropOffAndInShopWidget = "DropOffAndInShopWordingWidget"
const mobileWording = 'Mobile wording';
const nonMobileWording = 'Non mobile wording';
const mobileWidget = 'MobileWordingWidget';
const dropOffAndInShopWidget = 'DropOffAndInShopWordingWidget';
let mixin;
beforeEach(() => {
processIfStatements.mockImplementation((content) => content);
@ -765,13 +747,13 @@ describe('OrderConfirmation.vue', () => {
mixin = {
methods: {
getCmsContent: jest.fn().mockImplementation((widget, _) => {
if (widget == mobileWidget){
if (widget === mobileWidget) {
return mobileWording;
}
if (widget == dropOffAndInShopWidget){
if (widget === dropOffAndInShopWidget) {
return nonMobileWording;
}
return "";
return '';
}),
setCmsContent: jest.fn()
}
@ -784,15 +766,15 @@ describe('OrderConfirmation.vue', () => {
[AppointmentTypeStrings.IN_SHOP, nonMobileWording],
['unknown', null],
[null, null],
[undefined, null],
[undefined, null]
])('appointment type %p returns wording %p', (type, wording) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.serviceLocation.appointmentType = type;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
const { wrapper } = getMountedComponent({}, {}, mockStoreActions, mixin);
// Act
@ -803,10 +785,10 @@ describe('OrderConfirmation.vue', () => {
});
});
describe('appointmentWordingText2', () => {
const mobileWording = "Mobile wording";
const nonMobileWording = "Non mobile wording";
const mobileWidget = "MobileWordingWidget";
const dropOffAndInShopWidget = "DropOffAndInShopWordingWidget"
const mobileWording = 'Mobile wording';
const nonMobileWording = 'Non mobile wording';
const mobileWidget = 'MobileWordingWidget';
const dropOffAndInShopWidget = 'DropOffAndInShopWordingWidget';
let mixin;
beforeEach(() => {
processIfStatements.mockImplementation((content) => content);
@ -814,13 +796,13 @@ describe('OrderConfirmation.vue', () => {
mixin = {
methods: {
getCmsContent: jest.fn().mockImplementation((widget, _) => {
if (widget == mobileWidget){
if (widget === mobileWidget) {
return mobileWording;
}
if (widget == dropOffAndInShopWidget){
if (widget === dropOffAndInShopWidget) {
return nonMobileWording;
}
return "";
return '';
}),
setCmsContent: jest.fn()
}
@ -833,10 +815,10 @@ describe('OrderConfirmation.vue', () => {
[AppointmentTypeStrings.IN_SHOP, nonMobileWording],
['unknown', null],
[null, null],
[undefined, null],
[undefined, null]
])('appointment type %p returns wording "%p"', (type, wording) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.serviceLocation.appointmentType = type;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
@ -861,7 +843,7 @@ describe('OrderConfirmation.vue', () => {
[undefined, false]
])('appointment type %p returns %p', (type, expected) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.serviceLocation.appointmentType = type;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
@ -886,7 +868,7 @@ describe('OrderConfirmation.vue', () => {
[undefined, false]
])('appointment type %p returns %p', (type, expected) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.serviceLocation.appointmentType = type;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
@ -911,7 +893,7 @@ describe('OrderConfirmation.vue', () => {
[undefined, false]
])('appointment type %p returns %p', (type, expected) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
order.serviceLocation.appointmentType = type;
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
@ -957,7 +939,7 @@ describe('OrderConfirmation.vue', () => {
['Wednesday, December 30', '2026-12-30']
])('returns %p given %p', (expected, date) => {
// Arrange
var order = deepClone(sessionStorage);
const order = deepClone(sessionStorage);
const mockStoreActions = () => {
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
};
@ -970,5 +952,5 @@ describe('OrderConfirmation.vue', () => {
expect(result).toBe(expected);
});
});
})
});
});

View file

@ -4,14 +4,12 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader :cmsWidgetName="widgets.siteHeader" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader :cmsWidgetName="widgets.siteHeader" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="order-confirmation-container iss-heritage-content-container-width">
<div class="text-center text-color--black pt-5 pb-5 fs-5">
<img :src="orderConfirmationImage" />
<span
@ -19,15 +17,11 @@
v-html="orderConfirmationHeaderText"></span>
</div>
<div class="appointment-details">
<div>
<vehicleBanner
:cmsWidgetName="widgets.vehicleBanner"
:displayGenericVehicleImage="false">
</vehicleBanner>
</div>
<div class="appointment-date-time text-center mt-4">
<p>{{ formatDate(schedule.date) }}</p>
<p class="mt-2">{{ appointmentTimeText }}</p>
<p class="mt-2">
{{ appointmentTimeText }}
</p>
</div>
<addToCalendar
mobileWidgetName="AddToCalendar_Mobile"
@ -85,7 +79,6 @@
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import addToCalendar from '@/layouts/order-confirmation/add-to-calendar/add-to-calendar.vue';
import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
@ -117,7 +110,6 @@ export default {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
siteHeader,
vehicleBanner,
siteFooter,
addToCalendar,
cartDropdown
@ -174,14 +166,13 @@ export default {
referralNumber: referralNumber?.toString(),
widgets: {
siteHeader: 'SiteHeaderWidget',
vehicleBanner: 'VehicleBannerWidget',
emailConfirmation: 'EmailConfirmationWordingWidget',
orderConfirmation: 'OrderConfirmationContent',
mobile: 'MobileWordingWidget',
dropOffAndInShop: 'DropOffAndInShopWordingWidget',
siteFooter: 'SiteFooterWidget'
}
}
};
},
computed: {
customValueMap() {
@ -196,12 +187,13 @@ export default {
email: this.customerEmail,
CUSTOMER_PORTAL_URL: applicationConfig.CUSTOMER_PORTAL_URL,
CUSTOMER_PORTAL_LOGIN_TOKEN: this.customerPortalLoginToken
}
};
},
confirmationEmailText() {
var content = this.getCmsContentWithCustomValues(
const content = this.getCmsContentWithCustomValues(
this.widgets.emailConfirmation,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
);
return content
?.replaceAll('&lt;', '<')
?.replaceAll('&gt;', '>');
@ -209,41 +201,47 @@ export default {
orderConfirmationHeaderText() {
return this.getCmsContent(
this.widgets.orderConfirmation,
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT);
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT
);
},
orderConfirmationImage() {
return this.getCmsContent(
this.widgets.orderConfirmation,
widgetFields.CONTENT_GROUP_WIDGET.IMAGE);
widgetFields.CONTENT_GROUP_WIDGET.IMAGE
);
},
mobileWordingText() {
return this.getCmsContentWithCustomValues(
this.widgets.mobile,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
);
},
mobileWordingText2() {
return this.getCmsContent(
this.widgets.mobile,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2
);
},
nonMobileWordingText() {
return this.getCmsContentWithCustomValues(
this.widgets.dropOffAndInShop,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT);
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
);
},
nonMobileWordingText2() {
return this.getCmsContentWithCustomValues(
this.widgets.dropOffAndInShop,
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2);
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT_2
);
},
appointmentTimeText() {
const { startTime, endTime } = this.schedule;
if (this.isDropOffAppointment){
if (this.isDropOffAppointment) {
return 'Drop off before 9:30 AM';
}
if (this.isInShopAppointment){
if (this.isInShopAppointment) {
const formattedStartTime = get12HourTimeFormat(startTime);
return `at ${formattedStartTime}`
return `at ${formattedStartTime}`;
}
if (this.isMobileAppointment) {
const mobileStartTime = get12HourTimeMobileFormat(startTime);
@ -253,38 +251,38 @@ export default {
return null;
},
appointmentLocation() {
if (this.isMobileAppointment){
if (this.isMobileAppointment) {
return this.serviceLocationFullAddress;
}
if (this.isDropOffAppointment || this.isInShopAppointment){
if (this.isDropOffAppointment || this.isInShopAppointment) {
return this.providerFullAddress;
}
return null
return null;
},
serviceLocationFullAddress() {
var { address, address2, city, state, zipCode } = this.serviceLocation;
const { address, address2, city, state, zipCode } = this.serviceLocation;
return `${address ?? ''}, ${address2 ? `${address2},` : ''}<br/> ${city ?? ''}, ${state ?? ''} ${zipCode ?? ''}`;
},
providerFullAddress() {
var { streetAddress, city, state, zipCode } = this.providerAddress;
const { streetAddress, city, state, zipCode } = this.providerAddress;
return streetAddress
? `${toTitleCase(streetAddress)},<br/> ${toTitleCase(city)}, ${state ?? ''} ${zipCode ?? ''}`
: '';
},
appointmentWordingText() {
if (this.isMobileAppointment){
if (this.isMobileAppointment) {
return this.mobileWordingText;
}
if (this.isInShopAppointment || this.isDropOffAppointment){
if (this.isInShopAppointment || this.isDropOffAppointment) {
return this.nonMobileWordingText;
}
return null;
},
appointmentWordingText2() {
if (this.isMobileAppointment){
if (this.isMobileAppointment) {
return this.mobileWordingText2;
}
if (this.isInShopAppointment || this.isDropOffAppointment){
if (this.isInShopAppointment || this.isDropOffAppointment) {
return this.nonMobileWordingText2;
}
return null;
@ -293,7 +291,7 @@ export default {
const mobileAppointmentTypes = [
AppointmentTypeStrings.MOBILE,
AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
]
];
return mobileAppointmentTypes.includes(this.appointmentType);
},
isInShopAppointment() {
@ -402,7 +400,7 @@ export default {
const processedIfStatements = processIfStatements(
rawText,
'custom',
(v) => { return this.customValueMap[v] }
(v) => this.customValueMap[v]
);
return getStringWithCustomValues(processedIfStatements, this.customValueMap);
},
@ -420,6 +418,14 @@ export default {
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.order-confirmation-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.page-container-grouped-styles {
overflow: auto;

View file

@ -4,24 +4,19 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<div class="iss-heritage-container-width">
<div class="payment-method-container iss-heritage-content-container-width">
<siteSubHeader
class="mb-5 mt-4 px-3"
cmsWidgetName="SiteSubHeaderWidget"
subTextClasses="text-center"
subHeaderClasses="mt-2" />
subHeaderClasses="mt-4" />
<div class="main-content-container">
<hr class="my-0" />
<reviewDropdown ref="reviewDropdown" />
@ -88,7 +83,6 @@ import { Form } from 'vee-validate';
import issPageValues from '@/router/router-constants/issPage-values';
import bailoutMessage from '@/constants/bailoutMessage';
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import VehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import { saveSession, submitWorkOrder } from '@/helpers/order-helper.js';
import { experimentSettings } from '@/constants/experiments';
import submitType from '@/constants/submit-type';
@ -106,8 +100,7 @@ export default {
reviewDropdown,
cartDropdown,
paymentMethodQuestion,
alert,
VehicleBanner
alert
},
mixins: [baseFormMixin],
async beforeRouteEnter(to, from, next) {
@ -305,10 +298,18 @@ export default {
<style lang="scss" scoped>
$page-side-padding: 1.5rem;
.iss-heritage-container-width {
.payment-method-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.main-content-container {
padding: 0;
}
padding: 0;
}
.page-container-grouped-styles {
overflow: auto;

View file

@ -191,7 +191,7 @@ const defaultOrder = {
damage: {
isRepair: false,
numberOfChips: null,
glassToReplace: [{location: 'windshield'}]
glassToReplace: [{ location: 'windshield' }]
},
lineItems: {
glassParts: [parts.windshield],
@ -380,7 +380,7 @@ describe('payment-page.vue', () => {
// Arrange
const { wrapper } = getMountedComponent(defaultOrder);
const outerDiv = wrapper.find('.container-fluid');
const outerDiv = wrapper.find('.fade-on-route-transition');
const clickFn = jest.fn();
outerDiv.element.addEventListener('click', clickFn);
@ -443,7 +443,7 @@ describe('payment-page.vue', () => {
const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.paymentMethod = paymentMethods.PayNow;
useMainStore().savePaymentMethodChoice = jest.fn().mockImplementation((value) => {useMainStore().order.payment.paymentMethod = value});
useMainStore().savePaymentMethodChoice = jest.fn().mockImplementation((value) => { useMainStore().order.payment.paymentMethod = value; });
// Act
wrapper.vm.handleIFrameContentWindowMessage(event);

View file

@ -1,13 +1,11 @@
<template>
<Form>
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="payment-page-container iss-heritage-content-container-width">
<alert
v-if="displayPayInAdvanceCreditCardAlert"
name="payInAdvanceCreditCardErrorAlert"
@ -787,12 +785,19 @@ export default {
};
</script>
<style lang="scss" scoped>
.container-fluid {
&.fade-on-route-transition {
height: unset;
.iss-heritage-container-width {
.payment-page-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.fade-on-route-transition {
height: unset;
}
.payment p {
margin-bottom: 0.75rem;
}

View file

@ -4,20 +4,18 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="policy-endorsements-container iss-heritage-content-container-width">
<siteSubHeader
ref="siteSubHeader"
cmsWidgetName="SiteSubHeaderWidget"
class="mt-5" />
class="mt-4" />
<buttonQuestion
v-if="educatorEndorsement"
ref="schoolPropertyQuestion"
@ -82,7 +80,7 @@ export default {
siteFooter,
buttonQuestion,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
Form
},
mixins: [BaseFormMixin],
async beforeRouteEnter(to, from, next) {
@ -92,8 +90,8 @@ export default {
const promiseResultMap = [
{
resultKey: 'cmsContent',
promise: cmsContentPromise,
},
promise: cmsContentPromise
}
];
// use resultMap to populate layout content.
const resultMap = await settleAllPromises(promiseResultMap);
@ -113,11 +111,11 @@ export default {
schoolPropertyAnswer: '',
parkingLotAnswer: '',
hasValidCarId:
this.mainStore.vehicle.carId &&
this.mainStore.vehicle.carId !== '0',
this.mainStore.vehicle.carId
&& this.mainStore.vehicle.carId !== '0',
rules: {
selectionRequired: globalRules.OPTION_REQUIRED,
},
selectionRequired: globalRules.OPTION_REQUIRED
}
};
},
computed: {
@ -135,18 +133,14 @@ export default {
},
educatorEndorsement() {
return (
useMainStore().order.policy.endorsements?.includes(
endorsementOptions.EDUCATOR
) ?? false
useMainStore().order.policy.endorsements?.includes(endorsementOptions.EDUCATOR) ?? false
);
},
parkingGuardEndorsement() {
return (
useMainStore().order.policy.endorsements?.includes(
endorsementOptions.PARKING_GUARD
) ?? false
useMainStore().order.policy.endorsements?.includes(endorsementOptions.PARKING_GUARD) ?? false
);
},
}
},
methods: {
async forwardButtonAction() {
@ -156,7 +150,7 @@ export default {
questionNum: 1,
endorsementName: endorsementOptions.EDUCATOR,
questionText: this.schoolPropertyQuestionText,
selectedAnswer: this.schoolPropertyAnswer,
selectedAnswer: this.schoolPropertyAnswer
});
}
if (this.parkingGuardEndorsement) {
@ -164,14 +158,12 @@ export default {
questionNum: 2,
endorsementName: endorsementOptions.PARKING_GUARD,
questionText: this.parkingLotQuestionText,
selectedAnswer: this.parkingLotAnswer,
selectedAnswer: this.parkingLotAnswer
});
}
// save answers to store as order.policy.endorsementQuestionAnswers
useMainStore().saveEndorsementQuestionAnswers(
this.questionAnswersArray
);
useMainStore().saveEndorsementQuestionAnswers(this.questionAnswersArray);
return this.navigateForward();
},
@ -188,24 +180,33 @@ export default {
this.$route
);
}
},
},
}
}
};
</script>
<style lang="scss" scoped>
:deep .subheader-primary {
.iss-heritage-container-width {
.policy-endorsements-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
:deep(.subheader-primary) {
margin-bottom: map-get($spacers, 2);
}
:deep .subheader-secondary {
:deep(.subheader-secondary) {
p {
font-size: $h6-font-size;
line-height: map-get($spacers, 5);
}
}
:deep .subheader-secondary.justify-content-center {
:deep(.subheader-secondary.justify-content-center) {
p {
text-align: left;
}
@ -215,7 +216,7 @@ export default {
margin-bottom: map-get($spacers, 5);
}
:deep .question-text {
:deep(.question-text) {
& > span {
text-align: left;
line-height: map-get($spacers, 5);
@ -223,7 +224,7 @@ export default {
margin-bottom: map-get($spacers, 2);
}
:deep div.question-text.d-flex {
:deep(div.question-text.d-flex) {
margin-top: map-get($spacers, 4);
}
</style>

View file

@ -63,7 +63,6 @@ function setupMocks() {
wrapper.vm.$router.navigateWithSpinner = jest.fn();
wrapper.vm.navigateBack = baseMixin.methods.navigateBack;
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
wrapper.vm.$refs.siteFooter.disableForwardButton = jest.fn();
wrapper.vm.$refs.siteFooter.enableForwardAction = jest.fn();

View file

@ -4,17 +4,16 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2 mb-5">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="policy-holder-details-container iss-heritage-content-container-width">
<siteSubHeader
id="sub-header"
cmsWidgetName="SiteSubHeaderWidget" />
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
<addressQuestions
id="address-questions-wrapper"
ref="addressQuestions"
@ -161,14 +160,13 @@ export default {
</script>
<style lang="scss" scoped>
#sub-header p {
font-size: 16px;
line-height: 26px;
color: #4d5151;
}
#address-questions-wrapper {
margin-top: 24px;
.iss-heritage-container-width {
.policy-holder-details-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
#address-questions-wrapper .alert.heading {

View file

@ -72,7 +72,6 @@ function setupMocks() {
wrapper.vm.setCmsContent = jest.fn();
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.siteFooter.updateButtonText = jest.fn();
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
wrapper.vm.$refs.siteFooter.disableForwardButton = jest.fn();
return { wrapper };
}

View file

@ -4,29 +4,23 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition policy-vehicles">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition policy-vehicles">
<div class="justify-content-center">
<siteHeader
class="header"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="policy-vehicles-container iss-heritage-content-container-width">
<div class="select-car-form rounded text-center">
<vehicleBanner
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric"
class="mt-2" />
<policyVehiclesQuestion
v-model="selectedVehicleVin"
cmsWidgetName="PolicyVehiclesQuestion"
:vehicles="VehiclesForQuestions"
:validationRules="rules.optionRequired" />
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
ref="AlertNoService"
class="mt-3"
cmsWidgetName="AlertVehicleSelection"
alertClass="alert-danger"
@ -47,7 +41,6 @@
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import policyVehiclesQuestion from '@/layouts/policy-vehicles/policy-vehicles-question/policy-vehicles-question.vue';
// Supporting files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper.js';
@ -72,7 +65,6 @@ export default {
components: {
siteHeader,
siteFooter,
vehicleBanner,
policyVehiclesQuestion,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
@ -94,7 +86,6 @@ export default {
return {
policyVehicles,
selectedVehicleVin: '',
displayGeneric: true,
policyVinFound: true,
rules: {
optionRequired: globalRules.OPTION_REQUIRED
@ -150,7 +141,6 @@ export default {
if (value === vehicleSelectionOptions.VEHICLE_NOT_LISTED) {
// clear previously selected vehicle and image
this.mainStore.resetVehicleState();
this.displayGeneric = true;
} else {
// get vehicle details from selected VIN
const vehicle = await this.lookupVehicleByVin(value);
@ -158,7 +148,6 @@ export default {
// handle error in case vehicle info doesn't come back for selected VIN
if (vehicle?.error === true) {
this.mainStore.resetVehicleState();
this.displayGeneric = true;
return;
}
if (!vehicle?.data.canSafeliteService) {
@ -167,7 +156,6 @@ export default {
}
if (vehicle) {
// save selected vehicle to the store
this.displayGeneric = false;
useMainStore().updateVehicle({
...vehicle.data,
policyVehicleId: this.selectedPolicyVehicle?.id,
@ -232,8 +220,7 @@ export default {
repairWaived: this.repairWaivedForSelectedVehicle,
endorsements: this.endorsementsForSelectedVehicle
});
}
else {
} else {
useMainStore().updateCoverageType(coverageType.NONE);
}
return this.navigateForward();
@ -292,6 +279,15 @@ export default {
};
</script>
<style lang="scss">
.iss-heritage-container-width {
.policy-vehicles-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.policy-vehicles {
.button-question {
.question-text {

View file

@ -1,26 +1,20 @@
<template>
<Form
ref="theForm"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition provider-preference">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
ref="theForm"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="fade-on-route-transition provider-preference">
<div class="justify-content-center">
<siteHeader
class="mt-4 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="provider-preference-container iss-heritage-content-container-width">
<siteSubHeader
id="sub-header"
cmsWidgetName="SiteSubHeader"
class="mb-0 mt-4 text-center" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<buttonQuestion
ref="buttonQuestion"
v-model="selectedProvider"
@ -238,7 +232,6 @@ export default {
if (this.mainStore.issConfig.enableTPAFlow) {
if (this.mainStore.hasRecalibrationPart) {
this.$refs[TPA_RECAL_MODAL_REF_NAME].openModal();
this.$refs[SITE_FOOTER_REF_NAME].removeLoader();
return;
}
scenario =
@ -267,6 +260,15 @@ export default {
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.provider-preference-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.provider-preference {
#sub-header span {
color: $black;

View file

@ -4,16 +4,14 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 col-xl-6">
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
class="header"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="schedule-page-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="ScheduleSubHeaderWidget"
subTextClasses="text-center small sub-text"
@ -492,8 +490,13 @@ export default {
<style lang="scss" scoped>
$page-side-padding: 1.5rem;
.page-container-grouped-styles {
overflow: auto;
.iss-heritage-container-width {
.schedule-page-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
:deep(.text-link-small) {

View file

@ -4,13 +4,15 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 col-xl-6">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="iss-heritage-container-width">
<div class="service-location-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-5" />
class="mt-4" />
<serviceZipModalQuestion
ref="serviceZipCodeQuestion"
v-model="serviceZipCodeQuestion"
@ -57,24 +59,18 @@
class="my-5"
cmsWidgetName="AlertBigTruckNoShopsWidget"
alertClass="alert-warning" />
</div>
</div>
<div class="row justify-content-center appointment-type">
<div class="col-md-6">
<appointmentTypeQuestion
v-show="isAppointmentTypeDisplayed"
ref="appointmentTypeQuestion"
v-model="selectedAppointmentType"
:isServiceableMobile="isServiceableMobile"
:isServiceableInshop="isServiceableInshop"
:isDisplayed="isAppointmentTypeDisplayed"
groupName="appointmentTypeQuestion"
cmsWidgetName="AppointmentTypeQuestionWidget"
validationRules="option-required" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="appointment-type">
<appointmentTypeQuestion
v-show="isAppointmentTypeDisplayed"
ref="appointmentTypeQuestion"
v-model="selectedAppointmentType"
:isServiceableMobile="isServiceableMobile"
:isServiceableInshop="isServiceableInshop"
:isDisplayed="isAppointmentTypeDisplayed"
groupName="appointmentTypeQuestion"
cmsWidgetName="AppointmentTypeQuestionWidget"
validationRules="option-required" />
</div>
<mobileLocationModalQuestions
v-if="isMobileLocationDisplayed"
ref="mobileLocationQuestions"
@ -549,8 +545,13 @@ export default {
<style lang="scss">
$page-side-padding: 1.5rem;
.fade-on-route-transition {
overflow: auto;
.iss-heritage-container-width {
.service-location-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.question-text {

View file

@ -4,16 +4,14 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition service-packages">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition service-packages">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="service-packages-container iss-heritage-content-container-width">
<siteSubHeader
class="mb-2 mt-4"
class="mt-4"
subHeaderClasses="mt-5"
justification="left"
cmsWidgetName="SiteSubHeaderWidget"
@ -114,11 +112,16 @@ export default {
const { feeItems } = store.order.lineItems;
const availableLineItems = [
resultMap.rainDefense,
...resultMap.wipers,
...feeItems
];
let availableLineItems = [];
if ( resultMap?.rainDefense?.length > 0 )
availableLineItems.push(resultMap.rainDefense);
if ( resultMap?.wipers?.length > 0 )
availableLineItems.push(...resultMap.wipers);
if ( feeItems?.length > 0 )
availableLineItems.push(...feeItems);
let hasBailedOut = false;
await store.getCombinedQuote(availableLineItems)
@ -197,8 +200,16 @@ export default {
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.service-packages-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.subheader-secondary {
margin-top: 0.5rem;
padding: 0px;

View file

@ -78,18 +78,18 @@ function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRu
const defaultOrder = {
serviceLocation: {
provider: {
companyName: "Hershey",
phoneNumber: "726-117-0377"
companyName: 'Hershey',
phoneNumber: '726-117-0377'
}
},
currentDeductible: 479,
isVerified: false,
carrierPhoneNumber: "757-277-0388",
carrierPhoneNumber: '757-277-0388',
vehicle: {
imageUrl: 'url for image',
category: 'car'
}
}
};
describe('TPAConfirmation.vue', () => {
describe('Rendering', () => {
@ -108,13 +108,6 @@ describe('TPAConfirmation.vue', () => {
// Assert
expect(siteHeader.exists()).toBe(true);
});
test('Should render Vehicle Banner', () => {
// Act
const vehicleBanner = wrapper.findComponent({ ref: 'vehicleBanner' });
// Assert
expect(vehicleBanner.exists()).toBe(true);
});
test('Should render Confirmation Body One', () => {
// Act
const bodyOne = wrapper.findComponent({ ref: 'tpaConfirmationBodyOne' });
@ -249,7 +242,7 @@ describe('TPAConfirmation.vue', () => {
[false, false, 0],
[false, false, 500],
[true, true, 0],
[false, true, 500]
[false, true, 500]
])('with argument zeroDeductible', (expected, isVerified, deductible) => {
test(`returns ${expected} when coverageStatus is ${getEnumName(coverageStatuses, status)} and currentDeductible is ${deductible}`, () => {
// Arrange

View file

@ -4,21 +4,14 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
ref="vehicleBanner"
class="mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<div class="iss-heritage-container-width">
<div class="tpa-confirmation-container iss-heritage-content-container-width">
<div class="d-flex justify-content-center align-items-center text-color--black pb-2 fs-5">
<img :src="tpaConfirmationImage" />
<span
@ -69,7 +62,6 @@
<script>
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import deductibleBox from '@/layouts/tpa-submit/deductible-box/deductible-box.vue';
@ -96,7 +88,6 @@ export default {
components: {
siteHeader,
siteFooter,
vehicleBanner,
textBlock,
deductibleBox,
// eslint-disable-next-line vue/no-reserved-component-names
@ -219,6 +210,15 @@ export default {
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.tpa-confirmation-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.text-color--black {
color: $black;
}

View file

@ -20,7 +20,6 @@ Object {
"shop": "PreferredShopSubTitle",
"vehicle": "VehicleSubTitle",
},
"vehicleBanner": "VehicleBannerWidget",
},
}
`;

View file

@ -120,20 +120,6 @@ describe('tpa-submit', () => {
expect(siteHeader.exists()).toBeTruthy();
expect(siteHeader.props().cmsWidgetName).toBe(expectedWidgetName);
});
test('vehicle banner', () => {
// Arrange
const wrapper = shallowMount(tpaSubmit, getMountOptions());
const expectedWidgetName = 'VehicleBannerWidget';
// Act
const vehicleBanner = wrapper.findComponent({ ref: 'vehicleBanner' });
// Assert
expect(vehicleBanner.exists()).toBeTruthy();
expect(vehicleBanner.props().cmsWidgetName).toBe(expectedWidgetName);
expect(vehicleBanner.props().displayGenericVehicleImage).toBe(false);
expect(vehicleBanner.classes()).toContain('mt-5');
});
test('sub header', () => {
// Arrange
const wrapper = shallowMount(tpaSubmit, getMountOptions());

View file

@ -5,21 +5,14 @@
class="tpa-submit"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader
ref="siteHeader"
:cmsWidgetName="widget.siteHeader" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
ref="vehicleBanner"
:cmsWidgetName="widget.vehicleBanner"
:displayGenericVehicleImage="false"
class="mt-5" />
<div class="iss-heritage-container-width">
<div class="tpa-submit-container iss-heritage-content-container-width">
<!-- TODO fix styling -->
<textBlock
ref="subHeaderTitle"
@ -56,8 +49,8 @@
v-for="(section, index) in sections"
:key="section.title">
<hr
v-if="index !== 0"
class="my-3" />
v-if="index !== 0"
class="my-3" />
<reviewBlock
:id="'review-block-' + index"
:customHeaderText="section.title"
@ -107,7 +100,6 @@ class="my-3" />
import siteHeader from '@/iss-components/site-header/site-header.vue';
import buttonMain from '@/ux-components/button-main/button-main.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import reviewBlock from '@/layouts/tpa-submit/review-block/review-block.vue';
import deductibleBox from '@/layouts/tpa-submit/deductible-box/deductible-box.vue';
import contactDetailsDrawer from '@/layouts/tpa-submit/contact-details-drawer/contact-details-drawer.vue';
@ -144,7 +136,6 @@ export default {
name: 'tpa-submit',
components: {
siteHeader,
vehicleBanner,
textBlock,
buttonMain,
reviewBlock,
@ -170,7 +161,6 @@ export default {
siteHeader: 'SiteHeaderWidget',
siteSubHeader: 'SiteSubHeaderWidget',
serviceSummary: 'ServiceSummaryContent',
vehicleBanner: 'VehicleBannerWidget',
subheader: {
vehicle: 'VehicleSubTitle',
damage: 'DamageSubTitle',
@ -326,12 +316,10 @@ export default {
this.getDamageLines,
() => this.navigate(this.navigationScenarios.EDIT_DAMAGE)
),
// eslint-disable-next-line max-len
this.getSection(
this.widget.subheader.shop,
this.getPreferredShopLines,
() =>
this.navigate(this.navigationScenarios.EDIT_PREFERRED_SHOP)
() => this.navigate(this.navigationScenarios.EDIT_PREFERRED_SHOP)
),
// eslint-disable-next-line max-len
this.getSection(
@ -389,6 +377,15 @@ export default {
};
</script>
<style lang="scss">
.iss-heritage-container-width {
.tpa-submit-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.tpa-submit {
#tpaSubmitOrderDetailsBody {
p {

View file

@ -41,7 +41,6 @@ const mountOptions = {
},
stubs: {
siteHeader: true,
vehicleBanner: true,
siteSubHeader: true,
siteDoorOptions: true,
damageLocationQuestion: true,

View file

@ -4,20 +4,15 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div
class="container-fluid fade-on-route-transition replace-options-question">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition replace-options-question">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
class="mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<siteSubHeader cmsWidgetName="SiteSubHeaderWidget" />
<div class="iss-heritage-container-width">
<div class="vehicle-damage-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
<alert
v-if="shouldDisplayVehicleChangeAlert"
ref="vehicleChangeAlert"
@ -25,71 +20,71 @@
cmsWidgetName="VehicleChangeAlert"
alertClass="alert-warning"
:isDismissible="false" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6">
<damageLocationQuestion
ref="damageLocation"
v-model="selectedDamageLocations"
cmsWidgetName="DamageLocationQuestion"
groupName="DamageLocationQuestion" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<windshieldOptions
ref="windshieldOptions"
v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<alert
v-if="hasRepairReplaceConflict"
class="my-5"
cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger"
:isDismissible="false" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<sideDoorOptions
v-show="!hasRepairReplaceConflict"
ref="sideDoorOptions"
v-model="sideDoorOptionsData"
cmsWidgetName="SideDoorSideQuestion"
groupName="SideDoorSideQuestion"
:selectedDamageLocations="selectedDamageLocations" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<replaceOptionsQuestion
ref="backGlassOptions"
v-model="selectedRearReplaceOptions"
cmsWidgetName="RearReplaceOptionsQuestion"
:isAvailable="
isRearWindowDamageLocation &&
!hasRepairReplaceConflict
"
groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<site-footer
ref="siteFooter"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction" />
<div class="justify-content-center">
<div class="vehicle-damage-question-container">
<damageLocationQuestion
ref="damageLocation"
v-model="selectedDamageLocations"
cmsWidgetName="DamageLocationQuestion"
groupName="DamageLocationQuestion" />
</div>
</div>
<div class="justify-content-center">
<div class="vehicle-damage-question-container">
<windshieldOptions
ref="windshieldOptions"
v-model="selectedWindshieldOptions"
:hasRepairReplaceConflict="hasRepairReplaceConflict"
:hasSplitSingleConflict="hasSplitSingleConflict"
:selectedDamageLocations="selectedDamageLocations" />
</div>
</div>
<div class="justify-content-center">
<div class="vehicle-damage-question-container">
<alert
v-if="hasRepairReplaceConflict"
class="my-5"
cmsWidgetName="HasReplacementConflict"
alertClass="alert-danger"
:isDismissible="false" />
</div>
</div>
<div class="justify-content-center">
<div class="vehicle-damage-question-container">
<sideDoorOptions
v-show="!hasRepairReplaceConflict"
ref="sideDoorOptions"
v-model="sideDoorOptionsData"
cmsWidgetName="SideDoorSideQuestion"
groupName="SideDoorSideQuestion"
:selectedDamageLocations="selectedDamageLocations" />
</div>
</div>
<div class="justify-content-center">
<div class="vehicle-damage-question-container">
<replaceOptionsQuestion
ref="backGlassOptions"
v-model="selectedRearReplaceOptions"
cmsWidgetName="RearReplaceOptionsQuestion"
:isAvailable="
isRearWindowDamageLocation &&
!hasRepairReplaceConflict
"
groupName="BackGlassReplaceOptionsQuestion"
validationRules="replace-options-required" />
</div>
</div>
<div class="justify-content-center">
<div class="vehicle-damage-question-container">
<site-footer
ref="siteFooter"
class="mt-5"
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="!meta.valid"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</div>
</div>
@ -100,7 +95,6 @@
// Components
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import sideDoorOptions from '@/layouts/vehicle-damage/side-door-options/side-door-options.vue';
import damageLocationQuestion from '@/layouts/vehicle-damage/damage-location-question/damage-location-question.vue';
@ -133,7 +127,6 @@ export default {
components: {
siteHeader,
siteFooter,
vehicleBanner,
siteSubHeader,
sideDoorOptions,
damageLocationQuestion,
@ -433,7 +426,6 @@ export default {
if (partsOrQuestionsResponse.error) {
this.mainStore.setBailout(bailoutMessage.PartsServiceError(partsOrQuestionsResponse.error.data));
window.console.error('Error on retrieving PartsOrQuestions');
this.$refs.siteFooter.removeLoader();
this.hasBailedOut = true;
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
@ -500,18 +492,21 @@ export default {
</script>
<style lang="scss">
.replace-options-question {
.row {
margin-top: 0;
.col-12 {
margin: 0 0 .5rem 0;
&:last-child {
margin-bottom: 0;
}
.iss-heritage-container-width {
.vehicle-damage-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
.question-text {
margin-top: 0; //would need deep is changed to scoped. Was already not scoped.
}
}
}
.replace-options-question {
.question-text {
margin: 0;
span {
padding: 1rem 0;
text-align: center;

View file

@ -118,8 +118,7 @@ function setupMocks() {
},
stubs: {
SiteHeader: true,
SiteSubHeader: true,
VehicleBanner: true
SiteSubHeader: true
}
}
});

View file

@ -1,41 +1,34 @@
<template>
<Form
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="select-car-form rounded">
<VehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<SiteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mb-2"
subHeaderMarginClasses="mt-1" />
<VinLookupMethods
ref="VinLookupMethods"
v-model="selectedVinLookupMethod"
cmsWidgetName="VINLookupMethod"
groupName="VinLookupMethods" />
<SiteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
class="mt-5"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction" />
</div>
<div class="iss-heritage-container-width">
<div class="vehicle-lookup-container iss-heritage-content-container-width">
<SiteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4"
subHeaderMarginClasses="mt-1" />
<VinLookupMethods
ref="VinLookupMethods"
v-model="selectedVinLookupMethod"
cmsWidgetName="VINLookupMethod"
groupName="VinLookupMethods" />
<SiteFooter
cmsWidgetName="SiteFooterWidget"
:isForwardActionDisabled="isForwardActionDisabled"
class="mt-5"
@backClicked="navigateBack"
@forwardClicked="forwardButtonAction" />
</div>
</div>
</div>
</Form>
</template>
<script>
// Import Supporting Files
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
@ -46,9 +39,8 @@ import vinLookupMethodSelections from '@/constants/vin-lookup-methods';
// Import Component
import SiteFooter from '@/iss-components/site-footer/site-footer.vue';
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 VehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import VinLookupMethods from '@/layouts/vehicle-lookup/vin-lookup-methods/vin-lookup-methods.vue';
export default {
@ -57,9 +49,8 @@ export default {
// eslint-disable-next-line vue/no-reserved-component-names
Form,
SiteFooter,
SiteHeader,
siteHeader,
SiteSubHeader,
VehicleBanner,
VinLookupMethods
},
mixins: [BaseFormMixin],
@ -123,3 +114,15 @@ export default {
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.vehicle-lookup-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
</style>

View file

@ -62,10 +62,6 @@ function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {}
const apiResponses = {
cmsContent: {
SiteSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleBannerWidget: {
GenericVehicleImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/blurred-image.jpg`
},
FunnelHeaderWidget: {
LogoImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/logos/insuranceLogo.jpg`
@ -95,7 +91,6 @@ function setupMocks({ pageHeaderWidgetHeaderText = {}, mountOptionsMockData = {}
partQuestionRearWrapper.vm.initializeComponent = glassPartQuestion.methods.initializeComponent;
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
return { wrapper, apiPromise };
}

View file

@ -1,47 +1,36 @@
<template>
<Form ref="theForm" @submit="onSubmit" @invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<Form
ref="theForm"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<vehicleBanner
ref="vehicleBanner"
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="false" />
<div class="iss-heritage-container-width">
<div class="vehicle-parts-container iss-heritage-content-container-width">
<siteSubHeader
ref="siteSubHeader"
class="mt-4"
cmsWidgetName="SiteSubHeaderWidget" />
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<alert
id="vehicle-parts-alert"
class="mt-3 mb-3"
alertClass="alert-warning"
cmsWidgetName="AlertWidget"
:isDismissible="false" />
<div v-for="(item, i) in PartsOrQuestions" :key="i">
<div
v-for="(item, i) in PartsOrQuestions"
:key="i">
<!-- Render horizontal lines if there is multi-glass (aka if i > 0) -->
<hr v-if="i > 0" />
<glassPartQuestion
:ref="`${RefPrefix}-${item.glassLocation}-${item.glassName}`"
v-model="
selectedGlassParts[
item.glassLocation + '-' + item.glassName
]
"
v-model="selectedGlassParts[item.glassLocation + '-' + item.glassName]"
:glassLocation="item.glassLocation"
:glassName="item.glassName"
:colorAnswers="item.colorAnswers"
:alreadyPopulatedPartsData="
alreadyPopulatedPartsData
" />
:alreadyPopulatedPartsData="alreadyPopulatedPartsData" />
</div>
<siteFooter
ref="siteFooter"
@ -60,7 +49,6 @@
// Components
import glassPartQuestion from '@/layouts/vehicle-parts/glass-part-question/glass-part-question.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import alert from '@/ux-components/alert/alert.vue';
@ -81,7 +69,6 @@ export default {
Form,
glassPartQuestion,
siteHeader,
vehicleBanner,
siteSubHeader,
siteFooter,
alert
@ -207,7 +194,6 @@ export default {
}
// If no parts could be matched, throw an error (isForwardActionDisabled is based off of matchedParts)
if (this.isForwardActionDisabled) {
this.$refs.siteFooter.removeLoader();
throw new Error('Could not match any parts to the selected parts');
}
@ -239,9 +225,18 @@ export default {
};
</script>
<style lang="scss" scoped>
#vehicle-parts-alert {
.alert-heading {
margin-top: 0.25rem !important;
.iss-heritage-container-width {
.vehicle-parts-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
#vehicle-parts-alert {
.alert-heading {
margin-top: 0.25rem !important;
}
}
}
}
</style>

View file

@ -4,22 +4,16 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader
class="mb-2 header"
cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="vehicle-selection-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="siteSubHeader"
justification="center"
class="mt-4"
darkGraySubText />
<vehicleQuestion
ref="vehicleYearQuestion"
v-model="selectedYear"
@ -52,14 +46,9 @@
:updateValues="updateStyleValues"
validationRules="style-required"
inputId="styleQuestionField" />
<vehicleBanner
ref="banner"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="displayGeneric"
class="mt-5 mb-3" />
<alert
ref="AlertNoService"
v-if="displayNoServiceAlert"
ref="AlertNoService"
class="mt-5"
cmsWidgetName="AlertVehicleSelection"
alertClass="alert-danger"
@ -82,7 +71,6 @@
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import vehicleQuestion from '@/layouts/vehicle-selection/vehicle-question/vehicle-question.vue';
import alert from '@/ux-components/alert/alert.vue';
import { useMainStore } from '@/store';
@ -107,7 +95,6 @@ export default {
components: {
siteHeader,
siteSubHeader,
vehicleBanner,
siteFooter,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
@ -150,9 +137,6 @@ export default {
};
},
computed: {
displayGeneric() {
return !this.selectedStyle;
}
},
watch: {
selectedYear(value) {
@ -188,7 +172,7 @@ export default {
this.selectedModel,
this.selectedStyle
).then((result) => {
this.displayNoServiceAlert = !result.data.canSafeliteService;
this.displayNoServiceAlert = !result.data.canSafeliteService;
});
}
},
@ -210,7 +194,7 @@ export default {
this.selectedModel,
this.selectedStyle
).then((result) => {
this.displayNoServiceAlert = !result.data.canSafeliteService;
this.displayNoServiceAlert = !result.data.canSafeliteService;
});
}
},
@ -223,94 +207,101 @@ export default {
},
navigateForward() {
this.mainStore.setVehicle().then(() => {
if (this.mainStore.isBailout) {
this.mainStore.setVehicle().then(
() => {
if (this.mainStore.isBailout) {
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
return;
}
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
},
(error) => {
// eslint-disable-next-line max-len
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, this.mainStore.vehicle.make, this.mainStore.vehicle.model, this.mainStore.vehicle.style, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
return;
}
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
},
(error) => {
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, this.mainStore.vehicle.make, this.mainStore.vehicle.model, this.mainStore.vehicle.style, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
});
);
},
async updateYearValues() {
return this.mainStore.getVehicleYears().then((response) => {
return response;
},
(error) => {
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(null, null, null, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
});
return this.mainStore.getVehicleYears().then(
(response) => response,
(error) => {
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(null, null, null, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
}
);
},
async updateMakeValues() {
return this.mainStore.getVehicleMakes().then((response) => {
return response;
},
(error) => {
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, null, null, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
});
return this.mainStore.getVehicleMakes().then(
(response) => response,
(error) => {
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, null, null, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
}
);
},
async updateModelValues() {
return this.mainStore.getVehicleModels().then((response) => {
return response;
},
(error) => {
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, this.mainStore.vehicle.make, null, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
});
return this.mainStore.getVehicleModels().then(
(response) => response,
(error) => {
// eslint-disable-next-line max-len
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, this.mainStore.vehicle.make, null, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
}
);
},
async updateStyleValues() {
return this.mainStore.getVehicleStyles().then((response) => {
return response;
},
(error) => {
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, this.mainStore.vehicle.make, this.mainStore.vehicle.model, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
});
return this.mainStore.getVehicleStyles().then(
(response) => response,
(error) => {
// eslint-disable-next-line max-len
this.mainStore.setBailout(bailoutMessage.vehicleYMMSLookupError(this.mainStore.vehicle.year, this.mainStore.vehicle.make, this.mainStore.vehicle.model, null, error));
this.$router.navigate(
this.navigationScenarios.CLICKED_FORWARD_WITH_BAILOUT,
this.$route
);
}
);
},
resetAlert() {
this.displayNoServiceAlert = false;
}
}
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.vehicle-selection-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
.select-car-form {
margin-left: 0.75rem;
margin-right: 0.75rem;
}
.siteSubHeader {
margin-top: 1.5rem;
}
.subheader-secondary {
margin-top: 0.5rem;
padding: 0px;
}
</style>

View file

@ -202,7 +202,6 @@ const mountOptions = {
stubs: {
siteHeader: true,
siteSubHeader: true,
vehicleBanner: true,
vinLocationInformation: true,
vinLookupAlerts: true,
vinQuestion: true

View file

@ -4,21 +4,16 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="vin-lookup-container iss-heritage-content-container-width">
<div class="select-car-form rounded">
<vehicleBanner
class="mt-2 mb-4"
cmsWidgetName="VehicleBannerWidget"
:displayGenericVehicleImage="!carIdIsValid" />
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4"
subHeaderMarginClasses="mt-1" />
<vinLookupAlerts
class="mt-5"
@ -42,6 +37,7 @@
</div>
</Form>
</template>
<script>
// Import Supporting Files
import { computed } from 'vue';
@ -59,7 +55,6 @@ import { Form } from 'vee-validate';
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
import siteHeader from '@/iss-components/site-header/site-header.vue';
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
import vehicleBanner from '@/iss-components/vehicle-banner/vehicle-banner.vue';
import vinLocationInformation from '@/layouts/vin-lookup/vin-location-information/vin-location-information.vue';
import vinLookupAlerts from '@/layouts/vin-lookup/vin-lookup-alerts/vin-lookup-alerts.vue';
import vinQuestion from '@/layouts/vin-lookup/vin-question/vin-question.vue';
@ -73,7 +68,6 @@ export default {
siteSubHeader,
// eslint-disable-next-line vue/no-reserved-component-names
Form,
vehicleBanner,
vinLocationInformation,
vinLookupAlerts,
vinQuestion
@ -149,9 +143,6 @@ export default {
return `!X!X!X!X!X!X!X!X!X!X!X${lastSixChars}`;
}
return '*****************';
},
carIdIsValid() {
return this.hasValidCarId();
}
},
watch: {
@ -188,7 +179,6 @@ export default {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NOT_FOUND;
this.mainStore.setBailout(bailoutMessage.vehicleNotFound(this.vin));
this.resetVehicleFromLookup();
this.$refs.siteFooter.removeLoader();
// Temp solution to turn on 'disabled' style on the Continue button
// because the form itself actually passes its client-side validation.
// SSR-189 Scenario #4.
@ -200,7 +190,6 @@ export default {
this.activeVehicleLookupAlertType = vehicleLookupAlertTypes.NO_SERVICE;
this.resetVehicleFromLookup();
this.$refs.siteFooter.disableForwardButton();
this.$refs.siteFooter.removeLoader();
return;
}
@ -227,8 +216,6 @@ export default {
// eslint-disable-next-line max-len
`${this.vehicleFromLookup.year} ${this.vehicleFromLookup.make} ${this.vehicleFromLookup.model} ${this.forwardButtonCarStyle}`;
this.$refs.siteFooter.updateButtonText(`Continue with ${vehicleYearMakeModelStyle}`);
this.$refs.siteFooter.removeLoader();
this.needToLookupVehicle = false;
return null;
@ -311,3 +298,14 @@ export default {
}
};
</script>
<style lang="scss" scoped>
.iss-heritage-container-width {
.vin-lookup-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
</style>

View file

@ -58,10 +58,6 @@ function setupMocks({
const apiResponses = {
cmsContent: {
SiteSubHeaderWidget: pageHeaderWidgetHeaderText,
VehicleBannerWidget: {
GenericVehicleImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/blurred-image.jpg`
},
SiteHeaderWidget: {
LogoImage:
`${applicationConfig.ISS_DEV_CMS_DOMAIN}/images/default-source/default-album/logos/insuranceLogo.jpg`
@ -91,7 +87,6 @@ function setupMocks({
wrapper.vm.setCmsContent = baseMixin.methods.setCmsContent;
wrapper.vm.getCmsContent = jest.fn().mockImplementation(() => '');
wrapper.vm.$refs.siteFooter.removeLoader = jest.fn();
return { wrapper, apiPromise };
}

View file

@ -4,14 +4,12 @@
v-slot="{ meta }"
@submit="onSubmit"
@invalidSubmit="onInvalidSubmit">
<div class="container-fluid fade-on-route-transition">
<div class="row justify-content-center">
<div class="col-md-6 px-0 px-md-2">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="fade-on-route-transition">
<div class="justify-content-center">
<siteHeader cmsWidgetName="SiteHeaderWidget" />
</div>
<div class="row justify-content-center">
<div class="col-md-6 col-xl-4">
<div class="iss-heritage-container-width">
<div class="welcome-page-container iss-heritage-content-container-width">
<siteSubHeader
cmsWidgetName="SiteSubHeaderWidget"
class="mt-4" />
@ -23,8 +21,7 @@
isRequired
disableAutoFill
:isDisabled="isPolicyHolderDisabled"
:validationRules="rules.policyNumber"
class="mt-5" />
:validationRules="rules.policyNumber" />
<textboxQuestion
ref="policyZip"
v-model="welcomePageModel.policyZipCode"
@ -144,9 +141,6 @@
</div>
</div>
</div>
<!-- Footer image component must have parent (usually container-fluid)
set to display: flex and height 100dvh or height 100% -->
<footerImage />
</div>
</Form>
</template>
@ -163,7 +157,6 @@ import textboxQuestion from '@/digital-components/textbox-question/textbox-quest
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
import dropdownQuestion from '@/digital-components/dropdown-question/dropdown-question.vue';
import textBlock from '@/digital-components/text-block/text-block.vue';
import footerImage from '@/iss-components/site-footer/footer-image/footer-image.vue';
// Supporting files
import {
@ -196,7 +189,6 @@ export default {
components: {
siteHeader,
siteSubHeader,
footerImage,
alert,
buttonQuestion,
continueModal,
@ -340,7 +332,6 @@ export default {
return Promise.resolve();
} catch (e) {
this.displayInvalidZipAlert = true;
this.$refs.siteFooter.removeLoader();
return Promise.reject(e);
}
},
@ -462,11 +453,8 @@ export default {
console.error(`Error on loading session from cookie ${error}`);
this.startNewReferral();
} finally {
this.$refs.continueModal.removeLoader();
this.$refs.continueModal.closeModal();
}
} else {
this.$refs.continueModal.removeLoader();
}
},
startNewReferral() {
@ -482,13 +470,22 @@ export default {
<style lang="scss" scoped>
form {
height: 100dvh;
.container-fluid {
display: flex;
flex-direction: column;
height: 100%;
}
}
.iss-heritage-container-width {
.welcome-page-container {
position: relative;
min-height: 1px;
padding-left: .9375rem;
padding-right: .9375rem;
}
}
@-moz-document url-prefix() {
// Temporary solution that prevents the Continue button from being hidden in Firefox
#welcomeFooter {

View file

@ -1177,7 +1177,8 @@ export const useMainStore = defineStore({
},
Provider: {
ProviderNumber: this.providerNumber,
ProviderCtuNumber: serviceLocation.zipCodeCtu
ProviderCtuNumber: serviceLocation.zipCodeCtu,
ProviderState: serviceLocation.state
},
Vehicle: {
CarId: vehicle.carId,
@ -1241,6 +1242,17 @@ export const useMainStore = defineStore({
if (availableLineItems && availableLineItems.length > 0) {
const { vehicle, serviceLocation, policy, eon, referralNumber, referralDate, referralSequenceNumber, lineItems } = this.order;
const availableLineItemsFiltered = availableLineItems.filter((lineItem) => {
if ( lineItem.partNumber )
return true;
else
return false;
});
const lineItemsWithOnlyPartNumbers = availableLineItemsFiltered.map((lineItem) => {
return {partNumber: lineItem.partNumber};
});
const payload = {
ParentAccountNumber: this.order.parentAccountNumber,
BillToAccountNumber: this.billToAccountNumber,
@ -1258,7 +1270,7 @@ export const useMainStore = defineStore({
ServiceZipCode: serviceLocation.zipCode,
IsReplacement: !this.isRepair,
ServerData: lineItems.serverData,
LineItems: getLineItemsFlattened(availableLineItems),
LineItems: lineItemsWithOnlyPartNumbers,
FeatureToggles: getFeatureTogglesPayloadObject(this.experimentSettings)
};
@ -2624,6 +2636,7 @@ export const useMainStore = defineStore({
if (zipInfo?.isValid === true) {
this.order.serviceLocation.zipCodeCtu = zipInfo.zipCodeCtu;
this.order.serviceLocation.defaultProviderNumber = zipInfo.providerNumber;
this.order.serviceLocation.state = zipInfo.state;
return Promise.resolve(zipInfo);
}

View file

@ -8,16 +8,8 @@
$accent-fill: #e6f1f3; // Calendar background
$accent-color: #09748b;
$link: #09748b;
$button-color: #a9e3e9;
$button-text-color: #181643;
$svg-fill-color: '%2309748b'; // Color of calendar icon. Place HEX code *after* %23
//Variables
--iss-loader-color: #{$button-text-color};
.site-header {
background-color: $header-background;
}
$progress-bar-color: #181643;
svg,
.modal-text {
@ -30,52 +22,22 @@
background-image: url("data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M14.1762 1.52764H13.7656V1.50352C13.7656 1.10476 13.6076 0.722334 13.3263 0.44037C13.0451 0.158406 12.6636 0 12.2659 0C11.8681 0 11.4866 0.158406 11.2054 0.44037C10.9241 0.722334 10.7661 1.10476 10.7661 1.50352V1.52764H5.42476V1.50352C5.42476 1.10476 5.26675 0.722334 4.9855 0.44037C4.70424 0.158406 4.32277 0 3.92501 0C3.52725 0 3.14579 0.158406 2.86453 0.44037C2.58327 0.722334 2.42526 1.10476 2.42526 1.50352V1.52764H1.82376C1.34046 1.52891 0.877316 1.72195 0.53557 2.06455C0.193824 2.40716 0.00127018 2.87146 0 3.35598V14.1717C0.0016909 14.656 0.194379 15.1201 0.536035 15.4626C0.87769 15.8051 1.34059 15.9983 1.82376 16H14.1746C14.6581 15.9987 15.1214 15.8057 15.4634 15.4632C15.8054 15.1206 15.9983 14.6563 16 14.1717V3.35598C15.9987 2.87146 15.8062 2.40716 15.4644 2.06455C15.1227 1.72195 14.6595 1.52891 14.1762 1.52764ZM11.8889 1.50352C11.8889 1.4033 11.9286 1.30718 11.9993 1.23631C12.07 1.16544 12.1659 1.12563 12.2659 1.12563C12.3658 1.12563 12.4617 1.16544 12.5324 1.23631C12.6031 1.30718 12.6428 1.4033 12.6428 1.50352V2.99899C12.6428 3.09922 12.6031 3.19534 12.5324 3.2662C12.4617 3.33707 12.3658 3.37688 12.2659 3.37688C12.1659 3.37688 12.07 3.33707 11.9993 3.2662C11.9286 3.19534 11.8889 3.09922 11.8889 2.99899V1.50352ZM3.54807 1.50352C3.54807 1.4033 3.58778 1.30718 3.65847 1.23631C3.72916 1.16544 3.82504 1.12563 3.92501 1.12563C4.02498 1.12563 4.12086 1.16544 4.19155 1.23631C4.26224 1.30718 4.30195 1.4033 4.30195 1.50352V2.99899C4.30195 3.09922 4.26224 3.19534 4.19155 3.2662C4.12086 3.33707 4.02498 3.37688 3.92501 3.37688C3.82504 3.37688 3.72916 3.33707 3.65847 3.2662C3.58778 3.19534 3.54807 3.09922 3.54807 2.99899V1.50352ZM14.8772 14.1717C14.8747 14.3573 14.8001 14.5345 14.6691 14.6658C14.5382 14.797 14.3614 14.8719 14.1762 14.8744H1.82536C1.63995 14.8723 1.4627 14.7976 1.33144 14.6663C1.20018 14.5351 1.12531 14.3575 1.12281 14.1717V6.59296H14.8772V14.1717Z' fill='" + $svg-fill-color + "'/%3E%3Cpath d='M2.33063 11.282H3.93464V12.6006C3.93464 12.7499 3.99379 12.8931 4.09907 12.9986C4.20435 13.1041 4.34715 13.1634 4.49604 13.1634C4.64494 13.1634 4.78773 13.1041 4.89301 12.9986C4.9983 12.8931 5.05745 12.7499 5.05745 12.6006V11.282H7.46346V12.6006C7.46346 12.7499 7.52261 12.8931 7.62789 12.9986C7.73318 13.1041 7.87597 13.1634 8.02486 13.1634C8.17376 13.1634 8.31655 13.1041 8.42184 12.9986C8.52712 12.8931 8.58627 12.7499 8.58627 12.6006V11.282H10.9923V12.6006C10.9923 12.7499 11.0514 12.8931 11.1567 12.9986C11.262 13.1041 11.4048 13.1634 11.5537 13.1634C11.7026 13.1634 11.8454 13.1041 11.9507 12.9986C12.0559 12.8931 12.1151 12.7499 12.1151 12.6006V11.282H13.7191C13.868 11.282 14.0108 11.2227 14.1161 11.1172C14.2214 11.0116 14.2805 10.8685 14.2805 10.7192C14.2805 10.57 14.2214 10.4268 14.1161 10.3213C14.0108 10.2157 13.868 10.1564 13.7191 10.1564H12.1151V8.84425C12.1151 8.69498 12.0559 8.55183 11.9507 8.44628C11.8454 8.34073 11.7026 8.28143 11.5537 8.28143C11.4048 8.28143 11.262 8.34073 11.1567 8.44628C11.0514 8.55183 10.9923 8.69498 10.9923 8.84425V10.1628H8.58627V8.84425C8.58627 8.69498 8.52712 8.55183 8.42184 8.44628C8.31655 8.34073 8.17376 8.28143 8.02486 8.28143C7.87597 8.28143 7.73318 8.34073 7.62789 8.44628C7.52261 8.55183 7.46346 8.69498 7.46346 8.84425V10.1628H5.05745V8.84425C5.05745 8.69498 4.9983 8.55183 4.89301 8.44628C4.78773 8.34073 4.64494 8.28143 4.49604 8.28143C4.34715 8.28143 4.20435 8.34073 4.09907 8.44628C3.99379 8.55183 3.93464 8.69498 3.93464 8.84425V10.1628H2.33063C2.18174 10.1628 2.03894 10.2221 1.93366 10.3277C1.82837 10.4332 1.76923 10.5764 1.76923 10.7257C1.76923 10.8749 1.82837 11.0181 1.93366 11.1236C2.03894 11.2292 2.18174 11.2885 2.33063 11.2885V11.282Z' fill='" + $svg-fill-color + "'/%3E%3C/svg%3E");
}
a,
a.new-window-link {
color: $link;
}
.btn {
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
}
}
}
&.modal-open {
.modal {
.modal-body {
.btn {
&.btn-override[aria-disabled="false"]:not(.form-test-invalid) {
&.btn-primary {
background: $button-color;
color: $button-text-color;
}
.progress-bar-container {
.progress-bar-header {
color: $progress-bar-color;
}
&:focus-visible {
background: $button-color;
color: $button-text-color;
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $button-color;
}
.progress {
.progress-bar {
background-color: $progress-bar-color;
}
}
}
.modal-footer {
.btn:not(.navigation-link) {
background: $button-color;
color: $button-text-color;
.progress-bar-middle {
background-color: $progress-bar-color;
}
}
}

View file

@ -1,3 +1,5 @@
@import "@/styles/ux-variables-svg-strings.scss";
html {
.has-error {
@ -111,27 +113,20 @@ html {
input,
input.form-control,
select,
select.form-select {
border: 1px solid $red;
&:focus {
border: 1px solid transparent;
box-shadow: 0 0 0 2.5px $red;
}
&:hover {
box-shadow: 0px 0px 0px 4px $red-200;
border-radius: 0.5rem;
border: 1px solid $red;
}
select.form-select,
input:focus,
input.form-control:focus,
input.form-control:focus-within,
select:focus,
select.form-select:focus {
border-color: $red;
}
select,
select.form-select {
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%23d4281c'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 0.75rem center;
background-size: 16px 12px;
select.form-select,
select:focus,
select.form-select:focus {
background-image: url(~@/assets/img/icons/select-error.png);
}
}
}
@ -208,22 +203,8 @@ html {
.form-test-invalid {
&.btn.btn-primary {
color: $gray-600;
background: $gray-200;
cursor: pointer;
pointer-events: all;
font-weight: $font-weight-normal;
}
&.btn.btn-primary:hover,
&.btn.btn-primary:focus {
color: $gray-600;
background: $gray-200;
box-shadow: none;
}
&.btn.btn-primary:focus-visible {
box-shadow: 0 0 0 3px $white, 0 0 0 5.5px $gray-700;
}
}
}

View file

@ -127,6 +127,51 @@ body {
}
}
#app {
display: flex;
flex-direction: column;
height: 100dvh;
>form {
flex: 1 0 auto;
}
>.footer-menu-container {
flex: 0 0 auto;
}
@include media-breakpoint-up(xs) {
overflow: auto;
}
.iss-heritage-container-width {
margin-left: auto;
margin-right: auto;
@include media-breakpoint-up(xs) {
width: 100%;
}
@include media-breakpoint-up(md) {
width: 46.25rem; // 740px
}
@include media-breakpoint-up(xl) {
width: 63.75rem; // 1020px
}
}
.iss-heritage-content-container-width {
@include media-breakpoint-up(xs) {
width: 100%;
}
@include media-breakpoint-up(md) {
width: 58.33333333%;
}
}
}
:root {
--iss-loader-color: white;
}

View file

@ -73,55 +73,55 @@ caption,
// Urbanist Fonts
@font-face {
font-family: "UrbanistRegular";
src:
url("@/assets/fonts/Urbanist-Regular.woff") format("woff2"),
url("@/assets/fonts/Urbanist-Regular.woff2") format("woff");
font-weight: normal;
font-style: normal;
font-family: "Urbanist";
src:
url("@/assets/fonts/Urbanist-Regular.woff2") format("woff2"),
url("@/assets/fonts/Urbanist-Regular.woff") format("woff");
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: "UrbanistSemibold";
src:
url("@/assets/fonts/Urbanist-SemiBold.woff") format("woff2"),
url("@/assets/fonts/Urbanist-SemiBold.woff2") format("woff");
font-weight: normal;
font-style: normal;
font-family: "Urbanist";
src:
url("@/assets/fonts/Urbanist-SemiBold.woff2") format("woff2"),
url("@/assets/fonts/Urbanist-SemiBold.woff") format("woff");
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: "UrbanistBold";
src:
url("@/assets/fonts/Urbanist-Bold.woff") format("woff2"),
url("@/assets/fonts/Urbanist-Bold.woff2") format("woff");
font-weight: normal;
font-style: normal;
font-family: "Urbanist";
src:
url("@/assets/fonts/Urbanist-Bold.woff2") format("woff2"),
url("@/assets/fonts/Urbanist-Bold.woff") format("woff");
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: "UrbanistExtraBold";
src:
url("@/assets/fonts/Urbanist-ExtraBold.woff") format("woff2"),
url("@/assets/fonts/Urbanist-ExtraBold.woff2") format("woff");
font-weight: normal;
font-style: normal;
font-family: "Urbanist";
src:
url("@/assets/fonts/Urbanist-ExtraBold.woff2") format("woff2"),
url("@/assets/fonts/Urbanist-ExtraBold.woff") format("woff");
font-weight: 800;
font-style: normal;
}
@font-face {
font-family: "UrbanistMedium_Italic";
src:
url("@/assets/fonts/Urbanist-MediumItalic.woff") format("woff2"),
url("@/assets/fonts/Urbanist-MediumItalic.woff2") format("woff");
font-weight: normal;
font-style: normal;
font-family: "Urbanist";
src:
url("@/assets/fonts/Urbanist-MediumItalic.woff2") format("woff2"),
url("@/assets/fonts/Urbanist-MediumItalic.woff") format("woff");
font-weight: 500;
font-style: italic;
}
@font-face {
font-family: "UrbanistBold_Italic";
src:
url("@/assets/fonts/Urbanist-BoldItalic.woff") format("woff2"),
url("@/assets/fonts/Urbanist-BoldItalic.woff2") format("woff");
font-weight: normal;
font-style: normal;
}
font-family: "Urbanist";
src:
url("@/assets/fonts/Urbanist-BoldItalic.woff2") format("woff2"),
url("@/assets/fonts/Urbanist-BoldItalic.woff") format("woff");
font-weight: 700;
font-style: italic;
}

View file

@ -117,7 +117,7 @@ $theme-colors: (
$body-color: $gray-600;
//Fonts
$font-family-sans-serif: UrbanistRegular, Roboto, Arial, sans-serif;
$font-family-sans-serif: Urbanist, Roboto, Arial, sans-serif;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
monospace;
// stylelint-enable value-keyword-case
@ -155,6 +155,9 @@ $border-radius-sm: 0.2rem;
$border-radius-lg: 0.5rem; //Used for buttons. Can be used for other things, of course.
$border-radius-pill: 50rem;
//Progress Bar Styling
$progress-bar-color: $green;
//Spacing
// 8 spacers available instead of the usual 5
$spacer: 1rem;
@ -193,6 +196,7 @@ $box-shadow: 0 0.5rem 1rem rgba($black, 0.15);
$box-shadow-sm: 0 0.125rem 0.25rem rgba($black, 0.075);
$box-shadow-lg: 0 1rem 3rem rgba($black, 0.25); //Safelite default
$box-shadow-inset: inset 0 1px 2px rgba($black, 0.075);
$box-shadow-input: rgba($black, 0.2) 0rem 0.0625rem 0.3125rem 0rem;
//Alerts
$alert-bg-scale: -90%;
@ -209,3 +213,6 @@ $enable-important-utilities: false;
// Letter Spacing
$letter-spacing-primary: 0.03em;
// Borders
$border-input: 1px solid rgba(179, 180, 181);
$border-input-focus: 2.5px solid $blue;

View file

@ -1,6 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper.js';
import { nextTick } from 'vue';
import buttonMain from '@/ux-components/button-main/button-main.vue';
/** @ignore */
@ -48,27 +47,4 @@ describe('buttonMain.vue', () => {
// Expect
expect(button.attributes()['aria-disabled']).toEqual('true');
});
it('Should return loader position', async () => {
// Act
const wrapper = shallowMount(
buttonMain,
setupMocks({
propsData: {
loaderPosition: 'right',
loaderEnabled: true
}
})
);
// Assert
wrapper.vm.clicked();
await nextTick();
const loader = wrapper.find('loader-stub');
expect(loader.attributes('class')).toContain('right');
});
});

View file

@ -5,25 +5,15 @@
:class="[
isPrimary ? 'btn-primary' : 'btn-secondary',
isFloat ? 'float-end' : '',
isLoaderDisplayed ? 'has-loader' : '',
]"
@click="clicked">
<span class="m-0">{{ buttonText }}</span>
<loader
v-if="isLoaderDisplayed && !suppressLoader"
class="ms-2"
:class="[loaderPosition]" />
</button>
</template>
<script>
import loader from '@/ux-components/loader/loader.vue';
export default {
name: 'button-main',
components: {
loader
},
props: {
isPrimary: Boolean,
buttonText: String,
@ -33,66 +23,59 @@ export default {
suppressLoader: Boolean
},
emits: ['click-event'],
data() {
return {
isLoaderDisplayed: false
};
},
methods: {
removeLoader() {
this.isLoaderDisplayed = false;
},
clicked() {
if (!this.isDisabled) {
this.isLoaderDisplayed = true;
this.$emit('click-event');
}
},
resetButtonStyle() {
this.isLoaderDisplayed = false;
}
}
};
</script>
<style lang="scss" scoped>
$border-radius-heritage: 1.40625rem; // 22.5px
$button-height-heritage: 2.8125rem; // 45px
$button-width-heritage: 9.0625rem; // 145px
.btn {
&.btn-primary {
position: relative;
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
background: #0c7e47;
padding-left: 2rem;
padding-right: 2rem;
min-height: $button-height-heritage;
min-width: $button-width-heritage;
border: none;
border-radius: $border-radius-lg;
border-radius: $border-radius-heritage;
color: $white;
justify-content: center;
font-weight: 500;
font-weight: 600;
letter-spacing: inherit;
@media (hover: hover) {
background: linear-gradient(270deg, $blue 0%, $blue-800 100%);
}
// Mouse, touch, stylus focus
&:focus-visible {
&:focus {
// Keyboard focus for accessibility
outline: none;
box-shadow: 0 0 0 3px, 0 0 0 5.5px $blue-700;
color: $white;
background: linear-gradient(270deg, rgba(6, 87, 124, 1) 0%, rgba(6, 87, 124, 1) 100%);
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #0c7e47;
}
&:hover {
// Keyboard focus for accessibility
color: #fff;
background-color: #084f2d;
border-color: #042f1a;
}
&:active {
outline: none;
background-color: #0c7e47;
box-shadow: 0 0 0 3px #fff, 0 0 0 5.5px #0c7e47;
}
&:disabled {
background: $gray-200 !important;
background: linear-gradient(270deg, $gray-200 0%, $gray-200 100%) !important;
background: red;
color: $gray-600 !important;
font-weight: 400;
height: 48px;
border: none;
border-radius: $border-radius-lg;
border-radius: $border-radius-heritage;
cursor: pointer;
pointer-events: all;
}
&.has-loader {
color: $white;
background: $blue-700;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
@ -102,11 +85,10 @@ export default {
position: relative;
background: transparent;
border: 1px solid $blue;
border-radius: $border-radius-lg;
border-radius: $border-radius-heritage;
color: $blue;
font-weight: 500;
transition: all 150ms linear;
height: 3rem;
&:hover {
color: $white;
@include blue-gradient;
@ -123,16 +105,11 @@ export default {
background: transparent;
color: $gray-550 !important;
font-weight: 400;
height: 48px;
border: 1px solid $gray-550;
border-radius: $border-radius-lg;
border-radius: $border-radius-heritage;
cursor: pointer;
pointer-events: all;
}
&.has-loader {
color: $white;
@include blue-gradient;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;

View file

@ -45,97 +45,6 @@ describe('modal-button-main.vue', () => {
expect(button.attributes()['aria-disabled']).toEqual('true');
});
it('Should return loader color', async () => {
// Arrange
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
loaderColor: 'blue',
loaderEnabled: true
}
})
);
// Act
wrapper.vm.clicked();
await nextTick();
// Assert
const loader = wrapper.find('loader-stub');
expect(loader.attributes('class')).toContain('blue');
});
it('Should return loader position', async () => {
// Arrange
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
loaderPosition: 'right',
loaderEnabled: true
}
})
);
// Act
wrapper.vm.clicked();
await nextTick();
// Assert
const loader = wrapper.find('loader-stub');
expect(loader.attributes('class')).toContain('right');
});
it("Should set 'isLoaderDisplayed' to false when calling 'removeLoader'", async () => {
// Arrange
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
loaderPosition: 'right',
loaderEnabled: true
}
})
);
wrapper.setData({
isLoaderDisplayed: true
});
// Act
wrapper.vm.removeLoader();
await nextTick();
// Assert
expect(wrapper.vm.isLoaderDisplayed).toBe(false);
});
it("Should set 'isLoaderDisplayed' to false when calling 'resetButtonStyle'", async () => {
// Arrange
const wrapper = shallowMount(
modalButtonMain,
setupMocks({
propsData: {
loaderPosition: 'right',
loaderEnabled: true
}
})
);
wrapper.setData({
isLoaderDisplayed: true
});
// Act
wrapper.vm.resetButtonStyle();
await nextTick();
// Assert
expect(wrapper.vm.isLoaderDisplayed).toBe(false);
});
it("Should emit 'click-event' event when clicking if the button is enabled", async () => {
// Arrange
const wrapper = shallowMount(

View file

@ -6,25 +6,16 @@
:class="[
isPrimary ? 'btn-primary' : 'btn-secondary',
isFloat ? 'float-end' : '',
isLoaderDisplayed ? 'has-loader' : '',
]"
@click="clicked">
<span class="m-0">{{ buttonText }}</span>
<loader
v-if="isLoaderDisplayed && !suppressLoader"
class="ms-2"
:class="[loaderColor, loaderPosition]" />
</button>
</template>
<script>
import loader from '@/ux-components/loader/loader.vue';
export default {
name: 'modal-button-main',
components: {
loader
},
props: {
isPrimary: Boolean,
buttonText: String,
@ -35,15 +26,7 @@ export default {
suppressLoader: Boolean
},
emits: ['click-event'],
data() {
return {
isLoaderDisplayed: false
};
},
methods: {
removeLoader() {
this.isLoaderDisplayed = false;
},
clicked() {
this.pushEventToGA(
this.$route.query[this.queryStrings.ISS_PAGE],
@ -52,12 +35,8 @@ export default {
true
);
if (!this.isDisabled) {
this.isLoaderDisplayed = true;
this.$emit('click-event');
}
},
resetButtonStyle() {
this.isLoaderDisplayed = false;
}
}
};
@ -97,11 +76,6 @@ export default {
cursor: pointer;
pointer-events: all;
}
&.has-loader {
color: $white;
background: $blue-700;
pointer-events: none;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;
@ -138,11 +112,6 @@ export default {
cursor: pointer;
pointer-events: all;
}
&.has-loader {
color: $white;
@include blue-gradient;
pointer-events: none;
}
&.delay {
// fixes flicker while transitioning between states
transition: background 0s 0s ease-in-out;

View file

@ -21,7 +21,10 @@
@click="handleClick">
{{ text }}<slot name="after-text"></slot>
</a>
<a v-else-if="linkType === 'text'" :href="href" @click="handleClick">
<a
v-else-if="linkType === 'text'"
:href="href"
@click="handleClick">
{{ text }}<slot name="after-text"></slot>
</a>
<a
@ -29,9 +32,7 @@
class="new-window-link"
:href="href"
target="_blank"
@click="handleClick"
>{{ text }}<slot name="after-text"></slot
></a>
@click="handleClick">{{ text }}<slot name="after-text"></slot></a>
</template>
<script>
@ -41,8 +42,8 @@ export default {
linkType: String,
text: String,
href: {
type: String,
},
type: String
}
},
emits: ['click-event'],
methods: {
@ -54,32 +55,31 @@ export default {
true
);
this.$emit('click-event');
},
},
}
}
};
</script>
<style lang="scss" scoped>
a {
color: $blue;
text-underline-offset: 5px;
line-height: 2;
padding: 0 0 4px 0;
color: #0070d1;
text-decoration: none;
line-height: 1.56;
padding: 0;
font-weight: 500;
max-width: fit-content;
&:hover {
color: $blue-700;
color: #125b7e;
text-decoration: underline;
}
&.small {
line-height: 24px;
&:hover {
color: $blue-700;
}
}
&.navigation-link,
&.new-window-link {
color: $black;
line-height: 26px;
font-weight: 600;
white-space: nowrap;
align-items: center;
}