Merge pull request #874 from Safelite/feature/digital/SSR-1522

SSR-1522 Add Apple Pay
This commit is contained in:
Josh Dassinger 2024-10-25 13:44:41 -05:00 committed by GitHub
commit 70e1081019
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 1238 additions and 262 deletions

View file

@ -21,7 +21,7 @@ body span {
line-height: 24px; line-height: 24px;
} }
body a { body a {
color: #1574A1; color: #0070D1;
text-decoration: none; text-decoration: none;
} }
body .form-group { body .form-group {
@ -41,7 +41,7 @@ body select {
} }
body input, body input,
body select { body select {
border-radius: 8px; border-radius: 4px;
border: 1px solid #8E9292; border: 1px solid #8E9292;
padding: 16px; padding: 16px;
font-size: 16px; font-size: 16px;
@ -73,7 +73,7 @@ body select:hover {
box-shadow: 0 0 0 4px #9fcee6; box-shadow: 0 0 0 4px #9fcee6;
} }
body select { body select {
border-radius: 8px; border-radius: 4px;
border: 1px solid #8E9292; border: 1px solid #8E9292;
padding: 16px; padding: 16px;
width: 100%; width: 100%;
@ -128,17 +128,6 @@ body .optional-label:after {
} }
body .buttonContainer { body .buttonContainer {
height: 48px; height: 48px;
position: relative;
}
body .buttonContainer:after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: auto;
cursor: pointer;
} }
body .buttonContainer button { body .buttonContainer button {
position: relative; position: relative;
@ -154,6 +143,7 @@ body .buttonContainer button {
@media (hover: hover) { @media (hover: hover) {
body .buttonContainer button { body .buttonContainer button {
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%); background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
cursor: pointer;
} }
} }
body .buttonContainer button:focus { body .buttonContainer button:focus {
@ -173,6 +163,7 @@ body .buttonContainer button:disabled {
height: 48px; height: 48px;
border: none; border: none;
border-radius: 8px; border-radius: 8px;
cursor: pointer;
pointer-events: all; pointer-events: all;
} }
body .buttonContainer button.has-loader { body .buttonContainer button.has-loader {
@ -213,3 +204,125 @@ body .cc-error-container #alert-message {
background-color: #fcbfbb; background-color: #fcbfbb;
border: 1px solid #d4281c; border: 1px solid #d4281c;
} }
#fmg-checkout-shared .form-group .list-group.radio .list-group-item {
border-radius: 5px;
}
#fmg-checkout-shared .form-group .list-group.radio .list-group-item label {
padding: 12px 20px;
}
#fmg-checkout-shared #applepay-and-paypal-container {
display: inline-flex;
width: 100%;
justify-content: space-between;
}
#fmg-checkout-shared #applepay-and-paypal-container #paypalParentDiv {
padding-left: 10px;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group {
margin: 0;
width: 100%;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group.paymentSelection #applepayParentLink {
margin: 0;
padding: 10px 0;
background-color: #000000;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group.paymentSelection #applepayParentLink label {
padding: 0;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group.paymentSelection #applepayParentLink label apple-pay-button {
vertical-align: middle;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group.paymentSelection #applepayParentLink.list-group-item {
box-shadow: none;
border-radius: 10px;
border: 1px solid #8E9292;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group.paymentSelection #applepayParentLink:host {
--apple-pay-button-width: auto;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group #paypalParentLink {
margin: 0;
padding: 2px 0;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group #paypalParentLink #paypalImage {
max-width: 50%;
}
#fmg-checkout-shared #applepay-and-paypal-container .form-group .list-group #paypalParentLink.list-group-item {
box-shadow: none;
border-radius: 10px;
border: 1px solid #8E9292;
}
#fmg-checkout-shared #applepay-and-paypal-container.no-applepay .form-group {
width: 100%;
}
#fmg-checkout-shared #applepay-and-paypal-container.no-applepay .form-group#applepayParentDiv {
display: none;
}
#fmg-checkout-shared #applepay-and-paypal-container.no-applepay .form-group#paypalParentDiv {
padding-left: 0;
}
#fmg-checkout-shared #applepay-and-paypal-container.no-applepay .form-group .list-group.paymentSelection {
width: 100%;
}
#fmg-checkout-shared #applepay-and-paypal-container.no-applepay .form-group .list-group #paypalParentLink #paypalImage {
max-width: 25%;
}
#fmg-checkout-shared #other-payments-container label {
display: inline-flex;
text-align: left;
align-items: flex-start;
justify-content: space-between;
font-size: 16px;
font-weight: 500;
}
#fmg-checkout-shared #other-payments-container label span.paymentOptionText {
margin: auto 0;
padding-left: 0;
font-weight: 600;
}
#fmg-checkout-shared #other-payments-container #afterpayParentLink label > span:first-of-type {
width: 100%;
}
#fmg-checkout-shared #other-payments-container #afterpayParentLink label > span:last-of-type {
width: 0;
}
#fmg-checkout-shared #other-payments-container #creditCardParentDiv.active {
margin-bottom: 32px;
border: 1px solid #0070D1;
border-radius: 10px;
}
#fmg-checkout-shared #other-payments-container #creditCardParentDiv.active > .paymentSelection #creditCardParentLink {
border-width: 0 0 2px 0;
border-bottom-color: #0070D1;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
#fmg-checkout-shared #other-payments-container #creditCardParentDiv .paymentSelection #creditCardImages {
width: 50%;
text-align: right;
}
#fmg-checkout-shared #other-payments-container #creditCardParentDiv .paymentSelection #creditCardImages > img {
width: 20%;
}
#fmg-checkout-shared #other-payments-container #creditCardParentDiv .creditCardSpecific {
padding: 0 16px;
}
#fmg-checkout-shared #other-payments-container #creditCardParentDiv .creditCardSpecific > .form-group {
width: 100%;
}
#fmg-checkout-shared #other-payments-container .italicSmall {
margin-top: 10px;
}
#fmg-checkout-shared #other-payments-container .disclaimerContainerv2 {
margin-bottom: 32px;
}
@media only screen and (max-device-width: 767px) {
#fmg-checkout-shared #applepay-and-paypal-container {
width: 100%;
}
#fmg-checkout-shared #other-payments-container > .form-group {
width: 100%;
}
}

View file

@ -112,3 +112,401 @@
.creditCardSpecific { .creditCardSpecific {
display: none; display: none;
} }
* {
box-sizing: border-box;
}
*:before,
*:after {
box-sizing: border-box;
}
.form-group.radio .list-group .list-group-item {
border-radius: 22px;
text-align: center;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
}
.form-group.radio .list-group .list-group-item .radio .list-group,
.form-group.radio .list-group .list-group-item .radio.list-group {
margin: 0 0 22px 0;
}
.form-group.radio .list-group .list-group-item > label {
padding: 10px 32px 10px 32px;
}
.form-group.radio .list-group .list-group-item .checkbox .list-group .list-group-item label,
.form-group.radio .list-group .list-group-item .radio .list-group .list-group-item label,
.form-group.radio .list-group .list-group-item .checkbox.list-group .list-group-item label,
.form-group.radio .list-group .list-group-item .radio.list-group .list-group-item label {
padding-left: 55px;
}
.list-group.radio .list-group-item {
border-radius: 22px;
text-align: center;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
}
.list-group.radio .list-group-item .radio .list-group,
.list-group.radio .list-group-item .radio.list-group {
margin: 0 0 22px 0;
}
.list-group.radio .list-group-item > label {
padding: 10px 32px 10px 32px;
}
@media (max-width: 992px) {
.list-group.radio .list-group-item > label {
padding: 12px 20px 12px 20px;
}
}
html .list-group .list-group-item .list-group.radio .list-group-item {
text-align: left;
border-radius: 0;
}
html .list-group .list-group-item .list-group.radio .list-group-item input[type=radio] {
visibility: visible;
}
html .in-shop.vspacing .list-group.radio.vspacing .list-group-item {
border-radius: 48px;
}
.row > .form-group > .glyphicon {
right: 15px;
}
.form-group {
margin-bottom: 10px;
}
.form-group .control-label {
display: block;
margin-bottom: 2px;
}
.form-group .form-control {
margin-bottom: 2px;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
}
@media (min-width: 500px) {
.form-group {
width: 80%;
}
}
@media (min-width: 800px) {
.form-group {
width: 60%;
}
}
.list-group {
margin-bottom: 20px;
padding-left: 0;
}
.list-group-item {
position: relative;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
background-color: #ffffff;
border: 1px solid #dddddd;
}
.list-group-item:first-child {
border-top-right-radius: 5px;
border-top-left-radius: 5px;
}
.list-group-item:last-child {
margin-bottom: 0;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
}
a.list-group-item {
color: #555555;
}
a.list-group-item .list-group-item-heading {
color: #333333;
}
a.list-group-item:hover,
a.list-group-item:focus {
text-decoration: none;
color: #555555;
background-color: #f5f5f5;
}
.list-group-item.disabled,
.list-group-item.disabled:hover,
.list-group-item.disabled:focus {
background-color: #f0f1f2;
color: #9aa1a3;
cursor: not-allowed;
}
.list-group-item.disabled .list-group-item-heading,
.list-group-item.disabled:hover .list-group-item-heading,
.list-group-item.disabled:focus .list-group-item-heading {
color: inherit;
}
.list-group-item.disabled .list-group-item-text,
.list-group-item.disabled:hover .list-group-item-text,
.list-group-item.disabled:focus .list-group-item-text {
color: #9aa1a3;
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
z-index: 2;
color: #ffffff;
background-color: #167cac;
border-color: #167cac;
}
.list-group-item.active .list-group-item-heading,
.list-group-item.active:hover .list-group-item-heading,
.list-group-item.active:focus .list-group-item-heading,
.list-group-item.active .list-group-item-heading > small,
.list-group-item.active:hover .list-group-item-heading > small,
.list-group-item.active:focus .list-group-item-heading > small,
.list-group-item.active .list-group-item-heading > .small,
.list-group-item.active:hover .list-group-item-heading > .small,
.list-group-item.active:focus .list-group-item-heading > .small {
color: inherit;
}
.list-group-item.active .list-group-item-text,
.list-group-item.active:hover .list-group-item-text,
.list-group-item.active:focus .list-group-item-text {
color: #9cd7f2;
}
.list-group-item-success {
color: #cacbcc;
background-color: #e6f2ec;
}
a.list-group-item-success {
color: #cacbcc;
}
a.list-group-item-success .list-group-item-heading {
color: inherit;
}
a.list-group-item-success:hover,
a.list-group-item-success:focus {
color: #cacbcc;
background-color: #d5e9df;
}
a.list-group-item-success.active,
a.list-group-item-success.active:hover,
a.list-group-item-success.active:focus {
color: #fff;
background-color: #cacbcc;
border-color: #cacbcc;
}
.list-group-item-info {
color: #125b7e;
background-color: #e7f1f6;
}
a.list-group-item-info {
color: #125b7e;
}
a.list-group-item-info .list-group-item-heading {
color: inherit;
}
a.list-group-item-info:hover,
a.list-group-item-info:focus {
color: #125b7e;
background-color: #d4e6ef;
}
a.list-group-item-info.active,
a.list-group-item-info.active:hover,
a.list-group-item-info.active:focus {
color: #fff;
background-color: #125b7e;
border-color: #125b7e;
}
.list-group-item-warning {
color: #f8af1c;
background-color: #fef6e8;
}
a.list-group-item-warning {
color: #f8af1c;
}
a.list-group-item-warning .list-group-item-heading {
color: inherit;
}
a.list-group-item-warning:hover,
a.list-group-item-warning:focus {
color: #f8af1c;
background-color: #fdecd0;
}
a.list-group-item-warning.active,
a.list-group-item-warning.active:hover,
a.list-group-item-warning.active:focus {
color: #fff;
background-color: #f8af1c;
border-color: #f8af1c;
}
.list-group-item-danger {
color: #da291c;
background-color: #fbe9e8;
}
a.list-group-item-danger {
color: #da291c;
}
a.list-group-item-danger .list-group-item-heading {
color: inherit;
}
a.list-group-item-danger:hover,
a.list-group-item-danger:focus {
color: #da291c;
background-color: #f7d4d2;
}
a.list-group-item-danger.active,
a.list-group-item-danger.active:hover,
a.list-group-item-danger.active:focus {
color: #fff;
background-color: #da291c;
border-color: #da291c;
}
.list-group-item-heading {
margin-top: 0;
margin-bottom: 5px;
}
.list-group-item-text {
margin-bottom: 0;
line-height: 1.3;
}
.radio .list-group.paymentSelection, .radio.list-group.paymentSelection {
margin-top: 0;
margin-bottom: 0;
}
@media (max-width: 33.9em) {
.radio .list-group.paymentSelection label, .radio .list-group.paymentSelection a, .radio.list-group.paymentSelection label, .radio.list-group.paymentSelection a {
max-height: 52px;
}
}
.radio,
.checkbox,
.form-group.checkbox .list-group,
.form-group.checkbox .list-group,
.form-group.radio .list-group,
.form-group.radio .list-group,
.checkbox.list-group,
.checkbox.list-group,
.radio.list-group,
.radio.list-group {
position: relative;
display: block;
margin-top: 10px;
margin-bottom: 10px;
}
.form-group.checkbox .list-group .list-group-item > label,
.form-group.radio .list-group .list-group-item > label,
.checkbox.list-group .list-group-item > label,
.radio.list-group .list-group-item > label {
margin-bottom: initial;
width: 100%;
font-weight: normal;
padding: 12px 27px 12px 33px;
color: #525656;
}
.form-group.checkbox .list-group .list-group-item,
.form-group.radio .list-group .list-group-item,
.checkbox.list-group .list-group-item,
.radio.list-group .list-group-item {
margin-bottom: 12px;
border-width: 1px;
/* border-color: #cacbcc; */
border-radius: 5px;
padding: 0;
}
.form-group.checkbox .list-group .list-group-item.active,
.form-group.radio .list-group .list-group-item.active,
.checkbox.list-group .list-group-item.active,
.radio.list-group .list-group-item.active {
background-color: #e7f1f6;
color: #000000;
}
.radio label,
.checkbox label {
min-height: 23px;
padding-left: 20px;
margin-bottom: 0;
font-weight: normal;
cursor: pointer;
color: #525656;
}
img {
vertical-align: middle;
}
#paypalParentLink label,
#afterpayParentLink label,
#creditCardParentLink label {
padding-top: 9px;
padding-bottom: 9px;
}
#paypalParentLink label .paymentOptionText,
#creditCardParentLink label .paymentOptionText {
padding-left: 20px;
text-align: left;
}
html #creditCardParentLink.list-group-item {
border-radius: 48px;
text-align: center;
}
@media (max-width: 992px) {
.list-group.radio .list-group-item > label {
padding: 12px 20px 12px 20px;
}
}
label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: 500;
color: #000000;
}

View file

@ -24,7 +24,7 @@ body {
} }
a { a {
color: #1574A1; color: #0070D1;
text-decoration: none; text-decoration: none;
} }
@ -50,7 +50,7 @@ body {
input, input,
select { select {
border-radius: 8px; border-radius: 4px;
border: 1px solid #8E9292; border: 1px solid #8E9292;
padding: 16px; padding: 16px;
font-size: 16px; font-size: 16px;
@ -78,7 +78,7 @@ body {
} }
select { select {
border-radius: 8px; border-radius: 4px;
border: 1px solid #8E9292; border: 1px solid #8E9292;
padding: 16px; padding: 16px;
width: 100%; width: 100%;
@ -139,17 +139,6 @@ body {
.buttonContainer { .buttonContainer {
height: 48px; height: 48px;
position: relative;
&:after {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
pointer-events: auto;
cursor: pointer;
}
button { button {
position: relative; position: relative;
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%); background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
@ -162,6 +151,7 @@ body {
height: 48px; height: 48px;
@media (hover: hover) { @media (hover: hover) {
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%); background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
cursor: pointer;
} }
&:focus { &:focus {
box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c; box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c;
@ -182,6 +172,7 @@ body {
height: 48px; height: 48px;
border: none; border: none;
border-radius: 8px; border-radius: 8px;
cursor: pointer;
pointer-events: all; pointer-events: all;
} }
&.has-loader { &.has-loader {
@ -230,5 +221,199 @@ body {
border: 1px solid #d4281c; border: 1px solid #d4281c;
} }
} }
} }
#fmg-checkout-shared {
.form-group {
.list-group {
&.radio {
.list-group-item {
border-radius: 5px;
label {
padding: 12px 20px;
}
}
}
}
}
#applepay-and-paypal-container {
display: inline-flex;
width: 100%;
justify-content: space-between;
#paypalParentDiv {
padding-left: 10px;
}
.form-group {
margin: 0;
width: 100%;
.list-group {
&.paymentSelection {
#applepayParentLink {
margin: 0;
padding: 10px 0;
background-color: #000000;
label {
padding: 0;
apple-pay-button {
vertical-align: middle;
}
}
&.list-group-item {
box-shadow: none;
border-radius: 10px;
border: 1px solid #8E9292;
}
&:host {
--apple-pay-button-width: auto;
}
}
}
#paypalParentLink {
margin: 0;
padding: 2px 0;
#paypalImage {
max-width: 50%;
}
&.list-group-item {
box-shadow: none;
border-radius: 10px;
border: 1px solid #8E9292;
}
}
}
}
&.no-applepay {
.form-group {
width: 100%;
&#applepayParentDiv {
display: none;
}
&#paypalParentDiv {
padding-left: 0;
}
.list-group {
&.paymentSelection {
width: 100%;
}
#paypalParentLink {
#paypalImage {
max-width: 25%;
}
}
}
}
}
}
#other-payments-container {
label {
display: inline-flex;
text-align: left;
align-items: flex-start;
justify-content: space-between;
font-size: 16px;
font-weight: 500;
span {
&.paymentOptionText {
margin: auto 0;
padding-left: 0;
font-weight: 600;
}
}
}
#afterpayParentLink {
label {
> span {
&:first-of-type {
width: 100%;
}
&:last-of-type {
width: 0;
}
}
}
}
#creditCardParentDiv {
&.active {
margin-bottom: 32px;
border: 1px solid #0070D1;
border-radius: 10px;
> .paymentSelection {
#creditCardParentLink {
border-width: 0 0 2px 0;
border-bottom-color: #0070D1;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
}
}
.paymentSelection {
#creditCardImages {
width: 50%;
text-align: right;
> img {
width: 20%;
}
}
}
.creditCardSpecific {
padding: 0 16px;
> .form-group {
width: 100%;
}
}
}
.italicSmall {
margin-top: 10px;
}
.disclaimerContainerv2 {
margin-bottom: 32px;
}
}
@media only screen and (max-device-width: 767px) {
#applepay-and-paypal-container {
width: 100%;
}
#other-payments-container {
> .form-group {
width: 100%;
}
}
}
}

View file

@ -116,3 +116,361 @@
.creditCardSpecific { .creditCardSpecific {
display: none; display: none;
} }
* {
box-sizing: border-box;
}
*:before,
*:after {
box-sizing: border-box;
}
.form-group.radio .list-group .list-group-item {
border-radius: 22px;
text-align: center;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
}
.form-group.radio .list-group .list-group-item .radio .list-group,
.form-group.radio .list-group .list-group-item .radio.list-group {
margin: 0 0 22px 0;
}
.form-group.radio .list-group .list-group-item > label {
padding: 10px 32px 10px 32px;
}
.form-group.radio .list-group .list-group-item .checkbox .list-group .list-group-item label,
.form-group.radio .list-group .list-group-item .radio .list-group .list-group-item label,
.form-group.radio .list-group .list-group-item .checkbox.list-group .list-group-item label,
.form-group.radio .list-group .list-group-item .radio.list-group .list-group-item label {
padding-left: 55px;
}
.list-group.radio .list-group-item {
border-radius: 22px;
text-align: center;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
}
.list-group.radio .list-group-item .radio .list-group,
.list-group.radio .list-group-item .radio.list-group {
margin: 0 0 22px 0;
}
.list-group.radio .list-group-item > label {
padding: 10px 32px 10px 32px;
}
@media (max-width: 992px) {
.list-group.radio .list-group-item > label {
padding: 12px 20px 12px 20px;
}
}
html .list-group .list-group-item .list-group.radio .list-group-item {
text-align: left;
border-radius: 0;
}
html .list-group .list-group-item .list-group.radio .list-group-item input[type="radio"] {
visibility: visible;
}
html .in-shop.vspacing .list-group.radio.vspacing .list-group-item {
border-radius: 48px;
}
.row > .form-group > .glyphicon {
right: 15px;
}
.form-group {
margin-bottom: 10px;
}
.form-group .control-label {
display: block;
margin-bottom: 2px;
}
.form-group .form-control {
margin-bottom: 2px;
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2);
}
@media (min-width: 500px) {
.form-group {
width: 80%;
}
}
@media (min-width: 800px) {
.form-group {
width: 60%;
}
}
.list-group {
margin-bottom: 20px;
padding-left: 0;
}
.list-group-item {
position: relative;
display: block;
padding: 10px 15px;
margin-bottom: -1px;
background-color: #ffffff;
border: 1px solid #dddddd;
}
.list-group-item:first-child {
border-top-right-radius: 5px;
border-top-left-radius: 5px;
}
.list-group-item:last-child {
margin-bottom: 0;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
}
a.list-group-item {
color: #555555;
}
a.list-group-item .list-group-item-heading {
color: #333333;
}
a.list-group-item:hover,
a.list-group-item:focus {
text-decoration: none;
color: #555555;
background-color: #f5f5f5;
}
.list-group-item.disabled,
.list-group-item.disabled:hover,
.list-group-item.disabled:focus {
background-color: #f0f1f2;
color: #9aa1a3;
cursor: not-allowed;
}
.list-group-item.disabled .list-group-item-heading,
.list-group-item.disabled:hover .list-group-item-heading,
.list-group-item.disabled:focus .list-group-item-heading {
color: inherit;
}
.list-group-item.disabled .list-group-item-text,
.list-group-item.disabled:hover .list-group-item-text,
.list-group-item.disabled:focus .list-group-item-text {
color: #9aa1a3;
}
.list-group-item.active,
.list-group-item.active:hover,
.list-group-item.active:focus {
z-index: 2;
color: #ffffff;
background-color: #167cac;
border-color: #167cac;
}
.list-group-item.active .list-group-item-heading,
.list-group-item.active:hover .list-group-item-heading,
.list-group-item.active:focus .list-group-item-heading,
.list-group-item.active .list-group-item-heading > small,
.list-group-item.active:hover .list-group-item-heading > small,
.list-group-item.active:focus .list-group-item-heading > small,
.list-group-item.active .list-group-item-heading > .small,
.list-group-item.active:hover .list-group-item-heading > .small,
.list-group-item.active:focus .list-group-item-heading > .small {
color: inherit;
}
.list-group-item.active .list-group-item-text,
.list-group-item.active:hover .list-group-item-text,
.list-group-item.active:focus .list-group-item-text {
color: #9cd7f2;
}
.list-group-item-success {
color: #cacbcc;
background-color: #e6f2ec;
}
a.list-group-item-success {
color: #cacbcc;
}
a.list-group-item-success .list-group-item-heading {
color: inherit;
}
a.list-group-item-success:hover,
a.list-group-item-success:focus {
color: #cacbcc;
background-color: #d5e9df;
}
a.list-group-item-success.active,
a.list-group-item-success.active:hover,
a.list-group-item-success.active:focus {
color: #fff;
background-color: #cacbcc;
border-color: #cacbcc;
}
.list-group-item-info {
color: #125b7e;
background-color: #e7f1f6;
}
a.list-group-item-info {
color: #125b7e;
}
a.list-group-item-info .list-group-item-heading {
color: inherit;
}
a.list-group-item-info:hover,
a.list-group-item-info:focus {
color: #125b7e;
background-color: #d4e6ef;
}
a.list-group-item-info.active,
a.list-group-item-info.active:hover,
a.list-group-item-info.active:focus {
color: #fff;
background-color: #125b7e;
border-color: #125b7e;
}
.list-group-item-warning {
color: #f8af1c;
background-color: #fef6e8;
}
a.list-group-item-warning {
color: #f8af1c;
}
a.list-group-item-warning .list-group-item-heading {
color: inherit;
}
a.list-group-item-warning:hover,
a.list-group-item-warning:focus {
color: #f8af1c;
background-color: #fdecd0;
}
a.list-group-item-warning.active,
a.list-group-item-warning.active:hover,
a.list-group-item-warning.active:focus {
color: #fff;
background-color: #f8af1c;
border-color: #f8af1c;
}
.list-group-item-danger {
color: #da291c;
background-color: #fbe9e8;
}
a.list-group-item-danger {
color: #da291c;
}
a.list-group-item-danger .list-group-item-heading {
color: inherit;
}
a.list-group-item-danger:hover,
a.list-group-item-danger:focus {
color: #da291c;
background-color: #f7d4d2;
}
a.list-group-item-danger.active,
a.list-group-item-danger.active:hover,
a.list-group-item-danger.active:focus {
color: #fff;
background-color: #da291c;
border-color: #da291c;
}
.list-group-item-heading {
margin-top: 0;
margin-bottom: 5px;
}
.list-group-item-text {
margin-bottom: 0;
line-height: 1.3;
}
.radio .list-group.paymentSelection, .radio.list-group.paymentSelection {
margin-top: 0;
margin-bottom: 0;
@media (max-width: 33.9em) {
label, a {
max-height: 52px;
}
}
}
.radio,
.checkbox,
.form-group.checkbox .list-group,
.form-group.checkbox .list-group,
.form-group.radio .list-group,
.form-group.radio .list-group,
.checkbox.list-group,
.checkbox.list-group,
.radio.list-group,
.radio.list-group {
position: relative;
display: block;
margin-top: 10px;
margin-bottom: 10px;
}
.form-group.checkbox .list-group .list-group-item > label,
.form-group.radio .list-group .list-group-item > label,
.checkbox.list-group .list-group-item > label,
.radio.list-group .list-group-item > label {
margin-bottom: initial;
width: 100%;
font-weight: normal;
padding: 12px 27px 12px 33px;
color: #525656;
}
.form-group.checkbox .list-group .list-group-item,
.form-group.radio .list-group .list-group-item,
.checkbox.list-group .list-group-item,
.radio.list-group .list-group-item {
margin-bottom: 12px;
border-width: 1px;
/* border-color: #cacbcc; */
border-radius: 5px;
padding: 0;
}
.form-group.checkbox .list-group .list-group-item.active,
.form-group.radio .list-group .list-group-item.active,
.checkbox.list-group .list-group-item.active,
.radio.list-group .list-group-item.active {
background-color: #e7f1f6;
color: #000000;
}
.radio label,
.checkbox label {
min-height: 23px;
padding-left: 20px;
margin-bottom: 0;
font-weight: normal;
cursor: pointer;
color: #525656;
}
img {
vertical-align: middle;
}
#paypalParentLink label,
#afterpayParentLink label,
#creditCardParentLink label {
padding-top: 9px;
padding-bottom: 9px;
}
#paypalParentLink label .paymentOptionText,
#creditCardParentLink label .paymentOptionText {
padding-left: 20px;
text-align: left;
}
html #creditCardParentLink.list-group-item {
border-radius: 48px;
text-align: center;
}
@media (max-width: 992px) {
.list-group.radio .list-group-item > label {
padding: 12px 20px 12px 20px;
}
}
label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: 500;
color: #000000;
}

View file

@ -1,15 +1,11 @@
const hopPaymentMethods = Object.freeze({
CREDIT_CARD: 'cc',
PAYPAL: 'pp',
AFTERPAY: 'ap'
});
const paymentMethods = Object.freeze({ const paymentMethods = Object.freeze({
NONE: null, NONE: null,
PayNow: 'PayNow', // User selected the pay now and hasn't selected their payment method yet
PAY_AT_TIME_OF_SERVICE: 'PayAtTimeOfService', PAY_AT_TIME_OF_SERVICE: 'PayAtTimeOfService',
CREDIT_CARD: 'CreditCard', CREDIT_CARD: 'CreditCard',
PAYPAL: 'Paypal', PAYPAL: 'Paypal',
AFTERPAY: 'Afterpay' AFTERPAY: 'Afterpay',
APPLEPAY: 'ApplePay'
}); });
export { hopPaymentMethods, paymentMethods }; export { paymentMethods };

View file

@ -0,0 +1,3 @@
export function supportsApplePay() {
return !!(window.ApplePaySession && window.ApplePaySession.canMakePayments());
}

View file

@ -13,6 +13,7 @@ import coverageStatuses from '@/constants/coverage-statuses';
import coverageType from '@/constants/coverage-type'; import coverageType from '@/constants/coverage-type';
import { deepClone } from '@/helpers/object-helper'; import { deepClone } from '@/helpers/object-helper';
import { AppointmentTypeStrings } from '@/constants/schedule-constants'; import { AppointmentTypeStrings } from '@/constants/schedule-constants';
import { paymentMethods } from "@/constants/payment-method-constants";
jest.mock('@/helpers/layout-helper.js', () => jest.fn()); jest.mock('@/helpers/layout-helper.js', () => jest.fn());
@ -80,7 +81,7 @@ const initialStore = {
}, },
payment: { payment: {
isInsurance: true, isInsurance: true,
isPayInAdvance: false paymentMethod: paymentMethods.PAY_AT_TIME_OF_SERVICE
}, },
contactInfo: { contactInfo: {
firstName: 'Test', firstName: 'Test',

View file

@ -147,7 +147,7 @@ export default {
return { mainStore, submittedOrder }; return { mainStore, submittedOrder };
}, },
data() { data() {
var { const {
vehicle, vehicle,
serviceLocation, serviceLocation,
schedule, schedule,
@ -155,8 +155,9 @@ export default {
payment, payment,
customerPortalLoginToken, customerPortalLoginToken,
damage, damage,
referralNumber } = this.submittedOrder; referralNumber
var { issConfig, hasRecalibrationPart } = this.mainStore; } = this.submittedOrder;
const { issConfig, hasRecalibrationPart } = this.mainStore;
return { return {
vehicle, vehicle,
customerEmail: customer?.emailAddress, customerEmail: customer?.emailAddress,
@ -179,7 +180,7 @@ export default {
mobile: 'MobileWordingWidget', mobile: 'MobileWordingWidget',
dropOffAndInShop: 'DropOffAndInShopWordingWidget', dropOffAndInShop: 'DropOffAndInShopWordingWidget',
siteFooter: 'SiteFooterWidget' siteFooter: 'SiteFooterWidget'
}, }
} }
}, },
computed: { computed: {
@ -383,8 +384,7 @@ export default {
); );
// Payment // Payment
const paymentMethodReqs = const paymentMethodReqs = useMainStore().order.payment.paymentMethod != null;
useMainStore().order.payment.isPayInAdvance === false;
return ( return (
serviceLocationReqs serviceLocationReqs

View file

@ -72,8 +72,7 @@ describe('payment-method.vue', () => {
const store = { const store = {
order: { order: {
payment: { payment: {
isPayInAdvance: false, paymentMethod: null
payInAdvanceType: null
} }
} }
}; };
@ -91,8 +90,7 @@ describe('payment-method.vue', () => {
const store = { const store = {
order: { order: {
payment: { payment: {
isPayInAdvance: true, paymentMethod: payInAdvanceMethod
payInAdvanceType: payInAdvanceMethod
}, },
insuranceCoverage: { insuranceCoverage: {
coverageStatus: coverageStatuses.VERIFIED, coverageStatus: coverageStatuses.VERIFIED,
@ -115,8 +113,7 @@ describe('payment-method.vue', () => {
const store = { const store = {
order: { order: {
payment: { payment: {
isPayInAdvance: true, paymentMethod: payInAdvanceMethod
payInAdvanceType: payInAdvanceMethod
}, },
insuranceCoverage: { insuranceCoverage: {
coverageStatus: coverageStatuses.VERIFIED, coverageStatus: coverageStatuses.VERIFIED,
@ -139,8 +136,7 @@ describe('payment-method.vue', () => {
const store = { const store = {
order: { order: {
payment: { payment: {
isPayInAdvance: true, paymentMethod: payInAdvanceMethod
payInAdvanceType: payInAdvanceMethod
}, },
insuranceCoverage: { insuranceCoverage: {
coverageStatus: coverageStatuses.PENDING, coverageStatus: coverageStatuses.PENDING,
@ -173,8 +169,7 @@ describe('payment-method.vue', () => {
const store = { const store = {
order: { order: {
payment: { payment: {
isPayInAdvance: true, paymentMethod: payInAdvanceMethod
payInAdvanceType: payInAdvanceMethod
}, },
insuranceCoverage: { insuranceCoverage: {
coverageStatus: coverageStatuses.VERIFIED, coverageStatus: coverageStatuses.VERIFIED,
@ -327,8 +322,7 @@ describe('payment-method.vue', () => {
const store = { const store = {
order: { order: {
payment: { payment: {
isPayInAdvance: false, paymentMethod: paymentMethods.PAY_AT_TIME_OF_SERVICE
payInAdvanceType: null
} }
} }
}; };

View file

@ -43,8 +43,8 @@
:isDismissible="false" /> :isDismissible="false" />
<paymentMethodQuestion <paymentMethodQuestion
v-if="!isPayInAdvanceDisabled" v-if="!isPayInAdvanceDisabled"
v-model="paymentMethodInternalModel" v-model="paymentMethod"
cmsWidgetName="PaymentMethodWidget" :cmsWidgetName="paymentMethodWidgetName"
:validationRules="rules.optionRequired" /> :validationRules="rules.optionRequired" />
<alert <alert
v-if="isPayInAdvanceDisabled" v-if="isPayInAdvanceDisabled"
@ -93,6 +93,7 @@ import { saveSession, submitWorkOrder } from '@/helpers/order-helper.js';
import { experimentSettings } from '@/constants/experiments'; import { experimentSettings } from '@/constants/experiments';
import submitType from '@/constants/submit-type'; import submitType from '@/constants/submit-type';
import routerParams from '@/router/router-constants/router-params'; import routerParams from '@/router/router-constants/router-params';
import { supportsApplePay } from '@/helpers/browser-helper';
export default { export default {
name: 'payment-method', name: 'payment-method',
@ -131,7 +132,11 @@ export default {
}, },
data() { data() {
return { return {
paymentMethodInternalModel: this.getPaymentMethodFromStore(), paymentMethod: this.getPaymentMethodFromStore(),
widget: {
paymentMethod: 'PaymentMethodWidget',
paymentMethodApplePay: 'PaymentMethodWidgetApplePay'
},
rules: { rules: {
optionRequired: globalRules.OPTION_REQUIRED optionRequired: globalRules.OPTION_REQUIRED
} }
@ -140,10 +145,8 @@ export default {
computed: { computed: {
customCallToActionButtonCopy() { customCallToActionButtonCopy() {
switch (this.paymentMethod) { switch (this.paymentMethod) {
case paymentMethods.CREDIT_CARD: case paymentMethods.PayNow:
return 'Continue to checkout'; return 'Continue to checkout';
case paymentMethods.PAYPAL:
return 'Continue to Paypal';
case paymentMethods.AFTERPAY: case paymentMethods.AFTERPAY:
return 'Continue to Afterpay'; return 'Continue to Afterpay';
default: default:
@ -160,8 +163,8 @@ export default {
return !isEnabled || useMainStore().isUnverified || (useMainStore().isDeductible && isDeductibleTotalEqualToZero); return !isEnabled || useMainStore().isUnverified || (useMainStore().isDeductible && isDeductibleTotalEqualToZero);
}, },
paymentMethod() { paymentMethodWidgetName() {
return this.paymentMethodInternalModel; return supportsApplePay() ? this.widget.paymentMethodApplePay : this.widget.paymentMethod;
} }
}, },
watch: { watch: {
@ -252,22 +255,17 @@ export default {
); );
}, },
getPaymentMethodFromStore() { getPaymentMethodFromStore() {
const { payInAdvanceType } = useMainStore().order.payment; if (this.isPayInAdvanceDisabled) {
const isPayInAdvance = return paymentMethods.PAY_AT_TIME_OF_SERVICE;
useMainStore().order.payment.isPayInAdvance }
&& !!payInAdvanceType
&& !this.isPayInAdvanceDisabled;
return isPayInAdvance return useMainStore().order.payment.paymentMethod;
? payInAdvanceType
: paymentMethods.PAY_AT_TIME_OF_SERVICE;
}, },
updateFooterButtonText(newValue) { updateFooterButtonText(newValue) {
this.$refs.siteFooter.updateButtonText(newValue); this.$refs.siteFooter.updateButtonText(newValue);
}, },
async forwardButtonAction() { async forwardButtonAction() {
useMainStore().savePaymentMethodChoice(this.paymentMethod); useMainStore().savePaymentMethodChoice(this.paymentMethod);
if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) { if (this.paymentMethod === paymentMethods.PAY_AT_TIME_OF_SERVICE) {
try { try {
await submitWorkOrder({ submitType: submitType.SAFELITE }); await submitWorkOrder({ submitType: submitType.SAFELITE });

View file

@ -3,11 +3,10 @@ import payment from '@/layouts/payment-page/payment-page.vue';
// Supporting Files // Supporting Files
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { getMountOptions } from '@/helpers/unit-test-helper'; import { getEnumName, getMountOptions } from '@/helpers/unit-test-helper';
import { useMainStore } from '@/store'; import { useMainStore } from '@/store';
import { paymentMethods, hopPaymentMethods } from '@/constants/payment-method-constants.js'; import { paymentMethods } from '@/constants/payment-method-constants.js';
import queryStrings from '@/constants/query-strings'; import queryStrings from '@/constants/query-strings';
import CartDropdown from '@/iss-components/cart-dropdown/cart-dropdown.vue';
import { createTestingPinia } from '@pinia/testing'; import { createTestingPinia } from '@pinia/testing';
import settleAllPromises from '@/helpers/layout-helper'; import settleAllPromises from '@/helpers/layout-helper';
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper'; import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
@ -207,8 +206,7 @@ const defaultOrder = {
}, },
payment: { payment: {
isInsurance: false, isInsurance: false,
isPayInAdvance: true, paymentMethod: paymentMethods.AFTERPAY,
payInAdvanceType: 'Afterpay',
inactivePromos: [] inactivePromos: []
}, },
schedule: { schedule: {
@ -239,8 +237,7 @@ describe('payment-page.vue', () => {
test('Returns false if pia options are not valid', () => { test('Returns false if pia options are not valid', () => {
// Arrange // Arrange
const { wrapper } = getMountedComponent(defaultOrder); const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.isPayInAdvance = null; useMainStore().order.payment.paymentMethod = null;
useMainStore().order.payment.payInAdvanceType = null;
// Act // Act
const result = wrapper.vm.arePagePrerequisitesValid(); const result = wrapper.vm.arePagePrerequisitesValid();
@ -252,8 +249,7 @@ describe('payment-page.vue', () => {
test('Returns false if pay at time of service', () => { test('Returns false if pay at time of service', () => {
// Arrange // Arrange
const { wrapper } = getMountedComponent(defaultOrder); const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.isPayInAdvance = false; useMainStore().order.payment.paymentMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
useMainStore().order.payment.payInAdvanceType = null;
// Act // Act
const result = wrapper.vm.arePagePrerequisitesValid(); const result = wrapper.vm.arePagePrerequisitesValid();
@ -265,94 +261,6 @@ describe('payment-page.vue', () => {
}); });
describe('payment type mapping', () => { describe('payment type mapping', () => {
describe('getPaymentType', () => {
test('Maps AFTERPAY -> hopPaymentMethods.AFTERPAY', () => {
// Arrange
const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.payInAdvanceType = paymentMethods.AFTERPAY;
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe(hopPaymentMethods.AFTERPAY);
});
test('Maps CREDIT_CARD -> hopPaymentMethods.CREDIT_CARD', () => {
// Arrange
const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.payInAdvanceType = paymentMethods.CREDIT_CARD;
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe(hopPaymentMethods.CREDIT_CARD);
});
test('Maps PAYPAL -> hopPaymentMethods.PAYPAL', () => {
// Arrange
const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.payInAdvanceType = paymentMethods.PAYPAL;
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe(hopPaymentMethods.PAYPAL);
});
test('Maps other values to self', () => {
// Arrange
const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.payInAdvanceType = 'SomeOtherText';
// Act
const mapped = wrapper.vm.getPaymentType();
// Assert
expect(mapped).toBe('SomeOtherText');
});
});
describe('cart-dropdown', () => {
test('Show cart dropdown if credit card', async () => {
const { wrapper } = getMountedComponent(defaultOrder);
wrapper.vm.paymentType = hopPaymentMethods.CREDIT_CARD;
// Act
await wrapper.vm.$nextTick();
const cartTable = wrapper.findComponent(CartDropdown);
// Assert
expect(cartTable.exists()).toBeTruthy();
});
test('show cart dropdown if afterpay', async () => {
const { wrapper } = getMountedComponent(defaultOrder);
wrapper.vm.paymentType = hopPaymentMethods.AFTERPAY;
// Act
await wrapper.vm.$nextTick();
const cartTable = wrapper.findComponent(CartDropdown);
// Assert
expect(cartTable.exists()).toBeTruthy();
});
test('Hide cart dropdown if paypal', async () => {
const { wrapper } = getMountedComponent(defaultOrder);
wrapper.vm.paymentType = hopPaymentMethods.PAYPAL;
// Act
await wrapper.vm.$nextTick();
const cartTable = wrapper.findComponent(CartDropdown);
// Assert
expect(cartTable.exists()).toBeFalsy();
});
});
describe('isPaypal', () => { describe('isPaypal', () => {
test('Is responsive if initial data changes', async () => { test('Is responsive if initial data changes', async () => {
// Arrange // Arrange
@ -361,7 +269,7 @@ describe('payment-page.vue', () => {
// Act // Act
const preVal = wrapper.vm.isPaypal; const preVal = wrapper.vm.isPaypal;
wrapper.vm.paymentType = hopPaymentMethods.PAYPAL; wrapper.vm.paymentType = paymentMethods.PAYPAL;
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
const postVal = wrapper.vm.isPaypal; const postVal = wrapper.vm.isPaypal;
@ -441,6 +349,7 @@ describe('payment-page.vue', () => {
}; };
const { wrapper } = getMountedComponent(defaultOrder); const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.paymentMethod = paymentMethods.PayNow;
// Act // Act
wrapper.vm.handleIFrameContentWindowMessage(event); wrapper.vm.handleIFrameContentWindowMessage(event);
@ -522,4 +431,26 @@ describe('payment-page.vue', () => {
expect(afterPayErrorAlert.isVisible()).toBeTruthy(); expect(afterPayErrorAlert.isVisible()).toBeTruthy();
}); });
}); });
describe.each([
[paymentMethods.CREDIT_CARD, { data: 'creditCardSubmit' }],
[paymentMethods.AFTERPAY, { data: 'afterpayPaymentReceived' }],
[paymentMethods.APPLEPAY, { data: 'applepayOpened' }],
[paymentMethods.PAYPAL, { data: 'showLoaderForPaypal' }]
])('handleIFrameContentWindowMessage', (expected, event) => {
test(`sets paymentMethod to ${getEnumName(paymentMethods, expected)} when data is ${event.data}`, () => {
// Arrange
const { wrapper } = getMountedComponent(defaultOrder);
useMainStore().order.payment.paymentMethod = paymentMethods.PayNow;
useMainStore().savePaymentMethodChoice = jest.fn().mockImplementation((value) => {useMainStore().order.payment.paymentMethod = value});
// Act
wrapper.vm.handleIFrameContentWindowMessage(event);
const result = useMainStore().order.payment.paymentMethod;
// Assert
expect(result).toBe(expected);
});
});
}); });

View file

@ -33,12 +33,12 @@
class="hop-iframe payment-iframe" class="hop-iframe payment-iframe"
name="card-frame" name="card-frame"
seamless seamless
scrolling="no"> scrolling="no"
allow="payment *; microphone *; geolocation *;">
</iframe> </iframe>
</div> </div>
<div <div
v-if="isCreditCard || isAfterPay"
class="px-2"> class="px-2">
<hr :class="{'my-0': isCreditCard}"> <hr :class="{'my-0': isCreditCard}">
<cartDropdown <cartDropdown
@ -73,10 +73,6 @@
:target="isPaypal ? '_top' : 'card-frame'" :target="isPaypal ? '_top' : 'card-frame'"
method="POST" method="POST"
:action="checkoutUrl"> :action="checkoutUrl">
<input
type="hidden"
name="paymentType"
:value="paymentType" />
<input <input
type="hidden" type="hidden"
name="sgSessionId" name="sgSessionId"
@ -385,6 +381,10 @@
type="hidden" type="hidden"
name="calling_application" name="calling_application"
value="ISSNextGen" /> value="ISSNextGen" />
<input type="hidden"
name="parentdomainname"
:value="parentNomainName" />
</form> </form>
</template> </template>
<script> <script>
@ -403,10 +403,7 @@ import { useMainStore } from '@/store';
import iframeResize from 'iframe-resizer/js/iframeResizer.js'; import iframeResize from 'iframe-resizer/js/iframeResizer.js';
import externalUrls from '@/router/router-constants/externalUrl-values.js'; import externalUrls from '@/router/router-constants/externalUrl-values.js';
import widgetFields from '@/constants/cms-widget-fields.js'; import widgetFields from '@/constants/cms-widget-fields.js';
import { import { paymentMethods } from '@/constants/payment-method-constants.js';
hopPaymentMethods,
paymentMethods
} from '@/constants/payment-method-constants.js';
import { AppointmentTypeStrings } from '@/constants/schedule-constants.js'; import { AppointmentTypeStrings } from '@/constants/schedule-constants.js';
import queryStrings from '@/constants/query-strings'; import queryStrings from '@/constants/query-strings';
import alert from '@/ux-components/alert/alert.vue'; import alert from '@/ux-components/alert/alert.vue';
@ -440,8 +437,7 @@ export default {
// Call APIs // Call APIs
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage); const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
const paymentSignaturePromise = const paymentSignaturePromise = await useMainStore().getPaymentSignature();
await useMainStore().getPaymentSignature();
// Settle promises and get results // Settle promises and get results
const promiseResultMap = [ const promiseResultMap = [
@ -478,7 +474,7 @@ export default {
data() { data() {
return { return {
checkoutUrl: externalUrls.SAFELITE_HOP, checkoutUrl: externalUrls.SAFELITE_HOP,
paymentType: this.getPaymentType(), paymentType: useMainStore().order.payment.paymentMethod,
authToken: '', authToken: '',
authSignature: '', authSignature: '',
authSignatureStart: '', authSignatureStart: '',
@ -503,6 +499,9 @@ export default {
}; };
}, },
computed: { computed: {
parentNomainName() {
return window.location.hostname;
},
payInAdvanceResponseUrl() { payInAdvanceResponseUrl() {
const { protocol, host } = window.location; const { protocol, host } = window.location;
return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=iss-nextgen`; return `${protocol}//${host}/?issPage=${issPageValues.PAYMENT_RETURN}&src=iss-nextgen`;
@ -521,10 +520,7 @@ export default {
}, },
getHeaderLine1() { getHeaderLine1() {
if (!this.isPaypal) { if (!this.isPaypal) {
return this.getCmsContent( return this.getCmsContent('PayInAdvanceHeaderLine1', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
'PayInAdvanceHeaderLine1',
widgetFields.TEXT_BLOCK_WIDGET.TEXT
);
} }
return ''; return '';
}, },
@ -538,13 +534,13 @@ export default {
return ''; return '';
}, },
isPaypal() { isPaypal() {
return this.paymentType === hopPaymentMethods.PAYPAL; return this.paymentType === paymentMethods.PAYPAL;
}, },
isCreditCard() { isCreditCard() {
return this.paymentType === hopPaymentMethods.CREDIT_CARD; return this.paymentType === paymentMethods.CREDIT_CARD;
}, },
isAfterPay() { isAfterPay() {
return this.paymentType === hopPaymentMethods.AFTERPAY; return this.paymentType === paymentMethods.AFTERPAY;
}, },
displayPayInAdvanceCreditCardAlert() { displayPayInAdvanceCreditCardAlert() {
return this.displayPayInAdvanceAlert(paymentMethods.CREDIT_CARD); return this.displayPayInAdvanceAlert(paymentMethods.CREDIT_CARD);
@ -605,10 +601,7 @@ export default {
&& contactInfo.emailAddress && contactInfo.emailAddress
); );
const paymentMethodReqs = const paymentMethodReqs = useMainStore().isPayInAdvance;
useMainStore().order.payment.isPayInAdvance !== null
&& (useMainStore().order.payment.isPayInAdvance
|| !!useMainStore().order.payment.payInAdvanceType);
return ( return (
packageReqs packageReqs
@ -664,18 +657,6 @@ export default {
?? useMainStore().order.serviceLocation.provider.address.zipCode ?? useMainStore().order.serviceLocation.provider.address.zipCode
); );
}, },
getPaymentType() {
switch (useMainStore().order.payment.payInAdvanceType) {
case paymentMethods.AFTERPAY:
return hopPaymentMethods.AFTERPAY;
case paymentMethods.CREDIT_CARD:
return hopPaymentMethods.CREDIT_CARD;
case paymentMethods.PAYPAL:
return hopPaymentMethods.PAYPAL;
default:
return useMainStore().payment.payInAdvanceType;
}
},
getPayInAdvanceLineItems(cartItems) { getPayInAdvanceLineItems(cartItems) {
const { glassParts } = useMainStore().order.lineItems; const { glassParts } = useMainStore().order.lineItems;
const lineItems = const lineItems =
@ -724,21 +705,12 @@ export default {
if (iframe) { if (iframe) {
iframe.onload = () => { iframe.onload = () => {
if (iframe.contentWindow) { if (iframe.contentWindow) {
if ( iframe.contentWindow.postMessage('hybrid', '*');
this.paymentType
=== hopPaymentMethods.CREDIT_CARD if (this.isAfterPay) {
) { iframe.contentWindow.postMessage('afterpay', '*');
iframe.contentWindow.postMessage( } else {
'CreditCardChosen', iframe.contentWindow.postMessage('CreditCardChosen', '*');
'*'
);
} else if (
this.paymentType === hopPaymentMethods.AFTERPAY
) {
iframe.contentWindow.postMessage(
'afterpay',
'*'
);
} }
} }
}; };
@ -746,18 +718,34 @@ export default {
}); });
}, },
handleIFrameContentWindowMessage(event) { handleIFrameContentWindowMessage(event) {
if (typeof event.data === 'string') { if (typeof event.data !== 'string') {
if (event.data.indexOf('afterpayClosed') > -1) { return;
this.backButtonAction(); }
}
if (event.data.indexOf('creditCardSubmit') > -1) { if (event.data.includes('afterpayClosed')) {
this.setUIBlock(true); this.backButtonAction();
} }
if (useMainStore().order.payment.paymentMethod !== paymentMethods.PayNow) {
return;
}
if (event.data.includes('creditCardSubmit')) {
useMainStore().savePaymentMethodChoice(paymentMethods.CREDIT_CARD);
this.setUIBlock(true);
}
if (event.data.includes('afterpayPaymentReceived')) {
useMainStore().savePaymentMethodChoice(paymentMethods.AFTERPAY);
}
if (event.data.includes('applepayOpened')) {
useMainStore().savePaymentMethodChoice(paymentMethods.APPLEPAY);
}
if (event.data.includes('showLoaderForPaypal')) {
useMainStore().savePaymentMethodChoice(paymentMethods.PAYPAL);
} }
}, },
setIFrameListener() { setIFrameListener() {
window.addEventListener('message', (event) => window.addEventListener('message', this.handleIFrameContentWindowMessage);
this.handleIFrameContentWindowMessage(event));
}, },
setUIBlock(val) { setUIBlock(val) {
this.shouldBlockInteraction = val; this.shouldBlockInteraction = val;
@ -769,8 +757,7 @@ export default {
}, },
displayPayInAdvanceAlert(payMethod) { displayPayInAdvanceAlert(payMethod) {
return ( return (
this.$route.query[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT] this.$route.query[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT] === payMethod
=== payMethod
); );
}, },
paymentFailedPayLater() { paymentFailedPayLater() {

View file

@ -46,18 +46,18 @@ export default {
async mounted() { async mounted() {
showIssLoadingModal(true); showIssLoadingModal(true);
const payInAdvanceError = getQueryStringParameter(queryStrings.ERROR); const payInAdvanceError = getQueryStringParameter(queryStrings.ERROR);
const { payInAdvanceType } = useMainStore().order.payment; const { paymentMethod } = useMainStore().order.payment;
if (payInAdvanceError) { if (payInAdvanceError) {
console.error(`Error during payment: ${payInAdvanceError}`); console.error(`Error during payment: ${payInAdvanceError}`);
const paymentPageNavScenario = const paymentPageNavScenario =
payInAdvanceType === paymentMethods.CREDIT_CARD || payInAdvanceType === paymentMethods.AFTERPAY; paymentMethod === paymentMethods.CREDIT_CARD || paymentMethod === paymentMethods.AFTERPAY;
if (paymentPageNavScenario) { if (paymentPageNavScenario) {
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR, this.navigationScenarios.PAY_IN_ADVANCE_CREDIT_CARD_ERROR,
this.$route, this.$route,
{ {
[queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: payInAdvanceType [queryStrings.DISPLAY_PAY_IN_ADVANCE_ALERT]: paymentMethod
} }
); );
} else { } else {
@ -70,16 +70,17 @@ export default {
); );
} }
} else { } else {
switch (payInAdvanceType) { switch (paymentMethod) {
case paymentMethods.CREDIT_CARD: case paymentMethods.CREDIT_CARD:
case paymentMethods.AFTERPAY: case paymentMethods.AFTERPAY:
case paymentMethods.APPLEPAY:
await this.processCreditCardResponse(); await this.processCreditCardResponse();
break; break;
case paymentMethods.PAYPAL: case paymentMethods.PAYPAL:
await this.processPaypalResponse(); await this.processPaypalResponse();
break; break;
default: default:
console.log(`Unknown pay in advance type: ${payInAdvanceType}`); console.log(`Unknown payment method: ${paymentMethod}`);
this.$router.navigate( this.$router.navigate(
this.navigationScenarios.PAY_IN_ADVANCE_ERROR, this.navigationScenarios.PAY_IN_ADVANCE_ERROR,
this.$route, this.$route,

View file

@ -170,9 +170,8 @@ export const getDefaultState = () => ({
}, },
payment: { payment: {
parentAccountNumber: 0, parentAccountNumber: 0,
isPayInAdvance: null,
nextGenSettledAmount: 0, nextGenSettledAmount: 0,
payInAdvanceType: null, paymentMethod: null,
paypalToken: null, paypalToken: null,
creditCardToken: { creditCardToken: {
subscriptionId: null, subscriptionId: null,
@ -306,6 +305,7 @@ export const useMainStore = defineStore({
isUnverified: (s) => s.order.insuranceCoverage.coverageStatus !== coverageStatuses.VERIFIED, isUnverified: (s) => s.order.insuranceCoverage.coverageStatus !== coverageStatuses.VERIFIED,
isVerified: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.VERIFIED, isVerified: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.VERIFIED,
isPendingClaimRegistration: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.PENDING, isPendingClaimRegistration: (state) => state.order.insuranceCoverage.coverageStatus === coverageStatuses.PENDING,
isPayInAdvance: (state) => state.order.payment.paymentMethod != null && state.order.payment.paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE,
providerNumber: (state) => state.order.serviceLocation.provider.providerNumber || state.order.serviceLocation.defaultProviderNumber, providerNumber: (state) => state.order.serviceLocation.provider.providerNumber || state.order.serviceLocation.defaultProviderNumber,
hasOemEndorsement: (state) => state.order.policy.endorsements?.indexOf('OEM Approved') !== -1 ?? false, hasOemEndorsement: (state) => state.order.policy.endorsements?.indexOf('OEM Approved') !== -1 ?? false,
eventBusItem: (state) => (eventCategory, eventSubCategory) => { eventBusItem: (state) => (eventCategory, eventSubCategory) => {
@ -1457,7 +1457,7 @@ export const useMainStore = defineStore({
parentAccountNumber: this.issConfig.parentAccountNumber, parentAccountNumber: this.issConfig.parentAccountNumber,
billToAccountNumber: this.billToAccountNumber, billToAccountNumber: this.billToAccountNumber,
paypalToken: payment.paypalToken, paypalToken: payment.paypalToken,
paymentMethod: payment.payInAdvanceType, paymentMethod: payment.paymentMethod === paymentMethods.PayNow ? null : payment.paymentMethod,
nextGenSettledAmount: payment.nextGenSettledAmount, nextGenSettledAmount: payment.nextGenSettledAmount,
CCToken: payment.creditCardToken CCToken: payment.creditCardToken
}, },
@ -2043,6 +2043,25 @@ export const useMainStore = defineStore({
this.order.policy.deductible.replace = null; this.order.policy.deductible.replace = null;
}, },
resetPayment() {
this.order.payment.parentAccountNumber = 0;
this.order.payment.nextGenSettledAmount = 0;
this.order.payment.paymentMethod = null;
this.order.payment.paypalToken = null;
this.order.payment.creditCardToken.subscriptionId = null;
this.order.payment.creditCardToken.expMonth = null;
this.order.payment.creditCardToken.expYear = null;
this.order.payment.creditCardToken.cardType = null;
this.order.payment.creditCardToken.billToPostalCode = null;
this.order.payment.creditCardToken.billToFirstName = null;
this.order.payment.creditCardToken.billToLastName = null;
this.order.payment.creditCardToken.referenceNumber = null;
this.order.payment.creditCardToken.authCode = null;
this.order.payment.creditCardToken.transactionId = null;
this.order.payment.creditCardToken.transReferenceNumber = null;
this.order.payment.creditCardToken.lastFour = null;
},
resetCustomer() { resetCustomer() {
this.order.customer.emailAddress = null; this.order.customer.emailAddress = null;
this.order.customer.firstName = null; this.order.customer.firstName = null;
@ -2786,6 +2805,7 @@ export const useMainStore = defineStore({
this.resetOrder(); this.resetOrder();
this.resetCustomer(); this.resetCustomer();
this.resetPolicy(); this.resetPolicy();
this.resetPayment();
this.resetContactInfo(); this.resetContactInfo();
this.resetVehicleState(); this.resetVehicleState();
this.resetDamageState(); this.resetDamageState();
@ -2797,9 +2817,7 @@ export const useMainStore = defineStore({
this.resetSubmittedOrder(); this.resetSubmittedOrder();
}, },
savePaymentMethodChoice(paymentMethod) { savePaymentMethodChoice(paymentMethod) {
const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE; this.order.payment.paymentMethod = paymentMethod;
this.order.payment.isPayInAdvance = isPayInAdvance;
this.order.payment.payInAdvanceType = isPayInAdvance ? paymentMethod : null;
}, },
getPaymentSignature() { getPaymentSignature() {
@ -2828,6 +2846,7 @@ export const useMainStore = defineStore({
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;
// set to local storage // set to local storage
window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder)); window.sessionStorage.setItem(webStorageConstants.SUBMITTED_ORDER, JSON.stringify(submittedOrder));

View file

@ -2051,28 +2051,20 @@ describe('Store', () => {
}); });
}); });
describe('savePaymentMethodChoice method', () => { describe.each([
it('isPayInAdvance saved as false when choice is to pay at time of servce', () => { [paymentMethods.CREDIT_CARD],
[paymentMethods.AFTERPAY],
[paymentMethods.APPLEPAY],
[paymentMethods.PAYPAL]
])('savePaymentMethodChoice method', (expected) => {
test(`sets paymentMethod to ${getEnumName(paymentMethods, expected)} when value is ${getEnumName(paymentMethods, expected)}`, () => {
// Arrange // Arrange
const paymentMethod = paymentMethods.PAY_AT_TIME_OF_SERVICE;
// Act // Act
store.savePaymentMethodChoice(paymentMethod); store.savePaymentMethodChoice(expected);
// Assert // Assert
expect(store.order.payment.isPayInAdvance).toEqual(false); expect(store.order.payment.paymentMethod).toBe(expected);
expect(store.order.payment.payInAdvanceType).toEqual(null);
});
it('isPayInAdvance saved as true when choice is other than to pay at time of servce', () => {
// Arrange
const paymentMethod = paymentMethods.CREDIT_CARD;
// Act
store.savePaymentMethodChoice(paymentMethod);
// Assert
expect(store.order.payment.isPayInAdvance).toEqual(true);
expect(store.order.payment.payInAdvanceType).toEqual(paymentMethod);
}); });
}); });

View file

@ -3,7 +3,7 @@ process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io';
process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost'; process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost';
process.env.VUE_APP_CUSTOMER_PORTAL_URL = 'https://myaccountdev.safelite.com/'; process.env.VUE_APP_CUSTOMER_PORTAL_URL = 'https://myaccountdev.safelite.com/';
process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0'; process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0';
process.env.VUE_APP_SAFELITE_HOP = 'https://iss-hop-dev.safelite.net/fmgCheckoutEmbedded.aspx'; process.env.VUE_APP_SAFELITE_HOP = 'https://iss-hop-sys.glassclaim.com/fmgCheckoutShared.aspx';
// GA & GTM // GA & GTM
// NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon. // NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon.