Merge pull request #587 from Safelite/feature/digital/SSR-1148

Adds Cart Footer
This commit is contained in:
michaela-brydon-safelite 2024-03-15 01:05:19 -04:00 committed by GitHub
commit 5604d089ea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 170 additions and 67 deletions

View file

@ -5,5 +5,12 @@ Object {
"baseServiceLineItems": Array [], "baseServiceLineItems": Array [],
"deductible": null, "deductible": null,
"isExpanded": false, "isExpanded": false,
"widget": Object {
"amountDue": "AmountDueTextWidget",
"basePrice": "BasePriceWidget",
"deductible": "DeductibleWidget",
"salesTax": "SalesTaxWidget",
"subtotal": "SubtotalWidget",
},
} }
`; `;

View file

@ -121,6 +121,58 @@ describe('cart-dropdown component', () => {
// Assert // Assert
expect(cartBasePrice.exists()).toBeTruthy(); expect(cartBasePrice.exists()).toBeTruthy();
}); });
test('cart footer', () => {
// Arrange
const reference = '#cart-footer';
const isExpanded = true;
const initialData = { isExpanded };
const { wrapper } = getMountedComponent({}, {}, initialData);
// Act
const cartFooter = wrapper.find(reference);
// Assert
expect(cartFooter.exists()).toBeTruthy();
});
test('subtotal', () => {
// Arrange
const reference = '#cart-subtotal';
const isExpanded = true;
const initialData = { isExpanded };
const { wrapper } = getMountedComponent({}, {}, initialData);
// Act
const subtotal = wrapper.find(reference);
// Assert
expect(subtotal.exists()).toBeTruthy();
});
test('tax', () => {
// Arrange
const reference = '#cart-sales-tax';
const isExpanded = true;
const initialData = { isExpanded };
const { wrapper } = getMountedComponent({}, {}, initialData);
// Act
const salesTax = wrapper.find(reference);
// Assert
expect(salesTax.exists()).toBeTruthy();
});
test('bottom amount due', () => {
// Arrange
const reference = '#bottom-amount-due';
const isExpanded = true;
const initialData = { isExpanded };
const { wrapper } = getMountedComponent({}, {}, initialData);
// Act
const bottomAmountDue = wrapper.find(reference);
// Assert
expect(bottomAmountDue.exists()).toBeTruthy();
});
}); });
describe('does not display', () => { describe('does not display', () => {
test('cart deductible when showDeductibleLineItem is false', () => { test('cart deductible when showDeductibleLineItem is false', () => {

View file

@ -1,5 +1,5 @@
<template> <template>
<div :class="[isExpanded ? 'pb-3' : 'pb-4']"> <div :class="[isExpanded ? 'pb-5' : 'pb-4']">
<div <div
id="cart-dropdown-head" id="cart-dropdown-head"
class="row cart-toggle flex align-items-center pt-4" class="row cart-toggle flex align-items-center pt-4"
@ -9,50 +9,73 @@
aria-label="expand cart details" aria-label="expand cart details"
href="javascript:void(0)" href="javascript:void(0)"
class="col d-flex justify-content-between py-0"> class="col d-flex justify-content-between py-0">
<span class="cart-label color-black">{{ amountDueLabel }}</span> <span class="color-black">{{ amountDueLabel }}</span>
<span class="cart-label amount-due">{{ getDisplayed(amountDue) }}</span> <span class="color-green">{{ getDisplayed(amountDue) }}</span>
</a> </a>
</div> </div>
<div <div
id="cart-table" id="cart-table"
class="cart-table"> class="cart-table">
<!-- Deductible Line Item -->
<div <div
id="cart-deductible-or-base-price" id="cart-line-items"
class="mt-4 cart-line-item color-gray-100 px-5 py-1"> class="color-darker-gray">
<div <div
v-if="showDeductibleLineItem" id="cart-deductible-or-base-price"
id="cart-deductible" class="cart-deductible-or-base-price">
class="d-flex justify-content-between align-items-center"> <div
<span v-if="showDeductibleLineItem"
id="deductible-label" id="cart-deductible"
class="cart-label">{{ deductibleLabel }}</span> class="d-flex justify-content-between align-items-center">
<span id="deductible-value">{{ getDisplayed(deductible) }}</span> <span id="deductible-label">{{ deductibleLabel }}</span>
<span id="deductible-value">{{ getDisplayed(deductible) }}</span>
</div>
<div
v-else
id="cart-base-price"
class="d-flex justify-content-between align-items-center">
<span id="base-price-label">{{ basePriceLabel }}</span>
<span id="base-price-value">{{ getDisplayed(baseServicePrice) }}</span>
</div>
</div> </div>
<div
v-else <!-- Packaged Cart Items -->
id="cart-base-price"
class="d-flex justify-content-between align-items-center"> <!-- Nonpackaged Cart Items -->
<span <!-- This will be a loop when this is implemented -->
id="base-price-label" <div class="non-packaged-cart-item">
class="cart-label">{{ basePriceLabel }}</span> <textLink
<span id="base-price-value">{{ getDisplayed(baseServicePrice) }}</span> linkType="text"
text="Recycling"
href="javascript:void(0)"
@clickEvent="openModal(recyclingModalCmsWidgetName)" />
</div> </div>
</div> </div>
<div
<!-- Packaged Cart Items --> id="cart-footer"
class="cart-footer">
<!-- Nonpackaged Cart Items --> <div
<!-- This will be a loop when this is implemented --> id="cart-subtotal-and-tax"
<div class="non-packaged-cart-item"> class="subtotal-and-tax">
<textLink <div
linkType="text" id="cart-subtotal"
text="Recycling" class="col d-flex justify-content-between">
href="javascript:void(0)" <span id="subtotal-label">{{ subtotalLabel }}</span>
@clickEvent="openModal(recyclingModalCmsWidgetName)" /> <span id="subtotal-value">{{ getDisplayed(subTotal) }}</span>
</div>
<div
id="cart-sales-tax"
class="pt-1 col d-flex justify-content-between">
<span id="sales-tax-label">{{ salesTaxLabel }}</span>
<span id="sales-tax-value">{{ getDisplayed(salesTax) }}</span>
</div>
</div>
<div
id="bottom-amount-due"
class="bottom-amount-due col d-flex justify-content-between">
<span id="bottom-amount-due-label">{{ amountDueLabel }}</span>
<span id="bottom-amount-due-value">{{ getDisplayed(amountDue) }}</span>
</div>
</div> </div>
<!-- Sub total, sales tax, total columns -->
</div> </div>
<contentGroupModal <contentGroupModal
ref="RecycleModal" ref="RecycleModal"
@ -69,6 +92,7 @@ import textBlock from '@/digital-components/text-block/text-block.vue';
import textLink from '@/ux-components/text-link/text-link.vue'; import textLink from '@/ux-components/text-link/text-link.vue';
import getPriceOfLineItems from '@/helpers/price-calculator.js'; import getPriceOfLineItems from '@/helpers/price-calculator.js';
import { formatAmountInDollars } from '@/helpers/text-helper.js'; import { formatAmountInDollars } from '@/helpers/text-helper.js';
import widgetFields from '@/constants/cms-widget-fields.js';
const VERIFYING_COVERAGE = 'Verifying coverage'; const VERIFYING_COVERAGE = 'Verifying coverage';
@ -78,9 +102,6 @@ export default {
textBlock, textBlock,
textLink }, textLink },
props: { props: {
amountDueLabel: String,
basePriceLabel: String,
deductibleLabel: String,
recyclingModalCmsWidgetName: String, recyclingModalCmsWidgetName: String,
showAsPaid: Boolean showAsPaid: Boolean
}, },
@ -95,7 +116,14 @@ export default {
return { return {
deductible: currentDeductible, deductible: currentDeductible,
baseServiceLineItems, baseServiceLineItems,
isExpanded: false isExpanded: false,
widget: {
amountDue: 'AmountDueTextWidget',
deductible: 'DeductibleWidget',
basePrice: 'BasePriceWidget',
subtotal: 'SubtotalWidget',
salesTax: 'SalesTaxWidget'
}
}; };
}, },
computed: { computed: {
@ -120,6 +148,21 @@ export default {
return this.showAsPaid return this.showAsPaid
? 0 ? 0
: this.subTotal + this.salesTax; : this.subTotal + this.salesTax;
},
amountDueLabel() {
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
deductibleLabel() {
return this.getCmsContent(this.widget.deductible, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
basePriceLabel() {
return this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
subtotalLabel() {
return this.getCmsContent(this.widget.subtotal, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
salesTaxLabel() {
return this.getCmsContent(this.widget.salesTax, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
} }
}, },
methods: { methods: {
@ -136,7 +179,6 @@ export default {
} }
} }
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -145,11 +187,12 @@ export default {
.color-black { .color-black {
color: $black; color: $black;
} }
.color-gray-100 {
background-color: $gray-100; .color-green {
color: $green;
} }
.cart-line-item { .color-darker-gray {
color: $darker-gray; color: $darker-gray;
} }
@ -158,6 +201,29 @@ export default {
transition: all 350ms ease-in; transition: all 350ms ease-in;
overflow: hidden; overflow: hidden;
visibility: hidden; visibility: hidden;
.cart-deductible-or-base-price {
background-color: $gray-100;
margin-top: 1rem;
padding: 0.25rem 1.5rem;
}
.cart-footer {
border-top: 1px solid $green;
}
.subtotal-and-tax {
background-color: $green-150;
font-weight: $font-weight-bold;
color: $black;
padding: 0.25rem 1.5rem;
}
.bottom-amount-due {
color: $white;
background-color: $green;
padding: 0.25rem 1.5rem;
}
} }
:deep(.modal-content a.external-text) { :deep(.modal-content a.external-text) {
@ -175,6 +241,8 @@ export default {
} }
.cart-toggle { .cart-toggle {
font-weight: $font-weight-bold;
&:after { &:after {
content: ""; content: "";
transition: all 0.5s ease; transition: all 0.5s ease;
@ -201,13 +269,6 @@ export default {
a { a {
text-decoration: none; text-decoration: none;
} }
.cart-label {
font-weight: $font-weight-bold;
line-height: 1.625;
}
.amount-due {
color: $green;
}
} }
</style> </style>

View file

@ -21,9 +21,6 @@
<hr class="my-0" /> <hr class="my-0" />
<cartDropdown <cartDropdown
:showAsPaid="false" :showAsPaid="false"
:amountDueLabel="amountDueText"
:deductibleLabel="deductibleLabel"
:basePriceLabel="basePriceLabel"
recyclingModalCmsWidgetName="RecycleModal" /> recyclingModalCmsWidgetName="RecycleModal" />
<hr class="mt-0 mb-5" /> <hr class="mt-0 mb-5" />
<div>Pia Alert Placeholder</div> <div>Pia Alert Placeholder</div>
@ -61,7 +58,6 @@ import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
import { paymentMethods } from '@/constants/payment-method-constants'; import { paymentMethods } from '@/constants/payment-method-constants';
import globalRules from '@/constants/global-rules'; import globalRules from '@/constants/global-rules';
import { Form } from 'vee-validate'; import { Form } from 'vee-validate';
import widgetFields from '@/constants/cms-widget-fields.js';
import { AppointmentTypeStrings } from '@/constants/schedule-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants';
@ -109,11 +105,6 @@ export default {
paymentMethodInternalModel: this.getPaymentMethodFromStore(), paymentMethodInternalModel: this.getPaymentMethodFromStore(),
rules: { rules: {
optionRequired: globalRules.OPTION_REQUIRED optionRequired: globalRules.OPTION_REQUIRED
},
widget: {
amountDue: 'AmountDueTextWidget',
deductible: 'DeductibleWidget',
basePrice: 'BasePriceWidget'
} }
}; };
}, },
@ -132,15 +123,6 @@ export default {
}, },
paymentMethod() { paymentMethod() {
return this.paymentMethodInternalModel; return this.paymentMethodInternalModel;
},
amountDueText() {
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
deductibleLabel() {
return this.getCmsContent(this.widget.deductible, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
},
basePriceLabel() {
return this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
} }
}, },
watch: { watch: {

View file

@ -28,6 +28,7 @@ $red-900: #330300;
// Greens // Greens
$green-100: #e3f2ea; $green-100: #e3f2ea;
$green-150: #e6f2ec;
$green-200: #bcedd4; $green-200: #bcedd4;
$green-300: #94d7b6; $green-300: #94d7b6;
$green-400: #5abc8c; // Used in theme $green-400: #5abc8c; // Used in theme