Merge pull request #526 from Safelite/CSR-544-footer-modal

CSR 544 footer modal
This commit is contained in:
bmauger 2022-05-31 17:02:43 -04:00 committed by GitHub
commit 2b27eca24c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 151 additions and 107 deletions

View file

@ -27,6 +27,7 @@ module.exports = {
"!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue", "!src/layouts/address-vehicles/address-vehicles-question/address-vehicles-question.vue",
"!src/ux-components/alert\alert.vue", "!src/ux-components/alert\alert.vue",
"!src/helpers/validation-rules.js", "!src/helpers/validation-rules.js",
"!src/common-components/menu-modal/menu-modal.vue",
// END // END
], // ! means exclude from coverage. ], // ! means exclude from coverage.
testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"], testMatch: ["**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)"],

View file

@ -3,30 +3,6 @@ import funnelFooter from "./funnel-footer";
describe("funnel-footer.vue", () => { describe("funnel-footer.vue", () => {
it("Should return footer-link class", async () => {
// Act
const r = {
test:"testing",
clientHeight: 10,
offsetHeight: 24,
};
global.document.querySelector = jest.fn().mockImplementation(()=> {
return r;
});
const wrapper = mount(funnelFooter, {
mixins: [mockMixin]
});
// Assert
const link = wrapper.find("a");
// Expect
expect(link.attributes('class')).toContain("footer");
});
it("Should emit ForwardClicked on button click", async () => { it("Should emit ForwardClicked on button click", async () => {
// Act // Act
const wrapper = mount(funnelFooter, { const wrapper = mount(funnelFooter, {

View file

@ -1,21 +1,6 @@
<template> <template>
<div class="footer pt-4"> <footer class="footer container-fluid fixed-bottom g-5 bg-light py-4" id="infoBox">
<div class="container-fluid g-2"> <div class="row d-flex flex-row-reverse align-items-center vw-100">
<div class="row">
<div class="col-12 d-flex justify-content-center pb-2 fs-7">
&copy;&nbsp;{{new Date().getFullYear()}}&nbsp;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 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-5 bg-light py-4" id="infoBox">
<div class="row d-flex flex-row-reverse align-items-center">
<div class="col button-col d-flex" id="stacked"> <div class="col button-col d-flex" id="stacked">
<buttonMain <buttonMain
ref="buttonMain" ref="buttonMain"
@ -26,6 +11,8 @@
:aria-disabled="isForwardActionDisabled" :aria-disabled="isForwardActionDisabled"
:isDisabled="isForwardActionDisabled" :isDisabled="isForwardActionDisabled"
@click-event="buttonClick" @click-event="buttonClick"
data-bs-target="#footerModal"
data-bs-dismiss="modal"
/> />
</div> </div>
<div v-if="!isBackButtonHidden" class="col-auto link-col py-1 text-break"> <div v-if="!isBackButtonHidden" class="col-auto link-col py-1 text-break">
@ -34,11 +21,12 @@
:text="backLink" :text="backLink"
@click-event="linkClick" @click-event="linkClick"
href="javascript:void(0)" href="javascript:void(0)"
data-bs-target="#footerModal"
data-bs-dismiss="modal"
/> />
</div> </div>
</div> </div>
</div> </footer>
</div>
</template> </template>
<script> <script>
@ -80,7 +68,7 @@ export default {
}, },
buttonText(){ buttonText(){
return this.customButtontext ? this.customButtontext : this.getCmsContent(this.cmsWidgetName, 'ForwardButtonText'); return this.customButtontext ? this.customButtontext : this.getCmsContent(this.cmsWidgetName, 'ForwardButtonText');
} },
}, },
methods: { methods: {
onResize() { onResize() {
@ -112,7 +100,6 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
.footer { .footer {
display: flex; display: flex;
margin-top: auto;
a { a {
display: flex; display: flex;
justify-content: center; justify-content: center;

View file

@ -4,6 +4,7 @@
v-if="imageSrc" v-if="imageSrc"
> >
<img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" /> <img class="logo-image img-fluid" :src="imageSrc" alt="Safelite logo" />
<menuModal/>
</div> </div>
<alert <alert
class="position-absolute rounded-0 w-100 border-0 shadow-sm" class="position-absolute rounded-0 w-100 border-0 shadow-sm"
@ -19,6 +20,7 @@
import alert from "@/ux-components/alert/alert"; import alert from "@/ux-components/alert/alert";
import eventBus from "@/helpers/event-bus/event-bus"; import eventBus from "@/helpers/event-bus/event-bus";
import { globalEvents } from "@/constants/events"; import { globalEvents } from "@/constants/events";
import menuModal from "@/common-components/menu-modal/menu-modal";
export default { export default {
name: "funnel-header", name: "funnel-header",
@ -43,6 +45,7 @@ export default {
}, },
components: { components: {
alert, alert,
menuModal,
}, },
mounted() { mounted() {
// Check if alert event is on the bus // Check if alert event is on the bus
@ -50,7 +53,6 @@ export default {
globalEvents.Categories.GLOBAL_ALERT, globalEvents.Categories.GLOBAL_ALERT,
globalEvents.SubCategories.PAGE_NOT_FOUND globalEvents.SubCategories.PAGE_NOT_FOUND
); );
// If alert event is on the bus, then display the alert // If alert event is on the bus, then display the alert
if (alertEvent !== undefined) { if (alertEvent !== undefined) {
this.displayGlobalAlert = true; this.displayGlobalAlert = true;
@ -70,5 +72,6 @@ export default {
} }
.alert { .alert {
left: 0; left: 0;
top: 72px;
} }
</style> </style>

View file

@ -1,53 +0,0 @@
<template>
<div class="menu-button" :class="[isActive ? 'active' : '']" @click="toggleClass()">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
</div>
</template>
<script>
export default {
name: 'menuButton',
data() {
return {
isActive: false,
};
},
methods: {
toggleClass: function(event){
this.isActive = !this.isActive;
}
}
}
</script>
<style lang="scss">
.menu-button {
width: 1.5rem;
height: 1.5rem;
border-radius: 50%;
box-shadow: 0px 0px 8px 2px rgba(0,0,0,0.2);
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.bar1,
.bar2,
.bar3 {
width: 14px;
height: 2px;
background-color: $blue-400;
margin: 1px 0;
transition: 0.25s;
}
&.active .bar1 {
transform: rotate(-45deg) translate(-3px, 3px);
}
&.active .bar2 {opacity: 0;}
&.active .bar3 {
transform: rotate(45deg) translate(-3px, -3px);
}
}
</style>

View file

@ -0,0 +1,116 @@
<template>
<div class="menu-modal-container">
<button class="menu-button" type="button" :class="[isActive ? 'active' : '']" data-bs-toggle="modal" data-bs-target="#footerModal">
<div class="bar1"></div>
<div class="bar2"></div>
<div class="bar3"></div>
</button>
</div>
<!-- Modal -->
<div class="modal fade" id="footerModal" tabindex="-1" aria-labelledby="footerModalLabel" aria-hidden="true" :style="`height: calc(100% - ${currentFooterAndHeaderHeight}px);`">
<div class="modal-dialog modal-fullscreen">
<div class="modal-content">
<div class="modal-header visually-hidden">
<h5 class="modal-title" id="footerModalLabel">Footer Navigation</h5>
</div>
<div class="modal-body d-flex flex-column">
<textLink linkType="navigation" text="Terms of use" href="https://www.safelite.com/terms-of-use" />
<textLink linkType="navigation" text="Privacy policy" href="https://www.safelite.com/safelite-group-privacy-policy" />
<textLink linkType="navigation" 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="modal-footer d-flex justify-content-start">
&copy; {{new Date().getFullYear()}} Safelite Group
</div>
</div>
</div>
</div>
</template>
<script>
import textLink from "@/ux-components/text-link/text-link";
export default {
name: 'menuModal',
data() {
return {
isActive: false,
currentFooterAndHeaderHeight: 0,
};
},
mounted() {
const myModalEl = document.getElementById('footerModal');
var self = this;
myModalEl.addEventListener('hide.bs.modal', function (event) {
self.isActive = false;
});
myModalEl.addEventListener('show.bs.modal', function (event) {
self.currentFooterAndHeaderHeight = self.getFooterInfoBoxHeight() + 72;
self.isActive = true;
})
},
components: {
textLink,
}
}
</script>
<style lang="scss">
.menu-modal-container {
position: absolute;
padding: 1.47rem 1rem 1.47rem 1.47rem;
right: 0;
button {
border: none;
&.menu-button {
width: 1.5rem;
height: 1.5rem;
border-radius: 50%;
box-shadow: 0 2px 8px 0 rgba(0,0,0,0.2);
background-color: $white;
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 1056;
.bar1,
.bar2,
.bar3 {
width: 14px;
height: 2px;
background-color: $blue-400;
margin: 1px 0;
transition: 0.25s;
}
&.active .bar1 {
transform: rotate(-45deg) translate(-3px, 3px);
}
&.active .bar2 {opacity: 0;}
&.active .bar3 {
transform: rotate(45deg) translate(-3px, -3px);
}
}
}
}
.modal {
max-width: 576px;
left: auto;
height: calc(100% - 72px);
top: 72px;
border-top: 1px solid $gray-300;
.modal-body {
padding: 2rem;
}
.modal-fullscreen {
width: 100vw;
max-width: 576px;
}
.navigation-link {
margin-bottom: 1.5rem;
}
.modal-footer {
border-top: none;
padding: 2rem;
}
//.modal-backdrop styles are in common-styles.scss
}
</style>

View file

@ -7,7 +7,7 @@
</div> </div>
<div class="row my-2"> <div class="row my-2">
<div class="col"> <div class="col">
<menuButton/> <menuModal/>
</div> </div>
</div> </div>
<div class="row my-4"> <div class="row my-4">
@ -1089,7 +1089,7 @@
import textboxQuestion from "@/common-components/textbox-question/textbox-question"; import textboxQuestion from "@/common-components/textbox-question/textbox-question";
import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question"; import dropdownQuestion from "@/common-components/dropdown-question/dropdown-question";
import vinInformation from "@/layouts/vin-lookup/vin-information/vin-information"; import vinInformation from "@/layouts/vin-lookup/vin-information/vin-information";
import menuButton from "@/common-components/menu-button/menu-button"; import menuModal from "@/common-components/menu-modal/menu-modal";
export default { export default {
name: "App", name: "App",
components: { components: {
@ -1104,7 +1104,7 @@
textboxQuestion, textboxQuestion,
dropdownQuestion, dropdownQuestion,
vinInformation, vinInformation,
menuButton, menuModal,
}, },
data() { data() {
return { return {

View file

@ -43,9 +43,9 @@ export default {
} }
}, },
getFooterInfoBoxHeight() { getFooterInfoBoxHeight() {
const footerInfoBox = document.querySelector(".footer #infoBox"); const footerInfoBox = document.querySelector(".footer#infoBox");
return footerInfoBox ? footerInfoBox.offsetHeight : 0; return footerInfoBox ? footerInfoBox.offsetHeight : 0;
} },
}, },
computed: { computed: {
storeActions() { storeActions() {

View file

@ -47,4 +47,14 @@ body {
.page-container-grouped-styles { .page-container-grouped-styles {
@extend .container-fluid, .shadow, .rounded-3, .p-2, .position-relative, .make-tall, .px-5; @extend .container-fluid, .shadow, .rounded-3, .p-2, .position-relative, .make-tall, .px-5;
} }
//Footer modal backdrop adjustments for positioning
.modal-backdrop {
left: 50%;
transform: translateX(-50%);
max-width: 576px;
height: calc(100% - 152px);
top: 72px;
}
} }

View file

@ -180,3 +180,7 @@ $box-shadow-inset: inset 0 1px 2px rgba($black, .075);
$alert-bg-scale: -90%; $alert-bg-scale: -90%;
$alert-border-scale: -100%; $alert-border-scale: -100%;
$alert-color-scale: 40%; $alert-color-scale: 40%;
//Modal animation
$modal-fade-transform: translate(0, 0);
$modal-backdrop-opacity: 0;