SSR-1063 credit card form on payment-page
This commit is contained in:
parent
e774babe0e
commit
32af347771
14 changed files with 1631 additions and 11 deletions
13
package-lock.json
generated
13
package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
|||
"axios": "^1.4.0",
|
||||
"axios-retry": "^3.5.0",
|
||||
"bootstrap": "^5.3",
|
||||
"iframe-resizer": "^4.3.9",
|
||||
"maska": "^1.5.0",
|
||||
"pinia": "^2.1.4",
|
||||
"pinia-plugin-persistedstate": "^2.2.0",
|
||||
|
|
@ -9734,6 +9735,18 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/iframe-resizer": {
|
||||
"version": "4.3.9",
|
||||
"resolved": "https://registry.npmjs.org/iframe-resizer/-/iframe-resizer-4.3.9.tgz",
|
||||
"integrity": "sha512-MCt+V/THB4a9OcAdrWo5NsI2CRpeMM4ijhTfiLtsdgDJXWYXf62Ve8yO8rKGmYNs991zty/EolYOxActlkfU+A==",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://github.com/davidjbradshaw/iframe-resizer/blob/master/FUNDING.md"
|
||||
}
|
||||
},
|
||||
"node_modules/ignore": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
"axios": "^1.4.0",
|
||||
"axios-retry": "^3.5.0",
|
||||
"bootstrap": "^5.3",
|
||||
"iframe-resizer": "^4.3.9",
|
||||
"maska": "^1.5.0",
|
||||
"pinia": "^2.1.4",
|
||||
"pinia-plugin-persistedstate": "^2.2.0",
|
||||
|
|
|
|||
13
public/css/README.md
Normal file
13
public/css/README.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# Using Sass in this folder
|
||||
|
||||
This public/css folder uses a standalone .scss > .css setup.
|
||||
## Usage
|
||||
|
||||
From a Terminal window, run the Sass Watch command from the public folder only:
|
||||
|
||||
```bash
|
||||
sass --no-source-map --watch scss:css
|
||||
```
|
||||
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 files on their own. You must use the .scss files and have Sass compile them to .css files.
|
||||
205
public/css/hop-styling.css
Normal file
205
public/css/hop-styling.css
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/* 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! */
|
||||
body {
|
||||
font-family: Roboto;
|
||||
font-weight: 400;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
background-color: white;
|
||||
padding: 8px;
|
||||
}
|
||||
body .validation-info {
|
||||
display: none;
|
||||
}
|
||||
body .italicSmall {
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
}
|
||||
body span {
|
||||
line-height: 24px;
|
||||
}
|
||||
body a {
|
||||
color: #1574A1;
|
||||
text-decoration: none;
|
||||
}
|
||||
body .form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
body .headerlinecontainer .headerline1 {
|
||||
font-size: 20px;
|
||||
line-height: 32px;
|
||||
font-weight: 400;
|
||||
margin: 24px 0;
|
||||
text-align: center;
|
||||
}
|
||||
body input,
|
||||
body select {
|
||||
margin-top: 4px;
|
||||
}
|
||||
body input,
|
||||
body select {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #8E9292;
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
}
|
||||
body input:focus, body input:focus-visible,
|
||||
body select:focus,
|
||||
body select:focus-visible {
|
||||
box-shadow: 0 0 0 2.5px #1574a1;
|
||||
border: 1px solid transparent;
|
||||
outline: none;
|
||||
}
|
||||
body input:disabled, body input.disabled,
|
||||
body select:disabled,
|
||||
body select.disabled {
|
||||
background-color: #f5f5f5;
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
body input:disabled:hover, body input.disabled:hover,
|
||||
body select:disabled:hover,
|
||||
body select.disabled:hover {
|
||||
box-shadow: 0 0 0 4px transparent;
|
||||
border: 1px solid #8e9292;
|
||||
}
|
||||
body input:hover,
|
||||
body select:hover {
|
||||
border: 1px solid #8e9292;
|
||||
box-shadow: 0 0 0 4px #9fcee6;
|
||||
}
|
||||
body select {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #8E9292;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%231474a2'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 95% 50%;
|
||||
background-size: 15px 9px;
|
||||
appearance: none;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
}
|
||||
body .creditCardSpecific div {
|
||||
padding: 8px 0;
|
||||
}
|
||||
body .creditCardSpecific div .headerlinecontainer {
|
||||
display: none;
|
||||
}
|
||||
body .creditCardSpecific div label {
|
||||
font-weight: 500;
|
||||
}
|
||||
body .creditCardSpecific #infoRow2 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
body #cardExpirationContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
}
|
||||
@media (min-width: 400px) {
|
||||
body #cardExpirationContainer {
|
||||
flex-direction: row;
|
||||
}
|
||||
body #cardExpirationContainer .card_expirationYear,
|
||||
body #cardExpirationContainer .card_expirationMonth {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
body #cardExpirationContainer .card_expirationYear {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
body .optional-label span {
|
||||
display: none;
|
||||
}
|
||||
body .optional-label:after {
|
||||
content: " (optional)";
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-size: 15px;
|
||||
}
|
||||
body .buttonContainer {
|
||||
height: 48px;
|
||||
}
|
||||
body .buttonContainer button {
|
||||
position: relative;
|
||||
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
justify-content: center;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
body .buttonContainer button {
|
||||
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
|
||||
}
|
||||
}
|
||||
body .buttonContainer button:focus {
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c;
|
||||
}
|
||||
body .buttonContainer button:focus, body .buttonContainer button:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c;
|
||||
color: #fff;
|
||||
background: linear-gradient(270deg, rgb(6, 87, 124) 0%, rgb(6, 87, 124) 100%);
|
||||
}
|
||||
body .buttonContainer button:disabled {
|
||||
background: #e3e4e4 !important;
|
||||
background: linear-gradient(270deg, #e3e4e4 0%, #e3e4e4 100%) !important;
|
||||
color: #4d5151 !important;
|
||||
font-weight: 400;
|
||||
height: 48px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
body .buttonContainer button.has-loader {
|
||||
color: #fff;
|
||||
background: #06577c;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c;
|
||||
pointer-events: auto;
|
||||
}
|
||||
body .buttonContainer button.delay {
|
||||
transition: background 0s 0s ease-in-out;
|
||||
}
|
||||
body .has-error input,
|
||||
body .has-error select {
|
||||
border: 1px solid #d4281c;
|
||||
}
|
||||
body .has-error input:focus,
|
||||
body .has-error select:focus {
|
||||
box-shadow: 0 0 0 2.5px #fcbfbb;
|
||||
}
|
||||
body .has-error input:hover,
|
||||
body .has-error select:hover {
|
||||
border: 1px solid #d4281c;
|
||||
box-shadow: 0 0 0 4px #fcbfbb;
|
||||
}
|
||||
body .has-error select {
|
||||
border: 1px solid #d4281c;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%23d4281c'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 95% 50%;
|
||||
background-size: 15px 9px;
|
||||
appearance: none;
|
||||
}
|
||||
body .has-error small {
|
||||
margin-top: 4px;
|
||||
color: #d4281c;
|
||||
}
|
||||
body .cc-error-container #alert-message {
|
||||
background-color: #fcbfbb;
|
||||
border: 1px solid #d4281c;
|
||||
}
|
||||
114
public/css/site-2020Styling.css
Normal file
114
public/css/site-2020Styling.css
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* 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.4);
|
||||
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: 176px;
|
||||
height: 136px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg fill='none' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 84 32'%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' fill='%23fff'/%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' fill='%23fff'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06.8c8.08 0 11.89.935 11.89.935 3.58.576 5.696 7.207 5.696 7.207h.727c0-2.427 1.302-2.397 2.341-2 .723.292 1.363.76 1.86 1.361 1.319 1.547.465 1.674.465 1.674h-5.067l3.846 3.01v12.016c0 2.41-2.029 2.31-2.029 2.31H22.338s-2.029.1-2.029-2.31V12.996l3.84-3.009H19.07s-.853-.127.466-1.674a4.693 4.693 0 0 1 1.86-1.361c1.032-.397 2.341-.427 2.341 2h.736s2.117-6.64 5.696-7.21c0 0 3.81-.942 11.89-.942Z' fill='%23fff' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06 8.847c7.924 0 14.685.511 14.685.511 0-2.585-2.38-6.011-2.38-6.011S50.4 2.519 42.06 2.519s-12.303.828-12.303.828-2.38 3.426-2.38 6.011c0 0 6.76-.51 14.683-.51Z' fill='%23DA291C' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M35.277 16.523a62.558 62.558 0 0 1 13.277 0m3.276-.439s2.384-2.257 8.608-2.257c0 0 1.179 2.657-2.54 3.37m-25.894-1.113s-2.387-2.257-8.611-2.257c0 0-1.16 2.579 2.543 3.37m-3.546 5.856s21.52 3.647 39.123 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 96px;
|
||||
}
|
||||
#pageLoadingModal .modal-content:after {
|
||||
content: "";
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
width: 5.5rem;
|
||||
height: 5.5rem;
|
||||
border: 0.45em solid #d4281c;
|
||||
border-right-color: transparent;
|
||||
animation: spinnerrotate 0.75s linear infinite;
|
||||
}
|
||||
@keyframes spinnerrotate {
|
||||
0% {
|
||||
transform: rotate(0);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
#pageLoadingModal .modal-content p {
|
||||
display: none;
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
.buy-backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.3) !important;
|
||||
}
|
||||
.buy-backdrop #afterpay__iframe-checkout-container {
|
||||
width: 100%;
|
||||
}
|
||||
.buy-backdrop #afterpay__iframe-checkout-container .style_closeWrapper__lIHJe {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.buy-container-closer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
0% {
|
||||
transform: rotate(0);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.creditCardSpecific {
|
||||
display: none;
|
||||
}
|
||||
224
public/scss/hop-styling.scss
Normal file
224
public/scss/hop-styling.scss
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/* 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! */
|
||||
body {
|
||||
font-family: Roboto;
|
||||
font-weight: 400;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
background-color: white;
|
||||
padding: 8px;
|
||||
|
||||
.validation-info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.italicSmall {
|
||||
font-style: normal;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
span {
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #1574A1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.headerlinecontainer {
|
||||
.headerline1 {
|
||||
font-size: 20px;
|
||||
line-height: 32px;
|
||||
font-weight: 400;
|
||||
margin: 24px 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
select {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
input,
|
||||
select {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #8E9292;
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 2.5px #1574a1;
|
||||
border: 1px solid transparent;
|
||||
outline: none;
|
||||
}
|
||||
&:disabled,
|
||||
&.disabled {
|
||||
background-color: #f5f5f5;
|
||||
filter: grayscale(100%);
|
||||
&:hover {
|
||||
box-shadow: 0 0 0 4px transparent;
|
||||
border: 1px solid #8e9292;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
border: 1px solid #8e9292;
|
||||
box-shadow: 0 0 0 4px #9fcee6;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #8E9292;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%231474a2'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 95% 50%;
|
||||
background-size: 15px 9px;
|
||||
appearance: none;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.creditCardSpecific {
|
||||
div {
|
||||
padding: 8px 0;
|
||||
.headerlinecontainer {
|
||||
display: none;
|
||||
}
|
||||
label {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
#infoRow2 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#cardExpirationContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 0;
|
||||
@media (min-width: 400px) {
|
||||
flex-direction: row;
|
||||
.card_expirationYear,
|
||||
.card_expirationMonth {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
.card_expirationYear {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.optional-label {
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
&:after {
|
||||
content: " (optional)";
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
height: 48px;
|
||||
button {
|
||||
position: relative;
|
||||
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
color: #fff;
|
||||
justify-content: center;
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
height: 48px;
|
||||
@media (hover: hover) {
|
||||
background: linear-gradient(270deg, #1574a1 0%, #003d58 100%);
|
||||
}
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c;
|
||||
}
|
||||
&:focus, // Mouse, touch, stylus focus
|
||||
&:focus-visible {
|
||||
// Keyboard focus for accessibility
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c;
|
||||
color: #fff;
|
||||
background: linear-gradient(270deg, rgba(6, 87, 124, 1) 0%, rgba(6, 87, 124, 1) 100%);
|
||||
}
|
||||
&:disabled {
|
||||
background: #e3e4e4 !important;
|
||||
background: linear-gradient(270deg, #e3e4e4 0%, #e3e4e4 100%) !important;
|
||||
color: #4d5151 !important;
|
||||
font-weight: 400;
|
||||
height: 48px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
&.has-loader {
|
||||
color: #fff;
|
||||
background: #06577c;
|
||||
box-shadow: 0 0 0 3px, 0 0 0 5.5px #06577c;
|
||||
pointer-events: auto;
|
||||
}
|
||||
&.delay {
|
||||
// fixes flicker while transitioning between states
|
||||
transition: background 0s 0s ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Error Styling
|
||||
.has-error {
|
||||
input,
|
||||
select {
|
||||
border: 1px solid #d4281c;
|
||||
&:focus {
|
||||
box-shadow: 0 0 0 2.5px #fcbfbb;
|
||||
}
|
||||
&:hover {
|
||||
border: 1px solid #d4281c;
|
||||
box-shadow: 0 0 0 4px #fcbfbb;
|
||||
}
|
||||
}
|
||||
select {
|
||||
border: 1px solid #d4281c;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 8.89' xml:space='preserve'%3e%3cpath d='M8 8.89c-.24 0-.46-.09-.63-.26L.26 1.53a.901.901 0 0 1 0-1.27C.43.1.66 0 .9 0s.47.1.64.26L8 6.74 14.47.27c.17-.17.4-.27.64-.27s.47.1.63.27c.17.17.26.4.26.64s-.1.47-.27.63l-7.1 7.09a.86.86 0 0 1-.63.26z' fill='%23d4281c'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: 95% 50%;
|
||||
background-size: 15px 9px;
|
||||
appearance: none;
|
||||
}
|
||||
small {
|
||||
margin-top: 4px;
|
||||
color: #d4281c;
|
||||
}
|
||||
}
|
||||
|
||||
.cc-error-container {
|
||||
#alert-message {
|
||||
background-color: #fcbfbb;
|
||||
border: 1px solid #d4281c;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
118
public/scss/site-2020Styling.scss
Normal file
118
public/scss/site-2020Styling.scss
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/* 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.40);
|
||||
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: 176px;
|
||||
height: 136px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg fill='none' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 84 32'%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' fill='%23fff'/%3e%3cpath d='M22.39 27.313a3.53 3.53 0 0 0 7.058 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' fill='%23fff'/%3e%3cpath d='M54.459 27.313a3.527 3.527 0 0 0 7.054 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06.8c8.08 0 11.89.935 11.89.935 3.58.576 5.696 7.207 5.696 7.207h.727c0-2.427 1.302-2.397 2.341-2 .723.292 1.363.76 1.86 1.361 1.319 1.547.465 1.674.465 1.674h-5.067l3.846 3.01v12.016c0 2.41-2.029 2.31-2.029 2.31H22.338s-2.029.1-2.029-2.31V12.996l3.84-3.009H19.07s-.853-.127.466-1.674a4.693 4.693 0 0 1 1.86-1.361c1.032-.397 2.341-.427 2.341 2h.736s2.117-6.64 5.696-7.21c0 0 3.81-.942 11.89-.942Z' fill='%23fff' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M42.06 8.847c7.924 0 14.685.511 14.685.511 0-2.585-2.38-6.011-2.38-6.011S50.4 2.519 42.06 2.519s-12.303.828-12.303.828-2.38 3.426-2.38 6.011c0 0 6.76-.51 14.683-.51Z' fill='%23DA291C' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3cpath d='M35.277 16.523a62.558 62.558 0 0 1 13.277 0m3.276-.439s2.384-2.257 8.608-2.257c0 0 1.179 2.657-2.54 3.37m-25.894-1.113s-2.387-2.257-8.611-2.257c0 0-1.16 2.579 2.543 3.37m-3.546 5.856s21.52 3.647 39.123 0' stroke='%23000' stroke-width='.75' stroke-linecap='round' stroke-linejoin='round'/%3e%3c/svg%3e");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-size: 96px;
|
||||
&:after {
|
||||
content: '';
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
width: 5.5rem;
|
||||
height: 5.5rem;
|
||||
border: 0.45em solid #d4281c;
|
||||
border-right-color: transparent;
|
||||
animation: spinnerrotate 0.75s linear infinite;
|
||||
}
|
||||
@keyframes spinnerrotate {
|
||||
0% { transform: rotate(0)}
|
||||
100% { transform: rotate(360deg)}
|
||||
}
|
||||
p {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
background-color: #000000;
|
||||
&.fade {
|
||||
opacity: 0;
|
||||
filter: alpha(opacity=0);
|
||||
}
|
||||
}
|
||||
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// AfterPay Styles
|
||||
|
||||
.buy-backdrop {
|
||||
background-color: rgba(0,0,0,.3)!important;
|
||||
#afterpay__iframe-checkout-container {
|
||||
width: 100%;
|
||||
.style_closeWrapper__lIHJe {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.buy-container-closer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Modal Spinner
|
||||
|
||||
@keyframes rotate {
|
||||
0% { transform: rotate(0)}
|
||||
100% { transform: rotate(360deg)}
|
||||
}
|
||||
|
||||
.creditCardSpecific {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable no-restricted-globals */
|
||||
/**
|
||||
* @module applicationConfig
|
||||
* @author T-Wrecks Team
|
||||
|
|
@ -16,7 +17,17 @@ const applicationConfig = Object.freeze({
|
|||
CLIENTTAG_QUERYSTRING: 'ClientTag',
|
||||
GOOGLE_PLACES_API_KEY: process.env.VUE_APP_GOOGLE_PLACES_API_KEY,
|
||||
ISS_DEV_CMS_DOMAIN: 'https://digitalisscms.dev.safelite.io',
|
||||
CASH_PARENT_ACCOUNT_NUMBER: 167132
|
||||
CASH_PARENT_ACCOUNT_NUMBER: 167132,
|
||||
PAY_IN_ADVANCE_RESPONSE_URL:
|
||||
`${location.protocol
|
||||
}//${
|
||||
location.host
|
||||
}/?issPage=payment-return&src=iss-nextgen`,
|
||||
PAY_IN_ADVANCE_CANCEL_URL:
|
||||
`${location.protocol
|
||||
}//${
|
||||
location.host
|
||||
}/?issPage=payment-method&src=iss-nextgen`
|
||||
});
|
||||
|
||||
export default applicationConfig;
|
||||
|
|
|
|||
|
|
@ -178,6 +178,10 @@ const endpoints = Object.freeze({
|
|||
FinalDeductible: {
|
||||
url: '/coverage/api/v1/coverage/final-deductible',
|
||||
method: 'POST'
|
||||
},
|
||||
GetPaymentSignature: {
|
||||
url: '/order/api/v1/order/sign',
|
||||
method: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
492
src/layouts/payment-page/payment-page.spec.js
Normal file
492
src/layouts/payment-page/payment-page.spec.js
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
// Components
|
||||
import payment from '@/layouts/payment-page/payment-page.vue';
|
||||
|
||||
// Supporting Files
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
import { getMountOptions } from '@/helpers/unit-test-helper';
|
||||
import { useMainStore } from '@/store';
|
||||
import paymentMethods from '@/constants/payment-method-constants'
|
||||
|
||||
// Constants
|
||||
const parts = {
|
||||
windshield: {
|
||||
name: 'windshield',
|
||||
canSafeliteRecalibrate: true,
|
||||
childParts: [],
|
||||
color: 'Green Tint',
|
||||
description:
|
||||
'solar, soundproofing, lane keep assist, lane departure warning system, w/adaptive cruise control',
|
||||
id: 'db22fd44-10dd-456f-979b-ff88cf68cca6',
|
||||
partNumber: 'FW04896GTYN',
|
||||
partType: 'WINDSHIELD',
|
||||
recalibrationType: 'STATIC',
|
||||
requiresCapabilityQuestions: false,
|
||||
requiresRecalibration: true,
|
||||
salesTax: 63.86,
|
||||
sellingPrice: 791.46
|
||||
},
|
||||
frontWipers: {
|
||||
name: 'front wipers',
|
||||
partNumber: 'SBB16',
|
||||
description: 'SAFELITE BEAM BLADE 16',
|
||||
partType: 'FRONT WIPER',
|
||||
price: 32.64
|
||||
},
|
||||
rearWipers: {
|
||||
name: 'rear wipers',
|
||||
partNumber: 'SBBR12A',
|
||||
description: 'SAFELITE REAR BLADE 12A',
|
||||
partType: 'REAR WIPER',
|
||||
price: 24.48
|
||||
},
|
||||
rainDefense: {
|
||||
name: 'rain defense',
|
||||
partNumber: 'RAIN DEFENSE',
|
||||
description: null,
|
||||
partType: 'RAIN DEFENSE',
|
||||
price: 35.5
|
||||
}
|
||||
};
|
||||
|
||||
const pricedParts = {
|
||||
windshield: {
|
||||
...parts.windshield,
|
||||
kitPrice: 0,
|
||||
laborAmount: 60,
|
||||
salesTax: 0,
|
||||
sellingPrice: 791.46
|
||||
},
|
||||
frontWipers: {
|
||||
...parts.frontWipers,
|
||||
kitPrice: 0,
|
||||
laborAmount: 20,
|
||||
salesTax: 0,
|
||||
sellingPrice: 32.64
|
||||
},
|
||||
rearWipers: {
|
||||
...parts.rearWipers,
|
||||
kitPrice: 10,
|
||||
laborAmount: 10,
|
||||
salesTax: 0,
|
||||
sellingPrice: 24.48
|
||||
},
|
||||
rainDefense: {
|
||||
...parts.rainDefense,
|
||||
kitPrice: 20,
|
||||
laborAmount: 0,
|
||||
salesTax: 0,
|
||||
sellingPrice: 35.5
|
||||
}
|
||||
};
|
||||
|
||||
const taxedParts = {
|
||||
windshield: {
|
||||
...pricedParts.windshield,
|
||||
salesTax: 63.86,
|
||||
subTotal: 100
|
||||
},
|
||||
frontWipers: {
|
||||
...pricedParts.frontWipers,
|
||||
salesTax: 2.36,
|
||||
subTotal: 100
|
||||
},
|
||||
rearWipers: {
|
||||
...pricedParts.rearWipers,
|
||||
salesTax: 6.0,
|
||||
subTotal: 100
|
||||
},
|
||||
rainDefense: {
|
||||
...pricedParts.rainDefense,
|
||||
salesTax: 1.0,
|
||||
subTotal: 100
|
||||
}
|
||||
};
|
||||
|
||||
// Setup global mocks
|
||||
let mockCmsContent = {};
|
||||
|
||||
jest.mock('@/mixins/base-mixin.js', () => ({
|
||||
methods: {
|
||||
getAmountDue: jest.fn().mockImplementation(() => 5),
|
||||
getDisplayAmountDue: jest.fn().mockImplementation(() => '$5.00')
|
||||
}
|
||||
}));
|
||||
|
||||
jest.mock('@/helpers/cms-content-helper', () => ({
|
||||
fetchCmsContentForPage: () => Promise.resolve('content')
|
||||
}));
|
||||
|
||||
function setupMocks({ customMountOptions }) {
|
||||
const mountOptions = getMountOptions({
|
||||
...customMountOptions,
|
||||
route: { query: { issPage: 'page-name' }, params: {} }
|
||||
});
|
||||
|
||||
// set all mock stuff
|
||||
mountOptions.mixins = [
|
||||
{
|
||||
methods: {
|
||||
getCmsContent: jest.fn().mockImplementation((widgetName, fieldName) => {
|
||||
if (mockCmsContent[widgetName] && mockCmsContent[widgetName][fieldName]) {
|
||||
return mockCmsContent[widgetName][fieldName];
|
||||
}
|
||||
return undefined;
|
||||
}),
|
||||
setCmsContent: jest.fn()
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
const wrapper = shallowMount(payment, mountOptions);
|
||||
|
||||
// act on vm
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
describe('payment-page.vue', () => {
|
||||
beforeEach(() => {
|
||||
useMainStore().order =
|
||||
{
|
||||
vehicle: {
|
||||
year: '2020',
|
||||
make: 'acura',
|
||||
model: 'mdx',
|
||||
style: '4-door sedan',
|
||||
carId: 'dummyCarId',
|
||||
category: 'dummyCategory',
|
||||
vin: 'dummyVin'
|
||||
},
|
||||
serviceLocation: {
|
||||
address: 'add1',
|
||||
address2: 'add2',
|
||||
city: 'city',
|
||||
state: 'state',
|
||||
zipCode: 'zip',
|
||||
zipCodeCtu: 'zipCtu',
|
||||
appointmentType: 'IN_SHOP',
|
||||
isVehicleProtected: true,
|
||||
provider: {
|
||||
providerNumber: 2,
|
||||
address: {
|
||||
streetAddress: 'add3',
|
||||
city: 'city2',
|
||||
state: 'state2',
|
||||
zipCode: 'zip2',
|
||||
zipCodeCtu: 'zipCtu2'
|
||||
}
|
||||
},
|
||||
techNotes: ''
|
||||
},
|
||||
customer: {
|
||||
firstName: 'first',
|
||||
lastName: 'last',
|
||||
emailAddress: 'builddigitaltest@safelite.com',
|
||||
phoneNumber: '555-555-5555',
|
||||
isSmsOptIn: false
|
||||
},
|
||||
damage: {
|
||||
isRepair: false,
|
||||
numberOfChips: null,
|
||||
glassToReplace: [{ location: 'windshield' }]
|
||||
},
|
||||
lineItems: {
|
||||
glassParts: [parts.windshield],
|
||||
supportingItems: [],
|
||||
vaps: [parts.frontWipers],
|
||||
promos: []
|
||||
},
|
||||
payment: {
|
||||
isInsurance: false,
|
||||
insuranceCoverage: {
|
||||
isVerified: null,
|
||||
coverageStatus: null,
|
||||
coverageVerificationType: null
|
||||
},
|
||||
isPayInAdvance: true,
|
||||
payInAdvanceType: 'Afterpay',
|
||||
inactivePromos: []
|
||||
},
|
||||
schedule: {
|
||||
date: 'date',
|
||||
startTime: 'start',
|
||||
endTime: 'end',
|
||||
jobMinMinutes: '30',
|
||||
jobMaxMinutes: '45'
|
||||
}
|
||||
};
|
||||
|
||||
mockCmsContent = {};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('arePagePrerequisitesValid', () => {
|
||||
test('Returns true in nominal conditions', () => {
|
||||
// Arrange
|
||||
// Store defaults are valid
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
describe('Payment method cases', () => {
|
||||
test('Returns false if pia options are not valid', () => {
|
||||
// Arrange
|
||||
useMainStore().order.payment.isPayInAdvance = null;
|
||||
useMainStore().order.payment.payInAdvanceType = null;
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('Returns false if pay at time of service', () => {
|
||||
// Arrange
|
||||
useMainStore().order.payment.isPayInAdvance = false;
|
||||
useMainStore().order.payment.payInAdvanceType = null;
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const result = wrapper.vm.arePagePrerequisitesValid();
|
||||
|
||||
// Assert
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('beforeRouteEnter', () => {
|
||||
test('Properly initializes fields and kicks off hop', async () => {
|
||||
// Arrange
|
||||
const vmMock = {
|
||||
setCmsContent: jest.fn(),
|
||||
$refs: {
|
||||
cart: {
|
||||
cartItems: []
|
||||
}
|
||||
},
|
||||
getPiaLineItems: jest.fn(),
|
||||
fetchSignatureInfo: jest.fn(),
|
||||
setIFrameListener: jest.fn(),
|
||||
|
||||
$nextTick: (f) => {
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
const nextF = (f) => {
|
||||
f(vmMock);
|
||||
};
|
||||
|
||||
// Act
|
||||
await payment.beforeRouteEnter.call(
|
||||
vmMock,
|
||||
{ query: { issPage: 'payment-page' } },
|
||||
undefined,
|
||||
nextF
|
||||
);
|
||||
|
||||
// Assert
|
||||
expect(vmMock.setCmsContent).toBeCalled();
|
||||
expect(vmMock.fetchSignatureInfo).toBeCalled();
|
||||
expect(vmMock.setIFrameListener).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('payment type mapping', () => {
|
||||
describe('getPaymentType', () => {
|
||||
test('Maps AFTERPAY -> ap', () => {
|
||||
// Arrange
|
||||
useMainStore().order.payment.payInAdvanceType = paymentMethods.AFTERPAY;
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const mapped = wrapper.vm.getPaymentType();
|
||||
|
||||
// Assert
|
||||
expect(mapped).toBe('ap');
|
||||
});
|
||||
|
||||
test('Maps CREDIT_CARD -> cc', () => {
|
||||
// Arrange
|
||||
useMainStore().order.payment.payInAdvanceType = paymentMethods.CREDIT_CARD;
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const mapped = wrapper.vm.getPaymentType();
|
||||
|
||||
// Assert
|
||||
expect(mapped).toBe('cc');
|
||||
});
|
||||
|
||||
test('Maps PAYPAL -> pp', () => {
|
||||
// Arrange
|
||||
useMainStore().order.payment.payInAdvanceType = paymentMethods.PAYPAL;
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const mapped = wrapper.vm.getPaymentType();
|
||||
|
||||
// Assert
|
||||
expect(mapped).toBe('pp');
|
||||
});
|
||||
|
||||
test('Maps other values to self', () => {
|
||||
// Arrange
|
||||
useMainStore().order.payment.payInAdvanceType = 'SomeOtherText';
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const mapped = wrapper.vm.getPaymentType();
|
||||
|
||||
// Assert
|
||||
expect(mapped).toBe('SomeOtherText');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPaypal', () => {
|
||||
test('Is responsive if initial data changes', async () => {
|
||||
// Arrange
|
||||
// note: begins with payment-type = afterpay
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
const preVal = wrapper.vm.isPaypal;
|
||||
wrapper.vm.paymentType = 'pp';
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const postVal = wrapper.vm.isPaypal;
|
||||
|
||||
// Assert
|
||||
expect(preVal).toBe(false);
|
||||
expect(postVal).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('hop form', () => {
|
||||
describe('fetchSignatureInfo', () => {
|
||||
test('Sets auth fields', async () => {
|
||||
// Arrange
|
||||
const signature = {
|
||||
token: 'TOKEN',
|
||||
signature: 'SIGNATURE',
|
||||
startDate: 'STARTDATE'
|
||||
};
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
wrapper.vm.submitHopForm = jest.fn();
|
||||
|
||||
// Act
|
||||
await wrapper.vm.fetchSignatureInfo(signature);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.authToken).toBe(signature.token);
|
||||
expect(wrapper.vm.authSignature).toBe(signature.signature);
|
||||
expect(wrapper.vm.authSignatureStart).toBe(signature.startDate);
|
||||
|
||||
expect(wrapper.vm.submitHopForm).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('submitHopForm', () => {
|
||||
test('Submits form', async () => {
|
||||
// Arrange
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
wrapper.vm.$refs.hopForm.submit = jest.fn();
|
||||
wrapper.vm.$refs.paymentFrame = null;
|
||||
|
||||
// Act
|
||||
wrapper.vm.submitHopForm();
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.$refs.hopForm.submit).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleIFrameContentWindowMessage', () => {
|
||||
test('Navigates back if afterpay is closed', () => {
|
||||
// Arrange
|
||||
const event = {
|
||||
data: 'afterpayClosed'
|
||||
};
|
||||
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
wrapper.vm.backButtonAction = jest.fn();
|
||||
|
||||
// Act
|
||||
wrapper.vm.handleIFrameContentWindowMessage(event);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.backButtonAction).toBeCalled();
|
||||
});
|
||||
|
||||
test('Blocks UI interaction if credit card is submitted', () => {
|
||||
// Arrange
|
||||
const event = {
|
||||
data: 'creditCardSubmit'
|
||||
};
|
||||
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
wrapper.vm.handleIFrameContentWindowMessage(event);
|
||||
|
||||
// Assert
|
||||
expect(wrapper.vm.shouldBlockInteraction).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('UI Blocking', () => {
|
||||
test('UI block appears when toggled', async () => {
|
||||
// Arrange
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
// Act
|
||||
wrapper.vm.setUIBlock(true);
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const uiBlockElements = wrapper.findAll('.ui-block');
|
||||
|
||||
// Assert
|
||||
expect(uiBlockElements.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("Don't propogate clicks from UI block", async () => {
|
||||
// Arrange
|
||||
const wrapper = setupMocks({});
|
||||
|
||||
const outerDiv = wrapper.find('.container-fluid');
|
||||
const clickFn = jest.fn();
|
||||
outerDiv.element.addEventListener('click', clickFn);
|
||||
|
||||
// Act
|
||||
wrapper.vm.setUIBlock(true);
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const uiBlockElement = wrapper.find('.ui-block');
|
||||
|
||||
await uiBlockElement.trigger('click');
|
||||
|
||||
// Assert
|
||||
expect(clickFn).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -8,17 +8,155 @@
|
|||
<div class="fade-on-route-transition position-relative">
|
||||
<siteHeader cmsWidgetName="SiteHeaderWidget" />
|
||||
<div class="container-fluid pb-2 payment">
|
||||
<p>Placeholder for payment page</p>
|
||||
<div id="card-container">
|
||||
<iframe
|
||||
id="card-frame"
|
||||
ref="paymentFrame"
|
||||
v-resize
|
||||
class="hop-iframe payment-iframe"
|
||||
name="card-frame"
|
||||
seamless
|
||||
scrolling="no">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<siteFooter
|
||||
ref="siteFooter"
|
||||
cmsWidgetName="SiteFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
:isForwardActionDisabled="true"
|
||||
isForwardButtonHidden="true"
|
||||
@ForwardClicked="forwardButtonAction"
|
||||
@backClicked="navigateBack" />
|
||||
@backClicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="shouldBlockInteraction"
|
||||
class="ui-block"
|
||||
@click="supressClick"></div>
|
||||
</div>
|
||||
</Form>
|
||||
|
||||
<form
|
||||
ref="hopForm"
|
||||
id="card-data"
|
||||
:target="isPaypal ? '_top' : 'card-frame'"
|
||||
method="POST"
|
||||
:action="checkoutUrl">
|
||||
<input type="hidden" name="paymentType" :value="paymentType" />
|
||||
<input type="hidden" name="sgSessionId" :value="authToken" />
|
||||
<input type="hidden" name="sgAuthToken" :value="authToken" />
|
||||
<input type="hidden" name="sgSignaturePublic" :value="authSignature" />
|
||||
<input type="hidden" name="sgSignatureStartDate" :value="authSignatureStart" />
|
||||
<input type="hidden" name="referralSeqNum" :value="referralSequenceNumber" />
|
||||
|
||||
<input type="hidden" name="sge_commerce_indicator_isinternet" value="true" />
|
||||
<input type="hidden" name="sghopsource" value="Safelite.com" />
|
||||
<input type="hidden" name="sgHtmlStyle" value="ResourceSafeliteHtml" />
|
||||
<input type="hidden" name="sgErrorMessagesEmbedded" value="true" />
|
||||
|
||||
<input type="hidden" name="sgNoKeystrokeProcessing" value="false" />
|
||||
|
||||
<input type="hidden" name="maskCharacter" value="*" />
|
||||
<input type="hidden" name="styleSheetCode" :value="dynamicCSSUrl" />
|
||||
<input type="hidden" name="styleSheetCode2" :value="dynamicHopCSSUrl" />
|
||||
|
||||
<input type="hidden" name="sgReceiptResponseURL" :value="payInAdvanceResponseUrl" />
|
||||
<input type="hidden" name="sgDeclineResponseURL" :value="payInAdvanceResponseUrl" />
|
||||
<input type="hidden" name="sgErrorResponseURL" :value="payInAdvanceResponseUrl" />
|
||||
|
||||
<input type="hidden" name="sgheaderline1" :value="getHeaderLine1" />
|
||||
<input type="hidden" name="sgHeader1subtitle" value="" />
|
||||
<input type="hidden" name="sgheaderline2" :value="getHeaderLine2" />
|
||||
<input type="hidden" name="sgheaderline3" value="" />
|
||||
<input type="hidden" name="sgheaderline4" value="" />
|
||||
<input type="hidden" name="sgheaderline5" value="*Required information" />
|
||||
|
||||
<input type="hidden" name="billTo_firstName" :value="firstName" />
|
||||
<input type="hidden" name="billTo_firstNameShow" value="true" />
|
||||
<input type="hidden" name="sghopmiddleInitialShow" value="false" />
|
||||
<input type="hidden" name="billTo_lastName" :value="lastName" />
|
||||
<input type="hidden" name="billTo_lastNameShow" value="true" />
|
||||
|
||||
<input type="hidden" name="billTo_street1" value="" />
|
||||
<input type="hidden" name="billTo_street2" value="" />
|
||||
<input type="hidden" name="billTo_city" value="" />
|
||||
<input type="hidden" name="billTo_state" value="" />
|
||||
|
||||
<input type="hidden" name="billTo_postalCode" value="" />
|
||||
<input type="hidden" name="billTo_postalCodeShow" value="true" />
|
||||
<input type="hidden" name="billTo_postalCodeEnable" value="true" />
|
||||
<input type="hidden" name="sgLabelPostalCode" value="Billing ZIP" />
|
||||
|
||||
<input type="hidden" name="sgtotalamount" :value="displayAmount" />
|
||||
<input type="hidden" name="totalAmountDecimal" :value="totalAmount" />
|
||||
<input type="hidden" name="lineItems" :value="payInAdvanceLineItems" />
|
||||
|
||||
<input type="hidden" name="sgdiscountstrikethruamount" value="" />
|
||||
|
||||
<input type="hidden" name="callerDisplayText" value="" />
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name="sgtermsofusedisplaytext"
|
||||
value="By selecting submit, I agree to Safelite's" />
|
||||
<input type="hidden" name="sgtermsofuseurl" value="http://www.safelite.com/terms-of-use/" />
|
||||
<input type="hidden" name="sgtermsofuselinkdisplaytext" value="terms of use" />
|
||||
<input type="hidden" name="sgtermsofcancelrefunddisplaytext" value="and" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="sgtermsofcancelrefundlinkdisplaytext"
|
||||
value="cancellation and refund policy" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="sgtermsofcancelrefundurl"
|
||||
value="http://www.safelite.com/cancellation-refund-policy" />
|
||||
|
||||
<input
|
||||
type="hidden"
|
||||
name="sgErrorMessageCardVerification"
|
||||
value="Credit card could not be processed" />
|
||||
<input
|
||||
type="hidden"
|
||||
name="sgErrorMessageTimeOut"
|
||||
value="For your security, this transaction has been timed out." />
|
||||
|
||||
<input type="hidden" name="sgLabelCardNumber" value="" />
|
||||
<input type="hidden" name="sgLabelAddressLine1" :value="address1" />
|
||||
<input type="hidden" name="sgLabelAddressLine2" :value="address2" />
|
||||
<input type="hidden" name="sgLabelCity" :value="city" />
|
||||
<input type="hidden" name="sgLabelState" :value="state" />
|
||||
|
||||
<input type="hidden" name="sgCtu" :value="ctu" />
|
||||
<input type="hidden" name="sgWorkOrder" :value="workOrderNumber" />
|
||||
<input type="hidden" name="sgEmailAddress" :value="emailAddress" />
|
||||
<input type="hidden" name="paypalInvoiceNumber" :value="invoiceNumber" />
|
||||
<input type="hidden" name="paypalSuccessUrl" :value="payInAdvanceResponseUrl" />
|
||||
<input type="hidden" name="paypalCancelUrl" :value="payInAdvanceCancelUrl" />
|
||||
|
||||
<input type="hidden" name="sgCCDeclineURL" :value="payInAdvanceCancelUrl" />
|
||||
<input type="hidden" name="sgCCTimeoutURL" :value="payInAdvanceCancelUrl" />
|
||||
|
||||
<input type="hidden" name="sgTransactionType" value="authorization" />
|
||||
<input type="hidden" name="amount" :value="totalAmount" />
|
||||
<input type="hidden" name="ctu" :value="ctu" />
|
||||
<input type="hidden" name="orderNumber" :value="workOrderNumber" />
|
||||
|
||||
<input type="hidden" name="billTo_email" :value="emailAddress" />
|
||||
<input type="hidden" name="useDecisionManager" value="True" />
|
||||
<input type="hidden" name="correlationId" :value="referralCorrelationId" />
|
||||
<input type="hidden" name="sgErrorMessageCard_CVN" value="Please enter a valid CVV" />
|
||||
|
||||
<input type="hidden" name="ship_to_address_line1" :value="address1" />
|
||||
<input type="hidden" name="ship_to_address_line2" :value="address2" />
|
||||
<input type="hidden" name="ship_to_address_city" :value="city" />
|
||||
<input type="hidden" name="ship_to_address_state" :value="state" />
|
||||
<input type="hidden" name="ship_to_address_country" value="US" />
|
||||
<input type="hidden" name="ship_to_address_postal_code" :value="zipCode" />
|
||||
<input type="hidden" name="ship_to_phone" :value="phoneNumber" />
|
||||
|
||||
<input type="hidden" name="calling_application" value="NextGen" />
|
||||
</form>
|
||||
</template>
|
||||
<script>
|
||||
// Components
|
||||
|
|
@ -26,11 +164,17 @@ import siteHeader from '@/iss-components/site-header/site-header.vue';
|
|||
import siteFooter from '@/iss-components/site-footer/site-footer.vue';
|
||||
|
||||
// Supporting files
|
||||
import applicationConfig from '@/constants/application-config.js';
|
||||
import { fetchCmsContentForPage } from '@/helpers/cms-content-helper';
|
||||
import settleAllPromises from '@/helpers/layout-helper';
|
||||
import { Form } from 'vee-validate';
|
||||
import BaseFormMixin from '@/mixins/base-form-mixin.js';
|
||||
import { useMainStore } from '@/store';
|
||||
import iframeResize from '../../../node_modules/iframe-resizer/js/iframeResizer.js';
|
||||
import externalUrls from '@/router/router-constants/externalUrl-values';
|
||||
import widgetFields from '@/constants/cms-widget-fields.js';
|
||||
import paymentMethods from '@/constants/payment-method-constants';
|
||||
import { AppointmentTypeStrings } from '@/constants/schedule-constants';
|
||||
|
||||
export default {
|
||||
name: 'payment-page',
|
||||
|
|
@ -40,23 +184,47 @@ export default {
|
|||
// eslint-disable-next-line vue/no-reserved-component-names
|
||||
Form
|
||||
},
|
||||
directives: {
|
||||
resize: {
|
||||
mounted(el) {
|
||||
el.addEventListener('load', () => {
|
||||
iframeResize({ checkOrigin: false }, el);
|
||||
});
|
||||
},
|
||||
unmounted(el) {
|
||||
el.iFrameResizer.removeListeners();
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [BaseFormMixin],
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.issPage);
|
||||
|
||||
const paymentSignaturePromise = await useMainStore().getPaymentSignature();
|
||||
|
||||
// Settle promises and get results
|
||||
const promiseResultMap = [
|
||||
{
|
||||
resultKey: 'cmsContent',
|
||||
promise: cmsContentPromise
|
||||
}];
|
||||
},
|
||||
{
|
||||
resultKey: 'paymentSignature',
|
||||
promise: paymentSignaturePromise
|
||||
}
|
||||
];
|
||||
|
||||
// use resultMap to populate layout content.
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
||||
next((vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
|
||||
vm.$nextTick(() => {
|
||||
vm.fetchSignatureInfo(resultMap.paymentSignature);
|
||||
vm.setIFrameListener();
|
||||
});
|
||||
});
|
||||
},
|
||||
setup() {
|
||||
|
|
@ -64,20 +232,264 @@ export default {
|
|||
return { mainStore };
|
||||
},
|
||||
data() {
|
||||
|
||||
return {
|
||||
checkoutUrl: externalUrls.SAFELITE_HOP,
|
||||
payInAdvanceResponseUrl: applicationConfig.PAY_IN_ADVANCE_RESPONSE_URL,
|
||||
payInAdvanceCancelUrl: applicationConfig.PAY_IN_ADVANCE_CANCEL_URL,
|
||||
paymentType: this.getPaymentType(),
|
||||
authToken: '',
|
||||
authSignature: '',
|
||||
authSignatureStart: '',
|
||||
referralSequenceNumber: useMainStore().order.referralSequenceNumber,
|
||||
emailAddress: useMainStore().order.customer.emailAddress,
|
||||
address1: this.getAddress1(),
|
||||
address2: this.getAddress2(),
|
||||
city: this.getCity(),
|
||||
state: this.getState(),
|
||||
zipCode: this.getZipCode(),
|
||||
firstName: useMainStore().order.customer.firstName,
|
||||
lastName: useMainStore().order.customer.lastName,
|
||||
phoneNumber: useMainStore().order.customer.phoneNumber,
|
||||
ctu: useMainStore().order.serviceLocation.zipCodeCtu,
|
||||
referralCorrelationId: useMainStore().order.referralCorrelationId,
|
||||
workOrderNumber: this.getWorkOrderNumber(),
|
||||
invoiceNumber: this.getInvoiceNumber(),
|
||||
totalAmount: this.getAmountDue(),
|
||||
displayAmount: this.getDisplayAmountDue(),
|
||||
payInAdvanceLineItems: '',
|
||||
shouldBlockInteraction: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
dynamicCSSUrl() {
|
||||
const { protocol, hostname, port } = window.location;
|
||||
return `${protocol}//${hostname}:${port}/css/site-2020Styling.css`;
|
||||
},
|
||||
dynamicHopCSSUrl() {
|
||||
const { protocol, hostname, port } = window.location;
|
||||
return `${protocol}//${hostname}:${port}/css/hop-styling.css`;
|
||||
},
|
||||
getHeaderLine1() {
|
||||
if (!this.isPaypal) {
|
||||
return this.getCmsContent('PayInAdvanceHeaderLine1', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
getHeaderLine2() {
|
||||
if (!this.isPaypal) {
|
||||
return this.getCmsContent('PayInAdvanceHeaderLine2', widgetFields.TEXT_BLOCK_WIDGET.TEXT);
|
||||
}
|
||||
return '';
|
||||
},
|
||||
isPaypal() {
|
||||
if (this.paymentType === 'pp') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
methods:
|
||||
{
|
||||
forwardButtonAction() {
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route);
|
||||
},
|
||||
navigateForward() {
|
||||
{
|
||||
arePagePrerequisitesValid() {
|
||||
// Line Items
|
||||
const packageReqs = !!useMainStore().order.lineItems.supportingItems;
|
||||
|
||||
// Service Location
|
||||
const { serviceLocation } = useMainStore().order;
|
||||
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 = useMainStore().order.payment.isInsurance !== null;
|
||||
|
||||
// Schedule
|
||||
const { schedule } = useMainStore().order;
|
||||
const scheduleReqs = !!(
|
||||
schedule.date
|
||||
&& schedule.startTime
|
||||
&& schedule.endTime
|
||||
&& schedule.jobMaxMinutes
|
||||
&& schedule.jobMinMinutes
|
||||
);
|
||||
|
||||
// Customer
|
||||
const { customer } = useMainStore().order;
|
||||
const customerReqs = !!(
|
||||
customer.firstName
|
||||
&& customer.lastName
|
||||
&& customer.phoneNumber
|
||||
&& customer.emailAddress
|
||||
);
|
||||
|
||||
const paymentMethodReqs =
|
||||
useMainStore().order.payment.isPayInAdvance !== null
|
||||
&& (useMainStore().order.payment.isPayInAdvance || !!useMainStore().order.payment.payInAdvanceType);
|
||||
|
||||
return (
|
||||
packageReqs
|
||||
&& serviceLocationReqs
|
||||
&& isInsuranceSet
|
||||
&& scheduleReqs
|
||||
&& customerReqs
|
||||
&& paymentMethodReqs
|
||||
);
|
||||
},
|
||||
getWorkOrderNumber() {
|
||||
const { workOrderNumber } = useMainStore().order;
|
||||
if (workOrderNumber) {
|
||||
const items = workOrderNumber.split('-');
|
||||
if (items.length > 1) {
|
||||
return items[1];
|
||||
}
|
||||
}
|
||||
//this.backButtonAction();
|
||||
return undefined;
|
||||
},
|
||||
getInvoiceNumber() {
|
||||
const { workOrderNumber } = useMainStore().order;
|
||||
if (workOrderNumber) {
|
||||
return workOrderNumber.replace('-', '');
|
||||
}
|
||||
//this.backButtonAction();
|
||||
return undefined;
|
||||
},
|
||||
getAddress1() {
|
||||
return useMainStore().order.serviceLocation.address
|
||||
? useMainStore().order.serviceLocation.address
|
||||
: useMainStore().order.serviceLocation.provider.address.streetAddress;
|
||||
},
|
||||
getAddress2() {
|
||||
return useMainStore().order.serviceLocation.address2
|
||||
? useMainStore().order.serviceLocation.address2
|
||||
: null;
|
||||
},
|
||||
getCity() {
|
||||
return useMainStore().order.serviceLocation.city
|
||||
? useMainStore().order.serviceLocation.city
|
||||
: useMainStore().order.serviceLocation.provider.address.city;
|
||||
},
|
||||
getState() {
|
||||
return useMainStore().order.serviceLocation.state
|
||||
? useMainStore().order.serviceLocation.state
|
||||
: useMainStore().order.serviceLocation.provider.address.state;
|
||||
},
|
||||
getZipCode() {
|
||||
return useMainStore().order.serviceLocation.zipCode
|
||||
? useMainStore().order.serviceLocation.zipCode
|
||||
: useMainStore().order.serviceLocation.provider.address.zipCode;
|
||||
},
|
||||
getPaymentType() {
|
||||
switch (useMainStore().order.payment.payInAdvanceType) {
|
||||
case paymentMethods.AFTERPAY:
|
||||
return 'ap';
|
||||
case paymentMethods.CREDIT_CARD:
|
||||
return 'cc';
|
||||
case paymentMethods.PAYPAL:
|
||||
return 'pp';
|
||||
default:
|
||||
return useMainStore().payment.payInAdvanceType;
|
||||
}
|
||||
},
|
||||
getAmountDue() {
|
||||
return 0;
|
||||
},
|
||||
getDisplayAmountDue() {
|
||||
return 0;
|
||||
},
|
||||
fetchSignatureInfo(signatureInfo) {
|
||||
this.authToken = signatureInfo.token;
|
||||
this.authSignature = signatureInfo.signature;
|
||||
this.authSignatureStart = signatureInfo.startDate;
|
||||
|
||||
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', '*');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
handleIFrameContentWindowMessage(event) {
|
||||
if (typeof event.data === 'string') {
|
||||
if (event.data.indexOf('afterpayClosed') > -1) {
|
||||
this.backButtonAction();
|
||||
}
|
||||
if (event.data.indexOf('creditCardSubmit') > -1) {
|
||||
this.setUIBlock(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
setIFrameListener() {
|
||||
window.addEventListener('message', (event) =>
|
||||
this.handleIFrameContentWindowMessage(event));
|
||||
},
|
||||
setUIBlock(val) {
|
||||
this.shouldBlockInteraction = val;
|
||||
},
|
||||
supressClick(event) {
|
||||
if (this.shouldBlockInteraction) {
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
backButtonAction() {
|
||||
// page will not render with normal navigation due to navigating from the iframe
|
||||
window.location = this.payInAdvanceCancelUrl;
|
||||
},
|
||||
forwardButtonAction() {
|
||||
this.$router.navigate(this.navigationScenarios.CLICKED_FORWARD, this.$route);
|
||||
},
|
||||
navigateForward() {
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.payment p{
|
||||
margin-bottom:0.75rem;
|
||||
}
|
||||
|
||||
.hop-iframe {
|
||||
position: relative;
|
||||
min-height: 40.625rem;
|
||||
width: 100%;
|
||||
border: 0 none;
|
||||
}
|
||||
|
||||
.ui-block {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
5
src/router/router-constants/externalUrl-values.js
Normal file
5
src/router/router-constants/externalUrl-values.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
const externalUrls = {
|
||||
SAFELITE_HOP: process.env.VUE_APP_SAFELITE_HOP
|
||||
};
|
||||
|
||||
export default externalUrls;
|
||||
|
|
@ -2144,6 +2144,13 @@ export const useMainStore = defineStore({
|
|||
const isPayInAdvance = paymentMethod !== paymentMethods.PAY_AT_TIME_OF_SERVICE;
|
||||
this.order.payment.isPayInAdvance = isPayInAdvance;
|
||||
this.order.payment.payInAdvanceType = isPayInAdvance ? paymentMethod : null;
|
||||
},
|
||||
|
||||
getPaymentSignature() {
|
||||
return globalMethods.callHttpClient({
|
||||
method: endpoints.GetPaymentSignature.method,
|
||||
endpoint: endpoints.GetPaymentSignature.url
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
process.env.VUE_APP_CONSUMER_CF_DISTRO = 'https://digitalapi.dev.safelite.io';
|
||||
process.env.VUE_APP_CURRENT_ENVIRONMENT = 'Localhost';
|
||||
process.env.VUE_APP_GOOGLE_PLACES_API_KEY = 'AIzaSyCuLhQcDdZTTb4JzpUFms1OCch2dk5lHF0';
|
||||
process.env.VUE_APP_SAFELITE_HOP = 'https://sv2-safelitehop-sys.safelite.com/fmgCheckoutEmbedded.aspx';
|
||||
|
||||
// GA & GTM
|
||||
// NOTE: Using the old ISS site GTM Cotnainer ID for now, will create a new one soon.
|
||||
|
|
|
|||
Loading…
Reference in a new issue