Merge branch 'develop' into feature/CSR-1382-loose-ends

This commit is contained in:
Leah Schumann 2023-10-30 07:27:07 -04:00 committed by GitHub
commit 46473c5ba0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 686 additions and 241 deletions

View file

@ -3,11 +3,11 @@
This public/css folder uses a standalone .scss > .css setup. This public/css folder uses a standalone .scss > .css setup.
## Usage ## Usage
From a Terminal window, run the Sass Watch command on this folder only: From a Terminal window, run the Sass Watch command from the public folder only:
```bash ```bash
sass --no-source-map --watch public/css/hop-styling.scss:public/css/hop-styling.css sass --no-source-map --watch scss:css
``` ```
This will output a CSS file that can be consumed by the Payment page. This will compile and output .css files (into the public/css folder) that can be consumed by the Payment page.
# Do not use the .css file on its own. You must use the .scss file and have Sass compile it to the .css file. # Do not use the .css files on their own. You must use the .scss files and have Sass compile them to .css files.

View file

@ -15,6 +15,7 @@ body .validation-info {
} }
body .italicSmall { body .italicSmall {
font-style: normal; font-style: normal;
font-size: 14px;
} }
body span { body span {
line-height: 24px; line-height: 24px;
@ -27,7 +28,7 @@ body .form-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
body h2 { body .headerlinecontainer .headerline1 {
font-size: 20px; font-size: 20px;
line-height: 32px; line-height: 32px;
font-weight: 400; font-weight: 400;
@ -76,12 +77,12 @@ body .creditCardSpecific div {
body .creditCardSpecific div .headerlinecontainer { body .creditCardSpecific div .headerlinecontainer {
padding: 0; padding: 0;
} }
body .creditCardSpecific div .headerlinecontainer .headerline5v2 {
display: none;
}
body .creditCardSpecific div label { body .creditCardSpecific div label {
font-weight: 500; font-weight: 500;
} }
body .creditCardSpecific div:first-child {
display: none;
}
body .creditCardSpecific #infoRow2 { body .creditCardSpecific #infoRow2 {
margin-bottom: 0; margin-bottom: 0;
} }
@ -91,7 +92,7 @@ body #cardExpirationContainer {
justify-content: space-between; justify-content: space-between;
padding: 0; padding: 0;
} }
@media (min-width: 368px) { @media (min-width: 400px) {
body #cardExpirationContainer { body #cardExpirationContainer {
flex-direction: row; flex-direction: row;
} }
@ -116,7 +117,6 @@ body .optional-label:after {
} }
body .buttonContainer { body .buttonContainer {
height: 48px; height: 48px;
margin-top: 36px;
} }
body .buttonContainer button { body .buttonContainer button {
position: relative; position: relative;

View file

@ -0,0 +1,90 @@
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* Style the modal when PayPal button is selected */
#pageLoadingModal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1040;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.35);
display: flex;
}
#pageLoadingModal .modal-content {
margin: auto auto;
}
#pageLoadingModal p {
margin: 0;
text-transform: uppercase;
font-size: 14px;
}
#pageLoadingModal .modal {
display: none;
overflow: hidden;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1040;
-webkit-overflow-scrolling: touch;
outline: 0;
}
#pageLoadingModal .modal-content {
position: relative;
background-color: #fff;
border-radius: 8px;
background-clip: padding-box;
outline: 0;
width: 168px;
height: 168px;
display: flex;
justify-content: center;
align-items: center;
}
#pageLoadingModal .modal-content:before, #pageLoadingModal .modal-content:after {
content: "";
border-radius: 50%;
position: absolute;
inset: 0;
box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.25) inset;
top: 24px;
bottom: 24px;
right: 24px;
left: 24px;
}
#pageLoadingModal .modal-content:after {
box-shadow: 0 3px 0 #da291c inset;
animation: rotate 1s linear infinite;
}
#pageLoadingModal .modal-backdrop {
position: absolute;
top: 0;
right: 0;
left: 0;
background-color: #000000;
}
#pageLoadingModal .modal-backdrop.fade {
opacity: 0;
filter: alpha(opacity=0);
}
#pageLoadingModal.hide {
display: none;
}
@keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
.creditCardSpecific {
display: none;
}

View file

@ -16,6 +16,7 @@ body {
.italicSmall { .italicSmall {
font-style: normal; font-style: normal;
font-size: 14px;
} }
span { span {
@ -32,11 +33,13 @@ body {
flex-direction: column; flex-direction: column;
} }
h2 { .headerlinecontainer {
font-size: 20px; .headerline1 {
line-height: 32px; font-size: 20px;
font-weight: 400; line-height: 32px;
margin: 24px 0; font-weight: 400;
margin: 24px 0;
}
} }
input, input,
@ -86,13 +89,13 @@ body {
padding: 8px 0; padding: 8px 0;
.headerlinecontainer { .headerlinecontainer {
padding: 0; padding: 0;
.headerline5v2 {
display: none;
}
} }
label { label {
font-weight: 500; font-weight: 500;
} }
&:first-child {
display: none;
}
} }
#infoRow2 { #infoRow2 {
margin-bottom: 0; margin-bottom: 0;
@ -104,7 +107,7 @@ body {
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
padding: 0; padding: 0;
@media (min-width: 368px) { @media (min-width: 400px) {
flex-direction: row; flex-direction: row;
.card_expirationYear, .card_expirationYear,
.card_expirationMonth { .card_expirationMonth {
@ -132,7 +135,6 @@ body {
.buttonContainer { .buttonContainer {
height: 48px; height: 48px;
margin-top: 36px;
button { button {
position: relative; position: relative;
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%); background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);

View file

@ -0,0 +1,95 @@
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* IMPORTANT: READ README.md in this folder! Do not edit .css file directly! */
/* Style the modal when PayPal button is selected */
#pageLoadingModal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1040;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,.35);
display: flex;
.modal-content {
margin: auto auto;
}
p {
margin: 0;
text-transform: uppercase;
font-size: 14px;
}
.modal {
display: none;
overflow: hidden;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1040;
-webkit-overflow-scrolling: touch;
outline: 0;
}
.modal-content {
position: relative;
background-color: #fff;
border-radius: 8px;
background-clip: padding-box;
outline: 0;
width: 168px;
height: 168px;
display: flex;
justify-content: center;
align-items: center;
&:before,
&:after {
content: '';
border-radius: 50%;
position: absolute;
inset: 0;
box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.25) inset;
top: 24px;
bottom: 24px;
right: 24px;
left: 24px;
}
&:after {
box-shadow: 0 3px 0 #da291c inset;
animation: rotate 1s linear infinite;
}
}
.modal-backdrop {
position: absolute;
top: 0;
right: 0;
left: 0;
background-color: #000000;
&.fade {
opacity: 0;
filter: alpha(opacity=0);
}
}
&.hide {
display: none;
}
}
@keyframes rotate {
0% { transform: rotate(0)}
100% { transform: rotate(360deg)}
}
.creditCardSpecific {
display: none;
}

View file

@ -89,9 +89,6 @@ const storeActions = {
SAVE_PROMOS: "savePromos", SAVE_PROMOS: "savePromos",
SAVE_CUSTOMER_DETAILS: "saveCustomerDetails", SAVE_CUSTOMER_DETAILS: "saveCustomerDetails",
SAVE_SERVICE_LOCATION_TECH_NOTES: "saveServiceLocationTechNotes", SAVE_SERVICE_LOCATION_TECH_NOTES: "saveServiceLocationTechNotes",
SAVE_WORK_ORDER_FLAG: "saveWorkOrderFlag",
SAVE_PIA_ERROR_CODE: "savePiaErrorCode",
SAVE_PIA_WORK_ORDER: "savePiaWorkOrder",
SAVE_CCTOKEN: "saveCCToken", SAVE_CCTOKEN: "saveCCToken",
SAVE_PAYPAL_TOKEN: "savePaypalToken", SAVE_PAYPAL_TOKEN: "savePaypalToken",
}; };

View file

@ -1,8 +1,5 @@
const storeMutations = { const storeMutations = {
// PAYMENT MUTATIONS // PAYMENT MUTATIONS
UPDATE_WORK_ORDER_FLAG: "updateWorkOrderFlag",
UPDATE_PIA_ERROR_CODE: "updatePiaErrorCode",
UPDATE_PIA_WORK_ORDER: "updatePiaWorkOrder",
UPDATE_CCTOKEN: "updateCCToken", UPDATE_CCTOKEN: "updateCCToken",
UPDATE_PAYPAL_TOKEN: "updatePaypalToken", UPDATE_PAYPAL_TOKEN: "updatePaypalToken",

View file

@ -53,17 +53,30 @@ export async function loadSessionIfPresent(isConceptInsurance, pageNameToLog) {
This will also set Referral information in the store after saving, and then This will also set Referral information in the store after saving, and then
update the cookie. To force synchronous behavior pass in 'true' for shouldAwaitSaveSessionQueue update the cookie. To force synchronous behavior pass in 'true' for shouldAwaitSaveSessionQueue
*/ */
export async function saveSession({ pageNameToLog, shouldAwaitSaveSessionQueue = false }) { export async function saveSession({
pageNameToLog,
shouldAwaitSaveSessionQueue = false,
submitAfterSave = false,
createDeleteStatusWorkOrderForPia = false,
}) {
var saveSessionPromise; var saveSessionPromise;
if (store.getters.applicationUser.saveSessionPromise) { if (store.getters.applicationUser.saveSessionPromise) {
// queue newest request after current saveSessionPromise resolves // queue newest request after current saveSessionPromise resolves
saveSessionPromise = store.getters.applicationUser.saveSessionPromise.then(() => { saveSessionPromise = store.getters.applicationUser.saveSessionPromise.then(() => {
// get a new saveSessionPromise // get a new saveSessionPromise
return saveSessionHelper(pageNameToLog); return saveSessionHelper(
pageNameToLog,
submitAfterSave,
createDeleteStatusWorkOrderForPia
);
}); });
} else { } else {
// create an initial saveSessionPromise // create an initial saveSessionPromise
saveSessionPromise = saveSessionHelper(pageNameToLog); saveSessionPromise = saveSessionHelper(
pageNameToLog,
submitAfterSave,
createDeleteStatusWorkOrderForPia
);
} }
store.commit(storeMutations.UPDATE_SAVE_SESSION_PROMISE, saveSessionPromise); store.commit(storeMutations.UPDATE_SAVE_SESSION_PROMISE, saveSessionPromise);
// await here to allow for a caller to await and make the function synchronous // await here to allow for a caller to await and make the function synchronous
@ -72,10 +85,16 @@ export async function saveSession({ pageNameToLog, shouldAwaitSaveSessionQueue =
} }
} }
export async function submitWorkOrder({ pageNameToLog }) { export async function submitWorkOrder({
pageNameToLog,
submitAfterSave = false,
createDeleteStatusWorkOrderForPia = false,
}) {
await saveSession({ await saveSession({
pageNameToLog: pageNameToLog, pageNameToLog: pageNameToLog,
shouldAwaitSaveSessionQueue: true, shouldAwaitSaveSessionQueue: true,
submitAfterSave: submitAfterSave,
createDeleteStatusWorkOrderForPia: createDeleteStatusWorkOrderForPia,
}); });
} }
@ -117,10 +136,17 @@ async function loadSession(
/* /*
Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing Encapsulates asynchronous Save Session logic inside a promise to allow for Save Session queuing
*/ */
async function saveSessionHelper(pageNameToLog) { async function saveSessionHelper(
pageNameToLog,
submitAfterSave = false,
createDeleteStatusWorkOrderForPia = false
) {
const savedSessionInfo = await baseMixin.methods.dispatchStoreActionWithLogging( const savedSessionInfo = await baseMixin.methods.dispatchStoreActionWithLogging(
storeActions.SAVE_SESSION, storeActions.SAVE_SESSION,
null, {
submitAfterSave: submitAfterSave,
createDeleteStatusWorkOrderForPia: createDeleteStatusWorkOrderForPia,
},
pageNameToLog pageNameToLog
); );
// Update the store with information received from the saveSession response // Update the store with information received from the saveSession response

View file

@ -179,7 +179,7 @@ describe("saveSession", () => {
// Assert // Assert
expect(mocks.baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith( expect(mocks.baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
storeActions.SAVE_SESSION, storeActions.SAVE_SESSION,
null, { createDeleteStatusWorkOrderForPia: false, submitAfterSave: false },
"test" "test"
); );
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
@ -282,12 +282,12 @@ describe("submitWorkOrder", () => {
const mocks = setupMocksForJsFiles(mockData); const mocks = setupMocksForJsFiles(mockData);
// Act // Act
await submitWorkOrder({ pageNameToLog: "test" }); await submitWorkOrder({ pageNameToLog: "test", submitAfterSave: true });
// Assert // Assert
expect(mocks.baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith( expect(mocks.baseMixin.methods.dispatchStoreActionWithLogging).toHaveBeenCalledWith(
storeActions.SAVE_SESSION, storeActions.SAVE_SESSION,
null, { createDeleteStatusWorkOrderForPia: false, submitAfterSave: true },
"test" "test"
); );
expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith( expect(mocks.baseMixin.methods.dispatchStoreAction).toHaveBeenCalledWith(
@ -345,7 +345,7 @@ describe("submitWorkOrder", () => {
setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) }); setupCookies({ funnelCookieValue: JSON.stringify(testCookieValue) });
// Act // Act
await submitWorkOrder({ pageNameToLog: "test" }); await submitWorkOrder({ pageNameToLog: "test", submitAfterSave: true });
// Assert // Assert
expect(cookieHelper.getFunnelCookie().DidHeritageFunnelUpdateLast).toEqual(false); expect(cookieHelper.getFunnelCookie().DidHeritageFunnelUpdateLast).toEqual(false);

View file

@ -244,7 +244,7 @@ export default {
<style lang="scss"> <style lang="scss">
.main { .main {
padding: 1rem 0; padding: 1rem 1.5rem 1.5rem;
box-shadow: 0 3px 10px rgb(0 0 0 / 0.2); box-shadow: 0 3px 10px rgb(0 0 0 / 0.2);
border-radius: 5px; border-radius: 5px;
} }
@ -260,6 +260,7 @@ export default {
+ p { + p {
font-size: 1rem; font-size: 1rem;
margin-top: 0.5rem;
font-weight: 500; font-weight: 500;
} }
} }
@ -270,7 +271,7 @@ export default {
} }
.calendar-section .add-to-calendar { .calendar-section .add-to-calendar {
padding: 10px 0; padding: 1rem 0;
text-align: center; text-align: center;
} }
@ -279,6 +280,10 @@ export default {
background-color: #fff; background-color: #fff;
} }
.appoinmenttext p {
margin: 0;
}
.calendar-section .add-to-calendar .add-to-calendar-span { .calendar-section .add-to-calendar .add-to-calendar-span {
cursor: pointer; cursor: pointer;
} }
@ -296,12 +301,12 @@ export default {
} }
.header-container { .header-container {
text-align: center; text-align: center;
padding: 1rem 0 1.5rem 0;
p { p {
display: inline-block; display: inline-block;
font-weight: 400; font-weight: 400;
font-size: 1.25rem; font-size: 1.25rem;
padding: 0.3rem;
color: $black; color: $black;
} }
} }

View file

@ -3,39 +3,75 @@
<div class="add-vaps-buttons" aria-live="polite"> <div class="add-vaps-buttons" aria-live="polite">
<buttonQuestion <buttonQuestion
ref="buttonQuestion" ref="buttonQuestion"
:answers="answersToDisplay" :answers="buttonsToDisplay"
groupName="addVaps" groupName="addVaps"
v-model="answersToDisplay" v-model="buttonsToDisplay"
buttonTypeString="addVapsButton" buttonTypeString="addVapsButton"
:buttonTypeObject="addVapsButton" :buttonTypeObject="addVapsButton"
:isWide="answersToDisplay.length > 1 ? false : true" :isWide="buttonsToDisplay.length > 1 ? false : true"
@update:modelValue="openModal" /> @update:modelValue="openModal" />
<contentGroupModal <contentGroupModal
ref="RainDefenseModal" ref="RainDefenseModal"
cmsWidgetName="RainDefenseModal" cmsWidgetName="RainDefenseModal"
v-if="rainDefenseItem" v-if="rainDefenseModal"
@footer-button-action="addToCart('RainDefenseModal', rainDefenseItem)" @footer-button-action="addRainDefenseToCart('RainDefenseModal', rainDefenseModal)"
footerButtonActionName="footer-button-action"> footerButtonActionName="footer-button-action">
<p class="price">{{ rainDefenseItem.listPrice }}</p> <p class="price">+${{ rainDefenseModal.listPrice }}</p>
</contentGroupModal> </contentGroupModal>
<contentGroupModal <contentGroupModal
ref="WipersModal" ref="WipersModal"
cmsWidgetName="WipersModal" cmsWidgetName="WipersModal"
v-if="wipersItem" v-if="wipersModal"
@footer-button-action="addToCart('WipersModal', wipersItem)" @footer-button-action="addWipersToCart('WipersModal', wipersModal)"
footerButtonActionName="footer-button-action"> footerButtonActionName="footer-button-action">
<p class="price">{{ wipersItem.listPrice }}</p> <div v-if="wipersToDisplay === wipersToDisplayStrings.BOTH" class="wiper-options">
<div>
<checkboxQuestion
class="mb-5"
cmsWidgetName="AddFrontBladesQuestionWidget"
v-model="selectedFrontWipers" />
<p class="price">+${{ wipersModal.totalFrontPrice }}</p>
</div>
<div>
<checkboxQuestion
class="mb-5"
cmsWidgetName="AddRearBladesQuestionWidget"
v-model="selectedRearWipers" />
<p class="price">+${{ wipersModal.totalRearPrice }}</p>
</div>
</div>
<div
v-else-if="wipersToDisplay === wipersToDisplayStrings.FRONT"
class="wiper-options">
<p class="price">+${{ wipersModal.totalFrontPrice }}</p>
</div>
<div
v-else-if="wipersToDisplay === wipersToDisplayStrings.REAR"
class="wiper-options">
<p class="price">+${{ wipersModal.totalRearPrice }}</p>
</div>
</contentGroupModal> </contentGroupModal>
</div> </div>
</transition> </transition>
</template> </template>
<script> <script>
// COMPONENTS
import buttonQuestion from "@/digital-components/button-question/button-question"; import buttonQuestion from "@/digital-components/button-question/button-question";
import addVapsButton from "./add-vaps-button/add-vaps-button"; import addVapsButton from "./add-vaps-button/add-vaps-button";
import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal"; import contentGroupModal from "@/fmg-components/content-group-modal/content-group-modal";
import checkboxQuestion from "@/digital-components/checkbox-question/checkbox-question";
// SUPPORTING
import { partTypeStrings } from "@/constants/part-type-strings";
const wipersToDisplayStrings = {
FRONT: "FRONT",
REAR: "REAR",
BOTH: "BOTH",
};
export default { export default {
name: "add-vaps-modal-buttons", name: "add-vaps-modal-buttons",
@ -47,54 +83,73 @@ export default {
data() { data() {
return { return {
addVapsButton: addVapsButton, addVapsButton: addVapsButton,
selectedFrontWipers: false,
selectedRearWipers: false,
wipersToDisplay: null,
}; };
}, },
methods: { methods: {
openModal(modalName) { openModal(modalName) {
this.$refs[modalName].openModal(); this.$refs[modalName].openModal();
}, },
addToCart(modalName, part) { addRainDefenseToCart(modalName, part) {
const vapsItems = this.currentCartItems.vaps; const alreadyInCart = this.currentCartItems.vaps.some((item) => {
const alreadyInVaps = vapsItems.some((item) => {
return item.partType === part.partType; return item.partType === part.partType;
}); });
if (!alreadyInVaps) { if (!alreadyInCart) {
if (part.subItems) { this.currentCartItems.vaps.push(part);
// for wipers, a "combined" part (w/ subItems) }
part.subItems.forEach((part) => { this.$refs[modalName].closeModal();
},
addWipersToCart(modalName, part) {
const frontWipersAlreadyInCart = this.currentCartItems.vaps.some((item) => {
return item.partType === part.frontWiperLineItems[0].partType;
});
const rearWipersAlreadyInCart = this.currentCartItems.vaps.some((item) => {
return item.partType === part.rearWiperLineItems[0]?.partType;
});
if (this.wipersToDisplay === wipersToDisplayStrings.FRONT) {
this.selectedFrontWipers = true; // set as true if front wipers is only option
}
if (this.wipersToDisplay === wipersToDisplayStrings.REAR) {
this.selectedRearWipers = true; // set as true if rear wipers is only option
}
if (!frontWipersAlreadyInCart && this.selectedFrontWipers) {
if (part.frontWiperLineItems) {
// for wipers, a "combined" part (frontWiperLineItems)
part.frontWiperLineItems.forEach((part) => {
this.currentCartItems.vaps.push(part);
});
}
}
if (!rearWipersAlreadyInCart && this.selectedRearWipers) {
if (part.rearWiperLineItems) {
part.rearWiperLineItems.forEach((part) => {
this.currentCartItems.vaps.push(part); this.currentCartItems.vaps.push(part);
}); });
} else {
// for rain defense, a "single" part (w/o subItems)
this.currentCartItems.vaps.push(part);
} }
} }
this.$refs[modalName].closeModal(); this.$refs[modalName].closeModal();
if (this.wipersToDisplay === wipersToDisplayStrings.BOTH) {
this.selectedFrontWipers = false; // set as false if both options are given
this.selectedRearWipers = false; // set as false if both options are given
}
},
updateWipersToDisplay(value) {
this.wipersToDisplay = value;
}, },
}, },
computed: { computed: {
currentCartItems() { currentCartItems() {
return this.modelValue; const modelValue = this.modelValue;
if (!modelValue.vaps) modelValue.vaps = [];
return modelValue;
}, },
showAddRainDefense() { rainDefenseModal() {
// show if not in cart
return !this.currentCartItems.vaps?.some((vap) => {
return vap?.partType === "RAIN DEFENSE";
});
},
showAddWipers() {
// show if not in cart
if (this.currentCartItems && this.currentCartItems.vaps) {
return !this.currentCartItems.vaps.some((vap) => {
return vap?.partType?.includes(" WIPER");
});
} else {
return false;
}
},
rainDefenseItem() {
const lineItem = this.availableLineItems.find((item) => { const lineItem = this.availableLineItems.find((item) => {
return item.partType === "RAIN DEFENSE"; return item.partType === partTypeStrings.RAIN_DEFENSE;
}); });
if (lineItem) if (lineItem)
lineItem.listPrice = parseFloat( lineItem.listPrice = parseFloat(
@ -102,63 +157,161 @@ export default {
).toFixed(2); ).toFixed(2);
return lineItem; return lineItem;
}, },
wipersItem() { wipersModal() {
const wiperLineItems = this.availableLineItems.filter((item) => { // create a single wiper item for modal
return item.partType.includes("WIPER"); const frontWiperLineItems = this.availableLineItems.filter((item) => {
return item.partType.includes(partTypeStrings.FRONT_WIPER);
}); });
let wiperLineItem; const rearWiperLineItems = this.availableLineItems.filter((item) => {
if (wiperLineItems.length === 1) { return item.partType.includes(partTypeStrings.REAR_WIPER);
wiperLineItem = wiperLineItems[0]; });
wiperLineItem.listPrice = parseFloat( let wipersModal;
wiperLineItem.laborAmount + wiperLineItem.sellingPrice + wiperLineItem.kitPrice let totalFrontPrice = 0;
).toFixed(2); let totalRearPrice = 0;
return wiperLineItem;
} else if (wiperLineItems.length > 1) { // calculate prices to display
let combinedPrice = 0; frontWiperLineItems?.forEach((item) => {
wiperLineItems?.forEach((item) => { totalFrontPrice += item?.laborAmount + item?.sellingPrice + item?.kitPrice;
combinedPrice += item?.laborAmount + item?.sellingPrice + item?.kitPrice; });
}); rearWiperLineItems?.forEach((item) => {
wiperLineItem = { totalRearPrice += item?.laborAmount + item?.sellingPrice + item?.kitPrice;
description: "COMBINED ITEM", });
partType: "WIPERS",
subItems: [], wipersModal = {
listPrice: parseFloat(combinedPrice).toFixed(2), description: "WIPERS ITEM",
}; partType: "WIPERS",
wiperLineItems?.forEach((item) => { frontWiperLineItems: frontWiperLineItems,
wiperLineItem.subItems.push(item); rearWiperLineItems: rearWiperLineItems,
}); totalFrontPrice: parseFloat(totalFrontPrice).toFixed(2),
return wiperLineItem; totalRearPrice: parseFloat(totalRearPrice).toFixed(2),
} };
return [];
return wipersModal;
}, },
answersCmsData() { answersCmsData() {
return this.getCmsContent(this.vapsTilesCmsName, "Answers"); return this.getCmsContent(this.vapsTilesCmsName, "Answers");
}, },
answersToDisplay() { buttonsToDisplay() {
const answers = []; const buttons = [];
if (!this.answersCmsData) return answers; if (!this.answersCmsData) return buttons;
const rainDefenseInCart = this.currentCartItems.vaps?.some((vap) => {
return vap?.partType === partTypeStrings.RAIN_DEFENSE;
});
const frontWipersInCart = this.currentCartItems.vaps?.some((vap) => {
return vap?.partType?.includes(partTypeStrings.FRONT_WIPER);
});
const rearWipersInCart = this.currentCartItems.vaps?.some((vap) => {
return vap?.partType?.includes(partTypeStrings.REAR_WIPER);
});
const getAnswer = (name, answers) => { const getAnswer = (name, answers) => {
const answerIndex = answers.findIndex((answer) => { const answerIndex = answers.findIndex((answer) => {
return answer.Name === name; return answer.Name === name;
}); });
return answers[answerIndex]; return answers[answerIndex];
}; };
if (this.showAddWipers) {
const answer = getAnswer("WipersModal", this.answersCmsData); if (!rainDefenseInCart) {
answer.SubText = "+$" + this.wipersItem.listPrice; // NO RAIN DEFENSE IN CART; SHOW RAIN DEFENSE BUTTON
answers.push(answer); const modalData = getAnswer("RainDefenseModal", this.answersCmsData);
modalData.SubText = "+$" + this.rainDefenseModal?.listPrice;
buttons.push(modalData);
} }
if (this.showAddRainDefense) {
const answer = getAnswer("RainDefenseModal", this.answersCmsData); const modalData = getAnswer("WipersModal", this.answersCmsData);
answer.SubText = "+$" + this.rainDefenseItem.listPrice; if (!frontWipersInCart) {
answers.push(answer); if (!rearWipersInCart && this.wipersModal?.rearWiperLineItems.length > 0) {
// NO REAR WIPERS or FRONT WIPERS IN CART; SHOW COMBO BUTTON
const prices = [
this.wipersModal?.totalFrontPrice,
this.wipersModal?.totalRearPrice,
];
prices.sort((a, b) => a - b);
modalData.SubText = "+$" + prices[0] + " - $" + prices[prices.length - 1];
this.updateWipersToDisplay(wipersToDisplayStrings.BOTH);
buttons.push(modalData);
} else {
// NO FRONT WIPERS IN CART; SHOW ONLY FRONT WIPERS BUTTON
modalData.SubText = "+$" + this.wipersModal?.totalFrontPrice;
this.updateWipersToDisplay(wipersToDisplayStrings.FRONT);
buttons.push(modalData);
}
} else if (!rearWipersInCart && this.wipersModal?.rearWiperLineItems.length > 0) {
// NO REAR WIPERS IN CART; SHOW ONLY REAR WIPERS BUTTON
modalData.SubText = "+$" + this.wipersModal?.totalRearPrice;
this.updateWipersToDisplay(wipersToDisplayStrings.REAR);
buttons.push(modalData);
} }
return answers;
return buttons;
},
wipersToDisplayStrings() {
return wipersToDisplayStrings;
}, },
}, },
components: { components: {
buttonQuestion, buttonQuestion,
contentGroupModal, contentGroupModal,
checkboxQuestion,
}, },
}; };
</script> </script>
<style lang="scss">
.add-vaps-buttons {
// necessary overrides for modals
.modal {
&.modal-component {
.modal-dialog {
.modal-content {
.modal-body {
padding-bottom: 1.5rem;
& > img {
margin-bottom: 1.5rem;
line-height: 2;
text-align: center;
}
& > h5 {
text-align: center;
}
p {
margin-bottom: 1rem;
}
p.subheader-text {
text-align: center;
}
p.price {
text-align: center;
}
.wiper-options {
& > div {
display: flex;
justify-content: space-between;
margin-bottom: 1rem;
&:last-child {
margin-bottom: 0;
}
.form-check {
margin-bottom: 0;
}
}
p {
margin-bottom: 0;
}
p.price {
font-size: 0.875rem;
padding-left: 0.5rem;
color: $green;
}
}
}
}
}
}
}
}
</style>

View file

@ -50,12 +50,13 @@ function setupMocks() {
lineItems: [], lineItems: [],
order: { order: {
payment: { payment: {
piaErrorCode: "", isPia: false,
}, },
}, },
}; };
const mountOptions = getMountOptions({ const mountOptions = getMountOptions({
route: { query: {}, params: {} },
router: { router: {
navigate: jest.fn(), navigate: jest.fn(),
navigateWithSaving: jest.fn(), navigateWithSaving: jest.fn(),

View file

@ -35,7 +35,7 @@
<alert <alert
ref="piaErrorAlert" ref="piaErrorAlert"
class="my-4" class="my-4"
v-if="displayPiaAlert" v-if="shouldDisplayPiaAlert"
cmsWidgetName="PIAErrorAlertWidget" cmsWidgetName="PIAErrorAlertWidget"
alertClass="alert-danger" alertClass="alert-danger"
v-bind:isDismissible="false" /> v-bind:isDismissible="false" />
@ -262,7 +262,6 @@ export default {
} }
}, },
backButtonAction() { backButtonAction() {
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
}, },
async forwardButtonAction() { async forwardButtonAction() {
@ -276,42 +275,38 @@ export default {
await this.dispatchStoreAction(storeActions.SAVE_PROMOS, this.lineItems.promos, false); await this.dispatchStoreAction(storeActions.SAVE_PROMOS, this.lineItems.promos, false);
switch (this.paymentMethod) { if (this.paymentMethod == paymentMethods.LATER) {
case paymentMethods.CREDIT_CARD: // this creates the final work order
this.setupPia(this.paymentMethod); await submitWorkOrder({ pageNameToLog: "payment-method", submitAfterSave: true });
break; this.$router.navigateWithoutSaving(
case paymentMethods.PAYPAL: this.navigationScenarios.CLICKED_FORWARD,
this.setupPia(this.paymentMethod); this.$route
break; );
case paymentMethods.AFTERPAY: } else {
this.setupPia(this.paymentMethod); this.setupPia();
break;
default:
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
this.dispatchStoreAction(this.storeActions.SAVE_WORK_ORDER_FLAG, true, false);
await submitWorkOrder({ pageNameToLog: "payment-method" });
this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_FORWARD,
this.$route
);
} }
}, },
async setupPia(payNowType) { async setupPia() {
this.$refs.loadingModal.showModal(); this.$refs.loadingModal.showModal();
// since we're leaving the site for pia, clear any save session promises that we will not be able to resolve when we return // if we don't have a work order in delete substatus, set the flag and submit.
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); // we need a work order number for pia so we can pass it to safeliteHop.
// make sure pia error codes are reset
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
// if we don't have a work order in delete substatus, set the flag and submit
if (!store.getters.order.workOrderNumber) { if (!store.getters.order.workOrderNumber) {
this.dispatchStoreAction(storeActions.SAVE_PIA_WORK_ORDER, true); try {
await submitWorkOrder({ pageNameToLog: "payment-method" }); await submitWorkOrder({
this.dispatchStoreAction(storeActions.SAVE_PIA_WORK_ORDER, false); pageNameToLog: "payment-method",
submitAfterSave: false,
createDeleteStatusWorkOrderForPia: true,
});
} catch (error) {
console.log("error: response from pia submit work order:" + error.message);
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
this.$route.params[this.routerParams.DISPLAY_PIA_ALERT] = true;
return;
}
} }
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
this.$router.navigateWithoutSaving( this.$router.navigateWithoutSaving(
this.navigationScenarios.CLICKED_PAY_NOW, this.navigationScenarios.CLICKED_PAY_NOW,
this.$route this.$route
@ -340,11 +335,8 @@ export default {
isPiaDisabled() { isPiaDisabled() {
const piaExperience = const piaExperience =
this.getSettingValue(experimentSettings.PIA_EXPERIENCE) === "PIA Optional"; this.getSettingValue(experimentSettings.PIA_EXPERIENCE) === "PIA Optional";
const enablePIA =
this.getSettingValue(experimentSettings.SUBMIT_ORDER_ENABLE_PIA) === "true";
return false; return !piaExperience;
//return !(piaExperience && enablePIA);
}, },
paymentMethod() { paymentMethod() {
if (this.isPiaDisabled) { if (this.isPiaDisabled) {
@ -353,8 +345,8 @@ export default {
return this.paymentMethodInternalModel; return this.paymentMethodInternalModel;
}, },
displayPiaAlert() { shouldDisplayPiaAlert() {
return store.getters.order.payment.piaErrorCode ? true : false; return this.$route.params[this.routerParams.DISPLAY_PIA_ALERT];
}, },
}, },
watch: { watch: {

View file

@ -14,6 +14,7 @@ import baseMixin from "@/mixins/base-mixin.js";
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue"; import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
import { Form } from "vee-validate"; import { Form } from "vee-validate";
import { paymentMethods } from "@/constants/payment-method-constants"; import { paymentMethods } from "@/constants/payment-method-constants";
import { routerParams } from "@/router/router-constants/router-params";
export default { export default {
name: "payment-pia-return", name: "payment-pia-return",
@ -23,12 +24,12 @@ export default {
if (piaError) { if (piaError) {
console.log("Error during payment: " + piaError); console.log("Error during payment: " + piaError);
baseMixin.methods.dispatchStoreAction( this.$router.navigateWithoutSaving(
storeActions.SAVE_PIA_ERROR_CODE, this.navigationScenarios.PIA_ERROR,
piaError, this.$route,
false {},
{ [routerParams.DISPLAY_PIA_ALERT]: true }
); );
this.$router.navigateWithoutSaving(this.navigationScenarios.PIA_ERROR, this.$route);
} else { } else {
switch (store.getters.order.payment.piaType) { switch (store.getters.order.payment.piaType) {
case paymentMethods.CREDIT_CARD: case paymentMethods.CREDIT_CARD:
@ -41,14 +42,11 @@ export default {
default: default:
var msg = "Unknown Pia type: " + store.getters.order.payment.piaType; var msg = "Unknown Pia type: " + store.getters.order.payment.piaType;
console.log(msg); console.log(msg);
baseMixin.methods.dispatchStoreAction(
storeActions.SAVE_PIA_ERROR_CODE,
msg,
false
);
this.$router.navigateWithoutSaving( this.$router.navigateWithoutSaving(
this.navigationScenarios.PIA_ERROR, this.navigationScenarios.PIA_ERROR,
this.$route this.$route,
{},
{ [routerParams.DISPLAY_PIA_ALERT]: true }
); );
} }
} }
@ -60,16 +58,12 @@ export default {
async processPaypalResponse() { async processPaypalResponse() {
const token = getQuerystringParameter(queryStrings.TOKEN); const token = getQuerystringParameter(queryStrings.TOKEN);
const payerId = getQuerystringParameter(queryStrings.PAYERID); const payerId = getQuerystringParameter(queryStrings.PAYERID);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_WORK_ORDER_FLAG, true, false);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PAYPAL_TOKEN, token, false); baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PAYPAL_TOKEN, token, false);
await this.saveAndSubmitWorkOrder(); await this.saveAndSubmitWorkOrder();
}, },
async processCreditCardResponse() { async processCreditCardResponse() {
const subscriptionID = getQuerystringParameter(queryStrings.SUBSCRIPTIONID); const subscriptionID = getQuerystringParameter(queryStrings.SUBSCRIPTIONID);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_WORK_ORDER_FLAG, true, false);
const referralSeqNum = getQuerystringParameter(queryStrings.REFERRAL_SEQ_NUM); const referralSeqNum = getQuerystringParameter(queryStrings.REFERRAL_SEQ_NUM);
if (referralSeqNum != store.getters.order.referralSequenceNumber) { if (referralSeqNum != store.getters.order.referralSequenceNumber) {
@ -79,12 +73,12 @@ export default {
" " + " " +
store.getters.order.referralSequenceNumber store.getters.order.referralSequenceNumber
); );
baseMixin.methods.dispatchStoreAction( this.$router.navigateWithoutSaving(
storeActions.SAVE_PIA_ERROR_CODE, this.navigationScenarios.PIA_ERROR,
"unknown error", this.$route,
false {},
{ [routerParams.DISPLAY_PIA_ALERT]: true }
); );
this.$router.navigateWithoutSaving(this.navigationScenarios.PIA_ERROR, this.$route);
} else { } else {
const expMonth = getQuerystringParameter(queryStrings.CARD_EXPIRATION_MONTH); const expMonth = getQuerystringParameter(queryStrings.CARD_EXPIRATION_MONTH);
const expYear = getQuerystringParameter(queryStrings.CARD_EXPIRATION_YEAR); const expYear = getQuerystringParameter(queryStrings.CARD_EXPIRATION_YEAR);
@ -119,7 +113,23 @@ export default {
async saveAndSubmitWorkOrder() { async saveAndSubmitWorkOrder() {
// Final work order submit after returning from PIA. // Final work order submit after returning from PIA.
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE); await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
await submitWorkOrder({ pageNameToLog: "payment-pia-return" }); try {
await submitWorkOrder({
pageNameToLog: "payment-pia-return",
submitAfterSave: true,
});
} catch (error) {
console.log("error: response from submit work order:" + error.message);
this.$router.navigateWithoutSaving(
this.navigationScenarios.PIA_ERROR,
this.$route,
{},
{ [routerParams.DISPLAY_PIA_ALERT]: true }
);
this.$refs.loadingModal.isModalVisible = false;
return;
}
this.$refs.loadingModal.isModalVisible = false; this.$refs.loadingModal.isModalVisible = false;
this.$router.navigateWithoutSaving(this.navigationScenarios.PIA_SUCCESS, this.$route); this.$router.navigateWithoutSaving(this.navigationScenarios.PIA_SUCCESS, this.$route);
}, },

View file

@ -20,21 +20,52 @@
scrolling="no"> scrolling="no">
</iframe> </iframe>
</div> </div>
<div class="fade-on-route-transition sub-container make-tall"> <div>{{ switchPaymentText }}</div>
<navbar <div>
cmsWidgetName="FunnelFooterWidget" <button
isForwardActionDisabled="true" v-if="paymentType !== 'cc'"
:isBackButtonHidden="shouldHideBackButton" ref="switchToCCButton"
isSubmitHidden="true" type="button"
@back-clicked="backButtonAction" /> @mousedown="switchPIAMethod('cc')"
aria-label="Switch to Credit Card">
Switch to Credit Card
</button>
</div> </div>
<div v-if="paymentType !== 'cc'">or</div>
<div>
<button
v-if="paymentType !== 'pp'"
ref="switchToPPButton"
type="button"
@mousedown="switchPIAMethod('pp')"
aria-label="Switch to PayPal">
Switch to PayPal
</button>
</div>
<div v-if="paymentType === 'cc'">or</div>
<div>
<button
v-if="paymentType !== 'ap'"
ref="switchToAPButton"
type="button"
@mousedown="switchPIAMethod('ap')"
aria-label="Switch to Afterpay">
Switch to Afterpay
</button>
</div>
<navbar
cmsWidgetName="FunnelFooterWidget"
isForwardActionDisabled="true"
:isBackButtonHidden="shouldHideBackButton"
isSubmitHidden="true"
@back-clicked="backButtonAction" />
</div> </div>
</div> </div>
</div> </div>
</Form> </Form>
<form <form
ref="myForm" ref="hopForm"
id="card-data" id="card-data"
:target="paypalPayment ? '_top' : 'card-frame'" :target="paypalPayment ? '_top' : 'card-frame'"
method="POST" method="POST"
@ -54,6 +85,7 @@
<input type="hidden" name="sgNoKeystrokeProcessing" value="false" /> <input type="hidden" name="sgNoKeystrokeProcessing" value="false" />
<input type="hidden" name="maskCharacter" value="*" /> <input type="hidden" name="maskCharacter" value="*" />
<input type="hidden" name="styleSheetCode" :value="dynamicCSSUrl" />
<input type="hidden" name="styleSheetCode2" :value="dynamicHopCSSUrl" /> <input type="hidden" name="styleSheetCode2" :value="dynamicHopCSSUrl" />
<input type="hidden" name="sgReceiptResponseURL" :value="piaResponseUrl" /> <input type="hidden" name="sgReceiptResponseURL" :value="piaResponseUrl" />
@ -167,6 +199,7 @@ import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
import { settleAllPromises } from "@/helpers/layout-helper"; import { settleAllPromises } from "@/helpers/layout-helper";
import { applicationConfig } from "@/constants/application-config"; import { applicationConfig } from "@/constants/application-config";
import { paymentMethods } from "@/constants/payment-method-constants"; import { paymentMethods } from "@/constants/payment-method-constants";
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
import baseMixin from "@/mixins/base-mixin.js"; import baseMixin from "@/mixins/base-mixin.js";
// Validation // Validation
@ -234,6 +267,10 @@ export default {
}); });
}, },
computed: { computed: {
dynamicCSSUrl() {
const { protocol, hostname, port } = window.location;
return `${protocol}//${hostname}:${port}/fmg/css/site-2020Styling.css`;
},
dynamicHopCSSUrl() { dynamicHopCSSUrl() {
const { protocol, hostname, port } = window.location; const { protocol, hostname, port } = window.location;
return `${protocol}//${hostname}:${port}/fmg/css/hop-styling.css`; return `${protocol}//${hostname}:${port}/fmg/css/hop-styling.css`;
@ -250,11 +287,71 @@ export default {
} }
return ""; return "";
}, },
switchPaymentText() {
return this.getCmsContent("PaymentMethodWidget", "QuestionText");
},
}, },
methods: { methods: {
arePagePrerequisitesValid() { arePagePrerequisitesValid() {
// TODO // Line Items
return true; const packageReqs = !!store.getters.order.lineItems.supportingItems;
// Service Location
const serviceLocation = store.getters.order.serviceLocation;
const mobileReqs = !!(
serviceLocation.address &&
serviceLocation.city &&
serviceLocation.state &&
serviceLocation.zipCode
);
const providerLocation = serviceLocation.provider.address;
const dropOffInshopReqs = !!(
providerLocation.streetAddress &&
providerLocation.city &&
providerLocation.state &&
providerLocation.zipCode
);
const isMobile = serviceLocation.appointmentType === AppointmentTypeStrings.MOBILE;
const serviceLocationReqs =
(isMobile && mobileReqs) || (!isMobile && dropOffInshopReqs);
// Insurance
const isInsuranceSet = store.getters.order.payment.isInsurance !== null;
// Schedule
const schedule = store.getters.order.schedule;
const scheduleReqs = !!(
schedule.date &&
schedule.startTime &&
(!isMobile || schedule.endTime) &&
schedule.jobMaxMinutes &&
schedule.jobMinMinutes
);
// Customer
const customer = store.getters.order.customer;
const customerReqs = !!(
customer.firstName &&
customer.lastName &&
customer.phoneNumber &&
customer.emailAddress
);
const paymentMethodReqs =
store.getters.order.payment.isPia !== null &&
(store.getters.order.payment.isPia || !!store.getters.order.payment.piaType);
return (
packageReqs &&
serviceLocationReqs &&
isInsuranceSet &&
scheduleReqs &&
customerReqs &&
paymentMethodReqs
);
}, },
getWOrkOrderNumber() { getWOrkOrderNumber() {
if (store.getters.order.workOrderNumber) { if (store.getters.order.workOrderNumber) {
@ -262,8 +359,6 @@ export default {
return items[1]; return items[1];
} }
// no work order, set pia error and return
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, "NO WORK ORDER", false);
this.backButtonAction(); this.backButtonAction();
}, },
getInvoiceNumber() { getInvoiceNumber() {
@ -271,8 +366,6 @@ export default {
return store.getters.order.workOrderNumber.replace("-", ""); return store.getters.order.workOrderNumber.replace("-", "");
} }
// no work order, set pia error and return
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, "NO WORK ORDER", false);
this.backButtonAction(); this.backButtonAction();
}, },
getAddress1() { getAddress1() {
@ -351,6 +444,28 @@ export default {
window.location = applicationConfig.PIA_CANCEL_URL; window.location = applicationConfig.PIA_CANCEL_URL;
//this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route); //this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
}, },
switchPIAMethod(payMethod) {
this.paymentType = payMethod;
this.submitHopForm();
},
submitHopForm() {
this.$nextTick(() => {
this.$refs.hopForm.submit();
const iframe = this.$refs.paymentFrame;
if (iframe) {
iframe.onload = () => {
if (iframe.contentWindow) {
if (this.paymentType == "cc") {
iframe.contentWindow.postMessage("CreditCardChosen", "*");
} else if (this.paymentType == "ap") {
iframe.contentWindow.postMessage("afterpay", "*");
}
}
};
}
});
},
async fetchSignatureInfo(signatureInfo) { async fetchSignatureInfo(signatureInfo) {
if (this.isPaypal()) { if (this.isPaypal()) {
this.$refs.loadingModal.showModal(); this.$refs.loadingModal.showModal();
@ -360,20 +475,7 @@ export default {
this.authSignature = signatureInfo.signature; this.authSignature = signatureInfo.signature;
this.authSignatureStart = signatureInfo.startDate; this.authSignatureStart = signatureInfo.startDate;
this.$nextTick(() => { this.submitHopForm();
this.$refs.myForm.submit();
if (this.paymentType == "ap") {
const iframe = this.$refs.paymentFrame;
if (iframe) {
iframe.onload = () => {
if (iframe.contentWindow) {
iframe.contentWindow.postMessage("afterpay", "*");
}
};
}
}
});
}, },
}, },
components: { components: {
@ -387,8 +489,11 @@ export default {
<style lang="scss"> <style lang="scss">
.hop-iframe { .hop-iframe {
position: relative; position: relative;
min-height: 1600px; min-height: 1320px;
width: 100%; width: 100%;
border: 0 none; border: 0 none;
} }
#pageLoadingModal {
background-color: red;
}
</style> </style>

View file

@ -1,5 +1,6 @@
const routerParams = { const routerParams = {
DISPLAY_VEHICLE_CHANGE_ALERT: "displayVehicleChangeAlert", DISPLAY_VEHICLE_CHANGE_ALERT: "displayVehicleChangeAlert",
DISPLAY_PIA_ALERT: "displayPiaAlert",
}; };
export { routerParams }; export { routerParams };

View file

@ -28,7 +28,6 @@ import { getDateDifferenceInDays } from "@/helpers/date-helper";
// Export State // Export State
const getDefaultState = () => { const getDefaultState = () => {
return { return {
submitAfterSave: false,
order: { order: {
vehicle: { vehicle: {
year: null, year: null,
@ -97,7 +96,6 @@ const getDefaultState = () => {
parentAccountNumber: 0, parentAccountNumber: 0,
isPia: null, isPia: null,
piaType: null, piaType: null,
piaErrorCode: null,
inactivePromos: null, inactivePromos: null,
paypalToken: null, paypalToken: null,
ccToken: { ccToken: {
@ -128,7 +126,6 @@ const getDefaultState = () => {
referralCorrelationId: null, referralCorrelationId: null,
eon: null, eon: null,
workOrderNumber: null, workOrderNumber: null,
createDeleteStatusWorkOrderForPia: false,
}, },
applicationUser: { applicationUser: {
eventBus: [], eventBus: [],
@ -148,10 +145,6 @@ export const state = getDefaultState();
// Export Mutations // Export Mutations
export const mutations = { export const mutations = {
updateWorkOrderFlag(state, submitAfterSave) {
state.submitAfterSave = submitAfterSave;
},
// VEHICLE MUTATIONS // VEHICLE MUTATIONS
updateYear(state, year) { updateYear(state, year) {
state.order.vehicle.year = year; state.order.vehicle.year = year;
@ -249,12 +242,6 @@ export const mutations = {
updatePiaType(state, piaType) { updatePiaType(state, piaType) {
state.order.payment.piaType = piaType; state.order.payment.piaType = piaType;
}, },
updatePiaErrorCode(state, piaErrorCode) {
state.order.payment.piaErrorCode = piaErrorCode;
},
updatePiaWorkOrder(state, piaWorkOrder) {
state.order.createDeleteStatusWorkOrderForPia = piaWorkOrder;
},
updateWorkOrderNumber(state, workOrderNumber) { updateWorkOrderNumber(state, workOrderNumber) {
state.order.workOrderNumber = workOrderNumber; state.order.workOrderNumber = workOrderNumber;
}, },
@ -570,7 +557,6 @@ export const mutations = {
// Export Getters // Export Getters
export const getters = { export const getters = {
submitAfterSave: (state) => state.submitAfterSave,
vehicle: (state) => state.order.vehicle, vehicle: (state) => state.order.vehicle,
eventBusItem: (state) => (eventCategory, eventSubCategory) => { eventBusItem: (state) => (eventCategory, eventSubCategory) => {
const matchedEvent = state.applicationUser.eventBus.find( const matchedEvent = state.applicationUser.eventBus.find(
@ -697,6 +683,7 @@ export const getters = {
}, },
experimentSettings: (state) => experimentSettings: (state) =>
state.applicationUser.experiments state.applicationUser.experiments
.filter((x) => !!x.isActive)
.map((x) => x.settings) .map((x) => x.settings)
.reduce((r, c) => Object.assign(r, c), {}) ?? {}, .reduce((r, c) => Object.assign(r, c), {}) ?? {},
}; };
@ -1581,13 +1568,17 @@ export const actions = {
}, },
// Session API Actions // Session API Actions
saveSession(context, { pageNameToLog }) { saveSession(context, { pageNameToLog, payload }) {
const vehicle = context.getters.vehicle; const vehicle = context.getters.vehicle;
const damage = context.getters.damage; const damage = context.getters.damage;
const order = context.state.order; const order = context.state.order;
const applicationUser = context.getters.applicationUser; const applicationUser = context.getters.applicationUser;
const lineItems = context.state.order.lineItems; const lineItems = context.state.order.lineItems;
const submitAfterSave = payload?.submitAfterSave === "true";
const createDeleteStatusWorkOrderForPia =
payload?.createDeleteStatusWorkOrderForPia === "true";
// create a new array to avoid mutating state // create a new array to avoid mutating state
const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace); const newGlassToReplace = convertGlassPieceNamingForApi(damage.glassToReplace);
@ -1595,7 +1586,7 @@ export const actions = {
method: endpoints.SaveSession.method, method: endpoints.SaveSession.method,
endpoint: endpoints.SaveSession.url, endpoint: endpoints.SaveSession.url,
payload: { payload: {
submitAfterSave: context.state.submitAfterSave, submitAfterSave: submitAfterSave,
userAgent: navigator.userAgent, userAgent: navigator.userAgent,
applicationUser: { applicationUser: {
crmCustomerId: applicationUser.crmCustomerId, crmCustomerId: applicationUser.crmCustomerId,
@ -1706,7 +1697,7 @@ export const actions = {
referralNumber: order.referralNumber?.toString(), referralNumber: order.referralNumber?.toString(),
referralSequenceNumber: order.referralSequenceNumber, referralSequenceNumber: order.referralSequenceNumber,
eon: order.eon, eon: order.eon,
createDeleteStatusWorkOrderForPia: order.createDeleteStatusWorkOrderForPia, createDeleteStatusWorkOrderForPia: createDeleteStatusWorkOrderForPia,
}, },
}, },
logApiCall: true, logApiCall: true,
@ -1777,15 +1768,6 @@ export const actions = {
); );
}, },
saveWorkOrderFlag(context, submitAfterSave) {
context.commit(storeMutations.UPDATE_WORK_ORDER_FLAG, submitAfterSave);
},
savePiaErrorCode(context, piaErrorCode) {
context.commit(storeMutations.UPDATE_PIA_ERROR_CODE, piaErrorCode);
},
savePiaWorkOrder(context, piaWorkOrder) {
context.commit(storeMutations.UPDATE_PIA_WORK_ORDER, piaWorkOrder);
},
saveCCToken(context, ccToken) { saveCCToken(context, ccToken) {
context.commit(storeMutations.UPDATE_CCTOKEN, ccToken); context.commit(storeMutations.UPDATE_CCTOKEN, ccToken);
}, },

View file

@ -2791,17 +2791,6 @@ describe("Actions", () => {
}); });
describe("Getters", () => { describe("Getters", () => {
it("submitAfterSave, should return true", () => {
// Arrange
const storeState = state;
// Act
mutations.updateWorkOrderFlag(storeState, true);
// Assert
expect(getters.submitAfterSave(storeState)).toEqual(true);
});
it("Vehicle getter, should return vehicle data", () => { it("Vehicle getter, should return vehicle data", () => {
// Arrange // Arrange
const storeState = state; const storeState = state;