Merge pull request #1065 from Safelite/feature/humphries/INSR-7757
INSR-7757: order-confirmation Parity
This commit is contained in:
commit
c415f10ffa
20 changed files with 805 additions and 960 deletions
|
|
@ -56,4 +56,4 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
const cartItemType = Object.freeze({
|
const cartItemType = Object.freeze({
|
||||||
RECYCLE_FEE: 'RECYCLE FEE',
|
RECYCLE_FEE: 'RECYCLE FEE',
|
||||||
MOBILE_FEE: 'MOBILE FEE',
|
MOBILE_FEE: 'MOBILE FEE',
|
||||||
VAP: 'VAP'
|
VAP: 'VAP',
|
||||||
|
WARRANTY: 'WARRANTY'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default cartItemType;
|
export default cartItemType;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
RECALIBRATION: 'RECALIBRATION',
|
RECALIBRATION: 'RECALIBRATION',
|
||||||
REPLACE_FEE: 'REPLACE FEE',
|
REPLACE_FEE: 'REPLACE FEE',
|
||||||
MOBILE_FEE: 'MOBILE FEE',
|
MOBILE_FEE: 'MOBILE FEE',
|
||||||
REPAIR_FEE: 'REPAIR FEE'
|
REPAIR_FEE: 'REPAIR FEE',
|
||||||
|
WARRANTY: 'WARRANTY',
|
||||||
|
MOLDING: 'MOULDING'
|
||||||
});
|
});
|
||||||
|
|
||||||
export default partTypeStrings;
|
export default partTypeStrings;
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,26 @@ export async function isGlassAvailableForCarId(carId) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getGlassList(glassPieces) {
|
||||||
|
let names = '';
|
||||||
|
switch (glassPieces.length)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
names = glassPieces[0];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
names = glassPieces.join(' and ');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
names = glassPieces.slice(0, -1).join(', ') + ', and ' + glassPieces.slice(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return names.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commented code are copied directly from DigitalConsumer.FixMyGlass
|
* Commented code are copied directly from DigitalConsumer.FixMyGlass
|
||||||
* and have not been adjusted for ISS.
|
* and have not been adjusted for ISS.
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,21 @@ Object {
|
||||||
"MOBILE_FEE": "MOBILE FEE",
|
"MOBILE_FEE": "MOBILE FEE",
|
||||||
"RECYCLE_FEE": "RECYCLE FEE",
|
"RECYCLE_FEE": "RECYCLE FEE",
|
||||||
"VAP": "VAP",
|
"VAP": "VAP",
|
||||||
|
"WARRANTY": "WARRANTY",
|
||||||
},
|
},
|
||||||
"isExpanded": false,
|
|
||||||
"widget": Object {
|
"widget": Object {
|
||||||
"amountDue": "AmountDueTextWidget",
|
"amountDue": "AmountDueTextWidget",
|
||||||
"amountPaid": "AmountPaidTextWidget",
|
"amountPaid": "AmountPaidTextWidget",
|
||||||
"basePrice": "BasePriceWidget",
|
"basePrice": "BasePriceWidget",
|
||||||
"deductible": "DeductibleWidget",
|
"deductible": "DeductibleWidget",
|
||||||
|
"guaranteeText": "GuaranteeCartItemTextWidget",
|
||||||
"mobileFee": "MobileServiceWidget",
|
"mobileFee": "MobileServiceWidget",
|
||||||
"recycleFee": "RecycleFeeWidget",
|
"recycleFee": "RecycleFeeWidget",
|
||||||
"salesTax": "SalesTaxWidget",
|
"salesTax": "SalesTaxWidget",
|
||||||
"servicePackage": "ServicePackageTitle",
|
"servicePackage": "ServicePackageTitle",
|
||||||
"subtotal": "SubtotalWidget",
|
"subtotal": "SubtotalWidget",
|
||||||
"vapsItemDescriptions": "VapsItemDescriptions",
|
"vapsItemDescriptions": "VapsItemDescriptions",
|
||||||
|
"warrantyText": "WarrantyCartItemTextWidget",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
||||||
|
|
@ -73,47 +73,10 @@ describe('cart-dropdown component', () => {
|
||||||
expect(wrapper.vm.$data).toMatchSnapshot();
|
expect(wrapper.vm.$data).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
describe('displays', () => {
|
describe('displays', () => {
|
||||||
test('cart dropdown head', () => {
|
|
||||||
// Arrange
|
|
||||||
const reference = '#cart-dropdown-head';
|
|
||||||
const { wrapper } = getMountedComponent(cartDropdown);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const head = wrapper.find(reference);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(head.exists()).toBeTruthy();
|
|
||||||
});
|
|
||||||
test('cart dropdown head is visible', () => {
|
|
||||||
// Arrange
|
|
||||||
const reference = '#cart-dropdown-head';
|
|
||||||
const { wrapper } = getMountedComponent(cartDropdown, {}, { showDropdownHeader: true });
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const head = wrapper.find(reference);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(head.exists()).toBeTruthy();
|
|
||||||
expect(head.classes()).toContain('cart-toggle');
|
|
||||||
});
|
|
||||||
test('cart dropdown head is not visible', () => {
|
|
||||||
// Arrange
|
|
||||||
const reference = '#cart-dropdown-head';
|
|
||||||
const { wrapper } = getMountedComponent(cartDropdown, {}, { showDropdownHeader: false });
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const head = wrapper.find(reference);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(head.exists()).toBeTruthy();
|
|
||||||
expect(head.classes()).not.toContain('cart-toggle');
|
|
||||||
});
|
|
||||||
test('cart table', () => {
|
test('cart table', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-table';
|
const reference = '.cart-table';
|
||||||
const isExpanded = true;
|
const { wrapper } = getMountedComponent({}, {}, {});
|
||||||
const initialData = { isExpanded };
|
|
||||||
const { wrapper } = getMountedComponent({}, {}, initialData);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const cartTable = wrapper.find(reference);
|
const cartTable = wrapper.find(reference);
|
||||||
|
|
@ -121,11 +84,9 @@ describe('cart-dropdown component', () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(cartTable.exists()).toBeTruthy();
|
expect(cartTable.exists()).toBeTruthy();
|
||||||
});
|
});
|
||||||
test('cart deductible when showDeductibleLineItem is true', () => {
|
test('cart deductible when showDeductibleCartItem is true', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-deductible';
|
const reference = '#deductible-label';
|
||||||
const isExpanded = true;
|
|
||||||
const initialData = { isExpanded };
|
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
insuranceCoverage: {
|
insuranceCoverage: {
|
||||||
|
|
@ -134,7 +95,7 @@ describe('cart-dropdown component', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent(storeData, {}, initialData);
|
const { wrapper } = getMountedComponent(storeData, {}, {});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const cartDeductible = wrapper.find(reference);
|
const cartDeductible = wrapper.find(reference);
|
||||||
|
|
@ -144,9 +105,7 @@ describe('cart-dropdown component', () => {
|
||||||
});
|
});
|
||||||
test('cart base price when showDeductibleLineItem is false', () => {
|
test('cart base price when showDeductibleLineItem is false', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-base-price';
|
const reference = '#base-price-label';
|
||||||
const isExpanded = true;
|
|
||||||
const initialData = { isExpanded };
|
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
currentDeductible: 0,
|
currentDeductible: 0,
|
||||||
|
|
@ -160,7 +119,7 @@ describe('cart-dropdown component', () => {
|
||||||
isClaimRegistrationRequired: true
|
isClaimRegistrationRequired: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent(storeData, {}, initialData);
|
const { wrapper } = getMountedComponent(storeData, {}, {});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const cartBasePrice = wrapper.find(reference);
|
const cartBasePrice = wrapper.find(reference);
|
||||||
|
|
@ -168,25 +127,32 @@ describe('cart-dropdown component', () => {
|
||||||
// Assert
|
// Assert
|
||||||
expect(cartBasePrice.exists()).toBeTruthy();
|
expect(cartBasePrice.exists()).toBeTruthy();
|
||||||
});
|
});
|
||||||
test('service package', () => {
|
|
||||||
// Arrange
|
|
||||||
const reference = '#cart-service-package';
|
|
||||||
const isExpanded = true;
|
|
||||||
const initialData = { isExpanded };
|
|
||||||
const { wrapper } = getMountedComponent({}, {}, initialData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const servicePackage = wrapper.find(reference);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(servicePackage.exists()).toBeTruthy();
|
|
||||||
});
|
|
||||||
test('non service package cart items', () => {
|
test('non service package cart items', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#non-packaged-cart-items';
|
const reference = '.non-packaged.cart-item';
|
||||||
const isExpanded = true;
|
const part1 = { partType: 'apple' };
|
||||||
const initialData = { isExpanded };
|
const part2 = { partType: 'banana' };
|
||||||
const { wrapper } = getMountedComponent({}, {}, initialData);
|
const part3 = { partType: 'orange' };
|
||||||
|
const mobileFee = { partType: 'mobile' };
|
||||||
|
const storeData = {
|
||||||
|
order: {
|
||||||
|
currentDeductible: 0,
|
||||||
|
lineItems: {
|
||||||
|
glassParts: [part1],
|
||||||
|
supportingItems: [part2, part3],
|
||||||
|
otherParts: [],
|
||||||
|
feeItems: [mobileFee]
|
||||||
|
},
|
||||||
|
insuranceCoverage: {
|
||||||
|
coverageStatus: coverageStatuses.VERIFIED,
|
||||||
|
coverageType: coverageType.ITAC
|
||||||
|
}
|
||||||
|
},
|
||||||
|
issConfig: {
|
||||||
|
isClaimRegistrationRequired: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const { wrapper } = getMountedComponent(storeData, {}, {});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const nonPackagedCartItems = wrapper.find(reference);
|
const nonPackagedCartItems = wrapper.find(reference);
|
||||||
|
|
@ -220,9 +186,7 @@ describe('cart-dropdown component', () => {
|
||||||
test('cart footer', () => {
|
test('cart footer', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-footer';
|
const reference = '#cart-footer';
|
||||||
const isExpanded = true;
|
const { wrapper } = getMountedComponent({}, {}, {});
|
||||||
const initialData = { isExpanded };
|
|
||||||
const { wrapper } = getMountedComponent({}, {}, initialData);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const cartFooter = wrapper.find(reference);
|
const cartFooter = wrapper.find(reference);
|
||||||
|
|
@ -233,9 +197,7 @@ describe('cart-dropdown component', () => {
|
||||||
test('subtotal', () => {
|
test('subtotal', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-subtotal';
|
const reference = '#cart-subtotal';
|
||||||
const isExpanded = true;
|
const { wrapper } = getMountedComponent({}, {}, {});
|
||||||
const initialData = { isExpanded };
|
|
||||||
const { wrapper } = getMountedComponent({}, {}, initialData);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const subtotal = wrapper.find(reference);
|
const subtotal = wrapper.find(reference);
|
||||||
|
|
@ -246,9 +208,7 @@ describe('cart-dropdown component', () => {
|
||||||
test('tax', () => {
|
test('tax', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-sales-tax';
|
const reference = '#cart-sales-tax';
|
||||||
const isExpanded = true;
|
const { wrapper } = getMountedComponent({}, {}, {});
|
||||||
const initialData = { isExpanded };
|
|
||||||
const { wrapper } = getMountedComponent({}, {}, initialData);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const salesTax = wrapper.find(reference);
|
const salesTax = wrapper.find(reference);
|
||||||
|
|
@ -280,9 +240,7 @@ describe('cart-dropdown component', () => {
|
||||||
test('bottom amount due', () => {
|
test('bottom amount due', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#bottom-amount-due';
|
const reference = '#bottom-amount-due';
|
||||||
const isExpanded = true;
|
const { wrapper } = getMountedComponent({}, {}, {});
|
||||||
const initialData = { isExpanded };
|
|
||||||
const { wrapper } = getMountedComponent({}, {}, initialData);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const bottomAmountDue = wrapper.find(reference);
|
const bottomAmountDue = wrapper.find(reference);
|
||||||
|
|
@ -295,8 +253,6 @@ describe('cart-dropdown component', () => {
|
||||||
test('cart deductible when showDeductibleLineItem is false', () => {
|
test('cart deductible when showDeductibleLineItem is false', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-deductible';
|
const reference = '#cart-deductible';
|
||||||
const isExpanded = true;
|
|
||||||
const initialData = { isExpanded };
|
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
currentDeductible: 0,
|
currentDeductible: 0,
|
||||||
|
|
@ -310,7 +266,7 @@ describe('cart-dropdown component', () => {
|
||||||
isClaimRegistrationRequired: true
|
isClaimRegistrationRequired: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent(storeData, {}, initialData);
|
const { wrapper } = getMountedComponent(storeData, {}, {});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const cartDeductible = wrapper.find(reference);
|
const cartDeductible = wrapper.find(reference);
|
||||||
|
|
@ -321,8 +277,6 @@ describe('cart-dropdown component', () => {
|
||||||
test('cart base price when showDeductibleLineItem is true', () => {
|
test('cart base price when showDeductibleLineItem is true', () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const reference = '#cart-base-price';
|
const reference = '#cart-base-price';
|
||||||
const isExpanded = true;
|
|
||||||
const initialData = { isExpanded };
|
|
||||||
const storeData = {
|
const storeData = {
|
||||||
order: {
|
order: {
|
||||||
insuranceCoverage: {
|
insuranceCoverage: {
|
||||||
|
|
@ -331,7 +285,7 @@ describe('cart-dropdown component', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent(storeData, {}, initialData);
|
const { wrapper } = getMountedComponent(storeData, {}, {});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const cartBasePrice = wrapper.find(reference);
|
const cartBasePrice = wrapper.find(reference);
|
||||||
|
|
@ -1223,91 +1177,6 @@ describe('cart-dropdown component', () => {
|
||||||
expect(result.name).toBe(expectedName);
|
expect(result.name).toBe(expectedName);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('packagePrice', () => {
|
|
||||||
test('returns 0 when servicePackageCartItems is empty', () => {
|
|
||||||
// Arrange
|
|
||||||
getPriceOfLineItems.mockImplementation(() => 123);
|
|
||||||
getPackageContents.mockImplementationOnce(() => []);
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
lineItems: {
|
|
||||||
vaps: [
|
|
||||||
{
|
|
||||||
partType: partTypeStrings.REAR_WIPER
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.packagePrice;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(0);
|
|
||||||
});
|
|
||||||
test('returns expected when servicePackageCartItems not empty', () => {
|
|
||||||
// Arrange
|
|
||||||
const rearPrice = 101;
|
|
||||||
const frontPrice = 9;
|
|
||||||
getPriceOfLineItems.mockImplementation((lineItems) => {
|
|
||||||
if (lineItems.some((item) => item?.partType === partTypeStrings.FRONT_WIPER)) {
|
|
||||||
return frontPrice;
|
|
||||||
}
|
|
||||||
if (lineItems.some((item) => item?.partType === partTypeStrings.REAR_WIPER)) {
|
|
||||||
return rearPrice;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
getPackageContents.mockImplementationOnce(() => [partTypeStrings.FRONT_WIPER, partTypeStrings.REAR_WIPER]);
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
lineItems: {
|
|
||||||
vaps: [
|
|
||||||
{ partType: partTypeStrings.FRONT_WIPER },
|
|
||||||
{ partType: partTypeStrings.REAR_WIPER }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
const expectedPrice = 110;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.packagePrice;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(expectedPrice);
|
|
||||||
});
|
|
||||||
test('returns expected when servicePackageCartItems has one item', () => {
|
|
||||||
// Arrange
|
|
||||||
const frontPrice = 9;
|
|
||||||
getPriceOfLineItems.mockImplementation((lineItems) => {
|
|
||||||
if (lineItems.some((item) => item?.partType === partTypeStrings.FRONT_WIPER)) {
|
|
||||||
return frontPrice;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
getPackageContents.mockImplementationOnce(() => [partTypeStrings.FRONT_WIPER, partTypeStrings.REAR_WIPER]);
|
|
||||||
const storeData = {
|
|
||||||
order: {
|
|
||||||
lineItems: {
|
|
||||||
vaps: [
|
|
||||||
{ partType: partTypeStrings.FRONT_WIPER }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { wrapper } = getMountedComponent(storeData);
|
|
||||||
|
|
||||||
// Act
|
|
||||||
const result = wrapper.vm.packagePrice;
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(result).toBe(frontPrice);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
describe('method', () => {
|
describe('method', () => {
|
||||||
const dollarAmount = '$84.00';
|
const dollarAmount = '$84.00';
|
||||||
|
|
|
||||||
|
|
@ -1,156 +1,113 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="cart-table">
|
||||||
<div
|
<div class="cart-item-list">
|
||||||
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
|
<div
|
||||||
id="cart-line-items"
|
id="cart-deductible-or-base-price"
|
||||||
class="color-darker-gray">
|
class="cart-item">
|
||||||
<div
|
<div class="price-row">
|
||||||
id="cart-deductible-or-base-price"
|
<template
|
||||||
class="cart-item cart-gray">
|
v-if="showDeductibleCartItem">
|
||||||
<div
|
|
||||||
v-if="showDeductibleCartItem"
|
|
||||||
id="cart-deductible"
|
|
||||||
class="d-flex justify-content-between align-items-center py-2">
|
|
||||||
<span id="deductible-label">{{ deductibleLabel }}</span>
|
<span id="deductible-label">{{ deductibleLabel }}</span>
|
||||||
<span id="deductible-value">{{ getDisplayed(deductible) }}</span>
|
<span id="deductible-value">{{ getDisplayed(deductible) }}</span>
|
||||||
</div>
|
</template>
|
||||||
<div
|
<template
|
||||||
v-else
|
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-label">{{ basePriceLabel }}</span>
|
||||||
<span id="base-price-value">{{ getDisplayed(servicePrice) }}</span>
|
<span id="base-price-value">{{ getDisplayed(servicePrice) }}</span>
|
||||||
</div>
|
</template>
|
||||||
</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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<contentGroupModal
|
|
||||||
:ref="RECYCLING_MODAL_REF_NAME"
|
<!-- NonPackaged Cart Items -->
|
||||||
:cmsWidgetName="recyclingModalCmsWidgetName">
|
<div
|
||||||
<textBlock cmsWidgetName="RecycleTextBlock" />
|
v-for="(item, i) in nonServicePackageCartItems"
|
||||||
</contentGroupModal>
|
:key="i"
|
||||||
|
class="cart-item non-packaged">
|
||||||
|
<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 packaged">
|
||||||
|
<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>
|
||||||
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -176,28 +133,26 @@ import {
|
||||||
isOrderUnverified
|
isOrderUnverified
|
||||||
} from '@/helpers/cart-helper';
|
} from '@/helpers/cart-helper';
|
||||||
import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator';
|
import { getPriceOfLineItems, getTaxOfLineItems } from '@/helpers/price-calculator';
|
||||||
|
import { processIfStatements } from '@/helpers/cms-content-helper';
|
||||||
|
|
||||||
const VERIFYING_COVERAGE = 'Verifying coverage';
|
const VERIFYING_COVERAGE = 'Verifying coverage';
|
||||||
const RECYCLING_MODAL_REF_NAME = 'RecycleModal';
|
const RECYCLING_MODAL_REF_NAME = 'RecycleModal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'cart-dropdown',
|
name: 'confirmation-cart',
|
||||||
components: {
|
components: {
|
||||||
contentGroupModal,
|
contentGroupModal,
|
||||||
textBlock,
|
textBlock,
|
||||||
textLink
|
textLink
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
showAsPaid: Boolean,
|
|
||||||
readOnly: Boolean,
|
readOnly: Boolean,
|
||||||
|
showAsPaid: Boolean,
|
||||||
recyclingModalCmsWidgetName: String,
|
recyclingModalCmsWidgetName: String,
|
||||||
showDropdownHeader: Boolean,
|
|
||||||
isInitiallyExpanded: Boolean,
|
|
||||||
submittedOrder: Object
|
submittedOrder: Object
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isExpanded: this.isInitiallyExpanded,
|
|
||||||
widget: {
|
widget: {
|
||||||
amountDue: 'AmountDueTextWidget',
|
amountDue: 'AmountDueTextWidget',
|
||||||
amountPaid: 'AmountPaidTextWidget',
|
amountPaid: 'AmountPaidTextWidget',
|
||||||
|
|
@ -208,7 +163,9 @@ export default {
|
||||||
recycleFee: 'RecycleFeeWidget',
|
recycleFee: 'RecycleFeeWidget',
|
||||||
mobileFee: 'MobileServiceWidget',
|
mobileFee: 'MobileServiceWidget',
|
||||||
servicePackage: 'ServicePackageTitle',
|
servicePackage: 'ServicePackageTitle',
|
||||||
vapsItemDescriptions: 'VapsItemDescriptions'
|
vapsItemDescriptions: 'VapsItemDescriptions',
|
||||||
|
warrantyText: 'WarrantyCartItemTextWidget',
|
||||||
|
guaranteeText: 'GuaranteeCartItemTextWidget'
|
||||||
},
|
},
|
||||||
cartItemType,
|
cartItemType,
|
||||||
RECYCLING_MODAL_REF_NAME
|
RECYCLING_MODAL_REF_NAME
|
||||||
|
|
@ -273,7 +230,7 @@ export default {
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
vehicleDamage() {
|
vehicleDamage() {
|
||||||
return this.submittedOrder ? this.submittedOrder.damage : useMainStore().damage;
|
return this.cartOrder.damage;
|
||||||
},
|
},
|
||||||
servicePackageTier() {
|
servicePackageTier() {
|
||||||
const { glassToReplace, isRepair } = this.vehicleDamage;
|
const { glassToReplace, isRepair } = this.vehicleDamage;
|
||||||
|
|
@ -333,6 +290,9 @@ export default {
|
||||||
if (this.mobileFeeCartItem && !isMobileFeeHidden) {
|
if (this.mobileFeeCartItem && !isMobileFeeHidden) {
|
||||||
items.push(this.mobileFeeCartItem);
|
items.push(this.mobileFeeCartItem);
|
||||||
}
|
}
|
||||||
|
if (this.isITAC || this.isNoComp) {
|
||||||
|
items.push(this.warrantyCartItem);
|
||||||
|
}
|
||||||
return items;
|
return items;
|
||||||
},
|
},
|
||||||
frontWipersCartItem() {
|
frontWipersCartItem() {
|
||||||
|
|
@ -350,12 +310,6 @@ export default {
|
||||||
...this.nonServicePackageCartItems
|
...this.nonServicePackageCartItems
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
packagePrice() {
|
|
||||||
return this.servicePackageCartItems?.reduce(
|
|
||||||
(accumulator, cartItem) => accumulator + (cartItem?.subTotal ?? 0),
|
|
||||||
0
|
|
||||||
) ?? 0;
|
|
||||||
},
|
|
||||||
amountDueLabel() {
|
amountDueLabel() {
|
||||||
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
return this.getCmsContent(this.widget.amountDue, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
},
|
},
|
||||||
|
|
@ -366,7 +320,12 @@ export default {
|
||||||
return this.getCmsContent(this.widget.deductible, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
return this.getCmsContent(this.widget.deductible, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
},
|
},
|
||||||
basePriceLabel() {
|
basePriceLabel() {
|
||||||
return this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
const content = this.getCmsContent(this.widget.basePrice, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
|
return processIfStatements(
|
||||||
|
content,
|
||||||
|
'custom',
|
||||||
|
this.getCustomValueFromString
|
||||||
|
);
|
||||||
},
|
},
|
||||||
subtotalLabel() {
|
subtotalLabel() {
|
||||||
return this.getCmsContent(this.widget.subtotal, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
return this.getCmsContent(this.widget.subtotal, widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||||
|
|
@ -409,15 +368,29 @@ export default {
|
||||||
partTypeStrings.MOBILE_FEE
|
partTypeStrings.MOBILE_FEE
|
||||||
)
|
)
|
||||||
: null;
|
: 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: {
|
methods: {
|
||||||
openModal(modalName) {
|
openModal(modalName) {
|
||||||
this.$refs[modalName].openModal();
|
this.$refs[modalName].openModal();
|
||||||
},
|
},
|
||||||
toggleIsExpanded() {
|
|
||||||
this.isExpanded = !this.isExpanded;
|
|
||||||
},
|
|
||||||
getDisplayed(amount) {
|
getDisplayed(amount) {
|
||||||
return this.isUnverified
|
return this.isUnverified
|
||||||
? VERIFYING_COVERAGE
|
? VERIFYING_COVERAGE
|
||||||
|
|
@ -461,6 +434,16 @@ export default {
|
||||||
const vapsTypeDescription = vapsItemDescriptions?.find((entry) => entry?.Name === vapsPartType);
|
const vapsTypeDescription = vapsItemDescriptions?.find((entry) => entry?.Name === vapsPartType);
|
||||||
return vapsTypeDescription?.Text ?? '';
|
return vapsTypeDescription?.Text ?? '';
|
||||||
},
|
},
|
||||||
|
getCustomValueFromString(str) {
|
||||||
|
switch (str) {
|
||||||
|
case 'isRepair':
|
||||||
|
return this.cartOrder.damage.isRepair;
|
||||||
|
case 'hasMoldingPart':
|
||||||
|
return this.hasMoldingPart;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
formatAmountInDollars
|
formatAmountInDollars
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -471,45 +454,38 @@ export default {
|
||||||
|
|
||||||
$RECYCLING_MODAL_REF_NAME: 'RecycleModal';
|
$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 {
|
.cart-table {
|
||||||
max-height: 0;
|
max-height: 50rem;
|
||||||
transition: all 350ms ease-in;
|
transition: all 150ms ease-in;
|
||||||
overflow: hidden;
|
min-width: fit-content;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cart-item {
|
.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 {
|
.price-row {
|
||||||
background-color: $gray-100;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
span, a {
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: $heritage-blue-secondary;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cart-footer {
|
.cart-footer {
|
||||||
|
|
@ -520,13 +496,16 @@ $RECYCLING_MODAL_REF_NAME: 'RecycleModal';
|
||||||
background-color: $green-150;
|
background-color: $green-150;
|
||||||
font-weight: $font-weight-bold;
|
font-weight: $font-weight-bold;
|
||||||
color: $black;
|
color: $black;
|
||||||
padding: 0.25rem 1.5rem;
|
>div {
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom-amount-due {
|
.bottom-amount-due {
|
||||||
color: $white;
|
color: $white;
|
||||||
|
font-weight: 600;
|
||||||
background-color: $green;
|
background-color: $green;
|
||||||
padding: 0.5rem 1.5rem;
|
padding: .5rem 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -544,39 +523,6 @@ $RECYCLING_MODAL_REF_NAME: 'RecycleModal';
|
||||||
text-align: center;
|
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){
|
:deep(#recycle-fee-label a){
|
||||||
line-height: initial;
|
line-height: initial;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,10 @@
|
||||||
import calendarOptions from '@/constants/calendar-options';
|
import calendarOptions from '@/constants/calendar-options';
|
||||||
|
|
||||||
// Supporting Files
|
// Supporting Files
|
||||||
import { shallowMount, mount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
import { getMountOptions } from '@/helpers/unit-test-helper.js';
|
||||||
import { useMainStore } from '@/store';
|
import { useMainStore } from '@/store';
|
||||||
import addToCalendar from '@/layouts/order-confirmation/add-to-calendar/add-to-calendar.vue';
|
import addToCalendar from '@/layouts/order-confirmation/add-to-calendar/add-to-calendar.vue';
|
||||||
import { createTestingPinia } from '@pinia/testing';
|
|
||||||
|
|
||||||
const appointmentText = 'Appointment content';
|
const appointmentText = 'Appointment content';
|
||||||
function setupMocks({ customMountOptions }) {
|
function setupMocks({ customMountOptions }) {
|
||||||
|
|
@ -21,49 +20,6 @@ function setupMocks({ customMountOptions }) {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
const wrapper = shallowMount(addToCalendar, mountOptions);
|
const wrapper = shallowMount(addToCalendar, mountOptions);
|
||||||
wrapper.vm.$refs.calendarModalQuestion.openModal = jest.fn();
|
|
||||||
return { wrapper };
|
|
||||||
}
|
|
||||||
|
|
||||||
const calendarModalQuestionStub = {
|
|
||||||
render: () => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockMixin = {
|
|
||||||
methods: {
|
|
||||||
getCmsContent: jest.fn().mockImplementation(() => appointmentText)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function getMountedComponent(mainInitialState = {}, initialData = {}, methodToRun = () => {}, mixin = mockMixin) {
|
|
||||||
const mountOptions = getMountOptions({
|
|
||||||
router: {
|
|
||||||
navigate: jest.fn(),
|
|
||||||
navigateToExternalUrl: jest.fn()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mountOptions.global.stubs = {
|
|
||||||
calendarModalQuestion: calendarModalQuestionStub
|
|
||||||
};
|
|
||||||
|
|
||||||
const testingPinia = createTestingPinia({
|
|
||||||
initialState: {
|
|
||||||
main: mainInitialState
|
|
||||||
}
|
|
||||||
});
|
|
||||||
useMainStore(testingPinia);
|
|
||||||
methodToRun();
|
|
||||||
|
|
||||||
mountOptions.global.mixins[0].methods.getSettingValue = jest.fn(() => 'false');
|
|
||||||
mountOptions.global.plugins = [testingPinia];
|
|
||||||
mountOptions.mixins = [mixin];
|
|
||||||
mountOptions.data = () => (
|
|
||||||
initialData
|
|
||||||
);
|
|
||||||
|
|
||||||
const wrapper = shallowMount(addToCalendar, mountOptions);
|
|
||||||
wrapper.vm.$refs.calendarModalQuestion.openModal = jest.fn();
|
|
||||||
return { wrapper };
|
return { wrapper };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,51 +75,8 @@ afterEach(() => {
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
const sessionStorage = {
|
|
||||||
schedule: {
|
|
||||||
date: '2019-01-01',
|
|
||||||
startTime: '09:00',
|
|
||||||
endTime: '10:00',
|
|
||||||
routeCode: '000'
|
|
||||||
},
|
|
||||||
lineItems: {
|
|
||||||
glassParts: [
|
|
||||||
{
|
|
||||||
partNumber: 'ABC123'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
supportingItems: []
|
|
||||||
},
|
|
||||||
serviceLocation: {
|
|
||||||
address: '',
|
|
||||||
address2: null,
|
|
||||||
city: '',
|
|
||||||
state: 'AZ',
|
|
||||||
appointmentType: 'Inshop',
|
|
||||||
zipCode: '12345',
|
|
||||||
zipCodeCtu: '01234',
|
|
||||||
provider: {
|
|
||||||
providerNumber: '123',
|
|
||||||
address: {
|
|
||||||
streetAddress: 'test1',
|
|
||||||
city: 'test',
|
|
||||||
state: 'AZ',
|
|
||||||
zipCode: '12345',
|
|
||||||
zipCodeCtu: '01234'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
damage: {
|
|
||||||
isRepair: false
|
|
||||||
},
|
|
||||||
referralNumber: '1234567',
|
|
||||||
payment: {
|
|
||||||
isInsurance: true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Add-to-calendar methods...', () => {
|
describe('Add-to-calendar methods...', () => {
|
||||||
test('Add-to-calendar should trigger openModal method', () => {
|
test('Add-to-calendar should trigger open options', async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const { wrapper } = setupMocks({
|
const { wrapper } = setupMocks({
|
||||||
customMountOptions: {
|
customMountOptions: {
|
||||||
|
|
@ -183,10 +96,11 @@ describe('Add-to-calendar methods...', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
wrapper.vm.openCalendarModal();
|
wrapper.vm.openCalendarOptions();
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(wrapper.vm.$refs.calendarModalQuestion.openModal).toBeCalled();
|
expect(wrapper.vm.$refs.calendarOptions.open).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getCalendarData should return expected model value.', () => {
|
test('getCalendarData should return expected model value.', () => {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="calendar-section">
|
<div class="calendar-section">
|
||||||
<div class="add-to-calendar">
|
<div class="add-to-calendar">
|
||||||
<button @click="openCalendarModal">
|
<button @click="toggleCalendarOptionsOpen">
|
||||||
<span class="add-to-calendar-span">
|
<span class="add-to-calendar-span">
|
||||||
<img
|
<img
|
||||||
src="@/assets/img/icons/add-to-calendar.svg"
|
src="@/assets/img/icons/add-to-calendar.svg"
|
||||||
|
|
@ -10,14 +10,12 @@
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<calendarModalQuestion
|
<calendarOptionSelection
|
||||||
ref="calendarModalQuestion"
|
ref="calendarOptions"
|
||||||
v-model="selectedCalendarOption"
|
:open="calendarOptionsOpen"
|
||||||
customComponentId="calendarModalQuestion"
|
|
||||||
cmsWidgetName="CalendarModalQuestion"
|
|
||||||
:calendarOptionsData="calendarValues"
|
:calendarOptionsData="calendarValues"
|
||||||
@calendarModalClosed="calendarModalClosed">
|
@calendarOptionSelected="calendarOptionSelected">
|
||||||
</calendarModalQuestion>
|
</calendarOptionSelection>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
@ -32,12 +30,12 @@ import { AppointmentTypeStrings, RouteCodeFlags } from '@/constants/schedule-con
|
||||||
import { getCalendarFile, download } from '@/helpers/add-to-calendar-helper';
|
import { getCalendarFile, download } from '@/helpers/add-to-calendar-helper';
|
||||||
import serviceType from '@/constants/service-type';
|
import serviceType from '@/constants/service-type';
|
||||||
import applicationConfig from '@/constants/application-config.js';
|
import applicationConfig from '@/constants/application-config.js';
|
||||||
import calendarModalQuestion from '@/layouts/order-confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue';
|
import calendarOptionSelection from '@/layouts/order-confirmation/add-to-calendar/calendar-option-selection/calendar-option-selection.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'add-to-calendar',
|
name: 'add-to-calendar',
|
||||||
components: {
|
components: {
|
||||||
calendarModalQuestion
|
calendarOptionSelection
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
mobileWidgetName: String,
|
mobileWidgetName: String,
|
||||||
|
|
@ -59,7 +57,7 @@ export default {
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selectedCalendarOption: null
|
calendarOptionsOpen: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -84,7 +82,7 @@ export default {
|
||||||
return this.getCmsContent(this.mobileWidgetName, 'BodyText');
|
return this.getCmsContent(this.mobileWidgetName, 'BodyText');
|
||||||
},
|
},
|
||||||
AddToCalendar_InShop_Subject() {
|
AddToCalendar_InShop_Subject() {
|
||||||
return this.getCmsContent('AddToCalendar_InShop', 'HeaderText');
|
return this.getCmsContent(this.inShopWidgetName, 'HeaderText');
|
||||||
},
|
},
|
||||||
AddToCalendar_InShop_Body() {
|
AddToCalendar_InShop_Body() {
|
||||||
return this.getCmsContent(this.inShopWidgetName, 'BodyText');
|
return this.getCmsContent(this.inShopWidgetName, 'BodyText');
|
||||||
|
|
@ -192,14 +190,6 @@ export default {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
selectedCalendarOption(newValue) {
|
|
||||||
if (newValue) {
|
|
||||||
this.setCalendarAppointment(newValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
setCalendarAppointment(calendarOption) {
|
setCalendarAppointment(calendarOption) {
|
||||||
if (
|
if (
|
||||||
|
|
@ -211,12 +201,20 @@ export default {
|
||||||
window.open(calendarOption.url);
|
window.open(calendarOption.url);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
calendarModalClosed() {
|
toggleCalendarOptionsOpen() {
|
||||||
// Clear the selectedOption if close the modal
|
if (this.calendarOptionsOpen) {
|
||||||
this.selectedCalendarOption = null;
|
this.closeCalendarOptions();
|
||||||
|
} else {
|
||||||
|
this.openCalendarOptions();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
openCalendarModal() {
|
openCalendarOptions() {
|
||||||
this.$refs.calendarModalQuestion.openModal();
|
this.calendarOptionsOpen = true;
|
||||||
|
window.addEventListener('click', this.clickListener);
|
||||||
|
},
|
||||||
|
calendarOptionSelected(calendarOptionIndex) {
|
||||||
|
this.setCalendarAppointment(this.calendarValues[calendarOptionIndex]);
|
||||||
|
this.closeCalendarOptions();
|
||||||
},
|
},
|
||||||
getCalendarData(type) {
|
getCalendarData(type) {
|
||||||
let URL = '';
|
let URL = '';
|
||||||
|
|
@ -253,29 +251,39 @@ export default {
|
||||||
};
|
};
|
||||||
const calBody = getCalendarFile(calFile);
|
const calBody = getCalendarFile(calFile);
|
||||||
download('SafeliteAppointment.ics', calBody);
|
download('SafeliteAppointment.ics', calBody);
|
||||||
|
},
|
||||||
|
closeCalendarOptions() {
|
||||||
|
this.calendarOptionsOpen = false;
|
||||||
|
window.removeEventListener('click', this.clickListener);
|
||||||
|
},
|
||||||
|
clickListener(event) {
|
||||||
|
const calendarSection = document.querySelector('.calendar-section');
|
||||||
|
if (calendarSection && !calendarSection.contains(event.target)) {
|
||||||
|
this.closeCalendarOptions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
unmounted() {
|
||||||
|
window.removeEventListener('click', this.clickListener);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
|
div.calendar-section {
|
||||||
|
position: relative;
|
||||||
|
top: 17px;
|
||||||
|
display: inline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.add-to-calendar-text {
|
.add-to-calendar-text {
|
||||||
margin: 0 0 0 0.4375rem;
|
margin: 0 0 0 0.4375rem;
|
||||||
color: #1574a1;
|
color: $heritage-blue-secondary;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.add-to-calendar button {
|
.add-to-calendar button {
|
||||||
border: 0;
|
border: 0;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
.calendar-section {
|
|
||||||
display: table;
|
|
||||||
position: relative;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.calendar-section .add-to-calendar {
|
|
||||||
padding-top: 1rem;
|
|
||||||
padding-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.calendar-section .add-to-calendar .add-to-calendar-span {
|
.calendar-section .add-to-calendar .add-to-calendar-span {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
<template>
|
|
||||||
<baseInputButton
|
|
||||||
v-bind="$props"
|
|
||||||
v-model="selectedValue"
|
|
||||||
buttonWrapperClasses="list-group base-input-button list-button rounded-3 d-flex flex-column w-100 mb-2">
|
|
||||||
<div
|
|
||||||
:aria-label="buttonLabel"
|
|
||||||
class="button-content list-button-content d-flex flex-column justify-content-center py-3 px-4">
|
|
||||||
<span
|
|
||||||
class="m-0 position-relative"
|
|
||||||
:class="textPosition">
|
|
||||||
<img :src="buttonLabel" />
|
|
||||||
<span class="calendar-text">{{ value }}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</baseInputButton>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import baseInputButton from '@/digital-components/base-input-button/base-input-button.vue';
|
|
||||||
import inputButtonWrapperMixin from '@/mixins/input-button-wrapper-mixin.js';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'calendar-modal-list-button',
|
|
||||||
components: {
|
|
||||||
baseInputButton
|
|
||||||
},
|
|
||||||
mixins: [inputButtonWrapperMixin]
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.list-button {
|
|
||||||
outline: none;
|
|
||||||
input[type="radio"],
|
|
||||||
input[type="checkbox"] {
|
|
||||||
position: static; //override bootstrap
|
|
||||||
|
|
||||||
&:focus-visible + .list-button-content {
|
|
||||||
box-shadow: 0 0 0 2.5px $blue;
|
|
||||||
}
|
|
||||||
&:focus + .list-button-content {
|
|
||||||
box-shadow: 0 0 0 2.5px $blue;
|
|
||||||
}
|
|
||||||
&:checked + .list-button-content {
|
|
||||||
color: $black;
|
|
||||||
font-weight: 500;
|
|
||||||
background: $blue-100;
|
|
||||||
box-shadow: 0 0 0 1px $blue;
|
|
||||||
}
|
|
||||||
&:checked:focus + .list-button-content {
|
|
||||||
box-shadow: 0 0 0 2.5px $blue;
|
|
||||||
}
|
|
||||||
&:checked + .list-button-content p,
|
|
||||||
&:checked + .list-button-content span {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
&:checked + .list-button-content span:nth-child(2) {
|
|
||||||
font-weight: 400;
|
|
||||||
color: $gray-600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.list-button-content {
|
|
||||||
color: $gray-600;
|
|
||||||
position: relative;
|
|
||||||
background: $white;
|
|
||||||
transition: all 150ms linear;
|
|
||||||
border-radius: $border-radius-lg;
|
|
||||||
border: 0.063rem solid $gray-500;
|
|
||||||
width: 100%;
|
|
||||||
outline: none;
|
|
||||||
|
|
||||||
span.calendar-text {
|
|
||||||
margin-left: 0.313rem;
|
|
||||||
padding: 0.125rem 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.position-relative {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
import { shallowMount } from '@vue/test-utils';
|
|
||||||
import calendarModalQuestion from '@/layouts/order-confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue';
|
|
||||||
|
|
||||||
describe('calendar-modal-question.vue', () => {
|
|
||||||
test('When selected calendar option is changed, a correctly selectedCalendarOption should be emitted', async () => {
|
|
||||||
// Arrange
|
|
||||||
const url = 'iCal url';
|
|
||||||
const name = 'iCal';
|
|
||||||
const icon = 'iCal.svg';
|
|
||||||
const expectedEmit = [
|
|
||||||
[
|
|
||||||
{
|
|
||||||
url,
|
|
||||||
name,
|
|
||||||
icon
|
|
||||||
}
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
const wrapper = shallowMount(calendarModalQuestion, {
|
|
||||||
propsData: {
|
|
||||||
calendarOptionsData: [
|
|
||||||
{
|
|
||||||
url,
|
|
||||||
name,
|
|
||||||
icon
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
wrapper.vm.$refs.calendarOptions.closeModal = jest.fn();
|
|
||||||
wrapper.vm.selectedCalendarOption = name;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
wrapper.vm.setSelectedCalendarOption();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
expect(wrapper.emitted()['update:modelValue']).toEqual(expectedEmit);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
<template>
|
|
||||||
<modal
|
|
||||||
:ref="modalName"
|
|
||||||
:fontSize="true"
|
|
||||||
:headerText="modalHeaderText"
|
|
||||||
:footerButtonText="footerCloseButtonText"
|
|
||||||
:onModalClosedCallback="onModalClosed"
|
|
||||||
class="calendar-modal"
|
|
||||||
@isModalOpened="setModalStatus"
|
|
||||||
@footerButtonEvent="setSelectedCalendarOption">
|
|
||||||
<template v-if="isModalOpened">
|
|
||||||
<buttonQuestion
|
|
||||||
ref="buttonQuestion"
|
|
||||||
v-model="selectedCalendarOption"
|
|
||||||
buttonTypeString="calendarModalListButton"
|
|
||||||
:buttonTypeObject="calendarModalListButton"
|
|
||||||
:answers="getCalendarOptionData"
|
|
||||||
groupName="chooseCalendarType"
|
|
||||||
class="mt-1"
|
|
||||||
textPosition="text-center"
|
|
||||||
isRequired
|
|
||||||
validationRules="calendar-option-required" />
|
|
||||||
</template>
|
|
||||||
</modal>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import modal from '@/digital-components/modal/modal.vue';
|
|
||||||
import buttonQuestion from '@/digital-components/button-question/button-question.vue';
|
|
||||||
import { defineRule, useField } from 'vee-validate';
|
|
||||||
import errorMessages from '@/constants/error-messages.js';
|
|
||||||
import { required } from '@/helpers/validation-rules';
|
|
||||||
import { deepClone } from '@/helpers/object-helper';
|
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
import calendarModalListButton from './calendar-modal-list-button/calendar-modal-list-button.vue';
|
|
||||||
// Validation for the modal button
|
|
||||||
defineRule('calendar-option-required', required(errorMessages.OPTION_REQUIRED));
|
|
||||||
export default {
|
|
||||||
name: 'calendar-modal-question',
|
|
||||||
components: {
|
|
||||||
modal,
|
|
||||||
buttonQuestion
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
calendarOptionsData: Object,
|
|
||||||
modelValue: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({
|
|
||||||
url: null,
|
|
||||||
name: null,
|
|
||||||
icon: null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['calendar-modal-closed', 'update:modelValue'],
|
|
||||||
setup(props) {
|
|
||||||
const uuid = uuidv4();
|
|
||||||
const componentId = !props.customComponentId
|
|
||||||
? `component-${uuid}`
|
|
||||||
: props.customComponentId;
|
|
||||||
|
|
||||||
const { modelValue } = deepClone(props);
|
|
||||||
const initialValue = modelValue;
|
|
||||||
|
|
||||||
const fieldOptions = {
|
|
||||||
value: modelValue,
|
|
||||||
initialValue
|
|
||||||
};
|
|
||||||
|
|
||||||
const { errorMessage, handleChange, meta, validate, errors } = useField(
|
|
||||||
componentId,
|
|
||||||
props.validationRules,
|
|
||||||
fieldOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
componentId,
|
|
||||||
errorMessage,
|
|
||||||
handleChange,
|
|
||||||
validate,
|
|
||||||
meta,
|
|
||||||
errors
|
|
||||||
};
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isModalOpened: false,
|
|
||||||
selectedValue: null,
|
|
||||||
calendarModalListButton
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
modalName() {
|
|
||||||
return 'calendarOptions';
|
|
||||||
},
|
|
||||||
modalHeaderText() {
|
|
||||||
return 'Add to Calendar';
|
|
||||||
},
|
|
||||||
footerCloseButtonText() {
|
|
||||||
return 'Add to Calendar';
|
|
||||||
},
|
|
||||||
modal() {
|
|
||||||
return this.$refs[this.modalName];
|
|
||||||
},
|
|
||||||
selectedCalendarOption: {
|
|
||||||
get() {
|
|
||||||
return this.modelValue?.name;
|
|
||||||
},
|
|
||||||
set(newValue) {
|
|
||||||
// Button Question only supports Number, or String data types so we must convert to the full object before emitting
|
|
||||||
this.selectedValue = this.getSelectedCalendarObject(newValue);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getCalendarOptionData() {
|
|
||||||
return this.calendarOptionsData.map((item) => ({
|
|
||||||
value: item.name,
|
|
||||||
buttonLabel: item.icon
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
modelValue: {
|
|
||||||
handler(newValue) {
|
|
||||||
this.handleChange(newValue);
|
|
||||||
},
|
|
||||||
deep: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
openModal() {
|
|
||||||
this.modal.openModal();
|
|
||||||
},
|
|
||||||
setModalStatus(isOpened) {
|
|
||||||
this.isModalOpened = isOpened;
|
|
||||||
},
|
|
||||||
closeModal() {
|
|
||||||
this.modal.closeModal();
|
|
||||||
},
|
|
||||||
onModalClosed() {
|
|
||||||
this.$emit('calendar-modal-closed');
|
|
||||||
},
|
|
||||||
async setSelectedCalendarOption() {
|
|
||||||
this.$emit('update:modelValue', this.selectedValue);
|
|
||||||
this.closeModal();
|
|
||||||
},
|
|
||||||
|
|
||||||
getSelectedCalendarObject(calendarOptionId) {
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
const calendarOption = this.calendarOptionsData?.find((calendarOption) => calendarOption.name === calendarOptionId);
|
|
||||||
|
|
||||||
if (calendarOption) {
|
|
||||||
return {
|
|
||||||
url: calendarOption.url,
|
|
||||||
name: calendarOption.name,
|
|
||||||
icon: calendarOption.icon
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: null,
|
|
||||||
name: null,
|
|
||||||
icon: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.calendar-modal.modal.modal-component {
|
|
||||||
> .modal-dialog > .modal-content {
|
|
||||||
margin-top: 1.5rem;
|
|
||||||
}
|
|
||||||
.modal-header {
|
|
||||||
padding-bottom: 0;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<a
|
||||||
|
:aria-label="buttonLabel"
|
||||||
|
class="d-flex flex-row option-button">
|
||||||
|
<img :src="buttonLabel" />
|
||||||
|
<span class="calendar-text">{{ value }}</span>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'calendar-option-button',
|
||||||
|
props: {
|
||||||
|
buttonLabel: String,
|
||||||
|
value: String
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.option-button {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #4d4e53;
|
||||||
|
font-weight: 400;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: .75rem 3.125rem .0625rem 1rem;
|
||||||
|
height: 2.75rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: $background-color-selected;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-text {
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import calendarOptionSelection from '@/layouts/order-confirmation/add-to-calendar/calendar-option-selection/calendar-option-selection.vue';
|
||||||
|
|
||||||
|
describe('calendar-option-selection.vue', () => {
|
||||||
|
test('When selected calendar option is changed, a correctly selectedCalendarOption should be emitted', async () => {
|
||||||
|
// Arrange
|
||||||
|
const url = 'iCal url';
|
||||||
|
const name = 'iCal';
|
||||||
|
const icon = 'iCal.svg';
|
||||||
|
const url2 = 'Google url';
|
||||||
|
const name2 = 'Google';
|
||||||
|
const icon2 = 'Google.svg';
|
||||||
|
const expectedEmit = [
|
||||||
|
[
|
||||||
|
1
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
const wrapper = shallowMount(calendarOptionSelection, {
|
||||||
|
propsData: {
|
||||||
|
calendarOptionsData: [
|
||||||
|
{
|
||||||
|
url,
|
||||||
|
name,
|
||||||
|
icon
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: url2,
|
||||||
|
name: name2,
|
||||||
|
icon: icon2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
wrapper.vm.setSelectedCalendarOption(1);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(wrapper.emitted()['calendar-option-selected']).toEqual(expectedEmit);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-if="open"
|
||||||
|
class="calendar-selection">
|
||||||
|
<template
|
||||||
|
v-for="(option, index) in getCalendarOptionData"
|
||||||
|
:key="option.value">
|
||||||
|
<calendarOptionButton
|
||||||
|
:buttonLabel="option.buttonLabel"
|
||||||
|
:value="option.value"
|
||||||
|
@click="setSelectedCalendarOption(index)" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import calendarOptionButton from './calendar-option-button/calendar-option-button.vue';
|
||||||
|
export default {
|
||||||
|
name: 'calendar-option-selection',
|
||||||
|
components: {
|
||||||
|
calendarOptionButton
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
calendarOptionsData: Array,
|
||||||
|
open: Boolean
|
||||||
|
},
|
||||||
|
emits: ['calendar-option-selected'],
|
||||||
|
computed: {
|
||||||
|
getCalendarOptionData() {
|
||||||
|
return this.calendarOptionsData.map((item) => ({
|
||||||
|
value: item.name,
|
||||||
|
buttonLabel: item.icon
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async setSelectedCalendarOption(index) {
|
||||||
|
this.$emit('calendar-option-selected', index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.calendar-selection {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
display: table;
|
||||||
|
border: solid 1px #d4d6d8;
|
||||||
|
border-radius: .25rem;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 0 0 10px 0 rgba(88, 188, 233, 0.2);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -206,6 +206,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => sessionStorage);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => sessionStorage);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
|
||||||
|
console.log(wrapper.vm.$refs);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
const arePagePrerequisitesValid = wrapper.vm.arePagePrerequisitesValid();
|
||||||
|
|
@ -363,7 +364,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
expect(actualEmail).toBe(emailAddress);
|
expect(actualEmail).toBe(emailAddress);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('confirmationEmailText', () => {
|
describe('orderConfirmationUpdateAppointmentText', () => {
|
||||||
const greaterId = '>';
|
const greaterId = '>';
|
||||||
const lessId = '<';
|
const lessId = '<';
|
||||||
test.each([
|
test.each([
|
||||||
|
|
@ -383,7 +384,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent(initialStore, {}, mockStoreActions);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.confirmationEmailText;
|
const text = wrapper.vm.orderConfirmationUpdateAppointmentText;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
expect(text).toBe(expected);
|
expect(text).toBe(expected);
|
||||||
|
|
@ -391,13 +392,13 @@ describe('OrderConfirmation.vue', () => {
|
||||||
});
|
});
|
||||||
describe('appointmentTimeText', () => {
|
describe('appointmentTimeText', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['Between 9 AM - 10 AM', '09:00', '10:00'],
|
['Your appointment is at 9 AM - 10 AM', '09:00', '10:00'],
|
||||||
['Between 1 PM - 5 PM', '13:00', '17:00'],
|
['Your appointment is at 1 PM - 5 PM', '13:00', '17:00'],
|
||||||
['Between 8:30 AM - 3 PM', '08:30', '15:00'],
|
['Your appointment is at 8:30 AM - 3 PM', '08:30', '15:00'],
|
||||||
['Between 1 AM - 2 AM', '01:00', '02:00'],
|
['Your appointment is at 1 AM - 2 AM', '01:00', '02:00'],
|
||||||
['Between 12 AM - 2 AM', '00:00', '02:00'],
|
['Your appointment is at 12 AM - 2 AM', '00:00', '02:00'],
|
||||||
['Between 12 PM - 2 AM', '12:00', '02:00'],
|
['Your appointment is at 12 PM - 2 AM', '12:00', '02:00'],
|
||||||
['Between 11 PM - 12 AM', '23:00', '00:00']
|
['Your appointment is at 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) => {
|
])('should return Mobile time in expected format "%p" when start time "%p" and end time "%p"', (expected, startTime, endTime) => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const order = deepClone(sessionStorage);
|
const order = deepClone(sessionStorage);
|
||||||
|
|
@ -438,12 +439,12 @@ describe('OrderConfirmation.vue', () => {
|
||||||
expect(testValue).toEqual('Drop off before 9:30 AM');
|
expect(testValue).toEqual('Drop off before 9:30 AM');
|
||||||
});
|
});
|
||||||
test.each([
|
test.each([
|
||||||
['at 9:00 AM', '09:00', '10:00'],
|
['Your appointment is at 9:00 AM', '09:00', '10:00'],
|
||||||
['at 1:00 PM', '13:00', '17:00'],
|
['Your appointment is at 1:00 PM', '13:00', '17:00'],
|
||||||
['at 8:30 AM', '08:30', '15:00'],
|
['Your appointment is at 8:30 AM', '08:30', '15:00'],
|
||||||
['at 1:00 AM', '01:00', '02:00'],
|
['Your appointment is at 1:00 AM', '01:00', '02:00'],
|
||||||
['at 12:00 AM', '00:00', '02:00'],
|
['Your appointment is at 12:00 AM', '00:00', '02:00'],
|
||||||
['at 12:00 PM', '12:00', '02:00']
|
['Your appointment is at 12:00 PM', '12:00', '02:00']
|
||||||
])('should return In Shop time in expected format "%p" when start time "%p"', (expected, startTime, endTime) => {
|
])('should return In Shop time in expected format "%p" when start time "%p"', (expected, startTime, endTime) => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const order = deepClone(sessionStorage);
|
const order = deepClone(sessionStorage);
|
||||||
|
|
@ -479,8 +480,8 @@ describe('OrderConfirmation.vue', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const expectedServiceLocation = '123 Service Rd., Box 4,<br/> Columbus, OH 12345';
|
const expectedServiceLocation = '123 Service Rd., Box 4, Columbus, OH 12345';
|
||||||
const expectedShopLocation = '304 Provider Ln.,<br/> Pittsburg, PA 16001';
|
const expectedShopLocation = '304 Provider Ln., Pittsburg, PA 16001';
|
||||||
test.each([
|
test.each([
|
||||||
AppointmentTypeStrings.MOBILE,
|
AppointmentTypeStrings.MOBILE,
|
||||||
AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
|
AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP
|
||||||
|
|
@ -554,7 +555,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '123 Service Rd., Box 4,<br/> Columbus, OH 12345';
|
const expected = '123 Service Rd., Box 4, Columbus, OH 12345';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.serviceLocationFullAddress;
|
const text = wrapper.vm.serviceLocationFullAddress;
|
||||||
|
|
@ -568,7 +569,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = ', Box 4,<br/> Columbus, OH 12345';
|
const expected = ', Box 4, Columbus, OH 12345';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.serviceLocationFullAddress;
|
const text = wrapper.vm.serviceLocationFullAddress;
|
||||||
|
|
@ -582,7 +583,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '123 Service Rd., <br/> Columbus, OH 12345';
|
const expected = '123 Service Rd., Columbus, OH 12345';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.serviceLocationFullAddress;
|
const text = wrapper.vm.serviceLocationFullAddress;
|
||||||
|
|
@ -596,7 +597,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '123 Service Rd., Box 4,<br/> , OH 12345';
|
const expected = '123 Service Rd., Box 4, , OH 12345';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.serviceLocationFullAddress;
|
const text = wrapper.vm.serviceLocationFullAddress;
|
||||||
|
|
@ -610,7 +611,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '123 Service Rd., Box 4,<br/> Columbus, 12345';
|
const expected = '123 Service Rd., Box 4, Columbus, 12345';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.serviceLocationFullAddress;
|
const text = wrapper.vm.serviceLocationFullAddress;
|
||||||
|
|
@ -624,7 +625,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '123 Service Rd., Box 4,<br/> Columbus, OH ';
|
const expected = '123 Service Rd., Box 4, Columbus, OH ';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.serviceLocationFullAddress;
|
const text = wrapper.vm.serviceLocationFullAddress;
|
||||||
|
|
@ -642,7 +643,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = ', <br/> , ';
|
const expected = ', , ';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.serviceLocationFullAddress;
|
const text = wrapper.vm.serviceLocationFullAddress;
|
||||||
|
|
@ -675,7 +676,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '304 Provider Ln.,<br/> Pittsburg, PA 16001';
|
const expected = '304 Provider Ln., Pittsburg, PA 16001';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.providerFullAddress;
|
const text = wrapper.vm.providerFullAddress;
|
||||||
|
|
@ -703,7 +704,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '304 Provider Ln.,<br/> , PA 16001';
|
const expected = '304 Provider Ln., , PA 16001';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.providerFullAddress;
|
const text = wrapper.vm.providerFullAddress;
|
||||||
|
|
@ -717,7 +718,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '304 Provider Ln.,<br/> Pittsburg, 16001';
|
const expected = '304 Provider Ln., Pittsburg, 16001';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.providerFullAddress;
|
const text = wrapper.vm.providerFullAddress;
|
||||||
|
|
@ -731,7 +732,7 @@ describe('OrderConfirmation.vue', () => {
|
||||||
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
useMainStore().getSubmittedOrder = jest.fn().mockImplementation(() => order);
|
||||||
};
|
};
|
||||||
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
const { wrapper } = getMountedComponent({}, {}, mockStoreActions);
|
||||||
const expected = '304 Provider Ln.,<br/> Pittsburg, PA ';
|
const expected = '304 Provider Ln., Pittsburg, PA ';
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
const text = wrapper.vm.providerFullAddress;
|
const text = wrapper.vm.providerFullAddress;
|
||||||
|
|
@ -956,9 +957,9 @@ describe('OrderConfirmation.vue', () => {
|
||||||
describe('Methods', () => {
|
describe('Methods', () => {
|
||||||
describe('formatDate', () => {
|
describe('formatDate', () => {
|
||||||
test.each([
|
test.each([
|
||||||
['Wednesday, April 22', '2020-04-22'],
|
['Wednesday, April 22, 2020', '2020-04-22'],
|
||||||
['Thursday, February 1', '2018-02-01'],
|
['Thursday, February 1, 2018', '2018-02-01'],
|
||||||
['Wednesday, December 30', '2026-12-30']
|
['Wednesday, December 30, 2026', '2026-12-30']
|
||||||
])('returns %p given %p', (expected, date) => {
|
])('returns %p given %p', (expected, date) => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const order = deepClone(sessionStorage);
|
const order = deepClone(sessionStorage);
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,34 @@
|
||||||
<div class="justify-content-center">
|
<div class="justify-content-center">
|
||||||
<siteHeader :cmsWidgetName="widgets.siteHeader" />
|
<siteHeader :cmsWidgetName="widgets.siteHeader" />
|
||||||
</div>
|
</div>
|
||||||
<div class="iss-heritage-container-width">
|
<div class="iss-heritage-container-width order-confirmation-container row">
|
||||||
<div class="order-confirmation-container iss-heritage-content-container-width">
|
<div class="appointment-info-container col-lg-7">
|
||||||
<div class="text-center text-color--black pt-5 pb-5 fs-5">
|
<div class="header">
|
||||||
<img :src="orderConfirmationImage" />
|
<img :src="orderConfirmationImage" />
|
||||||
<span
|
<span
|
||||||
class="ms-2"
|
class="header-text"
|
||||||
v-html="orderConfirmationHeaderText"></span>
|
v-html="orderConfirmationHeaderText"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="appointment-details">
|
<div class="subheader">
|
||||||
<div class="appointment-date-time text-center mt-4">
|
<span
|
||||||
<p>{{ formatDate(schedule.date) }}</p>
|
class="subheader-text"
|
||||||
<p class="mt-2">
|
v-html="orderConfirmationSubheaderText"></span>
|
||||||
{{ appointmentTimeText }}
|
<span
|
||||||
</p>
|
class="update-appointment-text"
|
||||||
</div>
|
v-html="orderConfirmationUpdateAppointmentText"></span>
|
||||||
|
</div>
|
||||||
|
<div class="service-description confirmation-section">
|
||||||
|
<span>{{ serviceDescriptionText }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="work-order-details confirmation-section">
|
||||||
|
<span class="work-order-title">{{ workOrderTitle }}</span>
|
||||||
|
<span class="work-order-description">{{ workOrderNumber }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="appointment-details confirmation-section">
|
||||||
|
<span class="appointment-title">{{ appointmentWordingText }}</span>
|
||||||
|
<span>{{ formatDate(schedule.date) }}</span>
|
||||||
|
<span>{{ appointmentTimeText }}</span>
|
||||||
|
<span class="appointment-location">{{ appointmentLocation }}</span>
|
||||||
<addToCalendar
|
<addToCalendar
|
||||||
mobileWidgetName="AddToCalendar_Mobile"
|
mobileWidgetName="AddToCalendar_Mobile"
|
||||||
inShopWidgetName="AddToCalendar_InShop"
|
inShopWidgetName="AddToCalendar_InShop"
|
||||||
|
|
@ -40,29 +53,32 @@
|
||||||
:hasRecalibrationPart="hasRecalibrationPart"
|
:hasRecalibrationPart="hasRecalibrationPart"
|
||||||
:uniqueId="referralNumber"
|
:uniqueId="referralNumber"
|
||||||
:isRepair="isRepair" />
|
:isRepair="isRepair" />
|
||||||
<div
|
|
||||||
class="appointment-text text-center lh-base"
|
|
||||||
v-html="appointmentWordingText"></div>
|
|
||||||
<div
|
|
||||||
class="appointment-text text-center lh-base mt-2"
|
|
||||||
v-html="appointmentWordingText2"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<hr class="mb-0" />
|
<div
|
||||||
<div>
|
v-if="displayWipers"
|
||||||
<cartDropdown
|
class="wiper-details confirmation-section">
|
||||||
v-if="showCart"
|
<span class="wipers-title">{{ wipersTitle }}</span>
|
||||||
:showAsPaid="payment.isPayInAdvance"
|
<span
|
||||||
:readOnly="true"
|
v-for="(description, index) in wipersBody"
|
||||||
:isInitiallyExpanded="false"
|
:key="index"
|
||||||
:showDropdownHeader="true"
|
class="wipers-body">{{ description }}</span>
|
||||||
recyclingModalCmsWidgetName="RecycleModal"
|
</div>
|
||||||
servicePackageTitleWidgetName="ServicePackageTitle"
|
<div
|
||||||
:submittedOrder="submittedOrder" />
|
v-if="displayRainRepel"
|
||||||
|
class="rain-repel-details confirmation-section">
|
||||||
|
<span class="rain-repel-title">{{ rainRepelTitle }}</span>
|
||||||
|
<span class="rain-repel-body">{{ rainRepelBody }}</span>
|
||||||
</div>
|
</div>
|
||||||
<hr class="mt-0 mb-5" />
|
|
||||||
<div
|
<div
|
||||||
class="email-confirmation-text"
|
v-if="displaySMSPhone"
|
||||||
v-html="confirmationEmailText" />
|
class="sms-phone-details confirmation-section">
|
||||||
|
<span class="sms-phone-title">{{ smsTitle }}</span>
|
||||||
|
<span class="sms-phone-body">{{ contactInfo.servicePhone }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="contact-details confirmation-section">
|
||||||
|
<span class="contact-title">{{ contactDetailsTitle }}</span>
|
||||||
|
<span class="contact-body">{{ contactDetailsBody }}</span>
|
||||||
|
</div>
|
||||||
<siteFooter
|
<siteFooter
|
||||||
v-if="carrierUrl"
|
v-if="carrierUrl"
|
||||||
ref="siteFooter"
|
ref="siteFooter"
|
||||||
|
|
@ -72,6 +88,18 @@
|
||||||
@ForwardClicked="forwardButtonAction"
|
@ForwardClicked="forwardButtonAction"
|
||||||
@backClicked="navigateBack" />
|
@backClicked="navigateBack" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="cart-container col-lg-4 offset-lg-1 col-md-5">
|
||||||
|
<div class="cart-header">
|
||||||
|
{{ cartHeaderText }}
|
||||||
|
</div>
|
||||||
|
<cartDropdown
|
||||||
|
v-if="showCart"
|
||||||
|
:showAsPaid="payment.isPayInAdvance"
|
||||||
|
:readOnly="true"
|
||||||
|
recyclingModalCmsWidgetName="RecycleModal"
|
||||||
|
servicePackageTitleWidgetName="ServicePackageTitle"
|
||||||
|
:submittedOrder="submittedOrder" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
@ -103,6 +131,9 @@ import { toTitleCase } from '@/helpers/text-helper.js';
|
||||||
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||||
import applicationConfig from '@/constants/application-config';
|
import applicationConfig from '@/constants/application-config';
|
||||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||||
|
import { getGlassList } from '@/helpers/damage-helper';
|
||||||
|
import partTypeStrings from '@/constants/part-type-strings';
|
||||||
|
import coverageType from '@/constants/coverage-type';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'order-confirmation',
|
name: 'order-confirmation',
|
||||||
|
|
@ -144,18 +175,21 @@ export default {
|
||||||
serviceLocation,
|
serviceLocation,
|
||||||
schedule,
|
schedule,
|
||||||
customer,
|
customer,
|
||||||
|
contactInfo,
|
||||||
payment,
|
payment,
|
||||||
customerPortalLoginToken,
|
customerPortalLoginToken,
|
||||||
damage,
|
damage,
|
||||||
referralNumber
|
referralNumber,
|
||||||
|
hasRecalibrationPart
|
||||||
} = this.submittedOrder;
|
} = this.submittedOrder;
|
||||||
const { issConfig, hasRecalibrationPart } = this.mainStore;
|
const { issConfig } = this.mainStore;
|
||||||
return {
|
return {
|
||||||
vehicle,
|
vehicle,
|
||||||
customerEmail: customer?.emailAddress,
|
customerEmail: customer?.emailAddress,
|
||||||
payment,
|
payment,
|
||||||
schedule,
|
schedule,
|
||||||
serviceLocation,
|
serviceLocation,
|
||||||
|
contactInfo,
|
||||||
appointmentType: serviceLocation.appointmentType,
|
appointmentType: serviceLocation.appointmentType,
|
||||||
providerAddress: serviceLocation?.provider?.address,
|
providerAddress: serviceLocation?.provider?.address,
|
||||||
customerPortalLoginToken,
|
customerPortalLoginToken,
|
||||||
|
|
@ -164,12 +198,23 @@ export default {
|
||||||
isRepair: damage.isRepair,
|
isRepair: damage.isRepair,
|
||||||
hasRecalibrationPart,
|
hasRecalibrationPart,
|
||||||
referralNumber: referralNumber?.toString(),
|
referralNumber: referralNumber?.toString(),
|
||||||
|
isNoComp: this.submittedOrder.insuranceCoverage.coverageType === coverageType.NO_COMP,
|
||||||
widgets: {
|
widgets: {
|
||||||
siteHeader: 'SiteHeaderWidget',
|
siteHeader: 'SiteHeaderWidget',
|
||||||
emailConfirmation: 'EmailConfirmationWordingWidget',
|
emailConfirmation: 'EmailConfirmationWordingWidget',
|
||||||
|
emailConfirmationNoComp: 'EmailConfirmationNoCompWordingWidget',
|
||||||
orderConfirmation: 'OrderConfirmationContent',
|
orderConfirmation: 'OrderConfirmationContent',
|
||||||
|
serviceDescription: 'ServiceDescriptionTextWidget',
|
||||||
|
workOrderNumberTitle: 'WorkOrderNumberTextWidget',
|
||||||
mobile: 'MobileWordingWidget',
|
mobile: 'MobileWordingWidget',
|
||||||
dropOffAndInShop: 'DropOffAndInShopWordingWidget',
|
dropOffAndInShop: 'DropOffAndInShopWordingWidget',
|
||||||
|
wipersText: 'WipersTextWidget',
|
||||||
|
rainRepel: 'RainRepelWidget',
|
||||||
|
smsUpdates: 'SmsUpdatesWidget',
|
||||||
|
contactDetails: 'ContactDetailsWidget',
|
||||||
|
vapsItemDescriptions: 'VapsItemDescriptions',
|
||||||
|
payAtAppointment: 'PayAtAppointmentTextWidget',
|
||||||
|
orderDetails: 'OrderDetailsTextWidget',
|
||||||
siteFooter: 'SiteFooterWidget'
|
siteFooter: 'SiteFooterWidget'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -182,18 +227,29 @@ export default {
|
||||||
vehicleYear: this.vehicle?.year,
|
vehicleYear: this.vehicle?.year,
|
||||||
vehicleMake: this.vehicle?.make,
|
vehicleMake: this.vehicle?.make,
|
||||||
vehicleModel: this.vehicle?.model,
|
vehicleModel: this.vehicle?.model,
|
||||||
|
serviceType: this.serviceTypeText,
|
||||||
address: this.appointmentLocation,
|
address: this.appointmentLocation,
|
||||||
inShopDuration: this.inShopAppointmentDuration,
|
inShopDuration: this.inShopAppointmentDuration,
|
||||||
email: this.customerEmail,
|
email: this.customerEmail,
|
||||||
|
phone: this.contactInfo.servicePhone,
|
||||||
|
workOrderNumber: this.workOrderNumber,
|
||||||
CUSTOMER_PORTAL_URL: applicationConfig.CUSTOMER_PORTAL_URL,
|
CUSTOMER_PORTAL_URL: applicationConfig.CUSTOMER_PORTAL_URL,
|
||||||
CUSTOMER_PORTAL_LOGIN_TOKEN: this.customerPortalLoginToken
|
CUSTOMER_PORTAL_LOGIN_TOKEN: this.customerPortalLoginToken
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
confirmationEmailText() {
|
orderConfirmationUpdateAppointmentText() {
|
||||||
const content = this.getCmsContentWithCustomValues(
|
let content = '';
|
||||||
this.widgets.emailConfirmation,
|
if(this.isNoComp) {
|
||||||
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
|
content = this.getCmsContentWithCustomValues(
|
||||||
);
|
this.widgets.emailConfirmationNoComp,
|
||||||
|
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
content = this.getCmsContentWithCustomValues(
|
||||||
|
this.widgets.emailConfirmation,
|
||||||
|
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
|
||||||
|
);
|
||||||
|
}
|
||||||
return content
|
return content
|
||||||
?.replaceAll('<', '<')
|
?.replaceAll('<', '<')
|
||||||
?.replaceAll('>', '>');
|
?.replaceAll('>', '>');
|
||||||
|
|
@ -210,10 +266,51 @@ export default {
|
||||||
widgetFields.CONTENT_GROUP_WIDGET.IMAGE
|
widgetFields.CONTENT_GROUP_WIDGET.IMAGE
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
orderConfirmationSubheaderText() {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.orderConfirmation,
|
||||||
|
widgetFields.CONTENT_GROUP_WIDGET.SUBHEADER_TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
serviceDescriptionText() {
|
||||||
|
const content = this.getCmsContentWithCustomValues(
|
||||||
|
this.widgets.serviceDescription,
|
||||||
|
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
||||||
|
);
|
||||||
|
return content;
|
||||||
|
},
|
||||||
|
serviceTypeText() {
|
||||||
|
const glassPieces = this.submittedOrder.lineItems.glassParts?.map((part) => part.partType.toLowerCase()) ?? [];
|
||||||
|
let glassList = getGlassList(glassPieces);
|
||||||
|
let workType = '';
|
||||||
|
if (this.isRepair) {
|
||||||
|
workType = 'repair';
|
||||||
|
} else {
|
||||||
|
workType = 'replacement';
|
||||||
|
if (this.hasRecalibrationPart) {
|
||||||
|
if (glassList === 'windshield') {
|
||||||
|
workType = 'replacement and recalibration';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glassList = glassList.replace('windshield', 'windshield replacement, recalibration');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `${glassList} ${workType}`;
|
||||||
|
},
|
||||||
|
workOrderTitle() {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.workOrderNumberTitle,
|
||||||
|
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
workOrderNumber() {
|
||||||
|
return this.submittedOrder.workOrderNumber;
|
||||||
|
},
|
||||||
mobileWordingText() {
|
mobileWordingText() {
|
||||||
return this.getCmsContentWithCustomValues(
|
return this.getCmsContentWithCustomValues(
|
||||||
this.widgets.mobile,
|
this.widgets.mobile,
|
||||||
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
|
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
mobileWordingText2() {
|
mobileWordingText2() {
|
||||||
|
|
@ -225,7 +322,7 @@ export default {
|
||||||
nonMobileWordingText() {
|
nonMobileWordingText() {
|
||||||
return this.getCmsContentWithCustomValues(
|
return this.getCmsContentWithCustomValues(
|
||||||
this.widgets.dropOffAndInShop,
|
this.widgets.dropOffAndInShop,
|
||||||
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
|
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
nonMobileWordingText2() {
|
nonMobileWordingText2() {
|
||||||
|
|
@ -241,12 +338,12 @@ export default {
|
||||||
}
|
}
|
||||||
if (this.isInShopAppointment) {
|
if (this.isInShopAppointment) {
|
||||||
const formattedStartTime = get12HourTimeFormat(startTime);
|
const formattedStartTime = get12HourTimeFormat(startTime);
|
||||||
return `at ${formattedStartTime}`;
|
return `Your appointment is at ${formattedStartTime}`;
|
||||||
}
|
}
|
||||||
if (this.isMobileAppointment) {
|
if (this.isMobileAppointment) {
|
||||||
const mobileStartTime = get12HourTimeMobileFormat(startTime);
|
const mobileStartTime = get12HourTimeMobileFormat(startTime);
|
||||||
const mobileEndTime = get12HourTimeMobileFormat(endTime);
|
const mobileEndTime = get12HourTimeMobileFormat(endTime);
|
||||||
return `Between ${mobileStartTime} - ${mobileEndTime}`;
|
return `Your appointment is at ${mobileStartTime} - ${mobileEndTime}`;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
@ -261,12 +358,12 @@ export default {
|
||||||
},
|
},
|
||||||
serviceLocationFullAddress() {
|
serviceLocationFullAddress() {
|
||||||
const { address, address2, city, state, zipCode } = this.serviceLocation;
|
const { address, address2, city, state, zipCode } = this.serviceLocation;
|
||||||
return `${address ?? ''}, ${address2 ? `${address2},` : ''}<br/> ${city ?? ''}, ${state ?? ''} ${zipCode ?? ''}`;
|
return `${address ?? ''}, ${address2 ? `${address2},` : ''} ${city ?? ''}, ${state ?? ''} ${zipCode ?? ''}`;
|
||||||
},
|
},
|
||||||
providerFullAddress() {
|
providerFullAddress() {
|
||||||
const { streetAddress, city, state, zipCode } = this.providerAddress;
|
const { streetAddress, city, state, zipCode } = this.providerAddress;
|
||||||
return streetAddress
|
return streetAddress
|
||||||
? `${toTitleCase(streetAddress)},<br/> ${toTitleCase(city)}, ${state ?? ''} ${zipCode ?? ''}`
|
? `${toTitleCase(streetAddress)}, ${toTitleCase(city)}, ${state ?? ''} ${zipCode ?? ''}`
|
||||||
: '';
|
: '';
|
||||||
},
|
},
|
||||||
appointmentWordingText() {
|
appointmentWordingText() {
|
||||||
|
|
@ -318,6 +415,84 @@ export default {
|
||||||
// settleTenderAmount always shows 0 via localhost or dev.
|
// settleTenderAmount always shows 0 via localhost or dev.
|
||||||
// Temporarily set return true to see cart in localhost or dev environment
|
// Temporarily set return true to see cart in localhost or dev environment
|
||||||
return false;
|
return false;
|
||||||
|
},
|
||||||
|
displayWipers() {
|
||||||
|
const hasWiperPart = this.submittedOrder.lineItems.vaps.some((part) => part.partType.toLowerCase().includes('wiper'));
|
||||||
|
return hasWiperPart;
|
||||||
|
},
|
||||||
|
wipersTitle() {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.wipersText,
|
||||||
|
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
wipersBody() {
|
||||||
|
const wiperTypesOnOrder = [];
|
||||||
|
|
||||||
|
const hasFrontWiper = this.submittedOrder.lineItems.vaps.some((part) => part.partType === partTypeStrings.FRONT_WIPER);
|
||||||
|
const hasRearWiper = this.submittedOrder.lineItems.vaps.some((part) => part.partType === partTypeStrings.REAR_WIPER);
|
||||||
|
|
||||||
|
if (hasFrontWiper) {
|
||||||
|
wiperTypesOnOrder.push(partTypeStrings.FRONT_WIPER);
|
||||||
|
}
|
||||||
|
if (hasRearWiper) {
|
||||||
|
wiperTypesOnOrder.push(partTypeStrings.REAR_WIPER);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wiperDescriptions = wiperTypesOnOrder.map((type) => {
|
||||||
|
return this.getCmsContentForVapsType(type);
|
||||||
|
});
|
||||||
|
|
||||||
|
return wiperDescriptions;
|
||||||
|
},
|
||||||
|
displayRainRepel() {
|
||||||
|
return this.submittedOrder.lineItems.vaps.some((part) => part.partType === partTypeStrings.RAIN_DEFENSE);
|
||||||
|
},
|
||||||
|
rainRepelTitle() {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.rainRepel,
|
||||||
|
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
rainRepelBody() {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.rainRepel,
|
||||||
|
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
displaySMSPhone() {
|
||||||
|
return this.contactInfo.requestTextUpdates && this.contactInfo.servicePhone;
|
||||||
|
},
|
||||||
|
smsTitle() {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.smsUpdates,
|
||||||
|
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
contactDetailsTitle() {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.contactDetails,
|
||||||
|
widgetFields.CONTENT_GROUP_WIDGET.HEADER_TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
contactDetailsBody() {
|
||||||
|
return this.getCmsContentWithCustomValues(
|
||||||
|
this.widgets.contactDetails,
|
||||||
|
widgetFields.CONTENT_GROUP_WIDGET.BODY_TEXT
|
||||||
|
);
|
||||||
|
},
|
||||||
|
cartHeaderText() {
|
||||||
|
if (this.payment.isPayInAdvance) {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.orderDetails,
|
||||||
|
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return this.getCmsContent(
|
||||||
|
this.widgets.payAtAppointment,
|
||||||
|
widgetFields.TEXT_BLOCK_WIDGET.TEXT
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
@ -411,68 +586,138 @@ export default {
|
||||||
return dateObject.toLocaleDateString('en-us', {
|
return dateObject.toLocaleDateString('en-us', {
|
||||||
weekday: 'long',
|
weekday: 'long',
|
||||||
month: 'long',
|
month: 'long',
|
||||||
day: 'numeric'
|
day: 'numeric',
|
||||||
|
year: 'numeric'
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
getCmsContentForVapsType(vapsPartType) {
|
||||||
|
const vapsItemDescriptions = this.getCmsContent(
|
||||||
|
this.widgets.vapsItemDescriptions,
|
||||||
|
widgetFields.INPUT_QUESTION_WIDGET.ANSWERS
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!vapsItemDescriptions) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const vapsTypeDescription = vapsItemDescriptions?.find((entry) => entry?.Name === vapsPartType);
|
||||||
|
return vapsTypeDescription?.Text ?? '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.iss-heritage-container-width {
|
.order-confirmation-container {
|
||||||
.order-confirmation-container {
|
.appointment-info-container
|
||||||
position: relative;
|
{
|
||||||
min-height: 1px;
|
padding: 0 .9375rem;
|
||||||
padding-left: .9375rem;
|
margin-bottom: 1.875rem;
|
||||||
padding-right: .9375rem;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.page-container-grouped-styles {
|
.cart-container {
|
||||||
overflow: auto;
|
padding: 0 .9375rem;
|
||||||
}
|
|
||||||
|
|
||||||
.text-color--black {
|
|
||||||
color: $black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.appointment-details {
|
|
||||||
margin-bottom: 1.5rem;
|
|
||||||
padding: 1rem 1.5rem 1.5rem;
|
|
||||||
box-shadow: 0 0.188rem 0.625rem rgb(0 0 0 / 0.2);
|
|
||||||
border-radius: 0.313rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.appointment-date-time P {
|
|
||||||
color: $black;
|
|
||||||
font-size: $h5-font-size;
|
|
||||||
line-height: map-get($spacers, 6);
|
|
||||||
margin-bottom: 0;
|
|
||||||
|
|
||||||
+ p {
|
|
||||||
font-size: map-get($spacers, 4);
|
|
||||||
line-height: 1.625rem;
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.appointment-text {
|
.header {
|
||||||
:deep(p) {
|
flex-direction: row;
|
||||||
margin: 0;
|
margin-top: 1.25rem;
|
||||||
}
|
margin-bottom: .625rem;
|
||||||
:deep(strong) {
|
font-size: 1.25rem;
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
color: $black;
|
color: $black;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.email-confirmation-text {
|
img {
|
||||||
:deep(a) {
|
width: 2.25rem;
|
||||||
font-weight: $font-weight-bold;
|
height: 2.25rem;
|
||||||
text-decoration: underline;
|
margin-right: 1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
:deep(strong) {
|
|
||||||
font-weight: $font-weight-bold;
|
.subheader {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
|
||||||
|
.subheader-text {
|
||||||
|
margin-bottom: .625rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-appointment-text {
|
||||||
|
:deep(.text-primary) {
|
||||||
|
color: $heritage-blue-primary;
|
||||||
|
}
|
||||||
|
:deep(a) {
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
color: $heritage-blue-primary;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $heritage-blue-secondary;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirmation-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 1.875rem 0;
|
||||||
|
border-bottom: 1px solid lightgray;
|
||||||
|
|
||||||
|
>:first-child {
|
||||||
|
font-weight: 600;
|
||||||
|
color: $black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-description {
|
||||||
|
>span:first-child {
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-order-title {
|
||||||
|
margin-bottom: .625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appointment-details {
|
||||||
|
padding-bottom: 2.0625rem;
|
||||||
|
|
||||||
|
.appointment-title {
|
||||||
|
margin-bottom: .625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appointment-location {
|
||||||
|
margin-top: .625rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.rain-repel-details {
|
||||||
|
.rain-repel-title {
|
||||||
|
color: #4d4e53;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sms-phone-details {
|
||||||
|
.sms-phone-title {
|
||||||
|
color: #4d4e53;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-details {
|
||||||
|
.contact-title {
|
||||||
|
margin-bottom: .625rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cart-header {
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
margin-bottom: .625rem;
|
||||||
color: $black;
|
color: $black;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@
|
||||||
<cartDropdown
|
<cartDropdown
|
||||||
:showAsPaid="false"
|
:showAsPaid="false"
|
||||||
:readOnly="false"
|
:readOnly="false"
|
||||||
:showDropdownHeader="true"
|
|
||||||
:isInitiallyExpanded="false"
|
|
||||||
recyclingModalCmsWidgetName="RecycleModal"
|
recyclingModalCmsWidgetName="RecycleModal"
|
||||||
servicePackageTitleWidgetName="ServicePackageTitle" />
|
servicePackageTitleWidgetName="ServicePackageTitle" />
|
||||||
<hr class="mt-0 mb-5" />
|
<hr class="mt-0 mb-5" />
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,7 @@
|
||||||
<cartDropdown
|
<cartDropdown
|
||||||
ref="cart"
|
ref="cart"
|
||||||
:readOnly="true"
|
:readOnly="true"
|
||||||
:showDropdownHeader="true"
|
:showAsPaid="false"
|
||||||
:isInitiallyExpanded="true"
|
|
||||||
recyclingModalCmsWidgetName="RecycleModal"
|
recyclingModalCmsWidgetName="RecycleModal"
|
||||||
servicePackageTitleWidgetName="ServicePackageTitle" />
|
servicePackageTitleWidgetName="ServicePackageTitle" />
|
||||||
<hr class="my-0">
|
<hr class="my-0">
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,11 @@ export const useMainStore = defineStore({
|
||||||
const nonWindshieldItems = damage.glassToReplace?.filter((glass) => glass.glassLocation !== damageLocationsSelected.WINDSHIELD);
|
const nonWindshieldItems = damage.glassToReplace?.filter((glass) => glass.glassLocation !== damageLocationsSelected.WINDSHIELD);
|
||||||
return !!nonWindshieldItems?.length;
|
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
|
isMobileAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE
|
||||||
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
|
|| state.order.serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE_NOT_ITAC_AND_NOT_NOCOMP,
|
||||||
isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF,
|
isDropOffAppointment: (state) => state.order.serviceLocation.appointmentType === AppointmentTypeStrings.DROP_OFF,
|
||||||
|
|
@ -2886,12 +2891,13 @@ export const useMainStore = defineStore({
|
||||||
await this.getCarrierAccountInfo();
|
await this.getCarrierAccountInfo();
|
||||||
const submittedOrder = this.order;
|
const submittedOrder = this.order;
|
||||||
const { experiments } = this.applicationUser;
|
const { experiments } = this.applicationUser;
|
||||||
const { issConfig } = this;
|
const { issConfig, hasRecalibrationPart } = this;
|
||||||
|
|
||||||
submittedOrder.isUnverified = this.isUnverified;
|
submittedOrder.isUnverified = this.isUnverified;
|
||||||
submittedOrder.isVerified = this.isVerified;
|
submittedOrder.isVerified = this.isVerified;
|
||||||
submittedOrder.submitType = submitType;
|
submittedOrder.submitType = submitType;
|
||||||
submittedOrder.payment.isPayInAdvance = this.isPayInAdvance;
|
submittedOrder.payment.isPayInAdvance = this.isPayInAdvance;
|
||||||
|
submittedOrder.hasRecalibrationPart = hasRecalibrationPart;
|
||||||
|
|
||||||
// set to sessionStorage
|
// set to sessionStorage
|
||||||
window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder));
|
window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue