SSR-1064 payment method pia options
This commit is contained in:
parent
7215f0e464
commit
5559033c41
9 changed files with 785 additions and 14 deletions
7
src/constants/payment-method-constants.js
Normal file
7
src/constants/payment-method-constants.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
export const paymentMethods = {
|
||||
NONE: null,
|
||||
LATER: "Later",
|
||||
CREDIT_CARD: "CreditCard",
|
||||
PAYPAL: "Paypal",
|
||||
AFTERPAY: "Afterpay",
|
||||
};
|
||||
59
src/iss-components/nav-bar/nav-bar.spec.js
Normal file
59
src/iss-components/nav-bar/nav-bar.spec.js
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { mount } from "@vue/test-utils";
|
||||
import navbar from "./nav-bar";
|
||||
|
||||
describe("nav-bar.vue", () => {
|
||||
test("Should emit ForwardClicked on button click", async () => {
|
||||
// Act
|
||||
const wrapper = mount(navbar, {
|
||||
mixins: [mockMixin],
|
||||
});
|
||||
wrapper.vm.buttonClick();
|
||||
// Assert
|
||||
expect(wrapper.emitted()["ForwardClicked"][0]).toHaveBeenCalled;
|
||||
});
|
||||
|
||||
test("Should emit BackClicked on link click", async () => {
|
||||
// Act
|
||||
const wrapper = mount(navbar, {
|
||||
mixins: [mockMixin],
|
||||
});
|
||||
wrapper.vm.linkClick();
|
||||
// Assert
|
||||
expect(wrapper.emitted()["BackClicked"][0]).toHaveBeenCalled;
|
||||
});
|
||||
|
||||
test("Should change button text when update button text is called", async () => {
|
||||
// Act
|
||||
const wrapper = mount(navbar, {
|
||||
mixins: [mockMixin],
|
||||
});
|
||||
wrapper.vm.updateButtonText("newText");
|
||||
|
||||
// Assert
|
||||
expect(wrapper.componentVM.customButtontext).toBe("newText");
|
||||
});
|
||||
|
||||
test("should run removeLoader fn on buttonMain and return false for onkeydown fn", async () => {
|
||||
// Arrange
|
||||
const wrapper = mount(navbar, {
|
||||
mixins: [mockMixin],
|
||||
});
|
||||
|
||||
// Act
|
||||
wrapper.vm.$refs.buttonMain.removeLoader = jest.fn();
|
||||
wrapper.vm.removeLoader();
|
||||
const spy = jest.spyOn(document, "onkeydown");
|
||||
document.onkeydown();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$refs.buttonMain.removeLoader).toHaveBeenCalled();
|
||||
expect(spy).toReturnWith(true);
|
||||
});
|
||||
});
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn(),
|
||||
getFooterInfoBoxHeight: jest.fn(() => 80),
|
||||
},
|
||||
};
|
||||
163
src/iss-components/nav-bar/nav-bar.vue
Normal file
163
src/iss-components/nav-bar/nav-bar.vue
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<div class="row"></div>
|
||||
<div class="nav-bar container-fluid g-5 my-5 px-0" id="infoBox">
|
||||
<div
|
||||
class="row d-flex justify-content-between vw-100"
|
||||
:class="[
|
||||
buttonSize
|
||||
? 'flex-column align-items-stretch'
|
||||
: 'flex-row-reverse align-items-center',
|
||||
]">
|
||||
<div
|
||||
:class="['col button-col d-flex', buttonSize ? 'large-button' : 'medium-button']"
|
||||
id="stacked">
|
||||
<buttonMain
|
||||
ref="buttonMain"
|
||||
isPrimary
|
||||
:buttonText="buttonText"
|
||||
loaderColor="white"
|
||||
:class="isForwardActionDisabled && 'form-test-invalid'"
|
||||
:aria-disabled="isForwardActionDisabled"
|
||||
:isDisabled="isForwardActionDisabled"
|
||||
@click-event="buttonClick"
|
||||
data-bs-target="#footerModal"
|
||||
data-test-id="nav-bar-main-button"
|
||||
data-bs-dismiss="modal"
|
||||
v-if="!isSubmitHidden" />
|
||||
</div>
|
||||
<div
|
||||
v-if="!isBackButtonHidden"
|
||||
class="col-auto link-col py-1 text-break"
|
||||
:class="[buttonSize ? 'back-centered-below mt-5' : '']">
|
||||
<textLink
|
||||
linkType="navigation"
|
||||
:text="backLink"
|
||||
useLoadingModal
|
||||
@click-event="linkClick"
|
||||
href="javascript:void(0)"
|
||||
data-bs-target="#footerModal"
|
||||
data-bs-dismiss="modal" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import textLink from "@/ux-components/text-link/text-link";
|
||||
import buttonMain from "@/ux-components/button-main/button-main";
|
||||
|
||||
export default {
|
||||
name: "navbar",
|
||||
emits: ["BackClicked", "ForwardClicked"], // <--- should remove oodles of warnings in dev tools
|
||||
props: {
|
||||
isForwardActionDisabled: Boolean,
|
||||
isBackButtonHidden: { type: Boolean, default: false },
|
||||
cmsWidgetName: String,
|
||||
buttonSize: { type: Boolean, default: false },
|
||||
isSubmitHidden: { type: Boolean, default: false },
|
||||
},
|
||||
components: {
|
||||
textLink,
|
||||
buttonMain,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
customButtontext: "",
|
||||
};
|
||||
},
|
||||
|
||||
unmounted() {
|
||||
document.onkeydown = null;
|
||||
},
|
||||
computed: {
|
||||
backLink() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "BackButtonText");
|
||||
},
|
||||
buttonText() {
|
||||
return this.customButtontext
|
||||
? this.customButtontext
|
||||
: this.getCmsContent(this.cmsWidgetName, "ForwardButtonText");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateButtonText(newText) {
|
||||
this.customButtontext = newText;
|
||||
},
|
||||
removeLoader() {
|
||||
this.$refs.buttonMain.removeLoader();
|
||||
document.onkeydown = function (e) {
|
||||
return true;
|
||||
};
|
||||
},
|
||||
buttonClick() {
|
||||
//prevent keyboard input after button click
|
||||
document.onkeydown = function (e) {
|
||||
return false;
|
||||
};
|
||||
this.$emit("ForwardClicked");
|
||||
},
|
||||
linkClick() {
|
||||
this.$emit("BackClicked");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.nav-bar {
|
||||
overflow: visible;
|
||||
display: flex;
|
||||
padding: 0;
|
||||
a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.col,
|
||||
.col-auto,
|
||||
.col button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.back-centered-below {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 340px) {
|
||||
.col,
|
||||
.col-auto,
|
||||
.col button {
|
||||
width: auto;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.back-centered-below {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
width: auto;
|
||||
}
|
||||
a {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
& > .container-fluid {
|
||||
overflow-x: visible; // needed to fix hidden footer on some iphones
|
||||
}
|
||||
.medium-button {
|
||||
// Define styles for a medium button (default size)
|
||||
justify-content: flex-end;
|
||||
width: auto;
|
||||
}
|
||||
.large-button {
|
||||
justify-content: center;
|
||||
.btn-primary {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
|
||||
import paymentMethodListButton from "@/layouts/payment-method/payment-method-question/payment-method-list-button/payment-method-list-button";
|
||||
|
||||
const testConstants = {
|
||||
images: {
|
||||
A: "imageA",
|
||||
B: "imageB",
|
||||
NONE: null,
|
||||
},
|
||||
names: {
|
||||
A: "nameA",
|
||||
B: "nameB",
|
||||
},
|
||||
content: {
|
||||
withInline: "Button text with {custom:inlineImage} inline.",
|
||||
noInline: "Button text with no inline",
|
||||
},
|
||||
};
|
||||
|
||||
let cmsContent;
|
||||
|
||||
describe("Payment Method Question", () => {
|
||||
beforeEach(() => {
|
||||
cmsContent = {};
|
||||
});
|
||||
|
||||
describe("Side image", () => {
|
||||
it("Renders side image if image is present and not inline", () => {
|
||||
// Arrange
|
||||
const props = generateDefaultProps();
|
||||
const { wrapper } = setupMocks({
|
||||
propsData: props,
|
||||
});
|
||||
|
||||
// Act
|
||||
const showSideImage = wrapper.vm.shouldDisplaySideImage;
|
||||
|
||||
expect(showSideImage).toBe(true);
|
||||
});
|
||||
|
||||
it("Does not render side image if no image is present", () => {
|
||||
// Arrange
|
||||
let props = generateDefaultProps();
|
||||
|
||||
props.buttonImage = testConstants.images.NONE;
|
||||
|
||||
const { wrapper } = setupMocks({
|
||||
propsData: props,
|
||||
});
|
||||
|
||||
// Act
|
||||
const showSideImage = wrapper.vm.shouldDisplaySideImage;
|
||||
|
||||
expect(showSideImage).toBe(false);
|
||||
});
|
||||
|
||||
it("Does not render side image if inline", () => {
|
||||
// Arrange
|
||||
let props = generateDefaultProps();
|
||||
|
||||
props.buttonLabel = testConstants.content.withInline;
|
||||
props.altText = testConstants.content.withInline;
|
||||
|
||||
const { wrapper } = setupMocks({
|
||||
propsData: props,
|
||||
});
|
||||
|
||||
// Act
|
||||
const showSideImage = wrapper.vm.shouldDisplaySideImage;
|
||||
|
||||
expect(showSideImage).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function generateDefaultProps() {
|
||||
return {
|
||||
buttonLabel: testConstants.noInline,
|
||||
altText: testConstants.noInline,
|
||||
groupName: "payment-method",
|
||||
value: testConstants.names.A,
|
||||
buttonImage: testConstants.images.A,
|
||||
};
|
||||
}
|
||||
|
||||
function setupMocks(customMountOptions) {
|
||||
const mountOptions = getMountOptions(customMountOptions);
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return cmsContent?.[widgetName]?.[cmsFieldName] ?? "";
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
mountOptions.global.mixins = [mockMixin];
|
||||
|
||||
const wrapper = shallowMount(paymentMethodListButton, mountOptions);
|
||||
wrapper.vm.setCmsContent = jest.fn();
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<template>
|
||||
<baseInputButton
|
||||
v-bind="$props"
|
||||
buttonWrapperClasses="list-group base-input-button list-button rounded-3 d-flex flex-column w-100 mb-2"
|
||||
v-model="selectedValue">
|
||||
<div class="button-content list-button-content d-flex flex-row py-3 px-4">
|
||||
<img
|
||||
v-if="shouldDisplaySideImage"
|
||||
:id="buttonImageId"
|
||||
class="ms-auto order-3"
|
||||
:src="buttonImage"
|
||||
:alt="altText" />
|
||||
<div class="order-2">
|
||||
<p class="m-0">
|
||||
<span v-for="token in tokens" :key="token">
|
||||
<span v-if="isInlineImageToken(token)">
|
||||
<img
|
||||
v-if="hasImage"
|
||||
:src="buttonImage"
|
||||
:alt="getInlineAltText(token)" />
|
||||
<span v-else> {{ getInlineAltText(token) }}</span>
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ token }}
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</baseInputButton>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import baseInputButton from "@/digital-components/base-input-button/base-input-button";
|
||||
import inputButtonWrapperMixin from "@/mixins/input-button-wrapper-mixin";
|
||||
import { splitCopyOnCMSPlaceHolder } from "@/helpers/cms-content-helper";
|
||||
|
||||
const INLINE_IMAGE_TOKEN = "custom:inlineImage";
|
||||
|
||||
function isInlineImageToken(token) {
|
||||
return token.includes(INLINE_IMAGE_TOKEN);
|
||||
}
|
||||
|
||||
function getInlineAltText(token) {
|
||||
let innerTokens = token.split(",");
|
||||
|
||||
return innerTokens[1] ?? "";
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "payment-method-list-button",
|
||||
mixins: [inputButtonWrapperMixin],
|
||||
components: {
|
||||
baseInputButton,
|
||||
},
|
||||
methods: {
|
||||
isInlineImageToken,
|
||||
getInlineAltText,
|
||||
},
|
||||
computed: {
|
||||
tokens() {
|
||||
return splitCopyOnCMSPlaceHolder(this.buttonLabel ?? "");
|
||||
},
|
||||
hasImage() {
|
||||
return !!this.buttonImage;
|
||||
},
|
||||
shouldDisplaySideImage() {
|
||||
return this.hasImage && this.tokens.every((token) => !isInlineImageToken(token));
|
||||
},
|
||||
},
|
||||
};
|
||||
</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: 1px solid $gray-500;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
|
||||
span {
|
||||
&.small {
|
||||
font-size: 0.75rem;
|
||||
color: $gray-550;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
|
||||
import paymentMethodQuestion from "@/layouts/payment-method/payment-method-question/payment-method-question";
|
||||
|
||||
const testConstants = {
|
||||
cms: {
|
||||
question: {
|
||||
text: "Choose a payment option",
|
||||
},
|
||||
answers: {
|
||||
optionA: {
|
||||
name: "NameA",
|
||||
text: "TextA",
|
||||
subText: "SubTextA",
|
||||
imageId: "idA",
|
||||
image: "imageA",
|
||||
subWidget: "subWidgetA",
|
||||
},
|
||||
optionB: {
|
||||
name: "NameB",
|
||||
text: "TextB",
|
||||
subText: "SubTextB",
|
||||
imageId: "idB",
|
||||
image: "imageB",
|
||||
subWidget: "subWidgetB",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let cmsContent;
|
||||
|
||||
describe("Payment Method Question", () => {
|
||||
beforeEach(() => {
|
||||
cmsContent = {
|
||||
PaymentMethodWidget: {
|
||||
QuestionText: testConstants.cms.question,
|
||||
Answers: [
|
||||
{
|
||||
Name: testConstants.cms.answers.optionA.name,
|
||||
Text: testConstants.cms.answers.optionA.text,
|
||||
SubText: testConstants.cms.answers.optionA.subText,
|
||||
ImageId: testConstants.cms.answers.optionA.imageId,
|
||||
AnswerImageUrl: testConstants.cms.answers.optionA.image,
|
||||
SubWidgetName: testConstants.cms.answers.optionA.subWidget,
|
||||
},
|
||||
{
|
||||
Name: testConstants.cms.answers.optionB.name,
|
||||
Text: testConstants.cms.answers.optionB.text,
|
||||
SubText: testConstants.cms.answers.optionB.subText,
|
||||
ImageId: testConstants.cms.answers.optionB.imageId,
|
||||
AnswerImageUrl: testConstants.cms.answers.optionB.image,
|
||||
SubWidgetName: testConstants.cms.answers.optionB.subWidget,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it("Should map cms content correctly", () => {
|
||||
// Arrange
|
||||
const props = generateDefaultProps();
|
||||
|
||||
const { wrapper } = setupMocks({
|
||||
propsData: props,
|
||||
});
|
||||
|
||||
// Act
|
||||
const mappedContent = wrapper.vm.paymentMethodAnswerData;
|
||||
|
||||
// Assert
|
||||
expect(mappedContent).toEqual([
|
||||
{
|
||||
buttonLabel: testConstants.cms.answers.optionA.text,
|
||||
altText: testConstants.cms.answers.optionA.text,
|
||||
groupName: "payment-method",
|
||||
value: testConstants.cms.answers.optionA.name,
|
||||
buttonImage: testConstants.cms.answers.optionA.image,
|
||||
},
|
||||
{
|
||||
buttonLabel: testConstants.cms.answers.optionB.text,
|
||||
altText: testConstants.cms.answers.optionB.text,
|
||||
groupName: "payment-method",
|
||||
value: testConstants.cms.answers.optionB.name,
|
||||
buttonImage: testConstants.cms.answers.optionB.image,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("Handles null cms content gracefully", () => {
|
||||
// Arrange
|
||||
cmsContent = {};
|
||||
const props = generateDefaultProps();
|
||||
|
||||
const { wrapper } = setupMocks({
|
||||
propsData: props,
|
||||
});
|
||||
|
||||
// Act
|
||||
const mappedContent = wrapper.vm.paymentMethodAnswerData;
|
||||
|
||||
// Assert
|
||||
expect(mappedContent).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
function generateDefaultProps() {
|
||||
return {
|
||||
modelValue: "modelValue",
|
||||
};
|
||||
}
|
||||
|
||||
function setupMocks(customMountOptions) {
|
||||
const mountOptions = getMountOptions(customMountOptions);
|
||||
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn((widgetName, cmsFieldName) => {
|
||||
return cmsContent?.[widgetName]?.[cmsFieldName] ?? "";
|
||||
}),
|
||||
},
|
||||
};
|
||||
|
||||
mountOptions.global.mixins = [mockMixin];
|
||||
|
||||
const wrapper = shallowMount(paymentMethodQuestion, mountOptions);
|
||||
wrapper.vm.setCmsContent = jest.fn();
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<template>
|
||||
<div class="payment-method-question">
|
||||
<buttonQuestion
|
||||
groupName="payment-method"
|
||||
buttonTypeString="payment-method-list-button"
|
||||
:buttonTypeObject="paymentMethodListButton"
|
||||
isWide
|
||||
:questionText="paymentMethodQuestionText"
|
||||
:answers="paymentMethodAnswerData"
|
||||
isRequired
|
||||
:validationRules="validationRules"
|
||||
v-model="selectedMethod"
|
||||
textPosition="text-start" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import buttonQuestion from "@/digital-components/button-question/button-question";
|
||||
import paymentMethodListButton from "./payment-method-list-button/payment-method-list-button";
|
||||
|
||||
export default {
|
||||
name: "payment-method-question",
|
||||
data() {
|
||||
return {
|
||||
paymentMethodListButton: paymentMethodListButton,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
modelValue: String,
|
||||
validationRules: String,
|
||||
},
|
||||
methods: {
|
||||
getAnswersNullSafe(widgetName) {
|
||||
const rawData = this.getCmsContent(widgetName, "Answers");
|
||||
|
||||
if (!rawData) {
|
||||
return [];
|
||||
} else {
|
||||
return rawData;
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
selectedMethod: {
|
||||
get: function () {
|
||||
return this.modelValue;
|
||||
},
|
||||
set: function (selectedMethod) {
|
||||
this.$emit("update:modelValue", selectedMethod);
|
||||
},
|
||||
},
|
||||
paymentMethodQuestionText() {
|
||||
return this.getCmsContent("PaymentMethodWidget", "QuestionText");
|
||||
},
|
||||
paymentMethodAnswerData() {
|
||||
const cmsData = this.getAnswersNullSafe("PaymentMethodWidget");
|
||||
|
||||
return cmsData.map((answer) => {
|
||||
return {
|
||||
buttonLabel: answer.Text,
|
||||
altText: answer.Text,
|
||||
groupName: "payment-method",
|
||||
value: answer.Name,
|
||||
buttonImage: answer.AnswerImageUrl,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
components: {
|
||||
buttonQuestion,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.payment-method-question {
|
||||
.question-text span {
|
||||
text-align: left;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
v-slot="{ meta }"
|
||||
@submit="onSubmit"
|
||||
@invalidSubmit="onInvalidSubmit">
|
||||
<loadingModal notFullScreen ref="loadingModal" />
|
||||
<div class="page-container-grouped-styles">
|
||||
<siteHeader
|
||||
ref="siteHeader"
|
||||
|
|
@ -21,15 +22,18 @@
|
|||
<div>Cart Placeholder</div>
|
||||
<hr class="my-5" />
|
||||
<div>Pia Alert Placeholder</div>
|
||||
<div>Payment Method Question</div>
|
||||
<paymentMethodQuestion
|
||||
v-if="!isPiaDisabled"
|
||||
v-model="paymentMethodInternalModel"
|
||||
validationRules="option-required" />
|
||||
<div>Pia Disabled Placeholder</div>
|
||||
<siteFooter
|
||||
<navbar
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
:isBackButtonHidden="shouldHideBackButton"
|
||||
buttonSize
|
||||
@backClicked="navigateBack"
|
||||
@backClicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -39,14 +43,17 @@
|
|||
<script>
|
||||
// Components
|
||||
import siteHeader from '@/iss-components/site-header/site-header.vue';
|
||||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||
import navbar from "@/iss-components/nav-bar/nav-bar.vue";
|
||||
import siteSubHeader from '@/iss-components/site-sub-header/site-sub-header.vue';
|
||||
import reviewDropdown from '@/layouts/payment-method/review-dropdown/review-dropdown.vue';
|
||||
import paymentMethodQuestion from "@/layouts/payment-method/payment-method-question/payment-method-question.vue";
|
||||
import loadingModal from '@/iss-components/loading-modal/loading-modal.vue';
|
||||
|
||||
// Supporting Items
|
||||
import settleAllPromises from '@/helpers/layout-helper';
|
||||
import { useMainStore } from '@/store';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
|
||||
import { Form, defineRule } from 'vee-validate';
|
||||
|
||||
|
|
@ -63,8 +70,10 @@ export default {
|
|||
Form,
|
||||
siteHeader,
|
||||
siteSubHeader,
|
||||
siteFooter,
|
||||
reviewDropdown
|
||||
navbar,
|
||||
reviewDropdown,
|
||||
paymentMethodQuestion,
|
||||
loadingModal,
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
|
|
@ -87,16 +96,51 @@ export default {
|
|||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
|
||||
vm.updateFooterButtonText(vm.customCtaCopy);
|
||||
|
||||
vm.$refs.reviewDropdown.initializeComponent(resultMap.reviewDropdownData);
|
||||
});
|
||||
},
|
||||
data() {
|
||||
return { };
|
||||
return {
|
||||
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
damageInfo() {
|
||||
return useMainStore().order.damage;
|
||||
}
|
||||
},
|
||||
customCtaCopy() {
|
||||
switch (this.paymentMethod) {
|
||||
case paymentMethods.CREDIT_CARD:
|
||||
return "Continue to checkout";
|
||||
case paymentMethods.PAYPAL:
|
||||
return "Continue to Paypal";
|
||||
case paymentMethods.AFTERPAY:
|
||||
return "Continue to Afterpay";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
isPiaDisabled() {
|
||||
// do we have this experiment in NextGen ISS?
|
||||
|
||||
/*
|
||||
const piaExperience = this.getSettingValue(experimentSettings.PIA_EXPERIENCE);
|
||||
|
||||
const isEnabled = piaExperience === "PIA Optional" || piaExperience === "PIA Required";
|
||||
|
||||
return !isEnabled;
|
||||
*/
|
||||
return false;
|
||||
},
|
||||
paymentMethod() {
|
||||
if (this.isPiaDisabled) {
|
||||
return paymentMethods.LATER;
|
||||
}
|
||||
|
||||
return this.paymentMethodInternalModel;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
|
|
@ -167,11 +211,61 @@ export default {
|
|||
&& customerReqs
|
||||
);
|
||||
},
|
||||
getPaymentMethodFromStore() {
|
||||
const piaType = useMainStore().order.payment.piaType;
|
||||
const isPia = useMainStore().order.payment.isPia && !!piaType;
|
||||
|
||||
return isPia ? piaType : paymentMethods.LATER;
|
||||
},
|
||||
updateFooterButtonText(newValue) {
|
||||
this.$refs.siteFooter.updateButtonText(newValue);
|
||||
},
|
||||
backButtonAction() {
|
||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
// Multiple paths based on payment
|
||||
console.log('forward button hit...');
|
||||
}
|
||||
}
|
||||
await useMainStore().savePaymentMethodChoice(this.paymentMethod);
|
||||
|
||||
if (this.paymentMethod == paymentMethods.LATER) {
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
this.$route
|
||||
);
|
||||
} else {
|
||||
this.setupPia();
|
||||
}
|
||||
},
|
||||
async setupPia() {
|
||||
this.$refs.loadingModal.showModal();
|
||||
|
||||
// if we don't have a work order in delete substatus, set the flag and submit.
|
||||
// we need a work order number for pia so we can pass it to safeliteHop.
|
||||
if (!store.getters.order.workOrderNumber) {
|
||||
try {
|
||||
await submitWorkOrder({
|
||||
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[routerParams.DISPLAY_PIA_ALERT] = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_PAY_NOW,
|
||||
this.$route
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
customCtaCopy(newValue) {
|
||||
this.updateFooterButtonText(newValue);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import damageLocationsSelected from '@/constants/damage-locations-selected';
|
|||
import coverageStatuses from '@/constants/coverage-statuses';
|
||||
import { AppointmentTypeStrings, PREMIUM_FEE_PART_TYPE } from '@/constants/schedule-constants';
|
||||
import { convertDateStringToDate, getDateDifferenceInDays, militaryToTwelveHourTime } from '@/helpers/date-helper';
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
|
||||
const storeId = 'main';
|
||||
|
||||
|
|
@ -147,7 +148,9 @@ const getDefaultState = () => ({
|
|||
coverageStatus: coverageStatuses.PENDING,
|
||||
claimNumber: null
|
||||
},
|
||||
parentAccountNumber: 0
|
||||
parentAccountNumber: 0,
|
||||
isPia: null,
|
||||
piaType: null,
|
||||
},
|
||||
contactInfo: {
|
||||
firstName: null,
|
||||
|
|
@ -2127,7 +2130,13 @@ export const useMainStore = defineStore({
|
|||
this.resetVehicleState();
|
||||
this.resetDamageState();
|
||||
this.resetBailout();
|
||||
}
|
||||
},
|
||||
|
||||
savePaymentMethodChoice(paymentMethod) {
|
||||
const isPia = paymentMethod !== paymentMethods.LATER;
|
||||
this.order.payment.isPia = isPia;
|
||||
this.order.payment.piaType = isPia ? paymentMethod : null;
|
||||
},
|
||||
|
||||
},
|
||||
persist: true
|
||||
|
|
|
|||
Loading…
Reference in a new issue