Merge branch 'develop' into feature/CSR-1384-modals-for-add-vaps
This commit is contained in:
commit
c75c406c50
33 changed files with 1029 additions and 8536 deletions
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 on this folder only:
|
||||
|
||||
```bash
|
||||
sass --no-source-map --watch public/css/hop-styling.scss:public/css/hop-styling.css
|
||||
```
|
||||
This will output a CSS file that can be consumed by the Payment page.
|
||||
|
||||
# Do not use the .css file on its own. You must use the .scss file and have Sass compile it to the .css file.
|
||||
|
|
@ -1,336 +1,194 @@
|
|||
.btn-group-lg > .btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 20px;
|
||||
line-height: 1.3;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.btn-group-sm > .btn {
|
||||
padding: 3px 6px;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.btn-group-xs > .btn {
|
||||
padding: 1px 5px;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.dl-horizontal dd:before,
|
||||
.dl-horizontal dd:after,
|
||||
.container:before,
|
||||
.container:after,
|
||||
.container-fluid:before,
|
||||
.container-fluid:after,
|
||||
.row:before,
|
||||
.row:after,
|
||||
.form-horizontal .form-group:before,
|
||||
.form-horizontal .form-group:after,
|
||||
.btn-toolbar:before,
|
||||
.btn-toolbar:after,
|
||||
.btn-group-vertical > .btn-group:before,
|
||||
.btn-group-vertical > .btn-group:after,
|
||||
.panel-body:before,
|
||||
.panel-body:after,
|
||||
.modal-footer:before,
|
||||
.modal-footer:after {
|
||||
content: " ";
|
||||
display: table;
|
||||
}
|
||||
.dl-horizontal dd:after,
|
||||
.container:after,
|
||||
.container-fluid:after,
|
||||
.row:after,
|
||||
.form-horizontal .form-group:after,
|
||||
.btn-toolbar:after,
|
||||
.btn-group-vertical > .btn-group:after,
|
||||
.panel-body:after,
|
||||
.modal-footer:after {
|
||||
clear: both;
|
||||
}
|
||||
[data-icon]:before,
|
||||
[data-icon-after]:after,
|
||||
.ico:before {
|
||||
speak: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-transform: none !important;
|
||||
font-weight: normal !important;
|
||||
font-style: normal !important;
|
||||
font-variant: normal !important;
|
||||
font-size: 20px !important;
|
||||
font-family: "safelite-ico" !important;
|
||||
line-height: 20px !important;
|
||||
}
|
||||
html {
|
||||
position: static !important;
|
||||
height: auto !important;
|
||||
}
|
||||
html,
|
||||
/* 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 {
|
||||
background-color: #ffffff !important;
|
||||
}
|
||||
body {
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
.headerlinecontainer {
|
||||
color: #000000;
|
||||
font-family: Roboto, Arial, "Helvetica Neue", Helvetica, Tahoma, Verdana, sans-serif;
|
||||
}
|
||||
.headerline1 {
|
||||
display: block;
|
||||
margin-bottom: 11.5px;
|
||||
font-weight: 300;
|
||||
font-size: 20px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.headerline2,
|
||||
.headerline3,
|
||||
.headerline4,
|
||||
.headerline5 {
|
||||
margin-bottom: 11.5px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.headerline3 {
|
||||
color: #0c7e47;
|
||||
}
|
||||
.headerline5 {
|
||||
display: block;
|
||||
padding: 11.5px 0;
|
||||
color: #167cac;
|
||||
font-style: italic;
|
||||
}
|
||||
.headerline5v2 {
|
||||
display: block;
|
||||
padding: 11.5px 0;
|
||||
color: #da291c;
|
||||
font-style: italic;
|
||||
font-size: 12px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.form-group .control-label {
|
||||
display: block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
.form-group .form-control {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
@media (min-width: 500px) {
|
||||
.form-group {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
@media (min-width: 800px) {
|
||||
.form-group {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
@media (min-width: 576px) {
|
||||
#cardExpirationContainer .card_expirationMonth,
|
||||
#cardExpirationContainer .card_expirationYear {
|
||||
position: relative;
|
||||
width: 49%;
|
||||
}
|
||||
#cardExpirationContainer .card_expirationMonth {
|
||||
float: left;
|
||||
}
|
||||
#cardExpirationContainer .card_expirationYear {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.totalContainer {
|
||||
margin: 16px 0;
|
||||
font-family: Roboto;
|
||||
font-weight: 400;
|
||||
color: #4D5151;
|
||||
margin: 0;
|
||||
background-color: white;
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
background-color: #0c7e47;
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
}
|
||||
.totalContainer em {
|
||||
font-weight: 500;
|
||||
}
|
||||
.totalContainer .strikeThrough {
|
||||
padding-left: 8px;
|
||||
text-decoration: line-through;
|
||||
font-size: 14px;
|
||||
}
|
||||
.callerDisplayTextContainer {
|
||||
margin: 16px 0;
|
||||
font-style: italic;
|
||||
}
|
||||
.disclaimerContainer {
|
||||
margin: 16px 0;
|
||||
padding: 8px;
|
||||
border-radius: 5px;
|
||||
background-color: #f0f1f2;
|
||||
}
|
||||
.disclaimerContainerv2 {
|
||||
margin: 16px 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.buttonContainer #sghopcancelbutton {
|
||||
float: left;
|
||||
}
|
||||
.buttonContainer #sghopsubmitbutton {
|
||||
float: right;
|
||||
}
|
||||
.buttonContainer #sghopsubmitbutton.creditCardSpecific {
|
||||
float: right;
|
||||
}
|
||||
@media (max-width: 500px) {
|
||||
.buttonContainer #sghopsubmitbutton.creditCardSpecific {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.buttonContainer #selectPaymentTypeButton {
|
||||
float: right;
|
||||
}
|
||||
@media (max-width: 500px) {
|
||||
.buttonContainer #selectPaymentTypeButton {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.globalMessage .message {
|
||||
padding-left: 0;
|
||||
line-height: 1.25;
|
||||
}
|
||||
.globalMessage .message strong {
|
||||
color: #da291c;
|
||||
}
|
||||
.italicSmall {
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
font-size: 15px;
|
||||
}
|
||||
#pageLoadingModal {
|
||||
background-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");
|
||||
}
|
||||
#pageLoadingModal .modal-content {
|
||||
margin-top: 100px;
|
||||
}
|
||||
#paypalParentDiv {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
#creditCardParentDiv {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.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 label,
|
||||
.radio .list-group.paymentSelection a,
|
||||
.radio.list-group.paymentSelection a {
|
||||
max-height: 52px;
|
||||
}
|
||||
}
|
||||
#creditCardParentLink {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@media (max-width: 33.9em) {
|
||||
#creditCardParentLink {
|
||||
min-height: 57px;
|
||||
}
|
||||
}
|
||||
#creditCardImages,
|
||||
#paypalImageSpan {
|
||||
padding-right: 0;
|
||||
}
|
||||
@media (max-width: 33.9em) {
|
||||
.paymentOptionText {
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
.extraPaddingTop {
|
||||
padding-top: 20px;
|
||||
}
|
||||
.extraPaddingBottom {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
@media (min-width: 33.9em) {
|
||||
#paypalImage {
|
||||
max-width: 22%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 33.9em) {
|
||||
#paypalImage {
|
||||
max-width: 55px;
|
||||
}
|
||||
}
|
||||
label.centerme {
|
||||
position: inherit;
|
||||
display: table-cell;
|
||||
width: 9999px !important;
|
||||
/*This is kind of a hack*/
|
||||
vertical-align: middle;
|
||||
}
|
||||
input[name="rdioCreditCard"] {
|
||||
display: block;
|
||||
}
|
||||
@media (min-width: 33.9em) {
|
||||
input[name="rdioCreditCard"] {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 33.9em) {
|
||||
span.paymentOptionText {
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
.headerline1.safelitehop {
|
||||
margin-top: 20px;
|
||||
}
|
||||
@media (max-width: 499px) {
|
||||
#buttonContainer {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.has-success .control-label {
|
||||
color: #4d4e53;
|
||||
}
|
||||
#thm_fp {
|
||||
display: block;
|
||||
}
|
||||
#paypalParentLink label,
|
||||
#creditCardParentLink label {
|
||||
padding-top: 9px;
|
||||
padding-bottom: 9px;
|
||||
}
|
||||
#paypalParentLink label .paymentOptionText,
|
||||
#creditCardParentLink label .paymentOptionText {
|
||||
padding-left: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
#paypalParentLink {
|
||||
margin-top: 12px;
|
||||
}
|
||||
html #creditCardParentLink.list-group-item {
|
||||
border-radius: 48px;
|
||||
text-align: center;
|
||||
}
|
||||
.optional-label span {
|
||||
body .validation-info {
|
||||
display: none;
|
||||
}
|
||||
.optional-label::after {
|
||||
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;
|
||||
}
|
||||
body input,
|
||||
body select {
|
||||
margin-top: 4px;
|
||||
}
|
||||
body input {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #8E9292;
|
||||
padding: 16px;
|
||||
}
|
||||
body input:focus, body input:focus-visible {
|
||||
box-shadow: 0 0 0 2.5px #1574a1;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
body input:disabled, body input.disabled {
|
||||
background-color: #f5f5f5;
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
body input:disabled:hover, body input.disabled:hover {
|
||||
box-shadow: 0 0 0 4px transparent;
|
||||
border: 1px solid #8e9292;
|
||||
}
|
||||
body input: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;
|
||||
}
|
||||
body .creditCardSpecific div {
|
||||
padding: 8px 0;
|
||||
}
|
||||
body .creditCardSpecific div .headerlinecontainer {
|
||||
padding: 0;
|
||||
}
|
||||
body .creditCardSpecific div label {
|
||||
font-weight: 500;
|
||||
}
|
||||
body .creditCardSpecific div:first-child {
|
||||
display: none;
|
||||
}
|
||||
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;
|
||||
}
|
||||
.creditCardSpecific {
|
||||
display: none;
|
||||
body .buttonContainer {
|
||||
height: 48px;
|
||||
}
|
||||
@media (max-width: 500px) {
|
||||
.buy-backdrop.afterpay-checkout-wrapper {
|
||||
-webkit-box-align: start;
|
||||
-ms-flex-align: start;
|
||||
align-items: flex-start;
|
||||
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 {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
220
public/css/hop-styling.scss
Normal file
220
public/css/hop-styling.scss
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/* 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: #4D5151;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
select {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
input {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #8E9292;
|
||||
padding: 16px;
|
||||
&:focus,
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 2.5px #1574a1;
|
||||
border: none;
|
||||
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;
|
||||
}
|
||||
|
||||
.creditCardSpecific {
|
||||
div {
|
||||
padding: 8px 0;
|
||||
.headerlinecontainer {
|
||||
padding: 0;
|
||||
}
|
||||
label {
|
||||
font-weight: 500;
|
||||
}
|
||||
&:first-child {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#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 {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
&: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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -21,6 +21,10 @@ const applicationConfig = {
|
|||
"//" +
|
||||
location.host +
|
||||
"/fmg/?fmgPage=payment-method&src=concept-funnel",
|
||||
GOOGLE_CALENDAR: "https://www.google.com/calendar/render?action=TEMPLATE",
|
||||
YAHOO_CALENDAR: "https://calendar.yahoo.com/?v=60",
|
||||
OUTLOOK_CALENDAR:
|
||||
"https://outlook.office.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent",
|
||||
};
|
||||
|
||||
export { applicationConfig };
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ const storeActions = {
|
|||
SAVE_PIA_ERROR_CODE: "savePiaErrorCode",
|
||||
SAVE_PIA_WORK_ORDER: "savePiaWorkOrder",
|
||||
SAVE_CCTOKEN: "saveCCToken",
|
||||
SAVE_PAYPAL_TOKEN: "savePaypalToken",
|
||||
};
|
||||
|
||||
export { storeActions };
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ const storeMutations = {
|
|||
UPDATE_PIA_ERROR_CODE: "updatePiaErrorCode",
|
||||
UPDATE_PIA_WORK_ORDER: "updatePiaWorkOrder",
|
||||
UPDATE_CCTOKEN: "updateCCToken",
|
||||
UPDATE_PAYPAL_TOKEN: "updatePaypalToken",
|
||||
|
||||
// VEHICLE MUTATIONS
|
||||
UPDATE_YEAR: "updateYear",
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ https://safelite.atlassian.net/wiki/spaces/DC/pages/76644418/Button+Question+Com
|
|||
:isWide="isWide"
|
||||
:validationRules="validationRules"
|
||||
:textPosition="textPosition"
|
||||
:additionalButtonData="additionalButtonData"
|
||||
:additionalButtonData="answer.additionalButtonData"
|
||||
:lastValuePushedToGa="lastValuePushedToGa"
|
||||
:setLastValuePushedToGa="setLastValuePushedToGa"
|
||||
:suppressError="suppressError"
|
||||
|
|
@ -252,6 +252,7 @@ export default {
|
|||
buttonFooterCopy: answer.buttonFooterCopy ?? answer.buttonFooterCopy,
|
||||
buttonImage: answer.buttonImage ?? answer.AnswerImageUrl,
|
||||
buttonImageId: answer.buttonImageId ?? answer.ImageId,
|
||||
additionalButtonData: answer.additionalButtonData ?? answer.additionalButtonData,
|
||||
groupName: this.formatString(this.groupName),
|
||||
value:
|
||||
answer.value ??
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<vehicleBanner
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
:displayGenericVehicleImage="false" />
|
||||
|
|
|
|||
|
|
@ -10,8 +10,33 @@ export const promoPartNumberStrings = {
|
|||
GLASS_CLEANER_DISCOUNT_PART_NUMBER: "DISC GLASS CLN",
|
||||
};
|
||||
|
||||
export const addableVapsPromoPartNumbers = [
|
||||
promoPartNumberStrings.RAIN_DEFENSE_DISCOUNT_PART_NUMBER,
|
||||
promoPartNumberStrings.WIPER_DISCOUNT_PART_NUMBER,
|
||||
];
|
||||
|
||||
export const pagesToStripPromoQueryStringFrom = ["quote", "payment-method"];
|
||||
|
||||
export function getPromosWithAddableVaps(promoList) {
|
||||
if (!promoList.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return promoList.filter((promo) => addableVapsPromoPartNumbers.includes(promo.partNumber));
|
||||
}
|
||||
|
||||
export function getLineItemsThatMatchPromos(promos, availableLineItems) {
|
||||
const matchingLineItems = [];
|
||||
promos.forEach((promo) => {
|
||||
promo.discountedLineItemIds.forEach((discountedLineItemId) => {
|
||||
matchingLineItems.push(
|
||||
...availableLineItems.filter((lineItem) => lineItem.id === discountedLineItemId)
|
||||
);
|
||||
});
|
||||
});
|
||||
return matchingLineItems;
|
||||
}
|
||||
|
||||
export function getAddableVapsFromAvailableLineItems(availableLineItems) {
|
||||
const addableVaps = [];
|
||||
addableVaps.push(...findLineItemsWithPartType(partTypeStrings.FRONT_WIPER, availableLineItems));
|
||||
|
|
|
|||
|
|
@ -1,167 +0,0 @@
|
|||
<template>
|
||||
<div class="calendar-section">
|
||||
<div class="add-to-calendar">
|
||||
<button v-on:click="openCalendarModal">
|
||||
<span class="add-to-calendar-span">
|
||||
<img src="@/assets/img/icons/add-to-calendar.svg" class="add-to-calendar-img" />
|
||||
<span class="add-to-calendar-text">Add to calendar</span></span
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
<calendarModalQuestion
|
||||
ref="calendarModalQuestion"
|
||||
customComponentId="calendarModalQuestion"
|
||||
cmsWidgetName="CalendarModalQuestion"
|
||||
@calendar-modal-closed="calendarModalClosed"
|
||||
:calendarOptionsData="calendarValues"
|
||||
v-model="selectedCalendarOption">
|
||||
</calendarModalQuestion>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { calendarOptions } from "@/constants/calendar-options";
|
||||
import { calendarStatus } from "@/constants/calendar-status";
|
||||
import calendarModalQuestion from "@/layouts/add-to-calendar/calendar-modal-question/calendar-modal-question";
|
||||
import { getDateFormat } from "@/helpers/date-helper";
|
||||
import { getCalendarFile, download } from "@/helpers/add-to-calendar-helper";
|
||||
|
||||
export default {
|
||||
name: "add-to-calendar",
|
||||
components: {
|
||||
calendarModalQuestion,
|
||||
},
|
||||
props: {
|
||||
appointment: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedCalendarOption: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
calendarValues: {
|
||||
get: function () {
|
||||
var obj = [];
|
||||
const options = Object.values(calendarOptions);
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
obj[i] = this.getCalendarData(options[i]);
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectedCalendarOption(newValue) {
|
||||
if (newValue) {
|
||||
this.setCalendarAppointment(newValue);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
setCalendarAppointment(calendarOption) {
|
||||
if (
|
||||
calendarOption.name.includes(calendarOptions.ICAL) ||
|
||||
calendarOption.name.includes(calendarOptions.OUTLOOK)
|
||||
) {
|
||||
this.getAppointment();
|
||||
} else {
|
||||
window.open(calendarOption.url);
|
||||
}
|
||||
},
|
||||
calendarModalClosed() {
|
||||
// Clear the selectedOption if close the modal
|
||||
this.selectedCalendarOption = null;
|
||||
},
|
||||
openCalendarModal() {
|
||||
this.$refs["calendarModalQuestion"].openModal();
|
||||
},
|
||||
getCalendarData(type) {
|
||||
var URL = "";
|
||||
const dateFormat = "yyyyMMddTHHmmss";
|
||||
const outlookComTimeSpanFormat = "yyyy-MM-ddTHH:mm:ss";
|
||||
if (type == calendarOptions.OUTLOOKCOM) {
|
||||
URL = `https://outlook.office.com/calendar/deeplink/compose?path=/calendar/action/compose&rru=addevent&startdt=${encodeURIComponent(
|
||||
getDateFormat(this.appointment.StartDate, outlookComTimeSpanFormat)
|
||||
)}&enddt=${encodeURIComponent(
|
||||
getDateFormat(this.appointment.EndDate, outlookComTimeSpanFormat)
|
||||
)}&subject=${encodeURIComponent(
|
||||
this.appointment.Subject
|
||||
)}&body=${encodeURIComponent(this.appointment.Body)}&location=${encodeURIComponent(
|
||||
this.appointment.Location
|
||||
)}`;
|
||||
}
|
||||
if (type == calendarOptions.GOOGLE) {
|
||||
URL = `https://www.google.com/calendar/render?action=TEMPLATE&text=${encodeURIComponent(
|
||||
this.appointment.Subject
|
||||
)}&dates=${encodeURIComponent(
|
||||
getDateFormat(this.appointment.StartDate, dateFormat)
|
||||
)}/${encodeURIComponent(
|
||||
getDateFormat(this.appointment.EndDate, dateFormat)
|
||||
)}&details=${encodeURIComponent(
|
||||
this.appointment.Body
|
||||
)}&location=${encodeURIComponent(this.appointment.Location)}&sf=true&output=xml`;
|
||||
}
|
||||
if (type == calendarOptions.YAHOO) {
|
||||
URL = `https://calendar.yahoo.com/?v=60&TITLE=${encodeURIComponent(
|
||||
this.appointment.Subject
|
||||
)}&DESC=${encodeURIComponent(this.appointment.Body)}&ST=${encodeURIComponent(
|
||||
getDateFormat(this.appointment.StartDate, dateFormat)
|
||||
)}&DUR=${this.appointment.Duration}&in_loc=${encodeURIComponent(
|
||||
this.appointment.Location
|
||||
)}`;
|
||||
}
|
||||
return {
|
||||
url: URL,
|
||||
name: type,
|
||||
icon: require(`@/assets/img/icons/${type}.svg`),
|
||||
};
|
||||
},
|
||||
getAppointment() {
|
||||
let body = this.appointment.Body;
|
||||
body = body.replace("|", "<").replace("~", ">");
|
||||
|
||||
const calFile = {
|
||||
Location: this.appointment.Location,
|
||||
Body: body,
|
||||
IsHTML: this.appointment.IsHTML,
|
||||
UniqueId: this.appointment.RefrrlSeqNum,
|
||||
Subject: this.appointment.Subject,
|
||||
StartDate: this.appointment.StartDate,
|
||||
EndDate: this.appointment.EndDate,
|
||||
Status: calendarStatus.BUSY,
|
||||
};
|
||||
var calBody = getCalendarFile(calFile);
|
||||
download("SafeliteAppointment.ics", calBody);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.add-to-calendar-text {
|
||||
margin: 0 0 0 7px;
|
||||
color: #1574a1;
|
||||
vertical-align: middle;
|
||||
font-weight: 500;
|
||||
font-family: "Roboto";
|
||||
}
|
||||
.add-to-calendar button {
|
||||
border: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
.calendar-section {
|
||||
display: table;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.calendar-section .add-to-calendar {
|
||||
padding-top: 15px;
|
||||
}
|
||||
.calendar-section .add-to-calendar .add-to-calendar-span {
|
||||
cursor: pointer;
|
||||
}
|
||||
.calendar-section .add-to-calendar .add-to-calendar-img {
|
||||
display: inline;
|
||||
width: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// Components
|
||||
import addToCalendar from "@/layouts/add-to-calendar/add-to-calendar.vue";
|
||||
import addToCalendar from "@/layouts/confirmation/add-to-calendar/add-to-calendar.vue";
|
||||
import { calendarOptions } from "@/constants/calendar-options";
|
||||
import { AppointmentTypeStrings, RouteCodeFlags } from "@/constants/schedule-constants";
|
||||
|
||||
|
|
@ -176,11 +176,20 @@ describe("Add-to-calendar methods...", () => {
|
|||
});
|
||||
});
|
||||
|
||||
var appointmentText = "Appointment content";
|
||||
function setupMocks({ customMountOptions }) {
|
||||
const mountOptions = getMountOptions({
|
||||
...customMountOptions,
|
||||
});
|
||||
|
||||
mountOptions.mixins = [
|
||||
{
|
||||
methods: {
|
||||
getCmsContent: jest.fn().mockImplementation(() => {
|
||||
return appointmentText;
|
||||
}),
|
||||
},
|
||||
},
|
||||
];
|
||||
const wrapper = shallowMount(addToCalendar, mountOptions);
|
||||
wrapper.vm.$refs.calendarModalQuestion.openModal = jest.fn();
|
||||
return { wrapper };
|
||||
314
src/layouts/confirmation/add-to-calendar/add-to-calendar.vue
Normal file
314
src/layouts/confirmation/add-to-calendar/add-to-calendar.vue
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
<template>
|
||||
<div class="calendar-section">
|
||||
<div class="add-to-calendar">
|
||||
<button v-on:click="openCalendarModal">
|
||||
<span class="add-to-calendar-span">
|
||||
<img src="@/assets/img/icons/add-to-calendar.svg" class="add-to-calendar-img" />
|
||||
<span class="add-to-calendar-text">Add to calendar</span></span
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
<calendarModalQuestion
|
||||
ref="calendarModalQuestion"
|
||||
customComponentId="calendarModalQuestion"
|
||||
cmsWidgetName="CalendarModalQuestion"
|
||||
@calendar-modal-closed="calendarModalClosed"
|
||||
:calendarOptionsData="calendarValues"
|
||||
v-model="selectedCalendarOption">
|
||||
</calendarModalQuestion>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { calendarOptions } from "@/constants/calendar-options";
|
||||
import { calendarStatus } from "@/constants/calendar-status";
|
||||
import calendarModalQuestion from "@/layouts/confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question";
|
||||
import { getDateFormat } from "@/helpers/date-helper";
|
||||
import { AppointmentTypeStrings, RouteCodeFlags } from "@/constants/schedule-constants";
|
||||
import { getCalendarFile, download } from "@/helpers/add-to-calendar-helper";
|
||||
import {
|
||||
calculateDuration,
|
||||
combineDateAndTime,
|
||||
shortTimeString,
|
||||
addMinutes,
|
||||
} from "@/helpers/date-helper";
|
||||
import store from "@/store";
|
||||
import { serviceType } from "@/constants/service-type";
|
||||
import { applicationConfig } from "@/constants/application-config.js";
|
||||
export default {
|
||||
name: "add-to-calendar",
|
||||
components: {
|
||||
calendarModalQuestion,
|
||||
},
|
||||
props: {
|
||||
mobileWidgetName: String,
|
||||
inShopWidgetName: String,
|
||||
dropOffWidgetName: String,
|
||||
overnightDropOffWidgetName: String,
|
||||
allDayDropOffWidgetName: String,
|
||||
sameDayDropOffWidgetName: String,
|
||||
serviceLocationFullAddress: String,
|
||||
providerFullAddress: String,
|
||||
appointmentType: String,
|
||||
scheduleDate: String,
|
||||
scheduleStartTime: String,
|
||||
scheduleEndTime: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedCalendarOption: null,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
calendarValues: {
|
||||
get: function () {
|
||||
var obj = [];
|
||||
const options = Object.values(calendarOptions);
|
||||
for (var i = 0; i < options.length; i++) {
|
||||
obj[i] = this.getCalendarData(options[i]);
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
},
|
||||
IsSameDayDropOff() {
|
||||
const todaysDate = new Date().toISOString().split("T")[0];
|
||||
return this.scheduleDate === todaysDate;
|
||||
},
|
||||
AddToCalendar_Mobile_Subject() {
|
||||
return this.getCmsContent(this.mobileWidgetName, "HeaderText");
|
||||
},
|
||||
AddToCalendar_Mobile_Body() {
|
||||
return this.getCmsContent(this.mobileWidgetName, "BodyText");
|
||||
},
|
||||
AddToCalendar_InShop_Subject() {
|
||||
return this.getCmsContent(this.inShopWidgetName, "HeaderText");
|
||||
},
|
||||
AddToCalendar_InShop_Body() {
|
||||
return this.getCmsContent(this.inShopWidgetName, "BodyText");
|
||||
},
|
||||
AddToCalendar_DropOff_Subject() {
|
||||
return this.getCmsContent(this.dropOffWidgetName, "HeaderText");
|
||||
},
|
||||
AddToCalendar_DropOff_Body() {
|
||||
return this.getCmsContent(this.dropOffWidgetName, "BodyText");
|
||||
},
|
||||
AddToCalendar_OvernightDropOff_Subject() {
|
||||
return this.getCmsContent(this.overnightDropOffWidgetName, "HeaderText");
|
||||
},
|
||||
AddToCalendar_OvernightDropOff_Body() {
|
||||
return this.getCmsContent(this.overnightDropOffWidgetName, "BodyText");
|
||||
},
|
||||
AddToCalendar_AllDayDropOff_Subject() {
|
||||
return this.getCmsContent(this.allDayDropOffWidgetName, "HeaderText");
|
||||
},
|
||||
AddToCalendar_AllDayDropOff_Body() {
|
||||
return this.getCmsContent(this.allDayDropOffWidgetName, "BodyText");
|
||||
},
|
||||
AddToCalendar_SameDayDropOff_Subject() {
|
||||
return this.getCmsContent(this.sameDayDropOffWidgetName, "HeaderText");
|
||||
},
|
||||
AddToCalendar_SameDayDropOff_Body() {
|
||||
return this.getCmsContent(this.sameDayDropOffWidgetName, "BodyText");
|
||||
},
|
||||
UniqueId() {
|
||||
return store.getters.order.referralNumber?.toString();
|
||||
},
|
||||
ServiceType() {
|
||||
const isRepair = store.getters.order.damage.isRepair;
|
||||
const funnelHasRecalibrationPart = store.getters.funnelHasRecalibrationPart;
|
||||
if (!isRepair) {
|
||||
if (funnelHasRecalibrationPart) {
|
||||
return serviceType.REPLACEMENT_AND_RECALIBRATION;
|
||||
} else {
|
||||
return serviceType.REPLACEMENT;
|
||||
}
|
||||
}
|
||||
return serviceType.REPAIR;
|
||||
},
|
||||
RouteCode() {
|
||||
return store.getters.order.schedule.routeCode;
|
||||
},
|
||||
Appointment() {
|
||||
var subject = "";
|
||||
var location = "";
|
||||
var startDateTime = combineDateAndTime(this.scheduleDate, this.scheduleStartTime);
|
||||
var endDateTime = combineDateAndTime(this.scheduleDate, this.scheduleEndTime);
|
||||
var body = "";
|
||||
var isHTML = false;
|
||||
var duration = "";
|
||||
|
||||
if (this.appointmentType === AppointmentTypeStrings.MOBILE) {
|
||||
location = this.serviceLocationFullAddress?.replace("<br/>", "");
|
||||
subject = this.AddToCalendar_Mobile_Subject?.replace(
|
||||
"{custom:SERVICETYPE}",
|
||||
this.ServiceType
|
||||
);
|
||||
body = this.AddToCalendar_Mobile_Body;
|
||||
} else {
|
||||
location = this.providerFullAddress?.replace("<br/>", "");
|
||||
if (this.appointmentType === AppointmentTypeStrings.DROP_OFF) {
|
||||
if (this.RouteCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
|
||||
subject = this.AddToCalendar_OvernightDropOff_Subject;
|
||||
body = this.AddToCalendar_OvernightDropOff_Body;
|
||||
} else if (this.RouteCode.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
|
||||
if (this.IsSameDayDropOff) {
|
||||
subject = this.AddToCalendar_SameDayDropOff_Subject;
|
||||
endDateTime = addMinutes(startDateTime, 120);
|
||||
body = this.AddToCalendar_SameDayDropOff_Body;
|
||||
} else {
|
||||
endDateTime = addMinutes(startDateTime, 120);
|
||||
subject = this.AddToCalendar_AllDayDropOff_Subject?.replace(
|
||||
"{custom:STARTDATETIME}",
|
||||
shortTimeString(startDateTime)
|
||||
).replace("{custom:ENDDATETIME}", shortTimeString(endDateTime));
|
||||
body = this.AddToCalendar_AllDayDropOff_Body?.replace(
|
||||
"{custom:ENDDATETIME}",
|
||||
shortTimeString(endDateTime)
|
||||
);
|
||||
}
|
||||
} //normal time slot
|
||||
else {
|
||||
subject = this.AddToCalendar_DropOff_Subject?.replace(
|
||||
"{custom:SERVICETYPE}",
|
||||
this.ServiceType
|
||||
);
|
||||
body = this.AddToCalendar_DropOff_Body?.replace(
|
||||
"{custom:ADDRESS}",
|
||||
location
|
||||
);
|
||||
}
|
||||
} else {
|
||||
subject = this.AddToCalendar_InShop_Subject?.replace(
|
||||
"{custom:SERVICETYPE}",
|
||||
this.ServiceType
|
||||
);
|
||||
body = this.AddToCalendar_InShop_Body?.replace("{custom:ADDRESS}", location);
|
||||
}
|
||||
duration = calculateDuration(startDateTime, endDateTime);
|
||||
}
|
||||
return {
|
||||
Subject: subject,
|
||||
Location: location,
|
||||
StartDate: startDateTime,
|
||||
EndDate: endDateTime,
|
||||
RefrrlSeqNum: this.UniqueId,
|
||||
Body: body,
|
||||
IsHTML: isHTML,
|
||||
Duration: duration,
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
selectedCalendarOption(newValue) {
|
||||
if (newValue) {
|
||||
this.setCalendarAppointment(newValue);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
setCalendarAppointment(calendarOption) {
|
||||
if (
|
||||
calendarOption.name == calendarOptions.ICAL ||
|
||||
calendarOption.name == calendarOptions.OUTLOOK
|
||||
) {
|
||||
this.getAppointment();
|
||||
} else {
|
||||
window.open(calendarOption.url);
|
||||
}
|
||||
},
|
||||
calendarModalClosed() {
|
||||
// Clear the selectedOption if close the modal
|
||||
this.selectedCalendarOption = null;
|
||||
},
|
||||
openCalendarModal() {
|
||||
this.$refs["calendarModalQuestion"].openModal();
|
||||
},
|
||||
getCalendarData(type) {
|
||||
var URL = "";
|
||||
const dateFormat = "yyyyMMddTHHmmss";
|
||||
const outlookComTimeSpanFormat = "yyyy-MM-ddTHH:mm:ss";
|
||||
if (type == calendarOptions.OUTLOOKCOM) {
|
||||
URL = `${applicationConfig.OUTLOOK_CALENDAR}&startdt=${encodeURIComponent(
|
||||
getDateFormat(this.Appointment.StartDate, outlookComTimeSpanFormat)
|
||||
)}&enddt=${encodeURIComponent(
|
||||
getDateFormat(this.Appointment.EndDate, outlookComTimeSpanFormat)
|
||||
)}&subject=${encodeURIComponent(
|
||||
this.Appointment.Subject
|
||||
)}&body=${encodeURIComponent(this.Appointment.Body)}&location=${encodeURIComponent(
|
||||
this.Appointment.Location
|
||||
)}`;
|
||||
}
|
||||
if (type == calendarOptions.GOOGLE) {
|
||||
URL = `${applicationConfig.GOOGLE_CALENDAR}&text=${encodeURIComponent(
|
||||
this.Appointment.Subject
|
||||
)}&dates=${encodeURIComponent(
|
||||
getDateFormat(this.Appointment.StartDate, dateFormat)
|
||||
)}/${encodeURIComponent(
|
||||
getDateFormat(this.Appointment.EndDate, dateFormat)
|
||||
)}&details=${encodeURIComponent(
|
||||
this.Appointment.Body
|
||||
)}&location=${encodeURIComponent(this.Appointment.Location)}&sf=true&output=xml`;
|
||||
}
|
||||
if (type == calendarOptions.YAHOO) {
|
||||
URL = `${applicationConfig.YAHOO_CALENDAR}&TITLE=${encodeURIComponent(
|
||||
this.Appointment.Subject
|
||||
)}&DESC=${encodeURIComponent(this.Appointment.Body)}&ST=${encodeURIComponent(
|
||||
getDateFormat(this.Appointment.StartDate, dateFormat)
|
||||
)}&DUR=${this.Appointment.Duration}&in_loc=${encodeURIComponent(
|
||||
this.Appointment.Location
|
||||
)}`;
|
||||
}
|
||||
return {
|
||||
url: URL,
|
||||
name: type,
|
||||
icon: require(`@/assets/img/icons/${type}.svg`),
|
||||
};
|
||||
},
|
||||
getAppointment() {
|
||||
let body = this.Appointment.Body;
|
||||
body = body?.replace("|", "<").replace("~", ">");
|
||||
|
||||
const calFile = {
|
||||
Location: this.Appointment.Location,
|
||||
Body: body,
|
||||
IsHTML: this.Appointment.IsHTML,
|
||||
UniqueId: this.Appointment.RefrrlSeqNum,
|
||||
Subject: this.Appointment.Subject,
|
||||
StartDate: this.Appointment.StartDate,
|
||||
EndDate: this.Appointment.EndDate,
|
||||
Status: calendarStatus.BUSY,
|
||||
};
|
||||
var calBody = getCalendarFile(calFile);
|
||||
download("SafeliteAppointment.ics", calBody);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.add-to-calendar-text {
|
||||
margin: 0 0 0 7px;
|
||||
color: #1574a1;
|
||||
vertical-align: middle;
|
||||
font-weight: 500;
|
||||
font-family: "Roboto";
|
||||
}
|
||||
.add-to-calendar button {
|
||||
border: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
.calendar-section {
|
||||
display: table;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.calendar-section .add-to-calendar {
|
||||
padding-top: 15px;
|
||||
}
|
||||
.calendar-section .add-to-calendar .add-to-calendar-span {
|
||||
cursor: pointer;
|
||||
}
|
||||
.calendar-section .add-to-calendar .add-to-calendar-img {
|
||||
display: inline;
|
||||
width: 20px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import calendarModalQuestion from "@/layouts/add-to-calendar/calendar-modal-question/calendar-modal-question.vue";
|
||||
import calendarModalQuestion from "@/layouts/confirmation/add-to-calendar/calendar-modal-question/calendar-modal-question.vue";
|
||||
|
||||
describe("calendar-modal-question.vue", () => {
|
||||
test("When selected calendar option is changed, a correctly selectedCalendarOption should be emitted", async () => {
|
||||
|
|
@ -20,7 +20,19 @@
|
|||
<p>{{ ScheduleDateFormatted }}</p>
|
||||
<p>{{ ScheduleTimeFormatted }}</p>
|
||||
</div>
|
||||
<addToCalendar :appointment="this.AppointmentData" />
|
||||
<addToCalendar
|
||||
mobileWidgetName="AddToCalendar_Mobile"
|
||||
inShopWidgetName="AddToCalendar_InShop"
|
||||
dropOffWidgetName="AddToCalendar_DropOff"
|
||||
overnightDropOffWidgetName="AddToCalendar_OvernightDropOff"
|
||||
allDayDropOffWidgetName="AddToCalendar_AllDayDropOff"
|
||||
sameDayDropOffWidgetName="AddToCalendar_SameDayDropOff"
|
||||
:serviceLocationFullAddress="ServiceLocationFullAddress"
|
||||
:providerFullAddress="ProviderFullAddress"
|
||||
:appointmentType="AppointmentType"
|
||||
:scheduleDate="ScheduleDate"
|
||||
:scheduleStartTime="ScheduleStartTime"
|
||||
:scheduleEndTime="ScheduleEndTime" />
|
||||
|
||||
<div class="appoinmenttext" v-html="AppointmentWordingText"></div>
|
||||
</div>
|
||||
|
|
@ -43,22 +55,17 @@
|
|||
import funnelHeader from "@/fmg-components/funnel-header/funnel-header";
|
||||
import vehicleBanner from "@/fmg-components/vehicle-banner/vehicle-banner";
|
||||
import navbar from "@/fmg-components/nav-bar/nav-bar";
|
||||
import addToCalendar from "@/layouts/add-to-calendar/add-to-calendar";
|
||||
import addToCalendar from "@/layouts/confirmation/add-to-calendar/add-to-calendar";
|
||||
//Supporting files
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { AppointmentTypeStrings, RouteCodeFlags } from "@/constants/schedule-constants";
|
||||
import { AppointmentTypeStrings } from "@/constants/schedule-constants";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import { applicationConfig } from "@/constants/application-config.js";
|
||||
import { convertDateStringToDate } from "@/layouts/schedule/helpers/schedule-helper";
|
||||
import {
|
||||
calculateDuration,
|
||||
combineDateAndTime,
|
||||
shortTimeString,
|
||||
addMinutes,
|
||||
} from "@/helpers/date-helper";
|
||||
|
||||
import { Form } from "vee-validate";
|
||||
import store from "@/store";
|
||||
import { serviceType } from "@/constants/service-type";
|
||||
|
||||
import { get12HourTimeFormat, get12HourTimeMobileFormat } from "@/helpers/date-helper";
|
||||
export default {
|
||||
name: "confirmation",
|
||||
|
|
@ -190,138 +197,6 @@ export default {
|
|||
return `at ${get12HourTimeFormat(this.ScheduleStartTime)}`;
|
||||
}
|
||||
},
|
||||
IsSameDayDropOff() {
|
||||
const todaysDate = new Date().toISOString().split("T")[0];
|
||||
return this.ScheduleDate === todaysDate;
|
||||
},
|
||||
Mobile_Appointment_Subject() {
|
||||
return this.getCmsContent("Mobile_Appointment_Widget", "HeaderText");
|
||||
},
|
||||
Mobile_Appointment_Body() {
|
||||
return this.getCmsContent("Mobile_Appointment_Widget", "BodyText");
|
||||
},
|
||||
InShop_Appointment_Subject() {
|
||||
return this.getCmsContent("InShop_Appointment_Widget", "HeaderText");
|
||||
},
|
||||
InShop_Appointment_Body() {
|
||||
return this.getCmsContent("InShop_Appointment_Widget", "BodyText");
|
||||
},
|
||||
Drop_Off_Appointment_Subject() {
|
||||
return this.getCmsContent("Drop_Off_Appointment_Widget", "HeaderText");
|
||||
},
|
||||
Drop_Off_Appointment_Body() {
|
||||
return this.getCmsContent("Drop_Off_Appointment_Widget", "BodyText");
|
||||
},
|
||||
Overnight_Drop_Off_Appointment_Subject() {
|
||||
return this.getCmsContent("Drop_Off_Appointment_Widget", "HeaderText");
|
||||
},
|
||||
Overnight_Drop_Off_Appointment_Body() {
|
||||
return this.getCmsContent("Drop_Off_Appointment_Widget", "BodyText");
|
||||
},
|
||||
All_Day_Drop_Off_Appointment_Subject() {
|
||||
return this.getCmsContent("All_Day_Drop_Off_Appointment_Widget", "HeaderText");
|
||||
},
|
||||
All_Day_Drop_Off_Appointment_Body() {
|
||||
return this.getCmsContent("All_Day_Drop_Off_Appointment_Widget", "BodyText");
|
||||
},
|
||||
Same_Day_Drop_Off_Appointment_Subject() {
|
||||
return this.getCmsContent("Same_Day_Drop_Off_Appointment_Widget", "HeaderText");
|
||||
},
|
||||
Same_Day_Drop_Off_Appointment_Body() {
|
||||
return this.getCmsContent("Same_Day_Drop_Off_Appointment_Widget", "BodyText");
|
||||
},
|
||||
UniqueId() {
|
||||
return store.getters.order.referralNumber?.toString();
|
||||
},
|
||||
ServiceType() {
|
||||
const isRepair = store.getters.order.damage.isRepair;
|
||||
const funnelHasRecalibrationPart = store.getters.funnelHasRecalibrationPart;
|
||||
if (!isRepair) {
|
||||
if (funnelHasRecalibrationPart) {
|
||||
return serviceType.REPLACEMENT_AND_RECALIBRATION;
|
||||
} else {
|
||||
return serviceType.REPLACEMENT;
|
||||
}
|
||||
}
|
||||
return serviceType.REPAIR;
|
||||
},
|
||||
RouteCode() {
|
||||
return store.getters.order.schedule.routeCode;
|
||||
},
|
||||
AppointmentData() {
|
||||
var subject = "";
|
||||
var location = "";
|
||||
var startDateTime = combineDateAndTime(this.ScheduleDate, this.ScheduleStartTime);
|
||||
var endDateTime = combineDateAndTime(this.ScheduleDate, this.ScheduleEndTime);
|
||||
var body = "";
|
||||
var isHTML = false;
|
||||
var duration = "";
|
||||
|
||||
if (this.AppointmentType === AppointmentTypeStrings.MOBILE) {
|
||||
location = this.ServiceLocationFullAddress?.replace("<br/>", "");
|
||||
subject = this.Mobile_Appointment_Subject?.replace(
|
||||
"{custom:SERVICETYPE}",
|
||||
this.ServiceType
|
||||
);
|
||||
body = this.Mobile_Appointment_Body;
|
||||
} else {
|
||||
location = this.ProviderFullAddress?.replace("<br/>", "");
|
||||
if (this.AppointmentType === AppointmentTypeStrings.DROP_OFF) {
|
||||
if (this.RouteCode.includes(RouteCodeFlags.OVERNIGHT_DROP_OFF)) {
|
||||
subject = this.Overnight_Drop_Off_Appointment_Subject;
|
||||
body = this.Overnight_Drop_Off_Appointment_Body;
|
||||
} else if (this.RouteCode.includes(RouteCodeFlags.ALL_DAY_DROP_OFF)) {
|
||||
if (this.IsSameDayDropOff) {
|
||||
subject = this.Same_Day_Drop_Off_Appointment_Subject;
|
||||
endDateTime = addMinutes(startDateTime, 120);
|
||||
body = this.Same_Day_Drop_Off_Appointment_Body;
|
||||
} else {
|
||||
endDateTime = addMinutes(startDateTime, 120);
|
||||
subject = this.All_Day_Drop_Off_Appointment_Subject?.replace(
|
||||
"{custom:STARTDATETIME}",
|
||||
shortTimeString(startDateTime)
|
||||
).replace("{custom:ENDDATETIME}", shortTimeString(endDateTime));
|
||||
body = this.All_Day_Drop_Off_Appointment_Body?.replace(
|
||||
"{custom:ENDDATETIME}",
|
||||
shortTimeString(endDateTime)
|
||||
);
|
||||
}
|
||||
} //normal time slot
|
||||
else {
|
||||
subject = this.Drop_Off_Appointment_Subject?.replace(
|
||||
"{custom:SERVICETYPE}",
|
||||
this.ServiceType
|
||||
);
|
||||
body = this.Drop_Off_Appointment_Body?.replace(
|
||||
"{custom:ADDRESS}",
|
||||
location
|
||||
);
|
||||
}
|
||||
} else {
|
||||
subject = this.InShop_Appointment_Subject?.replace(
|
||||
"{custom:SERVICETYPE}",
|
||||
this.ServiceType
|
||||
);
|
||||
body = this.InShop_Appointment_Body?.replace("{custom:ADDRESS}", location);
|
||||
}
|
||||
duration = calculateDuration(startDateTime, endDateTime);
|
||||
}
|
||||
return {
|
||||
Subject: subject,
|
||||
Location: location,
|
||||
StartDate: startDateTime,
|
||||
EndDate: endDateTime,
|
||||
RefrrlSeqNum: this.UniqueId,
|
||||
Body: body,
|
||||
IsHTML: isHTML,
|
||||
Duration: duration,
|
||||
};
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
workOrderNumber: store.getters.order.workOrderNumber,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
|
|
|
|||
|
|
@ -194,7 +194,6 @@ export default {
|
|||
taxedLineItems: [], // temporary, for use by cart.vue
|
||||
availableLineItems: [],
|
||||
paymentMethodInternalModel: this.getPaymentMethodFromStore(),
|
||||
displayPiaAlert: this.getPiaAlert(),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -250,9 +249,6 @@ export default {
|
|||
packageReqs && serviceLocationReqs && isInsuranceSet && scheduleReqs && customerReqs
|
||||
);
|
||||
},
|
||||
getPiaAlert() {
|
||||
return store.getters.order.payment.piaErrorCode ? true : false;
|
||||
},
|
||||
getPaymentMethodFromStore() {
|
||||
const isPia = store.getters.order.payment.isPia;
|
||||
|
||||
|
|
@ -283,24 +279,29 @@ export default {
|
|||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
async forwardButtonAction() {
|
||||
await this.dispatchStoreAction(
|
||||
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
||||
this.paymentMethod,
|
||||
false
|
||||
);
|
||||
|
||||
await this.dispatchStoreAction(storeActions.SAVE_VAPS, this.lineItems.vaps, false);
|
||||
|
||||
await this.dispatchStoreAction(storeActions.SAVE_PROMOS, this.lineItems.promos, false);
|
||||
|
||||
switch (this.paymentMethod) {
|
||||
case paymentMethods.CREDIT_CARD:
|
||||
this.piaSetup("cc");
|
||||
this.setupPia(this.paymentMethod);
|
||||
break;
|
||||
case paymentMethods.PAYPAL:
|
||||
this.piaSetup("pp");
|
||||
this.setupPia(this.paymentMethod);
|
||||
break;
|
||||
case paymentMethods.AFTERPAY:
|
||||
this.piaSetup("ap");
|
||||
this.setupPia(this.paymentMethod);
|
||||
break;
|
||||
default:
|
||||
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
||||
this.dispatchStoreAction(this.storeActions.SAVE_WORK_ORDER_FLAG, true, false);
|
||||
this.dispatchStoreAction(
|
||||
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
||||
this.paymentMethod,
|
||||
false
|
||||
);
|
||||
await submitWorkOrder({ pageNameToLog: "payment-method" });
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.CLICKED_FORWARD,
|
||||
|
|
@ -308,16 +309,11 @@ export default {
|
|||
);
|
||||
}
|
||||
},
|
||||
async piaSetup(payNowType) {
|
||||
async setupPia(payNowType) {
|
||||
this.$refs.loadingModal.showModal();
|
||||
|
||||
// since we're leaving the site for pia, clear any save session promises that we will not be able to resolve when we return
|
||||
await this.dispatchStoreAction(storeActions.RESET_SAVE_SESSION_PROMISE);
|
||||
await this.dispatchStoreAction(
|
||||
storeActions.SAVE_PAYMENT_METHOD_CHOICE,
|
||||
payNowType,
|
||||
false
|
||||
);
|
||||
|
||||
// make sure pia error codes are reset
|
||||
this.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
||||
|
|
@ -357,11 +353,8 @@ export default {
|
|||
isPiaDisabled() {
|
||||
const piaExperience =
|
||||
this.getSettingValue(experimentSettings.PIA_EXPERIENCE) === "PIA Optional";
|
||||
const enablePIA =
|
||||
this.getSettingValue(experimentSettings.SUBMIT_ORDER_ENABLE_PIA) === "true";
|
||||
|
||||
return false;
|
||||
//return !(piaExperience && enablePIA);
|
||||
return !piaExperience;
|
||||
},
|
||||
paymentMethod() {
|
||||
if (this.isPiaDisabled) {
|
||||
|
|
@ -370,6 +363,9 @@ export default {
|
|||
|
||||
return this.paymentMethodInternalModel;
|
||||
},
|
||||
displayPiaAlert() {
|
||||
return store.getters.order.payment.piaErrorCode ? true : false;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
customCtaCopy(newValue) {
|
||||
|
|
|
|||
|
|
@ -13,18 +13,13 @@ import store from "@/store";
|
|||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
import loadingModal from "@/fmg-components/loading-modal/loading-modal.vue";
|
||||
import { Form } from "vee-validate";
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
|
||||
export default {
|
||||
name: "payment-pia-return",
|
||||
async mounted() {
|
||||
this.$refs.loadingModal.showModal();
|
||||
// from paypal
|
||||
const piaError = getQuerystringParameter(queryStrings.ERROR);
|
||||
const token = getQuerystringParameter(queryStrings.TOKEN);
|
||||
const payerId = getQuerystringParameter(queryStrings.PAYERID);
|
||||
|
||||
// from credit card
|
||||
const subscriptionID = getQuerystringParameter(queryStrings.SUBSCRIPTIONID);
|
||||
|
||||
if (piaError) {
|
||||
console.log("Error during payment: " + piaError);
|
||||
|
|
@ -35,25 +30,26 @@ export default {
|
|||
);
|
||||
this.$router.navigateWithoutSaving(this.navigationScenarios.PIA_ERROR, this.$route);
|
||||
} else {
|
||||
if (token && payerId) {
|
||||
await this.processPaypalResponse();
|
||||
} else {
|
||||
if (subscriptionID) {
|
||||
await this.processCreditCardResponse(subscriptionID);
|
||||
} else {
|
||||
console.log(
|
||||
"Error during payment: " + token + " : " + payerId + " : " + subscriptionID
|
||||
);
|
||||
switch (store.getters.order.payment.piaType) {
|
||||
case paymentMethods.CREDIT_CARD:
|
||||
case paymentMethods.AFTERPAY:
|
||||
await this.processCreditCardResponse();
|
||||
break;
|
||||
case paymentMethods.PAYPAL:
|
||||
await this.processPaypalResponse();
|
||||
break;
|
||||
default:
|
||||
var msg = "Unknown Pia type: " + store.getters.order.payment.piaType;
|
||||
console.log(msg);
|
||||
baseMixin.methods.dispatchStoreAction(
|
||||
storeActions.SAVE_PIA_ERROR_CODE,
|
||||
piaError,
|
||||
msg,
|
||||
false
|
||||
);
|
||||
this.$router.navigateWithoutSaving(
|
||||
this.navigationScenarios.PIA_ERROR,
|
||||
this.$route
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -62,12 +58,16 @@ export default {
|
|||
return true;
|
||||
},
|
||||
async processPaypalResponse() {
|
||||
const token = getQuerystringParameter(queryStrings.TOKEN);
|
||||
const payerId = getQuerystringParameter(queryStrings.PAYERID);
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_WORK_ORDER_FLAG, true, false);
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PAYPAL_TOKEN, token, false);
|
||||
|
||||
await this.saveAndSubmitWorkOrder();
|
||||
},
|
||||
async processCreditCardResponse(subscriptionID) {
|
||||
async processCreditCardResponse() {
|
||||
const subscriptionID = getQuerystringParameter(queryStrings.SUBSCRIPTIONID);
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_PIA_ERROR_CODE, null, false);
|
||||
baseMixin.methods.dispatchStoreAction(storeActions.SAVE_WORK_ORDER_FLAG, true, false);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<Form @submit="onSubmit" @invalid-submit="onInvalidSubmit" ref="theForm" v-slot="{ meta }">
|
||||
<Form>
|
||||
<loadingModal notFullScreen ref="loadingModal" />
|
||||
<div class="container-fluid page-container-grouped-styles">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<funnelHeader cmsWidgetName="FunnelHeaderWidget" />
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<div class="col-md-6 col-xl-4 p-0">
|
||||
<div id="card-container">
|
||||
<iframe
|
||||
ref="paymentFrame"
|
||||
|
|
@ -20,15 +20,12 @@
|
|||
scrolling="no">
|
||||
</iframe>
|
||||
</div>
|
||||
<div class="fade-on-route-transition sub-container make-tall">
|
||||
<navbar
|
||||
cmsWidgetName="FunnelFooterWidget"
|
||||
:isForwardActionDisabled="!meta.valid"
|
||||
:isBackButtonHidden="shouldHideBackButton"
|
||||
isSubmitHidden="true"
|
||||
@back-clicked="backButtonAction"
|
||||
@ForwardClicked="forwardButtonAction" />
|
||||
</div>
|
||||
<navbar
|
||||
cmsWidgetName="FunnelFooterWidget"
|
||||
isForwardActionDisabled="true"
|
||||
:isBackButtonHidden="shouldHideBackButton"
|
||||
isSubmitHidden="true"
|
||||
@back-clicked="backButtonAction" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -55,16 +52,15 @@
|
|||
<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="piaResponseUrl" />
|
||||
<input type="hidden" name="sgDeclineResponseURL" :value="piaResponseUrl" />
|
||||
<input type="hidden" name="sgErrorResponseURL" :value="piaResponseUrl" />
|
||||
|
||||
<input type="hidden" name="sgheaderline1" :value="sgHeaderline1" />
|
||||
<input type="hidden" name="sgheaderline1" :value="getHeaderLine1" />
|
||||
<input type="hidden" name="sgHeader1subtitle" value="" />
|
||||
<input type="hidden" name="sgheaderline2" :value="sgHeaderline2" />
|
||||
<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" />
|
||||
|
|
@ -168,10 +164,10 @@ import { externalUrls } from "@/router/router-constants/externalUrl-values";
|
|||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import { settleAllPromises } from "@/helpers/layout-helper";
|
||||
import { applicationConfig } from "@/constants/application-config";
|
||||
import { paymentMethods } from "@/constants/payment-method-constants";
|
||||
import baseMixin from "@/mixins/base-mixin.js";
|
||||
|
||||
// Validation
|
||||
import { Form } from "vee-validate";
|
||||
|
||||
export default {
|
||||
name: "payment",
|
||||
|
|
@ -201,14 +197,19 @@ export default {
|
|||
totalAmount: this.getAmountDue(),
|
||||
displayAmount: this.getDisplayAmountDue(),
|
||||
piaLineItems: this.getPiaLineItems(),
|
||||
sgHeaderline1: this.getHeaderLine1(),
|
||||
sgHeaderline2: this.getHeaderLine2(),
|
||||
paypalPayment: this.isPaypal(),
|
||||
};
|
||||
},
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
// Call APIs
|
||||
const cmsContentPromise = fetchCmsContentForPage(to.query.fmgPage);
|
||||
|
||||
const signaturePromise = baseMixin.methods.dispatchStoreActionWithLogging(
|
||||
storeActions.GET_SIGNATURE,
|
||||
null,
|
||||
"payment"
|
||||
);
|
||||
|
||||
// TODO: Data fetching Promise declarations
|
||||
|
||||
const promiseResultMap = [
|
||||
|
|
@ -216,6 +217,10 @@ export default {
|
|||
resultKey: "cmsContent",
|
||||
promise: cmsContentPromise,
|
||||
},
|
||||
{
|
||||
resultKey: "signature",
|
||||
promise: signaturePromise,
|
||||
},
|
||||
];
|
||||
|
||||
const resultMap = await settleAllPromises(promiseResultMap);
|
||||
|
|
@ -223,18 +228,26 @@ export default {
|
|||
// Call the "next" function to complete the transition to this page.
|
||||
next(async (vm) => {
|
||||
vm.setCmsContent(resultMap.cmsContent);
|
||||
vm.fetchSignatureInfo();
|
||||
vm.fetchSignatureInfo(resultMap.signature);
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
dynamicCSSUrl() {
|
||||
const { protocol, hostname, port } = window.location;
|
||||
return `${protocol}//${hostname}:${port}/fmg/css/site-2020Styling.css`;
|
||||
},
|
||||
dynamicHopCSSUrl() {
|
||||
const { protocol, hostname, port } = window.location;
|
||||
return `${protocol}//${hostname}:${port}/fmg/css/hop-styling.css`;
|
||||
},
|
||||
getHeaderLine1() {
|
||||
if (!this.isPaypal()) {
|
||||
return this.getCmsContent("PIAHeaderLine1", "Text");
|
||||
}
|
||||
return "";
|
||||
},
|
||||
getHeaderLine2() {
|
||||
if (!this.isPaypal()) {
|
||||
return this.getCmsContent("PIAHeaderLine2", "Text");
|
||||
}
|
||||
return "";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
arePagePrerequisitesValid() {
|
||||
|
|
@ -243,7 +256,7 @@ export default {
|
|||
},
|
||||
getWOrkOrderNumber() {
|
||||
if (store.getters.order.workOrderNumber) {
|
||||
var items = store.getters.order.workOrderNumber.split("-");
|
||||
const items = store.getters.order.workOrderNumber.split("-");
|
||||
return items[1];
|
||||
}
|
||||
|
||||
|
|
@ -286,41 +299,36 @@ export default {
|
|||
: store.getters.order.serviceLocation.provider.address.zipCode;
|
||||
},
|
||||
getPaymentType() {
|
||||
return store.getters.order.payment.piaType;
|
||||
},
|
||||
getHeaderLine1() {
|
||||
if (!this.isPaypal()) {
|
||||
return "Submit payment information";
|
||||
switch (store.getters.order.payment.piaType) {
|
||||
case paymentMethods.AFTERPAY:
|
||||
return "ap";
|
||||
case paymentMethods.CREDIT_CARD:
|
||||
return "cc";
|
||||
case paymentMethods.PAYPAL:
|
||||
return "pp";
|
||||
default:
|
||||
return store.getters.payment.piaType;
|
||||
}
|
||||
return "";
|
||||
},
|
||||
getHeaderLine2() {
|
||||
if (!this.isPaypal()) {
|
||||
return "Save time when you pay for your service today! Please select a payment option.";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
getPiaLineItems() {
|
||||
const itemsClone = { ...store.getters.order.lineItems };
|
||||
delete itemsClone.serverData;
|
||||
let itemsForPia = "";
|
||||
const glassParts = store.getters.order.lineItems.glassParts;
|
||||
const supportingItems = store.getters.order.lineItems.supportingItems;
|
||||
const vaps = store.getters.order.lineItems.vaps;
|
||||
const items = [...(glassParts ?? []), ...(supportingItems ?? []), ...(vaps ?? [])];
|
||||
|
||||
var itemsForPia = "";
|
||||
for (var propertyName in itemsClone) {
|
||||
for (var item in itemsClone[propertyName]) {
|
||||
var amount =
|
||||
+itemsClone[propertyName][item].laborAmount +
|
||||
+itemsClone[propertyName][item].sellingPrice;
|
||||
itemsForPia += itemsClone[propertyName][item].partType + "|" + amount + "|1|";
|
||||
}
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const amount = items[i].laborAmount + items[i].sellingPrice;
|
||||
itemsForPia += items[i].partType + "|" + amount + "|1|";
|
||||
}
|
||||
return itemsForPia;
|
||||
},
|
||||
getAmountDue() {
|
||||
return 350.0;
|
||||
return 1600;
|
||||
//return baseMixin.methods.getAmountDue(store.getters.order.lineItems);
|
||||
},
|
||||
getDisplayAmountDue() {
|
||||
return "$350.00";
|
||||
return "$1600.00";
|
||||
//return baseMixin.methods.getDisplayAmountDue(store.getters.order.lineItems);
|
||||
},
|
||||
isPaypal() {
|
||||
|
|
@ -330,17 +338,25 @@ export default {
|
|||
return false;
|
||||
},
|
||||
backButtonAction() {
|
||||
this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
// The only way I could figure out how to get navigation to work on a page with the iframe.
|
||||
// This is also how a cancel from Paypal would work. Just a redirect to the payment-method page.
|
||||
// The normal navigation sort of works but the page does not render. The "next" callback function does not get
|
||||
// invoked in payment-method's beforeroute enter. I also spotted an error in vue-router.esm-bundler.js when this
|
||||
// happens but was unable to ignore it with a try catch. The navigation guard error is:
|
||||
// Error: Redirected from "/?fmgPage=payment-method" to "{ params: {isSavingNation: "false"}, query: "fmgPage: "payment-method"}"
|
||||
// I don't know if the navigation guard thinks the to and from are the same page.
|
||||
// Also tried overriding with a $router.push
|
||||
window.location = applicationConfig.PIA_CANCEL_URL;
|
||||
//this.$router.navigateWithoutSaving(this.navigationScenarios.CLICKED_BACK, this.$route);
|
||||
},
|
||||
forwardButtonAction() {},
|
||||
async fetchSignatureInfo() {
|
||||
async fetchSignatureInfo(signatureInfo) {
|
||||
if (this.isPaypal()) {
|
||||
this.$refs.loadingModal.showModal();
|
||||
}
|
||||
const signatureInfo = await this.dispatchStoreAction(storeActions.GET_SIGNATURE);
|
||||
this.authToken = signatureInfo.data.token;
|
||||
this.authSignature = signatureInfo.data.signature;
|
||||
this.authSignatureStart = signatureInfo.data.startDate;
|
||||
|
||||
this.authToken = signatureInfo.token;
|
||||
this.authSignature = signatureInfo.signature;
|
||||
this.authSignatureStart = signatureInfo.startDate;
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.$refs.myForm.submit();
|
||||
|
|
@ -361,7 +377,6 @@ export default {
|
|||
components: {
|
||||
funnelHeader,
|
||||
navbar,
|
||||
Form,
|
||||
loadingModal,
|
||||
},
|
||||
};
|
||||
|
|
@ -370,7 +385,7 @@ export default {
|
|||
<style lang="scss">
|
||||
.hop-iframe {
|
||||
position: relative;
|
||||
min-height: 1350px;
|
||||
min-height: 1320px;
|
||||
width: 100%;
|
||||
border: 0 none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
:groupName="groupName"
|
||||
buttonTypeString="listButtonHorizontal"
|
||||
v-model="selectedValues"
|
||||
:additionalButtonData="additionalButtonData"
|
||||
isRequired />
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -25,7 +24,13 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
answersFromCms() {
|
||||
return this.getCmsContent(this.cmsWidgetName, "Answers");
|
||||
const answers = this.getCmsContent(this.cmsWidgetName, "Answers");
|
||||
if (answers) {
|
||||
answers.forEach(
|
||||
(answer) => (answer.additionalButtonData = this.additionalButtonData)
|
||||
);
|
||||
}
|
||||
return answers;
|
||||
},
|
||||
additionalButtonData() {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@ export default {
|
|||
}
|
||||
|
||||
this.dispatchStoreAction(this.storeActions.SAVE_VAPS, this.selectedVaps, false);
|
||||
this.dispatchStoreAction(this.storeActions.SAVE_PROMOS, this.newValidatedPromos, false);
|
||||
this.dispatchStoreAction(this.storeActions.SAVE_PROMOS, this.allActivePromos, false);
|
||||
|
||||
const payment = this.$store.getters.payment;
|
||||
if (payment.isInsurance) {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ describe("service-package-question.vue", () => {
|
|||
price: 35.5,
|
||||
},
|
||||
],
|
||||
activePromos: [],
|
||||
};
|
||||
const packageNameKey = "05_01_CSR_Quote_Standard_Repair";
|
||||
Object.assign(processedCmsContent, mockProcessedCmsContent[packageNameKey]);
|
||||
|
|
@ -291,6 +292,7 @@ describe("service-package-question.vue, matching business rules for package disp
|
|||
price: 35.5,
|
||||
},
|
||||
],
|
||||
activePromos: [],
|
||||
};
|
||||
});
|
||||
it("should match the 05_01_CSR_Quote_Standard_Repair mock", () => {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ import {
|
|||
import {
|
||||
getPromosThatMatchLineItemsOnOrder,
|
||||
removeVapsPromosFromPromoArray,
|
||||
getPromosWithAddableVaps,
|
||||
getLineItemsThatMatchPromos,
|
||||
} from "@/helpers/promotions-helper";
|
||||
|
||||
export default {
|
||||
|
|
@ -54,7 +56,10 @@ export default {
|
|||
},
|
||||
watch: {
|
||||
availableLineItems() {
|
||||
if (this.$store.getters.payment.isInsurance != null) {
|
||||
if (
|
||||
this.$store.getters.payment.isInsurance != null ||
|
||||
getPromosWithAddableVaps(this.activePromos).length
|
||||
) {
|
||||
this.selectDefaultPackage();
|
||||
}
|
||||
},
|
||||
|
|
@ -217,13 +222,22 @@ export default {
|
|||
return price;
|
||||
},
|
||||
selectDefaultPackage() {
|
||||
const promosWithAddableVaps = getPromosWithAddableVaps(this.activePromos);
|
||||
const vapsThatMatchPromos = getLineItemsThatMatchPromos(
|
||||
promosWithAddableVaps,
|
||||
this.nullSafeAvailableLineItems
|
||||
);
|
||||
const vapsFromStore = this.$store.getters.lineItems.vaps ?? [];
|
||||
const vapsToUseForDefaultPackageSelection = this.combineLineItemsWithoutDuplicates(
|
||||
vapsThatMatchPromos,
|
||||
vapsFromStore
|
||||
);
|
||||
|
||||
this.selectedPackageName = getHighestRequiredTier(
|
||||
this.glassToReplace,
|
||||
this.nullSafeAvailableLineItems,
|
||||
this.isRepair,
|
||||
vapsFromStore
|
||||
vapsToUseForDefaultPackageSelection
|
||||
);
|
||||
},
|
||||
getVapsLineItemsForSelectedPackage(packageName) {
|
||||
|
|
@ -244,6 +258,17 @@ export default {
|
|||
|
||||
return vapsLineItemsForSelectedPackage;
|
||||
},
|
||||
combineLineItemsWithoutDuplicates(lineItemsOne, lineItemsTwo) {
|
||||
const combinedLineItemArray = [...lineItemsTwo];
|
||||
lineItemsOne.forEach((lineItemOne) => {
|
||||
if (
|
||||
!lineItemsTwo.filter((lineItemTwo) => lineItemTwo.id === lineItemOne.id).length
|
||||
) {
|
||||
combinedLineItemArray.push(lineItemOne);
|
||||
}
|
||||
});
|
||||
return combinedLineItemArray;
|
||||
},
|
||||
getCustomValueFromString(str) {
|
||||
switch (str) {
|
||||
case "isRecalibrationOnOrder":
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ const mockProps = {
|
|||
buttonBodyCopy:
|
||||
"<ul><li>buttonBodyCopy test copy</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>",
|
||||
buttonFooterCopy: "buttonFooterCopy test copy",
|
||||
buttonAuxillaryCopy: "buttonAuxillaryCopy test copy",
|
||||
additionalButtonData: { strikeThroughPrice: "strikeThroughPrice test copy" },
|
||||
};
|
||||
|
||||
function setupMocks({ mountOptionsMockData = {} }) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,13 @@
|
|||
<div class="package-specs">
|
||||
<p class="m-0">
|
||||
<span v-html="this.buttonLabel"></span>
|
||||
<span class="pricing-info" v-html="this.buttonAuxillaryCopy"></span>
|
||||
<span class="pricing-info">
|
||||
<span
|
||||
class="strikethrough-price"
|
||||
v-if="shouldDisplayStrikeThroughPrice"
|
||||
v-html="this.additionalButtonData.strikeThroughPrice"></span>
|
||||
<span v-html="this.buttonAuxillaryCopy"></span>
|
||||
</span>
|
||||
</p>
|
||||
<p
|
||||
class="sub-label m-0"
|
||||
|
|
@ -76,6 +82,12 @@ export default {
|
|||
arrayOfListItemsFromBodyText() {
|
||||
return this.getArrayOfListItemsFromRawCmsCopy(this.buttonBodyCopy);
|
||||
},
|
||||
shouldDisplayStrikeThroughPrice() {
|
||||
const displayPrice = this.buttonAuxillaryCopy.substring(
|
||||
this.buttonAuxillaryCopy.indexOf("$")
|
||||
);
|
||||
return displayPrice != this.additionalButtonData.strikeThroughPrice;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getRouterLinkDisplayTextFromCopy,
|
||||
|
|
@ -219,6 +231,13 @@ export default {
|
|||
&.pricing-info {
|
||||
color: $green;
|
||||
font-size: 0.875rem;
|
||||
span.strikethrough-price {
|
||||
text-decoration: line-through;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
color: $gray-550;
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.sub-label {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-5" />
|
||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="mt-4" />
|
||||
<template v-if="ChangeShopLink.length">
|
||||
<textBlock
|
||||
cmsWidgetName="ChangeShopLink"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<vehicleBanner
|
||||
ref="vehicleBanner"
|
||||
cmsWidgetName="VehicleBannerWidget"
|
||||
|
|
|
|||
|
|
@ -5,12 +5,19 @@ import vehicle from "@/layouts/vehicle/vehicle.vue";
|
|||
import { shallowMount } from "@vue/test-utils";
|
||||
import { nextTick } from "vue";
|
||||
import { getMountOptions } from "@/helpers/unit-test-helper.js";
|
||||
import { fetchCmsContentForPage } from "@/helpers/cms-content-helper";
|
||||
import baseMixin from "../../mixins/base-mixin";
|
||||
|
||||
// Mock our module for promises.
|
||||
jest.mock("@/helpers/layout-helper.js", () => ({
|
||||
settleAllPromises: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock fetchCmsContentForPage
|
||||
jest.mock("@/helpers/cms-content-helper", () => ({
|
||||
fetchCmsContentForPage: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("vehicle.vue", () => {
|
||||
test("arePagePrerequisitesValid should be true ", async () => {
|
||||
//Arrange
|
||||
|
|
@ -40,17 +47,24 @@ describe("vehicle.vue", () => {
|
|||
});
|
||||
|
||||
function setupMocks() {
|
||||
const wrapper = shallowMount(
|
||||
vehicle,
|
||||
getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigate: jest.fn(),
|
||||
navigateWithSaving: jest.fn(),
|
||||
navigateWithoutSaving: jest.fn(),
|
||||
},
|
||||
})
|
||||
);
|
||||
const mountOptions = getMountOptions({
|
||||
router: {
|
||||
navigate: jest.fn(),
|
||||
navigate: jest.fn(),
|
||||
navigateWithSaving: jest.fn(),
|
||||
navigateWithoutSaving: jest.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
//Mock props
|
||||
const mockMixin = {
|
||||
methods: {
|
||||
getCmsContent: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
mountOptions.mixins = [mockMixin];
|
||||
const wrapper = shallowMount(vehicle, mountOptions);
|
||||
|
||||
return { wrapper };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@
|
|||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 col-xl-4">
|
||||
<funnelSubHeader cmsWidgetName="FunnelSubHeaderWidget" class="siteSubHeader" />
|
||||
<div
|
||||
cmsWidgetName="FindYourVehicleCopyWidget"
|
||||
v-html="this.findYourVehicleCopy"
|
||||
class="mt-2 mb-4 small"></div>
|
||||
<vehicleQuestion
|
||||
ref="vehicleYearQuestion"
|
||||
v-model="selectedYear"
|
||||
|
|
@ -294,6 +298,9 @@ export default {
|
|||
else if (this.imageUrl == null && this.carId !== null) return false;
|
||||
else return true;
|
||||
},
|
||||
findYourVehicleCopy() {
|
||||
return this.getCmsContent("FindYourVehicleCopyWidget", "QuestionText");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getVehicle(year, make, model, style) {
|
||||
|
|
@ -430,6 +437,6 @@ export default {
|
|||
}
|
||||
.siteSubHeader {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -124,16 +124,17 @@ export default {
|
|||
},
|
||||
getAmountDue(lineItems) {
|
||||
// TODO: verify tax is included in lineitems
|
||||
// Price everything in lineitems except the server data string
|
||||
var amountDue = 0;
|
||||
const itemsClone = { ...lineItems };
|
||||
delete itemsClone.serverData;
|
||||
for (var propertyName in itemsClone) {
|
||||
if (itemsClone[propertyName]) {
|
||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
itemsClone[propertyName]
|
||||
);
|
||||
}
|
||||
if (lineItems.glassParts) {
|
||||
amountDue = this.getTotalPriceOfAllLineItemsAndChildParts(lineItems.glassParts);
|
||||
}
|
||||
if (lineItems.supportingItems) {
|
||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(
|
||||
lineItems.supportingItems
|
||||
);
|
||||
}
|
||||
if (lineItems.supportingItems.vaps) {
|
||||
amountDue += this.getTotalPriceOfAllLineItemsAndChildParts(lineItems.vaps);
|
||||
}
|
||||
return amountDue;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ const getDefaultState = () => {
|
|||
piaType: null,
|
||||
piaErrorCode: null,
|
||||
inactivePromos: null,
|
||||
paypalToken: null,
|
||||
ccToken: {
|
||||
subscriptionId: null,
|
||||
expMonth: null,
|
||||
|
|
@ -270,6 +271,9 @@ export const mutations = {
|
|||
state.order.payment.ccToken.transactionId = ccToken.transactionId;
|
||||
state.order.payment.ccToken.transReferenceNumber = ccToken.transReferenceNumber;
|
||||
},
|
||||
updatePaypalToken(state, ppToken) {
|
||||
state.order.payment.paypalToken = ppToken;
|
||||
},
|
||||
updateInsuranceVerifiedStatus(state, isVerified) {
|
||||
state.order.payment.insuranceCoverage.isVerified = isVerified;
|
||||
},
|
||||
|
|
@ -495,10 +499,12 @@ export const mutations = {
|
|||
state.order.lineItems.glassParts = sessionInformation.order.lineItems.glassParts;
|
||||
state.order.lineItems.supportingItems = sessionInformation.order.lineItems.supportingItems;
|
||||
state.order.lineItems.vaps = sessionInformation.order.lineItems.vaps;
|
||||
state.order.lineItems.promos = sessionInformation.order.lineItems.promos;
|
||||
state.order.lineItems.serverData = sessionInformation.order.lineItems.serverData;
|
||||
|
||||
state.order.payment.parentAccountNumber =
|
||||
sessionInformation.order.payment.parentAccountNumber;
|
||||
state.order.payment.inactivePromos = sessionInformation.order.payment.inactivePromos;
|
||||
|
||||
state.order.serviceLocation.address =
|
||||
sessionInformation.order.serviceLocation.streetAddress;
|
||||
|
|
@ -691,6 +697,7 @@ export const getters = {
|
|||
},
|
||||
experimentSettings: (state) =>
|
||||
state.applicationUser.experiments
|
||||
.filter((x) => !!x.isActive)
|
||||
.map((x) => x.settings)
|
||||
.reduce((r, c) => Object.assign(r, c), {}) ?? {},
|
||||
};
|
||||
|
|
@ -1644,6 +1651,11 @@ export const actions = {
|
|||
isInsurance: order.payment.isInsurance,
|
||||
parentAccountNumber: order.payment.parentAccountNumber,
|
||||
inactivePromos: order.payment.inactivePromos,
|
||||
isCreditCard:
|
||||
order.payment.piaType == paymentMethods.CREDIT_CARD ? true : false,
|
||||
isPaypal: order.payment.piaType == paymentMethods.PAYPAL ? true : false,
|
||||
isAfterPay: order.payment.piaType == paymentMethods.AFTERPAY ? true : false,
|
||||
paypalToken: order.payment.paypalToken,
|
||||
ccToken: {
|
||||
subscriptionId: order.payment.ccToken.subscriptionId,
|
||||
expMonth: order.payment.ccToken.expMonth,
|
||||
|
|
@ -1777,6 +1789,9 @@ export const actions = {
|
|||
saveCCToken(context, ccToken) {
|
||||
context.commit(storeMutations.UPDATE_CCTOKEN, ccToken);
|
||||
},
|
||||
savePaypalToken(context, ppToken) {
|
||||
context.commit(storeMutations.UPDATE_PAYPAL_TOKEN, ppToken);
|
||||
},
|
||||
|
||||
// Business domain actions
|
||||
|
||||
|
|
@ -2229,6 +2244,7 @@ export const actions = {
|
|||
addGuidToLineItemsIfNotAlreadyThere(addableVaps);
|
||||
const requestObject = {
|
||||
promoCode: promoCode,
|
||||
addableVaps: addableVaps,
|
||||
order: {
|
||||
appointmentType: order.serviceLocation.appointmentType,
|
||||
carId: order.vehicle.carId,
|
||||
|
|
@ -2237,7 +2253,6 @@ export const actions = {
|
|||
isRepair: order.damage.isRepair,
|
||||
glassToReplace: renameGlassToReplaceAttributes(order.damage.glassToReplace),
|
||||
lineItemsOnOrder: getArrayOfAllLineItems(order.lineItems),
|
||||
addableVaps: addableVaps,
|
||||
parentAccountNumber: order.payment.parentAccountNumber,
|
||||
referralSequenceNumber: order.referralSequenceNumber,
|
||||
serviceState: order.serviceLocation.state,
|
||||
|
|
@ -2258,10 +2273,12 @@ export const actions = {
|
|||
pageNameToLog: pageNameToLog,
|
||||
});
|
||||
|
||||
context.commit(
|
||||
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
|
||||
validateResponse.data.lineItemsServerData
|
||||
);
|
||||
if (validateResponse?.data?.serverData) {
|
||||
context.commit(
|
||||
storeMutations.UPDATE_LINE_ITEMS_SERVER_DATA,
|
||||
validateResponse.data.serverData
|
||||
);
|
||||
}
|
||||
|
||||
return validateResponse;
|
||||
},
|
||||
|
|
@ -2516,8 +2533,7 @@ function convertGlassPieceNamingFromApi(glassArray) {
|
|||
}
|
||||
|
||||
function addPricesToLineItems(lineItems, pricingLineItems) {
|
||||
const pricedLineItems = deepClone(lineItems);
|
||||
pricedLineItems.forEach((lineItem) => {
|
||||
lineItems.forEach((lineItem) => {
|
||||
let lineItemIndex = pricingLineItems.findIndex(
|
||||
(pricingLineItem) => pricingLineItem.partNumber === lineItem.partNumber
|
||||
);
|
||||
|
|
@ -2533,7 +2549,7 @@ function addPricesToLineItems(lineItems, pricingLineItems) {
|
|||
lineItem.salesTax = pricedLineItem.salesTax;
|
||||
});
|
||||
|
||||
return pricedLineItems;
|
||||
return lineItems;
|
||||
}
|
||||
|
||||
function addTaxesToPricedLineItems(lineItems, taxingLineItems) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div
|
||||
class="alert fade show text-center mb-0 py-2 px-4"
|
||||
class="alert fade show text-center mb-0 py-2 px-4 border-0"
|
||||
role="alert"
|
||||
:class="[
|
||||
isDismissible ? 'alert-dismissible' : '',
|
||||
|
|
|
|||
Loading…
Reference in a new issue