Merge branch 'develop' into feature/CSR-269
This commit is contained in:
commit
fef27c4394
7 changed files with 262 additions and 181 deletions
|
|
@ -14,18 +14,17 @@ describe("funnel-footer.vue", () => {
|
|||
remove: jest.fn()
|
||||
},
|
||||
};
|
||||
|
||||
global.document.getElementById = jest.fn().mockImplementation(()=> {
|
||||
return r;
|
||||
});
|
||||
|
||||
const wrapper = mount(funnelFooter, {
|
||||
propsData: {
|
||||
footer: true
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const link = wrapper.find("a");
|
||||
console.log(wrapper.html());
|
||||
|
||||
// Expect
|
||||
expect(link.attributes('class')).toContain("footer-link");
|
||||
|
|
|
|||
|
|
@ -1,104 +1,82 @@
|
|||
<template>
|
||||
<div class="container-fluid g-2 footer">
|
||||
<div class="container-fluid g-2 footer">
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center pb-2 fs-7">
|
||||
© <span id="years"></span> Safelite Group
|
||||
</div>
|
||||
<div class="col-12 d-flex justify-content-center pb-2 fs-7">
|
||||
© <span id="years"></span> Safelite Group
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" :style="`padding-bottom: ${paddingHeight}px`">
|
||||
<div class="col d-flex justify-content-center justify-content-around text-center">
|
||||
<textLink
|
||||
footer=true
|
||||
text="Terms of use"
|
||||
href="https://www.safelite.com/terms-of-use"
|
||||
/>
|
||||
<textLink
|
||||
footer=true
|
||||
text="Privacy policy"
|
||||
href="https://www.safelite.com/safelite-group-privacy-policy"
|
||||
/>
|
||||
<textLink
|
||||
footer=true
|
||||
text="Do not sell my information"
|
||||
href="https://privacyportal-cdn.onetrust.com/dsarwebform/d3b95a93-e22e-4d4d-a806-482052406557/9e371601-eae3-4338-9430-b90b9036022b.html"
|
||||
/>
|
||||
</div>
|
||||
<div class="col d-flex justify-content-center justify-content-around text-center">
|
||||
<textLink linkType="footer" text="Terms of use" href="https://www.safelite.com/terms-of-use" />
|
||||
<textLink linkType="footer" text="Privacy policy" href="https://www.safelite.com/safelite-group-privacy-policy" />
|
||||
<textLink linkType="footer" text="Do not sell my information" href="https://privacyportal-cdn.onetrust.com/dsarwebform/d3b95a93-e22e-4d4d-a806-482052406557/9e371601-eae3-4338-9430-b90b9036022b.html" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid fixed-bottom g-4 bg-light py-4" id="infoBox">
|
||||
</div>
|
||||
<div class="container-fluid fixed-bottom g-4 bg-light py-4" id="infoBox">
|
||||
<div class="row d-flex flex-row-reverse align-items-center">
|
||||
<div class="col d-flex justify-content-end" id="stacked">
|
||||
<buttonMain
|
||||
isPrimary
|
||||
buttonText="Button test"
|
||||
loaderColor="white"
|
||||
sizeInRem="1"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<textLink
|
||||
navigation=true
|
||||
text="back"
|
||||
/>
|
||||
</div>
|
||||
<div class="col d-flex justify-content-end" id="stacked">
|
||||
<buttonMain isPrimary buttonText="Button test" loaderColor="white" sizeInRem="1" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<textLink linkType="navigation" text="back" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import textLink from "@/ux-components/text-link/text-link";
|
||||
import buttonMain from "@/ux-components/button-main/button-main";
|
||||
|
||||
export default {
|
||||
name: "funnelFooter",
|
||||
components: {
|
||||
textLink,
|
||||
buttonMain
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
paddingHeight: 0
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.paddingHeight = document.getElementById("infoBox").offsetHeight;
|
||||
this.$nextTick(() => {
|
||||
window.addEventListener('resize', this.onResize);
|
||||
})
|
||||
setTimeout(function(){ // Give it a moment to set the date
|
||||
document.getElementById('years').innerHTML += new Date().getFullYear();
|
||||
}, 100);
|
||||
this.checkHeight();
|
||||
},
|
||||
beforeUnmount() {
|
||||
window.removeEventListener('resize', this.onResize);
|
||||
},
|
||||
methods: {
|
||||
onResize() {
|
||||
this.paddingHeight = document.getElementById("infoBox").offsetHeight;
|
||||
this.checkHeight();
|
||||
name: "funnelFooter",
|
||||
components: {
|
||||
textLink,
|
||||
buttonMain
|
||||
},
|
||||
checkHeight() {
|
||||
const parentHeight = document.getElementById('infoBox').clientHeight;
|
||||
const wrapper2 = document.getElementById('stacked');
|
||||
console.log(parentHeight);
|
||||
console.log(wrapper2);
|
||||
if (parentHeight > 80) {
|
||||
wrapper2.classList.add("justify-content-start");
|
||||
wrapper2.classList.remove("justify-content-end");
|
||||
} else {
|
||||
wrapper2.classList.add("justify-content-end");
|
||||
wrapper2.classList.remove("justify-content-start");
|
||||
}
|
||||
data() {
|
||||
return {
|
||||
paddingHeight: 0
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.paddingHeight = document.getElementById("infoBox").offsetHeight;
|
||||
this.$nextTick(() => {
|
||||
window.addEventListener('resize', this.onResize);
|
||||
})
|
||||
setTimeout(function () { // Give it a moment to set the date
|
||||
document.getElementById('years').innerHTML += new Date().getFullYear();
|
||||
}, 100);
|
||||
this.checkHeight();
|
||||
},
|
||||
beforeUnmount() {
|
||||
window.removeEventListener('resize', this.onResize);
|
||||
},
|
||||
methods: {
|
||||
onResize() {
|
||||
this.paddingHeight = document.getElementById("infoBox").offsetHeight;
|
||||
this.checkHeight();
|
||||
},
|
||||
checkHeight() {
|
||||
const parentHeight = document.getElementById('infoBox').clientHeight;
|
||||
const wrapper2 = document.getElementById('stacked');
|
||||
|
||||
if (parentHeight > 80) {
|
||||
wrapper2.classList.add("justify-content-start");
|
||||
wrapper2.classList.remove("justify-content-end");
|
||||
} else {
|
||||
wrapper2.classList.add("justify-content-end");
|
||||
wrapper2.classList.remove("justify-content-start");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
button {
|
||||
button {
|
||||
min-width: 200px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -7,18 +7,79 @@
|
|||
</div>
|
||||
<div class="row my-4">
|
||||
<div class="col">
|
||||
<label for="autocomplete">Home address</label>
|
||||
<input
|
||||
ref="autocomplete"
|
||||
id="autocomplete"
|
||||
placeholder="Search"
|
||||
class="form-control search-location"
|
||||
onfocus="value = ''"
|
||||
type="text"
|
||||
/>
|
||||
<label for="autocomplete">Street address</label>
|
||||
<input ref="autocomplete"
|
||||
id="autocomplete"
|
||||
placeholder="Search"
|
||||
class="form-control search-location"
|
||||
type="text" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showAddressFields" class="row my-4">
|
||||
<div class="col">
|
||||
<label for="city">City</label>
|
||||
<input ref="city"
|
||||
id="city"
|
||||
class="form-control"
|
||||
type="text" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showAddressFields" class="row my-4">
|
||||
<div class="col-6">
|
||||
<label for="state">State</label>
|
||||
<input ref="state"
|
||||
id="state"
|
||||
class="form-control"
|
||||
type="text" />
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label for="zip">Zip</label>
|
||||
<input ref="zip"
|
||||
id="zip"
|
||||
class="form-control"
|
||||
type="text" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-show="displayVerificationWarning" class="row my-4">
|
||||
<div class="col">
|
||||
<span style="color: red;">An accurate match may not have have been located. Please verify your address before continuing</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="displayNoMatchWarning" class="row my-4">
|
||||
<div class="col">
|
||||
<span style="color: red;">An accurate match could not be located. Please re-enter your street address before continuing</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-4">
|
||||
<div class="col">
|
||||
<label for="firstName">First name</label>
|
||||
<input ref="firstName"
|
||||
id="firstName"
|
||||
class="form-control"
|
||||
type="text" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-4">
|
||||
<div class="col">
|
||||
<label for="lastName">Last name</label>
|
||||
<input ref="lastName"
|
||||
id="lastName"
|
||||
class="form-control"
|
||||
type="text" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-4">
|
||||
<div class="col">
|
||||
<label for="email">Email address</label>
|
||||
<input ref="email"
|
||||
id="email"
|
||||
class="form-control"
|
||||
type="text" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
@ -28,21 +89,29 @@ export default {
|
|||
components: {
|
||||
vehicleBanner,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
showAddressFields: false,
|
||||
displayVerificationWarning: false,
|
||||
displayNoMatchWarning: false
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.vehicleBanner.initializeComponent({
|
||||
GenericVehicleImage:
|
||||
"https://digitalconsumercms-dev.safelite.com/images/default-source/default-album/blurred-image.jpg?sfvrsn=a6ce3034_3",
|
||||
});
|
||||
|
||||
let addressField1 = document.getElementById("autocomplete");
|
||||
let self = this;
|
||||
//AIzaSyDptGCkOPgN2uWJOy4ou4M33phRD4MAoJo - localhost:8080
|
||||
//AIzaSyBji_2ApAj2vE_XNGyV-LaUEKrmuElpJ1w
|
||||
this.$loadScript(
|
||||
"https://maps.googleapis.com/maps/api/js?key=AIzaSyBji_2ApAj2vE_XNGyV-LaUEKrmuElpJ1w&libraries=places"
|
||||
)
|
||||
|
||||
//let apiKey = "AIzaSyDptGCkOPgN2uWJOy4ou4M33phRD4MAoJo"; // localhost:8080
|
||||
let apiKey = "AIzaSyBji_2ApAj2vE_XNGyV-LaUEKrmuElpJ1w"; // Dev and above
|
||||
|
||||
this.$loadScript(`https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places`)
|
||||
.then(() => {
|
||||
// Script is loaded, do something
|
||||
|
||||
// Script is loaded, initialize the autocomplete textbox
|
||||
self.autocomplete = new window.google.maps.places.Autocomplete(
|
||||
self.$refs.autocomplete,
|
||||
{
|
||||
|
|
@ -52,53 +121,101 @@ export default {
|
|||
}
|
||||
);
|
||||
|
||||
self.autocomplete.addListener("place_changed", () => {
|
||||
let place = self.autocomplete.getPlace();
|
||||
let address1 = "";
|
||||
let postcode = "";
|
||||
self.autocomplete.addListener('place_changed', fillInAddress);
|
||||
|
||||
addressField1.onblur = function() {
|
||||
var hover = document.querySelector(".pac-container .pac-item:hover");
|
||||
|
||||
let input = document.getElementById("autocomplete");
|
||||
// if an item has been clicked, do nothing, otherwise get first solution and use Geocoder to get the place
|
||||
if (hover === null) {
|
||||
var item = document.querySelector(".pac-container .pac-item");
|
||||
if (item != null) {
|
||||
var firstResult = item.textContent;
|
||||
var geocoder = new window.google.maps.Geocoder();
|
||||
geocoder.geocode({
|
||||
address: firstResult
|
||||
}, function (results, status) {
|
||||
if (status === window.google.maps.GeocoderStatus.OK) {
|
||||
fillInAddress(results[0]);
|
||||
self.displayVerificationWarning = true;
|
||||
self.displayNoMatchWarning = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
let city = document.querySelector("#city");
|
||||
let state = document.querySelector("#state");
|
||||
let zip = document.querySelector("#zip");
|
||||
|
||||
for (const component of place.address_components) {
|
||||
const componentType = component.types[0];
|
||||
city.value = "";
|
||||
state.value = "";
|
||||
zip.value = "";
|
||||
|
||||
switch (componentType) {
|
||||
case "street_number": {
|
||||
address1 = `${component.long_name} ${address1}`;
|
||||
break;
|
||||
}
|
||||
self.displayVerificationWarning = false;
|
||||
self.displayNoMatchWarning = true;
|
||||
}
|
||||
|
||||
case "route": {
|
||||
address1 += component.short_name;
|
||||
break;
|
||||
}
|
||||
case "locality":
|
||||
address1 += ", " + component.long_name;
|
||||
break;
|
||||
case "administrative_area_level_1": {
|
||||
address1 += ", " + component.short_name;
|
||||
break;
|
||||
}
|
||||
case "postal_code": {
|
||||
postcode = `${component.long_name}${postcode}`;
|
||||
break;
|
||||
}
|
||||
|
||||
case "postal_code_suffix": {
|
||||
postcode = `${postcode}-${component.long_name}`;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
let addressField1 = document.querySelector("#autocomplete");
|
||||
addressField1.value = address1 + " " + postcode;
|
||||
function fillInAddress(place) {
|
||||
if (!place) {
|
||||
place = self.autocomplete.getPlace();
|
||||
}
|
||||
});
|
||||
|
||||
if (place && place.address_components) {
|
||||
let address1 = "";
|
||||
let city = document.querySelector("#city");
|
||||
let state = document.querySelector("#state");
|
||||
let zip = document.querySelector("#zip");
|
||||
self.showAddressFields = true;
|
||||
|
||||
for (const component of place.address_components) {
|
||||
const componentType = component.types[0];
|
||||
|
||||
switch (componentType) {
|
||||
case "street_number": {
|
||||
address1 = `${component.long_name} ${address1}`;
|
||||
break;
|
||||
}
|
||||
|
||||
case "route": {
|
||||
address1 += component.short_name;
|
||||
break;
|
||||
}
|
||||
case "locality": {
|
||||
city.value = component.long_name;
|
||||
break;
|
||||
}
|
||||
case "administrative_area_level_1": {
|
||||
state.value = component.short_name;
|
||||
break;
|
||||
}
|
||||
case "postal_code": {
|
||||
zip.value = component.long_name;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addressField1.value = address1;
|
||||
self.displayVerificationWarning = false;
|
||||
self.displayNoMatchWarning = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
self.displayVerificationWarning = true;
|
||||
self.displayNoMatchWarning = false;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// Failed to fetch script
|
||||
console.log("Unable to load Google Places API script");
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -48,18 +48,19 @@
|
|||
<div class="row">
|
||||
<div class="col my-3">
|
||||
<textLink
|
||||
navigation=true
|
||||
linkType=navigation
|
||||
text="Navigation Link"
|
||||
/><br><br>
|
||||
<textLink
|
||||
linkType="text"
|
||||
text="Default Link"
|
||||
/><br><br>
|
||||
<textLink
|
||||
textSmall=true
|
||||
linkType=textSmall
|
||||
text="Small Link"
|
||||
/><br><br>
|
||||
<textLink
|
||||
footer=true
|
||||
linkType=footer
|
||||
text="Footer Link"
|
||||
href="https://google.com"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -133,21 +133,22 @@ export default {
|
|||
position: static; //override bootstrap
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
&:focus-visible + label {
|
||||
box-shadow: 0 0 0 2.5px $blue inset;
|
||||
}
|
||||
&:focus + label {
|
||||
box-shadow: 0 0 0 2.5px $blue inset;
|
||||
}
|
||||
&:checked + label {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
background: $blue-100;
|
||||
box-shadow: 0 0 0 1px $blue;
|
||||
}
|
||||
&:checked + label p:first-child {
|
||||
font-weight: 500;
|
||||
|
||||
&:focus-visible + label {
|
||||
box-shadow: 0 0 0 2.5px $blue inset;
|
||||
}
|
||||
&:focus + label {
|
||||
box-shadow: 0 0 0 2.5px $blue inset;
|
||||
}
|
||||
&:checked + label {
|
||||
color: $black;
|
||||
font-weight: 500;
|
||||
background: $blue-100;
|
||||
box-shadow: 0 0 0 1px $blue;
|
||||
}
|
||||
&:checked + label p:first-child {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
label {
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ import textLink from "./text-link";
|
|||
import { nextTick } from "vue";
|
||||
|
||||
describe("text-link.vue", () => {
|
||||
it("Should return text-link type is navigation if prop navigation is true", async () => {
|
||||
|
||||
it("Should return class navigation-link", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(textLink, {
|
||||
propsData: {
|
||||
navigation: true,
|
||||
linkType: "navigation",
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -18,11 +19,11 @@ describe("text-link.vue", () => {
|
|||
expect(paragraph.attributes("class")).toContain("navigation-link");
|
||||
});
|
||||
|
||||
it("Should return text-link type is footer if prop footer is true", async () => {
|
||||
it("Should return class footer", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(textLink, {
|
||||
propsData: {
|
||||
footer: true,
|
||||
linkType: "footer",
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -30,14 +31,14 @@ describe("text-link.vue", () => {
|
|||
const paragraph = wrapper.find("a");
|
||||
|
||||
// Expect
|
||||
expect(paragraph.attributes("class")).toContain("footer-link");
|
||||
expect(paragraph.attributes("class")).toContain("footer");
|
||||
});
|
||||
|
||||
it("Should return text-link type is textSmall if prop textSmall is true", async () => {
|
||||
it("Should return class text-small", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(textLink, {
|
||||
propsData: {
|
||||
textSmall: true,
|
||||
linkType: "textSmall",
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -48,18 +49,4 @@ describe("text-link.vue", () => {
|
|||
expect(paragraph.attributes("class")).toContain("small");
|
||||
});
|
||||
|
||||
it("Should return text for href", async () => {
|
||||
// Act
|
||||
const wrapper = shallowMount(textLink, {
|
||||
propsData: {
|
||||
text: "This is link text",
|
||||
},
|
||||
});
|
||||
|
||||
// Assert
|
||||
const paragraph = wrapper.find("a");
|
||||
|
||||
// Expect
|
||||
expect(paragraph.text()).toEqual("This is link text");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
<template>
|
||||
<a v-if="navigation" @click="handleClick" class="navigation-link" :href="href">{{text}}</a>
|
||||
<a v-else-if="footer" @click="handleClick" class="footer-link" :href="href" target="_blank">{{text}}</a>
|
||||
<a v-else-if="textSmall" @click="handleClick" class="small" :href="href">{{text}}</a>
|
||||
<a v-else @click="handleClick" :href="href">{{text}}</a>
|
||||
<a v-if="linkType === 'navigation'" @click="handleClick" class="navigation-link" :href="href">{{text}}</a>
|
||||
<a v-else-if="linkType === 'footer'" @click="handleClick" class="footer-link" :href="href" target="_blank">{{text}}</a>
|
||||
<a v-else-if="linkType === 'textSmall'" @click="handleClick" class="small" :href="href">{{text}}</a>
|
||||
<a v-else-if="linkType === 'text'" @click="handleClick" :href="href">{{text}}</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "textLink",
|
||||
props: {
|
||||
navigation: Boolean,
|
||||
footer: Boolean,
|
||||
textSmall: Boolean,
|
||||
linkType: String,
|
||||
text: String,
|
||||
href: {
|
||||
type: String,
|
||||
|
|
|
|||
Loading…
Reference in a new issue