INSR-7757: More cart updates
This commit is contained in:
parent
b5ecac8b5a
commit
4dab87bf3f
9 changed files with 199 additions and 2297 deletions
|
|
@ -1,7 +1,8 @@
|
|||
const cartItemType = Object.freeze({
|
||||
RECYCLE_FEE: 'RECYCLE FEE',
|
||||
MOBILE_FEE: 'MOBILE FEE',
|
||||
VAP: 'VAP'
|
||||
VAP: 'VAP',
|
||||
WARRANTY: 'WARRANTY'
|
||||
});
|
||||
|
||||
export default cartItemType;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@
|
|||
REPLACE_FEE: 'REPLACE FEE',
|
||||
MOBILE_FEE: 'MOBILE FEE',
|
||||
REPAIR_FEE: 'REPAIR FEE',
|
||||
WARRANTY: 'WARRANTY'
|
||||
WARRANTY: 'WARRANTY',
|
||||
MOLDING: 'MOULDING'
|
||||
});
|
||||
|
||||
export default partTypeStrings;
|
||||
|
|
|
|||
|
|
@ -1,156 +1,113 @@
|
|||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-if="showDropdownHeader"
|
||||
id="cart-dropdown-head"
|
||||
class="row flex align-items-center pt-4 cart-header cart-toggle"
|
||||
:class="[isExpanded ? 'expanded' : '']"
|
||||
@click="toggleIsExpanded">
|
||||
<a
|
||||
aria-label="expand cart details"
|
||||
href="javascript:void(0)"
|
||||
class="col d-flex justify-content-between py-0">
|
||||
<span class="color-black">{{ amountDueLabel }}</span>
|
||||
<span class="color-green">{{ getDisplayed(amountDue) }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
id="cart-dropdown-head"
|
||||
class="expanded cart-header">
|
||||
</div>
|
||||
<div
|
||||
id="cart-table"
|
||||
class="cart-table">
|
||||
<div class="cart-table">
|
||||
<div class="cart-item-list">
|
||||
<div
|
||||
id="cart-line-items"
|
||||
class="color-darker-gray">
|
||||
<div
|
||||
id="cart-deductible-or-base-price"
|
||||
class="cart-item cart-gray">
|
||||
<div
|
||||
v-if="showDeductibleCartItem"
|
||||
id="cart-deductible"
|
||||
class="d-flex justify-content-between align-items-center py-2">
|
||||
id="cart-deductible-or-base-price"
|
||||
class="cart-item">
|
||||
<div class="price-row">
|
||||
<template
|
||||
v-if="showDeductibleCartItem">
|
||||
<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">
|
||||
</template>
|
||||
<template
|
||||
v-else>
|
||||
<span id="base-price-label">{{ basePriceLabel }}</span>
|
||||
<span id="base-price-value">{{ getDisplayed(servicePrice) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Packaged Cart Items -->
|
||||
<div
|
||||
id="cart-service-package"
|
||||
class="px-5">
|
||||
<div
|
||||
id="service-package-name"
|
||||
class="py-2 d-flex justify-content-between align-items-center">
|
||||
<textBlock
|
||||
:cmsWidgetName="servicePackageLabelWidget"
|
||||
class="force-no-top-margin" />
|
||||
<span id="service-package-price">{{ formatAmountInDollars(packagePrice) }}</span>
|
||||
</div>
|
||||
<div
|
||||
id="service-items"
|
||||
class="ps-4">
|
||||
<div
|
||||
v-for="(item, i) in servicePackageCartItems"
|
||||
:key="i">
|
||||
<div class="py-2 d-flex justify-content-between align-items-center">
|
||||
<span>{{ item?.name ?? '' }}</span>
|
||||
<textLink
|
||||
v-if="!readOnly"
|
||||
linkType="text"
|
||||
text="Remove"
|
||||
href="javascript:void(0)"
|
||||
@clickEvent="removeVap(item.partType)">
|
||||
<template #after-text>
|
||||
<span class="sr-only">{{ item?.name ?? '' }}</span>
|
||||
</template>
|
||||
</textLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- NonPackaged Cart Items -->
|
||||
<div id="non-packaged-cart-items">
|
||||
<div
|
||||
v-for="(item, i) in nonServicePackageCartItems"
|
||||
:key="i"
|
||||
class="px-5 py-2 non-packaged-cart-item">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span
|
||||
v-if="item.cartItemType === cartItemType.RECYCLE_FEE"
|
||||
id="recycle-fee-label">
|
||||
<textLink
|
||||
linkType="text"
|
||||
:text="item?.name ?? ''"
|
||||
href="javascript:void(0)"
|
||||
@clickEvent="openModal(RECYCLING_MODAL_REF_NAME)" />
|
||||
</span>
|
||||
<span v-else>{{ item?.name ?? '' }}</span>
|
||||
<span>{{ formatAmountInDollars(item?.subTotal ?? 0) }}</span>
|
||||
</div>
|
||||
<textLink
|
||||
v-if="item.cartItemType === cartItemType.VAP
|
||||
&& !readOnly"
|
||||
linkType="text"
|
||||
text="Remove"
|
||||
href="javascript:void(0)"
|
||||
@clickEvent="removeVap(item.partType)">
|
||||
<template #after-text>
|
||||
<span class="sr-only">{{ item?.name ?? '' }}</span>
|
||||
</template>
|
||||
</textLink>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="cart-footer"
|
||||
class="cart-footer pb-5">
|
||||
<div
|
||||
id="cart-subtotal-and-tax"
|
||||
class="subtotal-and-tax">
|
||||
<div
|
||||
id="cart-subtotal"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="subtotal-label">{{ subtotalLabel }}</span>
|
||||
<span id="subtotal-value">{{ getDisplayed(subTotal) }}</span>
|
||||
</div>
|
||||
<div
|
||||
id="cart-sales-tax"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="sales-tax-label">{{ salesTaxLabel }}</span>
|
||||
<span id="sales-tax-value">{{ formatAmountInDollars(salesTax) }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="showAsPaid"
|
||||
id="cart-amount-paid"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="amount-paid-label">{{ amountPaidLabel }}</span>
|
||||
<span if="amount-paid-value">{{ getDisplayed(amountPaid) }}</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>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<contentGroupModal
|
||||
:ref="RECYCLING_MODAL_REF_NAME"
|
||||
:cmsWidgetName="recyclingModalCmsWidgetName">
|
||||
<textBlock cmsWidgetName="RecycleTextBlock" />
|
||||
</contentGroupModal>
|
||||
|
||||
<!-- NonPackaged Cart Items -->
|
||||
<div
|
||||
v-for="(item, i) in nonServicePackageCartItems"
|
||||
:key="i"
|
||||
class="cart-item">
|
||||
<div class="price-row">
|
||||
<span
|
||||
v-if="item.cartItemType === cartItemType.RECYCLE_FEE"
|
||||
id="recycle-fee-label">
|
||||
<textLink
|
||||
linkType="text"
|
||||
:text="item?.name ?? ''"
|
||||
href="javascript:void(0)"
|
||||
@clickEvent="openModal(RECYCLING_MODAL_REF_NAME)" />
|
||||
</span>
|
||||
<span v-else>{{ item?.name ?? '' }}</span>
|
||||
<span>{{ formatAmountInDollars(item?.subTotal ?? 0) }}</span>
|
||||
</div>
|
||||
<textLink
|
||||
v-if="item.cartItemType === cartItemType.VAP
|
||||
&& !readOnly"
|
||||
linkType="text"
|
||||
text="Remove"
|
||||
href="javascript:void(0)"
|
||||
@clickEvent="removeVap(item.partType)">
|
||||
<template #after-text>
|
||||
<span class="sr-only">{{ item?.name ?? '' }}</span>
|
||||
</template>
|
||||
</textLink>
|
||||
</div>
|
||||
|
||||
<!-- Packaged Cart Items -->
|
||||
<div
|
||||
v-for="(item, i) in servicePackageCartItems"
|
||||
:key="i"
|
||||
class="cart-item">
|
||||
<div class="price-row">
|
||||
<span>{{ item?.name ?? '' }}</span>
|
||||
<span>{{ formatAmountInDollars(item?.subTotal ?? 0) }}</span>
|
||||
</div>
|
||||
<textLink
|
||||
v-if="!readOnly"
|
||||
linkType="text"
|
||||
text="Remove"
|
||||
href="javascript:void(0)"
|
||||
@clickEvent="removeVap(item.partType)">
|
||||
<template #after-text>
|
||||
<span class="sr-only">{{ item?.name ?? '' }}</span>
|
||||
</template>
|
||||
</textLink>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="cart-footer"
|
||||
class="cart-footer pb-5">
|
||||
<div
|
||||
id="cart-subtotal-and-tax"
|
||||
class="subtotal-and-tax">
|
||||
<div
|
||||
id="cart-subtotal"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="subtotal-label">{{ subtotalLabel }}</span>
|
||||
<span id="subtotal-value">{{ getDisplayed(subTotal) }}</span>
|
||||
</div>
|
||||
<div
|
||||
id="cart-sales-tax"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="sales-tax-label">{{ salesTaxLabel }}</span>
|
||||
<span id="sales-tax-value">{{ formatAmountInDollars(salesTax) }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="showAsPaid"
|
||||
id="cart-amount-paid"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="amount-paid-label">{{ amountPaidLabel }}</span>
|
||||
<span if="amount-paid-value">{{ getDisplayed(amountPaid) }}</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>
|
||||
<contentGroupModal
|
||||
:ref="RECYCLING_MODAL_REF_NAME"
|
||||
:cmsWidgetName="recyclingModalCmsWidgetName">
|
||||
<textBlock cmsWidgetName="RecycleTextBlock" />
|
||||
</contentGroupModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -176,28 +133,26 @@ import {
|
|||
isOrderUnverified
|
||||
} from '@/helpers/cart-helper';
|
||||
import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator';
|
||||
import { processIfStatements } from '@/helpers/cms-content-helper';
|
||||
|
||||
const VERIFYING_COVERAGE = 'Verifying coverage';
|
||||
const RECYCLING_MODAL_REF_NAME = 'RecycleModal';
|
||||
|
||||
export default {
|
||||
name: 'cart-dropdown',
|
||||
name: 'confirmation-cart',
|
||||
components: {
|
||||
contentGroupModal,
|
||||
textBlock,
|
||||
textLink
|
||||
},
|
||||
props: {
|
||||
showAsPaid: Boolean,
|
||||
readOnly: Boolean,
|
||||
showAsPaid: Boolean,
|
||||
recyclingModalCmsWidgetName: String,
|
||||
showDropdownHeader: Boolean,
|
||||
isInitiallyExpanded: Boolean,
|
||||
submittedOrder: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isExpanded: this.isInitiallyExpanded,
|
||||
widget: {
|
||||
amountDue: 'AmountDueTextWidget',
|
||||
amountPaid: 'AmountPaidTextWidget',
|
||||
|
|
@ -208,7 +163,9 @@ export default {
|
|||
recycleFee: 'RecycleFeeWidget',
|
||||
mobileFee: 'MobileServiceWidget',
|
||||
servicePackage: 'ServicePackageTitle',
|
||||
vapsItemDescriptions: 'VapsItemDescriptions'
|
||||
vapsItemDescriptions: 'VapsItemDescriptions',
|
||||
warrantyText: 'WarrantyCartItemTextWidget',
|
||||
guaranteeText: 'GuaranteeCartItemTextWidget'
|
||||
},
|
||||
cartItemType,
|
||||
RECYCLING_MODAL_REF_NAME
|
||||
|
|
@ -273,7 +230,7 @@ export default {
|
|||
return result;
|
||||
},
|
||||
vehicleDamage() {
|
||||
return this.submittedOrder ? this.submittedOrder.damage : useMainStore().damage;
|
||||
return this.cartOrder.damage;
|
||||
},
|
||||
servicePackageTier() {
|
||||
const { glassToReplace, isRepair } = this.vehicleDamage;
|
||||
|
|
@ -333,6 +290,9 @@ export default {
|
|||
if (this.mobileFeeCartItem && !isMobileFeeHidden) {
|
||||
items.push(this.mobileFeeCartItem);
|
||||
}
|
||||
if (this.isITAC || this.isNoComp) {
|
||||
items.push(this.warrantyCartItem);
|
||||
}
|
||||
return items;
|
||||
},
|
||||
frontWipersCartItem() {
|
||||
|
|
@ -350,12 +310,6 @@ export default {
|
|||
...this.nonServicePackageCartItems
|
||||
];
|
||||
},
|
||||
packagePrice() {
|
||||
return this.servicePackageCartItems?.reduce(
|
||||
(accumulator, cartItem) => accumulator + (cartItem?.subTotal ?? 0),
|
||||
0
|
||||
) ?? 0;
|
||||
},
|
||||
amountDueLabel() {
|
||||
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
},
|
||||
|
|
@ -366,7 +320,13 @@ export default {
|
|||
return this.getCmsContent(this.widget.deductible, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
},
|
||||
basePriceLabel() {
|
||||
return this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
const content = this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
console.log('Base Price Label before processing if statements:', content);
|
||||
return processIfStatements(
|
||||
content,
|
||||
'custom',
|
||||
this.getCustomValueFromString
|
||||
);
|
||||
},
|
||||
subtotalLabel() {
|
||||
return this.getCmsContent(this.widget.subtotal, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
|
|
@ -409,15 +369,29 @@ export default {
|
|||
partTypeStrings.MOBILE_FEE
|
||||
)
|
||||
: null;
|
||||
},
|
||||
warrantyCartItem() {
|
||||
const label = this.cartOrder.damage.glassToReplace?.length > 0
|
||||
? this.getCmsContent(this.widget.warrantyText, widgetFields.TEXT_BLOCK_WIDGET.TEXT)
|
||||
: this.getCmsContent(this.widget.guaranteeText, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
return {
|
||||
name: label,
|
||||
cartItemType: cartItemType.WARRANTY,
|
||||
partType: partTypeStrings.WARRANTY,
|
||||
subTotal: 0,
|
||||
salesTax: 0
|
||||
}
|
||||
},
|
||||
hasMoldingPart() {
|
||||
return this.cartOrder.lineItems.glassParts?.some((glassPart) => {
|
||||
return glassPart.childParts?.some((childPart) => childPart.partType === partTypeStrings.MOLDING);
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openModal(modalName) {
|
||||
this.$refs[modalName].openModal();
|
||||
},
|
||||
toggleIsExpanded() {
|
||||
this.isExpanded = !this.isExpanded;
|
||||
},
|
||||
getDisplayed(amount) {
|
||||
return this.isUnverified
|
||||
? VERIFYING_COVERAGE
|
||||
|
|
@ -461,6 +435,17 @@ export default {
|
|||
const vapsTypeDescription = vapsItemDescriptions?.find((entry) => entry?.Name === vapsPartType);
|
||||
return vapsTypeDescription?.Text ?? '';
|
||||
},
|
||||
getCustomValueFromString(str) {
|
||||
console.log(this.cartOrder)
|
||||
switch (str) {
|
||||
case 'isRepair':
|
||||
return this.cartOrder.damage.isRepair;
|
||||
case 'hasMoldingPart':
|
||||
return this.hasMoldingPart;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
formatAmountInDollars
|
||||
}
|
||||
};
|
||||
|
|
@ -471,45 +456,38 @@ export default {
|
|||
|
||||
$RECYCLING_MODAL_REF_NAME: 'RecycleModal';
|
||||
|
||||
.force-no-top-margin {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.color-black {
|
||||
color: $black;
|
||||
}
|
||||
|
||||
.color-green {
|
||||
color: $green;
|
||||
}
|
||||
|
||||
.color-darker-gray {
|
||||
color: $darker-gray;
|
||||
}
|
||||
|
||||
.cart-table {
|
||||
max-height: 0;
|
||||
transition: all 350ms ease-in;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
margin-top: 1rem;
|
||||
|
||||
:deep(a) {
|
||||
padding-bottom: 0 !important;
|
||||
line-height: 1.625rem !important;
|
||||
text-underline-offset: auto !important;
|
||||
}
|
||||
|
||||
.non-packaged-cart-item:nth-child(odd){
|
||||
background-color: $gray-100;
|
||||
}
|
||||
max-height: 50rem;
|
||||
transition: all 150ms ease-in;
|
||||
min-width: fit-content;
|
||||
|
||||
.cart-item {
|
||||
padding: 0.25rem 1.5rem;
|
||||
}
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: .5rem 0rem;
|
||||
width: 100%;
|
||||
min-width: fit-content;
|
||||
&:nth-child(odd) {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 1px solid #d4d6d8;
|
||||
}
|
||||
|
||||
.cart-gray {
|
||||
background-color: $gray-100;
|
||||
.price-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
span, a {
|
||||
white-space: nowrap;
|
||||
padding: 0rem 1rem;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $heritage-blue-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-footer {
|
||||
|
|
@ -520,13 +498,16 @@ $RECYCLING_MODAL_REF_NAME: 'RecycleModal';
|
|||
background-color: $green-150;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $black;
|
||||
padding: 0.25rem 1.5rem;
|
||||
>div {
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-amount-due {
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
background-color: $green;
|
||||
padding: 0.5rem 1.5rem;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -544,39 +525,6 @@ $RECYCLING_MODAL_REF_NAME: 'RecycleModal';
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.cart-header {
|
||||
&.cart-toggle {
|
||||
font-weight: $font-weight-bold;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
transition: all 0.5s ease;
|
||||
background-image: url($svg-payment-method-review-toggle);
|
||||
background-repeat: no-repeat;
|
||||
background-position: right center;
|
||||
width: 1rem;
|
||||
height: 0.5625rem;
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
right: 0.75rem;
|
||||
margin: 0.5rem 0 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
&.expanded:after {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
&.expanded + .cart-table {
|
||||
max-height: 50rem;
|
||||
transition: all 150ms ease-in;
|
||||
overflow: hidden;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(#recycle-fee-label a){
|
||||
line-height: initial;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,478 +0,0 @@
|
|||
<template>
|
||||
<div class="cart-table">
|
||||
<div class="cart-item-list">
|
||||
<div
|
||||
id="cart-deductible-or-base-price"
|
||||
class="cart-item">
|
||||
<template
|
||||
v-if="showDeductibleCartItem">
|
||||
<span id="deductible-label">{{ deductibleLabel }}</span>
|
||||
<span id="deductible-value">{{ getDisplayed(deductible) }}</span>
|
||||
</template>
|
||||
<template
|
||||
v-else>
|
||||
<span id="base-price-label">{{ basePriceLabel }}</span>
|
||||
<span id="base-price-value">{{ getDisplayed(servicePrice) }}</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- NonPackaged Cart Items -->
|
||||
<div
|
||||
v-for="(item, i) in nonServicePackageCartItems"
|
||||
:key="i"
|
||||
class="cart-item">
|
||||
<span
|
||||
v-if="item.cartItemType === cartItemType.RECYCLE_FEE"
|
||||
id="recycle-fee-label">
|
||||
<textLink
|
||||
linkType="text"
|
||||
:text="item?.name ?? ''"
|
||||
href="javascript:void(0)"
|
||||
@clickEvent="openModal(RECYCLING_MODAL_REF_NAME)" />
|
||||
</span>
|
||||
<span v-else>{{ item?.name ?? '' }}</span>
|
||||
<span>{{ formatAmountInDollars(item?.subTotal ?? 0) }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Packaged Cart Items -->
|
||||
<div
|
||||
v-for="(item, i) in servicePackageCartItems"
|
||||
:key="i"
|
||||
class="cart-item">
|
||||
<span>{{ item?.name ?? '' }}</span>
|
||||
<span>{{ formatAmountInDollars(item?.subTotal ?? 0) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="cart-footer"
|
||||
class="cart-footer pb-5">
|
||||
<div
|
||||
id="cart-subtotal-and-tax"
|
||||
class="subtotal-and-tax">
|
||||
<div
|
||||
id="cart-subtotal"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="subtotal-label">{{ subtotalLabel }}</span>
|
||||
<span id="subtotal-value">{{ getDisplayed(subTotal) }}</span>
|
||||
</div>
|
||||
<div
|
||||
id="cart-sales-tax"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="sales-tax-label">{{ salesTaxLabel }}</span>
|
||||
<span id="sales-tax-value">{{ formatAmountInDollars(salesTax) }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="showAsPaid"
|
||||
id="cart-amount-paid"
|
||||
class="py-2 col d-flex justify-content-between">
|
||||
<span id="amount-paid-label">{{ amountPaidLabel }}</span>
|
||||
<span if="amount-paid-value">{{ getDisplayed(amountPaid) }}</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>
|
||||
<contentGroupModal
|
||||
:ref="RECYCLING_MODAL_REF_NAME"
|
||||
:cmsWidgetName="recyclingModalCmsWidgetName">
|
||||
<textBlock cmsWidgetName="RecycleTextBlock" />
|
||||
</contentGroupModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { useMainStore } from '@/store';
|
||||
import contentGroupModal from '@/iss-components/content-group-modal/content-group-modal.vue';
|
||||
import textBlock from '@/digital-components/text-block/text-block.vue';
|
||||
import textLink from '@/ux-components/text-link/text-link.vue';
|
||||
import { formatAmountInDollars } from '@/helpers/text-helper.js';
|
||||
import { getHighestFullySatisfiedTier, getPackageContents } from '@/helpers/service-package-helper.js';
|
||||
|
||||
// Constants
|
||||
import { experimentSettings } from '@/constants/experiments';
|
||||
import partTypeStrings from '@/constants/part-type-strings.js';
|
||||
import cartItemType from '@/constants/cart-item-type.js';
|
||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||
import {
|
||||
getCartTotal,
|
||||
getDeductible,
|
||||
getLineItems, getMobileFeeLineItem,
|
||||
getRecycleFeeLineItem, getSalesTax,
|
||||
getServiceLineItems, getSubtotal, isOrderITAC, isOrderNoComp,
|
||||
isOrderUnverified
|
||||
} from '@/helpers/cart-helper';
|
||||
import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator';
|
||||
|
||||
const VERIFYING_COVERAGE = 'Verifying coverage';
|
||||
const RECYCLING_MODAL_REF_NAME = 'RecycleModal';
|
||||
|
||||
export default {
|
||||
name: 'confirmation-cart',
|
||||
components: {
|
||||
contentGroupModal,
|
||||
textBlock,
|
||||
textLink
|
||||
},
|
||||
props: {
|
||||
showAsPaid: Boolean,
|
||||
recyclingModalCmsWidgetName: String,
|
||||
submittedOrder: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
widget: {
|
||||
amountDue: 'AmountDueTextWidget',
|
||||
amountPaid: 'AmountPaidTextWidget',
|
||||
deductible: 'DeductibleWidget',
|
||||
basePrice: 'BasePriceWidget',
|
||||
subtotal: 'SubtotalWidget',
|
||||
salesTax: 'SalesTaxWidget',
|
||||
recycleFee: 'RecycleFeeWidget',
|
||||
mobileFee: 'MobileServiceWidget',
|
||||
servicePackage: 'ServicePackageTitle',
|
||||
vapsItemDescriptions: 'VapsItemDescriptions',
|
||||
warrantyText: 'WarrantyCartItemTextWidget',
|
||||
guaranteeText: 'GuaranteeCartItemTextWidget'
|
||||
},
|
||||
cartItemType,
|
||||
RECYCLING_MODAL_REF_NAME
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
cartOrder() {
|
||||
return this.submittedOrder ?? useMainStore().order;
|
||||
},
|
||||
availableVaps() {
|
||||
return this.cartOrder.availableVaps;
|
||||
},
|
||||
deductible() {
|
||||
return getDeductible(this.cartOrder);
|
||||
},
|
||||
showDeductibleCartItem() {
|
||||
return this.isUnverified || (!this.isNoComp && !this.isITAC);
|
||||
},
|
||||
lineItems() {
|
||||
return getLineItems(this.cartOrder);
|
||||
},
|
||||
recycleFeeLineItem() {
|
||||
return getRecycleFeeLineItem(this.cartOrder);
|
||||
},
|
||||
servicePrice() {
|
||||
return getPriceOfLineItems(getServiceLineItems(this.cartOrder)) ?? 0;
|
||||
},
|
||||
isUnverified() {
|
||||
return isOrderUnverified(this.cartOrder);
|
||||
},
|
||||
isITAC() {
|
||||
return isOrderITAC(this.cartOrder);
|
||||
},
|
||||
isNoComp() {
|
||||
return isOrderNoComp(this.cartOrder);
|
||||
},
|
||||
// TODO fix rounding
|
||||
subTotal() {
|
||||
return getSubtotal(this.cartOrder);
|
||||
},
|
||||
salesTax() {
|
||||
return getSalesTax(this.cartOrder);
|
||||
},
|
||||
total() {
|
||||
return getCartTotal(this.cartOrder);
|
||||
},
|
||||
amountDue() {
|
||||
return this.showAsPaid ? 0 : this.total;
|
||||
},
|
||||
amountPaid() {
|
||||
return !this.showAsPaid ? 0 : this.total;
|
||||
},
|
||||
availableLineItems() {
|
||||
const { supportingItems, glassParts, otherParts, feeItems } = this.lineItems;
|
||||
const result = [
|
||||
...(supportingItems ?? []),
|
||||
...(glassParts ?? []),
|
||||
...(otherParts ?? []),
|
||||
...(this.availableVaps ?? []),
|
||||
...(feeItems ?? [])
|
||||
];
|
||||
return result;
|
||||
},
|
||||
vehicleDamage() {
|
||||
return this.submittedOrder ? this.submittedOrder.damage : useMainStore().damage;
|
||||
},
|
||||
servicePackageTier() {
|
||||
const { glassToReplace, isRepair } = this.vehicleDamage;
|
||||
const { vaps } = this.lineItems;
|
||||
return getHighestFullySatisfiedTier(
|
||||
glassToReplace ?? [],
|
||||
this.availableLineItems,
|
||||
isRepair,
|
||||
vaps ?? []
|
||||
);
|
||||
},
|
||||
partTypesInServicePackage() {
|
||||
const { glassToReplace, isRepair } = this.vehicleDamage;
|
||||
return getPackageContents(
|
||||
glassToReplace ?? [],
|
||||
this.availableLineItems,
|
||||
isRepair,
|
||||
this.servicePackageTier
|
||||
) ?? [];
|
||||
},
|
||||
servicePackageCartItems() {
|
||||
const items = [];
|
||||
if (this.partTypesInServicePackage.includes(partTypeStrings.FRONT_WIPER) ?? this.frontWipersCartItem) {
|
||||
items.push(this.frontWipersCartItem);
|
||||
}
|
||||
if (this.partTypesInServicePackage.includes(partTypeStrings.REAR_WIPER) ?? this.rearWipersCartItem) {
|
||||
items.push(this.rearWipersCartItem);
|
||||
}
|
||||
if (this.partTypesInServicePackage.includes(partTypeStrings.RAIN_DEFENSE) ?? this.rainDefenseCartItem) {
|
||||
items.push(this.rainDefenseCartItem);
|
||||
}
|
||||
return items;
|
||||
},
|
||||
nonServicePackageCartItems() {
|
||||
const vapPartTypesInOrder = Array.from(new Set(this.lineItems.vaps?.map((vap) => vap.partType) ?? []));
|
||||
const vapPartTypesInOrderButNotPackage = vapPartTypesInOrder
|
||||
.filter((partType) => !this.partTypesInServicePackage.includes(partType))
|
||||
?? [];
|
||||
const vapsCartItemsNotInPackage = vapPartTypesInOrderButNotPackage.map((partType) => {
|
||||
switch (partType) {
|
||||
case partTypeStrings.FRONT_WIPER:
|
||||
return this.frontWipersCartItem;
|
||||
case partTypeStrings.REAR_WIPER:
|
||||
return this.rearWipersCartItem;
|
||||
case partTypeStrings.RAIN_DEFENSE:
|
||||
return this.rainDefenseCartItem;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
});
|
||||
const items = vapsCartItemsNotInPackage.filter((item) => item != null);
|
||||
const isRecycleFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_RECYCLE_FEE_HIDDEN) === 'true';
|
||||
const isMobileFeeHidden = this.getSettingValue(experimentSettings.ISS_FEATURE_TOGGLE_IS_MOBILE_FEE_HIDDEN) === 'true';
|
||||
if (this.recycleFeeCartItem && !isRecycleFeeHidden) {
|
||||
items.push(this.recycleFeeCartItem);
|
||||
}
|
||||
if (this.mobileFeeCartItem && !isMobileFeeHidden) {
|
||||
items.push(this.mobileFeeCartItem);
|
||||
}
|
||||
if (this.isITAC || this.isNoComp) {
|
||||
items.push(this.warrantyCartItem);
|
||||
}
|
||||
return items;
|
||||
},
|
||||
frontWipersCartItem() {
|
||||
return this.getCartItemForVapsPart(partTypeStrings.FRONT_WIPER);
|
||||
},
|
||||
rearWipersCartItem() {
|
||||
return this.getCartItemForVapsPart(partTypeStrings.REAR_WIPER);
|
||||
},
|
||||
rainDefenseCartItem() {
|
||||
return this.getCartItemForVapsPart(partTypeStrings.RAIN_DEFENSE);
|
||||
},
|
||||
allCartItems() {
|
||||
return [
|
||||
...this.servicePackageCartItems,
|
||||
...this.nonServicePackageCartItems
|
||||
];
|
||||
},
|
||||
amountDueLabel() {
|
||||
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
},
|
||||
amountPaidLabel() {
|
||||
return this.getCmsContent(this.widget.amountPaid, 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);
|
||||
},
|
||||
servicePackageNames() {
|
||||
return this.getCmsContent(
|
||||
this.widget.servicePackage,
|
||||
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
|
||||
);
|
||||
},
|
||||
servicePackageLabelWidget() {
|
||||
if (!this.servicePackageNames) {
|
||||
return '';
|
||||
}
|
||||
const currentPackage = this.servicePackageNames
|
||||
?.find((entry) => entry?.Name === this.servicePackageTier);
|
||||
|
||||
return currentPackage?.SubWidgetName ?? '';
|
||||
},
|
||||
recycleFeeCartItem() {
|
||||
return this.recycleFeeLineItem
|
||||
? this.getCartItem(
|
||||
this.getCmsContent(this.widget.recycleFee, widgetFields.TEXT_BLOCK_WIDGET.TEXT),
|
||||
[this.recycleFeeLineItem],
|
||||
cartItemType.RECYCLE_FEE,
|
||||
partTypeStrings.REPLACE_FEE
|
||||
)
|
||||
: null;
|
||||
},
|
||||
mobileFeeCartItem() {
|
||||
const mobileFeeLineItem = getMobileFeeLineItem(this.cartOrder);
|
||||
return mobileFeeLineItem
|
||||
? this.getCartItem(
|
||||
this.getCmsContent(this.widget.mobileFee, widgetFields.TEXT_BLOCK_WIDGET.TEXT),
|
||||
[mobileFeeLineItem],
|
||||
cartItemType.MOBILE_FEE,
|
||||
partTypeStrings.MOBILE_FEE
|
||||
)
|
||||
: null;
|
||||
},
|
||||
warrantyCartItem() {
|
||||
const label = this.submittedOrder.damage.glassToReplace?.length > 0
|
||||
? this.getCmsContent(this.widget.warrantyText, widgetFields.TEXT_BLOCK_WIDGET.TEXT)
|
||||
: this.getCmsContent(this.widget.guaranteeText, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
return {
|
||||
name: label,
|
||||
cartItemType: cartItemType.VAP,
|
||||
partType: partTypeStrings.WARRANTY,
|
||||
subTotal: 0,
|
||||
salesTax: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
openModal(modalName) {
|
||||
this.$refs[modalName].openModal();
|
||||
},
|
||||
getDisplayed(amount) {
|
||||
return this.isUnverified
|
||||
? VERIFYING_COVERAGE
|
||||
: formatAmountInDollars(amount);
|
||||
},
|
||||
getCartItem(label, lineItems, cartItemTypeString, partType) {
|
||||
let cartItem = null;
|
||||
|
||||
if (lineItems && lineItems.length > 0) {
|
||||
cartItem = {
|
||||
name: label,
|
||||
cartItemType: cartItemTypeString,
|
||||
partType,
|
||||
subTotal: getPriceOfLineItems(lineItems),
|
||||
salesTax: getTaxOfLineItems(lineItems)
|
||||
};
|
||||
}
|
||||
|
||||
return cartItem;
|
||||
},
|
||||
getCartItemForVapsPart(partType) {
|
||||
const label = this.getCmsContentForVapsType(partType);
|
||||
const lineItems = this.lineItems.vaps
|
||||
?.filter((vapsLineItem) => vapsLineItem.partType === partType) ?? [];
|
||||
return this.getCartItem(label, lineItems, cartItemType.VAP, partType);
|
||||
},
|
||||
removeVap(partType) {
|
||||
const newVaps = useMainStore().lineItems.vaps?.filter((vap) => vap?.partType !== partType) ?? [];
|
||||
useMainStore().updateVaps(newVaps);
|
||||
},
|
||||
getCmsContentForVapsType(vapsPartType) {
|
||||
const vapsItemDescriptions = this.getCmsContent(
|
||||
this.widget.vapsItemDescriptions,
|
||||
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
|
||||
);
|
||||
|
||||
if (!vapsItemDescriptions) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const vapsTypeDescription = vapsItemDescriptions?.find((entry) => entry?.Name === vapsPartType);
|
||||
return vapsTypeDescription?.Text ?? '';
|
||||
},
|
||||
formatAmountInDollars
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/styles/ux-variables-svg-strings.scss";
|
||||
|
||||
$RECYCLING_MODAL_REF_NAME: 'RecycleModal';
|
||||
|
||||
.cart-table {
|
||||
max-height: 50rem;
|
||||
transition: all 150ms ease-in;
|
||||
min-width: fit-content;
|
||||
|
||||
:deep(a) {
|
||||
padding-bottom: 0 !important;
|
||||
line-height: 1.625rem !important;
|
||||
text-underline-offset: auto !important;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: .5rem 0rem;
|
||||
width: 100%;
|
||||
min-width: fit-content;
|
||||
&:nth-child(odd) {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 1px solid #d4d6d8;
|
||||
}
|
||||
|
||||
span {
|
||||
white-space: nowrap;
|
||||
padding: 0rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-footer {
|
||||
border-top: 1px solid $green;
|
||||
}
|
||||
|
||||
.subtotal-and-tax {
|
||||
background-color: $green-150;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $black;
|
||||
>div {
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-amount-due {
|
||||
color: $white;
|
||||
font-weight: 600;
|
||||
background-color: $green;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.modal-content a.external-text) {
|
||||
text-underline-offset: 0.25rem;
|
||||
line-height: 2;
|
||||
padding: 0 0 0.25rem 0;
|
||||
font-weight: 500;
|
||||
max-width: -webkit-fit-content;
|
||||
max-width: -moz-fit-content;
|
||||
max-width: fit-content;
|
||||
}
|
||||
|
||||
:deep(##{$RECYCLING_MODAL_REF_NAME} h5) {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
:deep(#recycle-fee-label a){
|
||||
line-height: initial;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -92,9 +92,10 @@
|
|||
<div class="cart-header">
|
||||
{{ cartHeaderText }}
|
||||
</div>
|
||||
<confirmationCart
|
||||
<cartDropdown
|
||||
v-if="showCart"
|
||||
:showAsPaid="payment.isPayInAdvance"
|
||||
:readOnly="true"
|
||||
recyclingModalCmsWidgetName="RecycleModal"
|
||||
servicePackageTitleWidgetName="ServicePackageTitle"
|
||||
:submittedOrder="submittedOrder" />
|
||||
|
|
@ -108,7 +109,7 @@
|
|||
import siteHeader from '@/iss-components/site-header/site-header.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 confirmationCart from '@/iss-components/confirmation-cart/confirmation-cart.vue';
|
||||
import cartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
|
||||
|
||||
// Supporting files
|
||||
import {
|
||||
|
|
@ -142,7 +143,7 @@ export default {
|
|||
siteHeader,
|
||||
siteFooter,
|
||||
addToCalendar,
|
||||
confirmationCart
|
||||
cartDropdown
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
|
|
@ -683,6 +684,12 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.service-description {
|
||||
>span:first-child {
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
}
|
||||
|
||||
.work-order-title {
|
||||
margin-bottom: .625rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
<cartDropdown
|
||||
:showAsPaid="false"
|
||||
:readOnly="false"
|
||||
:showAmountInHeader="true"
|
||||
recyclingModalCmsWidgetName="RecycleModal"
|
||||
servicePackageTitleWidgetName="ServicePackageTitle" />
|
||||
<hr class="mt-0 mb-5" />
|
||||
|
|
|
|||
|
|
@ -42,8 +42,7 @@
|
|||
<cartDropdown
|
||||
ref="cart"
|
||||
:readOnly="true"
|
||||
:showDropdownHeader="true"
|
||||
:isInitiallyExpanded="true"
|
||||
:showAsPaid="false"
|
||||
recyclingModalCmsWidgetName="RecycleModal"
|
||||
servicePackageTitleWidgetName="ServicePackageTitle" />
|
||||
<hr class="my-0">
|
||||
|
|
|
|||
|
|
@ -299,6 +299,11 @@ export const useMainStore = defineStore({
|
|||
const nonWindshieldItems = damage.glassToReplace?.filter((glass) => glass.glassLocation !== damageLocationsSelected.WINDSHIELD);
|
||||
return !!nonWindshieldItems?.length;
|
||||
},
|
||||
hasMoldingPart: (s) => {
|
||||
return s.order.lineItems.glassParts?.some((glassPart) => {
|
||||
return glassPart.childParts?.some((childPart) => childPart.partType === partTypeStrings.MOLDING);
|
||||
});
|
||||
},
|
||||
isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
||||
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
|
||||
isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF,
|
||||
|
|
|
|||
Loading…
Reference in a new issue