Update the Settings UI design to match the Figma files

This commit is contained in:
Daniel Dudzic 2024-12-08 09:33:49 +01:00
parent 7bf579c508
commit 390a3f69f8
No known key found for this signature in database
GPG key ID: 31B40D33E3465483
41 changed files with 1887 additions and 1541 deletions

View file

@ -13,7 +13,8 @@ $color-gray-200: #E0E0E0;
$color-gray: #646970;
$color-text-tertiary: #505050;
$color-text-text: #070707;
$color-border:#AEAEAE;
$color-border: #AEAEAE;
$color-divider: #F0F0F0;
$shadow-card: 0 3px 6px 0 rgba(0, 0, 0, 0.15);
$shadow-selection-box: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
@ -24,6 +25,8 @@ $max-width-onboarding: 1024px;
$max-width-onboarding-content: 500px;
$max-width-settings: 938px;
$card-vertical-gap: 48px;
#ppcp-settings-container {
--max-width-settings: #{$max-width-settings};
--max-width-onboarding: #{$max-width-onboarding};

View file

@ -18,6 +18,7 @@ button.components-button, a.components-button {
&:not(:disabled) {
background-color: $color-blueberry;
color: $color-white;
}
}

View file

@ -56,13 +56,13 @@
position: relative;
label {
@include font(14, 20, 400);
@include font(13, 20, 400);
color: $color-gray-800;
}
}
&__radio-description {
@include font(14, 20, 400);
@include font(13, 20, 400);
margin: 0;
color: $color-gray-800;
}

View file

@ -1,75 +1,78 @@
.ppcp-r-payment-method-item-list {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.ppcp-r-payment-method-item {
display: flex;
align-items: flex-start;
width: calc(100% / 3 - 32px / 3);
border: 1px solid $color-gray-300;
padding: 16px;
border-radius: 8px;
min-height: 200px;
@media screen and (max-width: 767px) {
width: calc(50% - 8px);
}
@media screen and (max-width: 480px) {
width: 100%;
}
&__wrap {
.ppcp-r-settings-block__payment-methods {
&.ppcp-r-settings-block {
display: flex;
flex-direction: column;
height: 100%;
flex-wrap: wrap;
flex-direction: row;
gap: 16px;
}
&__title-wrap {
&__item {
display: flex;
align-items: center;
margin: 0 0 8px 0;
gap: 12px;
}
align-items: flex-start;
width: calc(100% / 3 - 32px / 3);
border: 1px solid $color-gray-300;
padding: 16px;
border-radius: 8px;
min-height: 200px;
&__content {
p {
margin: 0;
color: $color-text-tertiary;
@include font(13, 20, 400);
@media screen and (max-width: 767px) {
width: calc(50% - 8px);
}
margin: 0 0 12px 0;
}
@media screen and (max-width: 480px) {
width: 100%;
}
&__title {
@include font(13, 20, 500);
color: $color-black;
display: block;
}
&__inner {
display: flex;
flex-direction: column;
height: 100%;
}
&__settings-button {
line-height: 0;
transition: 0.2s ease-out transform;
transform: rotate(0deg);
zoom: 1.005;
&__title-wrapper {
display: flex;
align-items: center;
margin: 0 0 8px 0;
gap: 12px;
}
&:hover {
transform: rotate(45deg);
cursor: pointer;
&__description {
p {
margin: 0;
color: $color-text-tertiary;
@include font(13, 20, 400);
}
margin: 0 0 12px 0;
}
&__title {
@include font(13, 20, 500);
color: $color-black;
display: block;
}
&__settings {
line-height: 0;
transition: 0.2s ease-out transform;
transform: rotate(0deg);
zoom: 1.005;
&:hover {
transform: rotate(45deg);
cursor: pointer;
}
}
button.is-secondary {
@include small-button;
}
&__footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: auto;
}
}
button.is-secondary {
@include small-button;
}
&__footer {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: auto;
}
}

View file

@ -16,6 +16,17 @@
}
}
&-settings {
> * {
margin-bottom: $card-vertical-gap;
}
> *:not(:last-child) {
padding-bottom: $card-vertical-gap;
border-bottom: 1px solid $color-gray-200;
}
}
&-settings-card {
@media screen and (min-width: 960px) {
display: flex;
@ -26,6 +37,12 @@
padding: 24px;
}
&__content-wrapper {
display: flex;
flex-direction: column;
gap: 24px;
}
&__header {
display: flex;
gap: 18px;
@ -43,21 +60,25 @@
}
&__content {
border: 1px solid $color-gray-200;
border-radius: 4px;
padding: 24px;
@media screen and (min-width: 960px) {
flex: 1;
}
}
&__title {
@include font(16, 24, 600);
color: $color-blueberry;
@include font(13, 24, 600);
color: $color-text-text;
margin: 0 0 4px 0;
display: block;
}
&__description {
@include font(14, 20, 400);
color: $color-gray-800;
@include font(13, 20, 400);
color: $color-text-tertiary;
margin: 0;
}
}

View file

@ -1,12 +1,11 @@
.ppcp-r-title-badge{
@include font(12, 16, 400);
margin-left:12px;
padding:4px 8px;
padding: 4px 8px;
border-radius: 2px;
white-space: nowrap;
&--positive{
color:#005C12;
background-color: #EDFAEF;
color: #144722;
background-color: #DAFFE0;
}
&--negative{
color:#5c0000;

View file

@ -1,3 +1,4 @@
// Container and Tab Settings
.ppcp-r-tabs.settings,
.ppcp-r-container--settings {
--max-container-width: var(--max-width-settings);
@ -6,3 +7,543 @@
max-width: var(--max-container-width);
}
}
// Todo List and Feature Items
.ppcp-r-tab-overview-todo {
margin: 0 0 48px 0;
}
.ppcp-r-todo-item {
position: relative;
display: flex;
align-items: center;
gap: 18px;
width: 100%;
&:not(:last-child) {
border-bottom: 1px solid $color-gray-400;
padding-bottom: 16px;
}
&:not(:first-child) {
padding-top: 16px;
}
p {
@include font(14, 20, 400);
}
&__inner {
position: relative;
display: flex;
align-items: center;
gap: 18px;
}
&__close {
margin-left: auto;
&:hover {
cursor: pointer;
color: $color-blueberry;
}
}
&__description {
@include font(13, 20, 400);
color: $color-blueberry;
}
}
.ppcp-r-feature-item {
padding-top: 32px;
border-top: 1px solid $color-gray-400;
&__title {
@include font(16, 20, 600);
color: $color-black;
display: block;
margin: 0 0 8px 0;
}
&__description {
@include font(14, 20, 400);
color: $color-gray-800;
margin: 0 0 18px 0;
}
&:not(:last-child) {
padding-bottom: 32px;
}
&__buttons {
display: flex;
gap: 18px;
}
&__notes {
display: flex;
flex-direction: column;
span {
font-weight: 500;
}
}
}
// Connection Status
.ppcp-r-connection-status {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 12px;
&__status-status {
margin: 0 0 8px 0;
strong {
@include font(14, 24, 700);
color: $color-black;
}
}
&__show-all-data {
margin-left: 12px;
}
&__status-label {
@include font(11, 22, 600);
color: $color-gray-900;
display: block;
text-transform: uppercase;
}
&__status-value {
@include font(13, 26, 400);
color: $color-text-tertiary;
}
&__data {
display: flex;
flex-direction: column;
gap: 12px;
}
&__status-toggle--toggled {
.ppcp-r-connection-status__show-all-data {
transform: rotate(180deg);
}
}
&__status-row {
display: flex;
flex-direction: column;
* {
user-select: none;
}
strong {
@include font(14, 24, 600);
color: $color-gray-800;
margin-right: 12px;
white-space: nowrap;
}
.ppcp-r-connection-status__status-toggle {
line-height: 0;
}
&--first {
&:hover {
cursor: pointer;
}
}
}
@media screen and (max-width: 767px) {
flex-wrap: wrap;
&__status {
width: 100%;
}
&__status-row {
flex-wrap: wrap;
strong {
width: 100%;
}
span {
word-break: break-all;
}
}
}
}
// Feature Refresh
.ppcp-r-feature-refresh {
display: flex;
gap: 12px;
margin-bottom: 24px;
&__row {
display: flex;
align-items: center;
}
&__content {
width: 100%;
&-title {
@include font(16, 20, 700);
color: $color-black;
display: block;
margin: 0 0 4px 0;
}
p {
@include font(12, 20, 400);
color: $color-gray-700;
margin: 0;
}
}
button {
display: flex;
gap: 4px;
@include font(13, 20, 400);
}
}
// Payment Methods
.ppcp-r-payment-methods {
display: flex;
flex-direction: column;
gap: 48px;
}
// Settings Card and Block Styles
.ppcp-r-settings-card__content {
> .ppcp-r-settings-block {
&:not(:last-child) {
border-bottom: 1px solid $color-divider;
}
}
}
.ppcp-r-settings-block {
display: flex;
flex-direction: column;
gap: 16px 0;
&.ppcp-r-settings-block__input,
&.ppcp-r-settings-block__select {
gap: 6px 0;
}
.ppcp-r-settings-block__header {
display: flex;
flex-direction: column;
gap: 6px;
&:not(:last-child):not(.ppcp-r-settings-block--accordion__header) {
padding-bottom: 6px;
}
}
.ppcp-r-settings-block__title {
@include font(11, 22, 600);
color: $color-gray-900;
display: block;
text-transform: uppercase;
.ppcp-r-title-badge {
text-transform: none;
margin-left: 6px;
}
}
.ppcp-r-settings-block__title-wrapper {
display: flex;
justify-content: space-between;
align-items: center;
}
&.ppcp-r-settings-block__accordion,
&.ppcp-r-settings-block__feature {
.ppcp-r-settings-block__title {
@include font(13, 20, 600);
color: $color-text-text;
text-transform: none;
}
.ppcp-r-settings-block--accordion__title {
@include font(14, 20, 600);
}
.ppcp-r-settings-block--accordion__description,
.ppcp-r-settings-block__feature__description {
color: $color-gray-700;
@include font(13, 20, 400);
}
}
&.ppcp-r-settings-block__toggle {
display: flex;
flex-direction: row;
.ppcp-r-settings-block__title {
color: $color-text-text;
@include font(13, 20, 400);
text-transform: none;
}
}
.ppcp-r-settings-block__description {
margin: 0;
@include font(13, 20, 400);
color: $color-gray-800;
&:not(:last-child) {
padding-bottom: 1em;
}
a {
color: $color-blueberry;
}
strong {
color: $color-gray-800;
}
}
.ppcp-r-settings-block__supplementary-title-label {
@include font(13, 20, 400);
color: $color-text-tertiary;
text-transform: none;
margin-left: 5px;
}
// Types
&--toggle-content {
&.ppcp-r-settings-block--content-visible {
.ppcp-r-settings-block__toggle-content {
transform: rotate(180deg);
}
}
.ppcp-r-settings-block__header {
user-select: none;
&:hover {
cursor: pointer;
}
}
}
&--sandbox-connected {
.ppcp-r-settings-block__content {
margin-top: 24px;
}
.ppcp-r-connection-status__data {
margin-bottom: 20px;
}
}
&--connect-sandbox {
button.components-button {
@include small-button;
}
.ppcp-r__radio-content-additional {
.ppcp-r-vertical-text-control {
width: 100%;
}
@include vertical-layout-event-gap(24px);
align-items: flex-start;
input[type='text'] {
width: 100%;
}
}
}
&--troubleshooting,
&--settings {
> .ppcp-r-settings-block__content > *:not(:last-child) {
padding-bottom: 32px;
margin-bottom: 32px;
border-bottom: 1px solid $color-gray-500;
}
}
// Fields
input[type='text'] {
border-color: $color-gray-700;
width: 100%;
max-width: 100%;
color: $color-gray-800;
&::placeholder {
color: $color-gray-700;
}
}
// MultiSelect control
.ppcp-r {
&__radio-wrapper {
align-items: flex-start;
gap: 12px;
}
&__radio-content {
display: flex;
flex-direction: column;
gap: 4px;
label {
font-weight: 600;
}
}
&__radio-content-additional {
padding-left: 32px;
}
// Select control styles
&__control {
border-radius: 2px;
border-color: $color-gray-700;
min-height: auto;
padding: 0;
}
&__input-container {
padding: 0;
margin: 0;
}
&__value-container {
padding: 0 0 0 7px;
}
&__indicator {
padding: 5px;
}
&__indicator-separator {
display: none;
}
&__value-container--has-value {
.ppcp-r__single-value {
color: $color-gray-800;
}
}
&__placeholder,
&__single-value {
@include font(13, 20, 400);
}
&__option {
&--is-selected {
background-color: $color-gray-200;
}
}
}
}
// Hooks table
.ppcp-r-table {
&__hooks-url {
width: 70%;
padding-right: 20%;
text-align: left;
vertical-align: top;
}
&__hooks-events {
vertical-align: top;
text-align: left;
width: 40%;
span {
display: block;
}
}
td.ppcp-r-table__hooks-url,
td.ppcp-r-table__hooks-events {
padding-top: 12px;
color: $color-gray-800;
@include font(14, 20, 400);
span {
color: inherit;
@include font(14, 20, 400);
}
}
th.ppcp-r-table__hooks-url,
th.ppcp-r-table__hooks-events {
@include font(14, 20, 700);
color: $color-gray-800;
border-bottom: 1px solid $color-gray-600;
padding-bottom: 4px;
}
}
// Settings specific styles
.ppcp-r-settings-card--common-settings .ppcp-r-settings-card__content,
.ppcp-r-settings-card--expert-settings .ppcp-r-settings-card__content {
> .ppcp-r-settings-block {
&:not(:last-child) {
padding-bottom: 32px;
margin-bottom: 32px;
}
}
}
.ppcp-r-settings-block {
&--order-intent,
&--save-payment-methods {
@include vertical-layout-event-gap(24px);
> .ppcp-r-settings-block__content {
@include vertical-layout-event-gap(24px);
}
}
}
.ppcp-r-settings-block__accordion {
.ppcp-r-settings-block--accordion__header {
gap: 4px;
}
&.ppcp-r-settings-block--content-visible .ppcp-r-settings-block--accordion__header {
margin-bottom: 24px;
}
&.ppcp-r-settings-block {
gap: 0;
.ppcp-r-settings-block:not(:last-child) {
&:not(.ppcp-r__radio-content-additional .ppcp-r-settings-block) {
padding-bottom: 32px;
margin-bottom: 32px;
border-bottom: 1px solid $color-divider;
}
}
}
}
.ppcp-r-settings-block--toggle-content {
.ppcp-r-settings-block__content {
margin-top: 32px;
}
}
.ppcp-r-settings-block__button {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 50px;
}

View file

@ -1,193 +0,0 @@
.ppcp-r-tab-overview-todo {
margin: 0 0 48px 0;
}
.ppcp-r-todo-item {
position: relative;
display: flex;
align-items: center;
gap: 18px;
width: 100%;
&:not(:last-child) {
border-bottom: 1px solid $color-gray-400;
padding-bottom: 24px;
}
&:not(:first-child) {
padding-top: 24px;
}
p {
@include font(14, 20, 400);
}
&__inner {
position: relative;
display: flex;
align-items: center;
gap: 18px;
}
&__close {
margin-left: auto;
&:hover {
cursor: pointer;
color: $color-blueberry;
}
}
}
.ppcp-r-feature-item {
padding-top: 32px;
border-top: 1px solid $color-gray-400;
&__title {
@include font(16, 20, 600);
color: $color-black;
display: block;
margin: 0 0 8px 0;
}
&__description {
@include font(14, 20, 400);
color: $color-gray-800;
margin: 0 0 18px 0;
}
&:not(:last-child) {
padding-bottom: 32px;
}
&__buttons {
display: flex;
gap: 18px;
}
&__notes {
display: flex;
flex-direction: column;
span {
font-weight: 500;
}
}
}
.ppcp-r-connection-status {
display: flex;
gap: 32px;
padding-bottom: 48px;
margin-bottom: 48px;
border-bottom: 2px solid $color-gray-500;
&__status-status {
margin: 0 0 8px 0;
strong {
@include font(14, 24, 700);
color: $color-black;
}
}
&__show-all-data {
margin-left: 12px;
}
&__status-label {
span {
@include font(12, 16, 400);
color: $color-gray-700;
}
}
&__data {
display: flex;
flex-direction: column;
gap: 12px;
}
&__status-toggle--toggled{
.ppcp-r-connection-status__show-all-data{
transform:rotate(180deg);
}
}
&__status-row {
display: flex;
align-items: center;
*{
user-select: none;
}
strong {
@include font(14, 24, 600);
color: $color-gray-800;
margin-right: 12px;
white-space: nowrap;
}
span:not(.ppcp-r-connection-status__status-toggle) {
@include font(14, 24, 400);
color: $color-gray-800;
}
.ppcp-r-connection-status__status-toggle{
line-height: 0;
}
&--first{
&:hover{
cursor: pointer;
}
}
}
@media screen and (max-width: 767px) {
flex-wrap: wrap;
&__status {
width: 100%;
}
&__status-row {
flex-wrap: wrap;
strong{
width: 100%;
}
span{
word-break:break-all;
}
}
}
}
.ppcp-r-feature-refresh {
display: flex;
gap: 12px;
margin-bottom: 24px;
&__row {
display: flex;
align-items: center;
}
&__content {
width: 100%;
&-title {
@include font(16, 20, 700);
color: $color-black;
display: block;
margin: 0 0 4px 0;
}
p {
@include font(12, 20, 400);
color: $color-gray-700;
margin: 0;
}
}
button {
display: flex;
gap: 4px;
@include font(13, 20, 400);
}
}

View file

@ -1,5 +0,0 @@
.ppcp-r-payment-methods{
display: flex;
flex-direction: column;
gap:48px;
}

View file

@ -1,312 +0,0 @@
// Global settings styles
.ppcp-r-settings {
@include vertical-layout-event-gap(48px);
}
.ppcp-r-settings-card__content {
> .ppcp-r-settings-block {
&:not(:last-child) {
border-bottom: 1.5px solid $color-gray-700;
}
}
}
.ppcp-r-settings-block {
.ppcp-r-settings-block__header {
display: flex;
gap: 48px;
&-inner {
display: flex;
flex-direction: column;
gap: 4px;
}
}
&__action {
margin-left: auto;
}
&--primary {
> .ppcp-r-settings-block__header {
.ppcp-r-settings-block__title {
@include font(16, 20, 700);
color: $color-black;
}
}
}
&--secondary {
> .ppcp-r-settings-block__header {
.ppcp-r-settings-block__title {
@include font(16, 20, 600);
color: $color-gray-800;
}
}
}
&--tertiary {
padding-bottom: 0;
margin-bottom: 24px;
> .ppcp-r-settings-block__header {
align-items: center;
.ppcp-r-settings-block__title {
color: $color-gray-800;
@include font(14, 20, 400);
}
}
}
.ppcp-r-settings-block__description {
margin: 0;
@include font(14, 20, 400);
color: $color-gray-800;
a {
color: $color-blueberry;
}
strong {
color: $color-gray-800;
}
}
// Types
&--toggle-content {
&.ppcp-r-settings-block--content-visible {
.ppcp-r-settings-block__toggle-content {
transform: rotate(180deg);
}
}
.ppcp-r-settings-block__header {
user-select: none;
&:hover {
cursor: pointer;
}
}
}
&--sandbox-connected {
.ppcp-r-settings-block__content {
margin-top: 24px;
}
button.is-secondary {
@include small-button;
}
.ppcp-r-connection-status__data {
margin-bottom: 20px;
}
}
&--expert-rdb{
@include vertical-layout-event-gap(24px);
}
&--connect-sandbox {
button.components-button {
@include small-button;
}
.ppcp-r__radio-content-additional {
.ppcp-r-vertical-text-control {
width: 100%;
}
@include vertical-layout-event-gap(24px);
align-items: flex-start;
input[type='text'] {
width: 100%;
}
}
}
&--troubleshooting {
> .ppcp-r-settings-block__content > *:not(:last-child) {
padding-bottom: 32px;
margin-bottom: 32px;
border-bottom: 1px solid $color-gray-500;
}
}
&--settings{
> .ppcp-r-settings-block__content > *:not(:last-child){
padding-bottom: 32px;
margin-bottom: 32px;
border-bottom: 1px solid $color-gray-500;
}
}
// Fields
input[type='text'] {
border-color: $color-gray-700;
width: 282px;
max-width: 100%;
color: $color-gray-800;
}
input[type='text'] {
&::placeholder {
color: $color-gray-700;
}
}
.ppcp-r {
&__radio-wrapper {
align-items: flex-start;
gap: 12px;
}
&__radio-content {
display: flex;
flex-direction: column;
gap: 4px;
label {
font-weight: 600;
}
}
&__radio-content-additional {
padding-left: 32px;
}
}
// MultiSelect control
.ppcp-r {
&__control {
border-radius: 2px;
border-color: $color-gray-700;
width: 282px;
min-height: auto;
padding: 0;
}
&__input-container {
padding: 0;
margin: 0;
}
&__value-container {
padding: 0 0 0 7px;
}
&__indicator {
padding: 5px;
}
&__indicator-separator {
display: none;
}
&__value-container--has-value {
.ppcp-r__single-value {
color: $color-gray-800;
}
}
&__placeholde, &__single-value {
@include font(13, 20, 400);
}
&__option {
&--is-selected {
background-color: $color-gray-200;
}
}
}
}
// Special settings styles
// Hooks table
.ppcp-r-table {
&__hooks-url {
width: 70%;
padding-right: 20%;
text-align: left;
vertical-align: top;
}
&__hooks-events {
vertical-align: top;
text-align: left;
width: 40%;
span {
display: block;
}
}
td.ppcp-r-table__hooks-url, td.ppcp-r-table__hooks-events {
padding-top: 12px;
color: $color-gray-800;
@include font(14, 20, 400);
span {
color: inherit;
@include font(14, 20, 400);
}
}
th.ppcp-r-table__hooks-url, th.ppcp-r-table__hooks-events {
@include font(14, 20, 700);
color: $color-gray-800;
border-bottom: 1px solid $color-gray-600;
padding-bottom: 4px;
}
}
// Common settings have 48px margin&padding bottom between blocks
.ppcp-r-settings-card--common-settings .ppcp-r-settings-card__content {
> .ppcp-r-settings-block {
&:not(:last-child) {
padding-bottom: 48px;
margin-bottom: 48px;
}
}
}
// Expert settings have 32px margin&padding bottom between blocks
.ppcp-r-settings-card--expert-settings .ppcp-r-settings-card__content {
> .ppcp-r-settings-block {
&:not(:last-child) {
padding-bottom: 32px;
margin-bottom: 32px;
}
}
}
// Order intent block has 32px gap and no lines in between
// Save payment methods block has 32px gap and no lines in between
.ppcp-r-settings-block {
&--order-intent, &--save-payment-methods {
@include vertical-layout-event-gap(32px);
> .ppcp-r-settings-block__content {
@include vertical-layout-event-gap(32px);
}
}
}
// Most primary settings block in the expert settings have 32px space after description
.ppcp-r-settings-block--toggle-content {
.ppcp-r-settings-block__content {
margin-top: 32px;
}
}
// Common settings have actions aligned top with the text, Expert settings have actions alligned middle with the text
.ppcp-r-settings-card--expert-settings {
.ppcp-r-settings-block__header {
align-items: center;
}
}

View file

@ -21,9 +21,6 @@
@import './components/reusable-components/welcome-docs';
@import './components/screens/onboarding';
@import './components/screens/settings';
@import './components/screens/overview/tab-overview';
@import './components/screens/overview/tab-payment-methods';
@import './components/screens/overview/tab-settings';
}
@import './components/reusable-components/payment-method-modal';

View file

@ -1,5 +1,4 @@
import { __ } from '@wordpress/i18n';
import data from '../../utils/data';
import { useState } from '@wordpress/element';
const ConnectionInfo = ( { connectionStatusDataDefault } ) => {
@ -7,13 +6,6 @@ const ConnectionInfo = ( { connectionStatusDataDefault } ) => {
...connectionStatusDataDefault,
} );
const showAllData = () => {
setConnectionData( {
...connectionData,
showAllData: ! connectionData.showAllData,
} );
};
const toggleStatusClassName = [ 'ppcp-r-connection-status__status-toggle' ];
if ( connectionData.showAllData ) {
@ -24,43 +16,30 @@ const ConnectionInfo = ( { connectionStatusDataDefault } ) => {
return (
<div className="ppcp-r-connection-status__data">
<div
className="ppcp-r-connection-status__status-row ppcp-r-connection-status__status-row--first"
onClick={ () => showAllData() }
>
<strong>
{ __( 'Email address:', 'woocommerce-paypal-payments' ) }
</strong>
<span>{ connectionData.email }</span>
<span className={ toggleStatusClassName.join( ' ' ) }>
{ data().getImage(
'icon-arrow-down.svg',
'ppcp-r-connection-status__show-all-data'
) }
<div className="ppcp-r-connection-status__status-row ppcp-r-connection-status__status-row--first">
<span className="ppcp-r-connection-status__status-label">
{ __( 'Merchant ID', 'woocommerce-paypal-payments' ) }
</span>
<span className="ppcp-r-connection-status__status-value">
{ connectionData.merchantId }
</span>
</div>
<div className="ppcp-r-connection-status__status-row">
<span className="ppcp-r-connection-status__status-label">
{ __( 'Email address', 'woocommerce-paypal-payments' ) }
</span>
<span className="ppcp-r-connection-status__status-value">
{ connectionData.email }
</span>
</div>
<div className="ppcp-r-connection-status__status-row">
<span className="ppcp-r-connection-status__status-label">
{ __( 'Client ID', 'woocommerce-paypal-payments' ) }
</span>
<span className="ppcp-r-connection-status__status-value">
{ connectionData.clientId }
</span>
</div>
{ connectionData.showAllData && (
<>
<div className="ppcp-r-connection-status__status-row">
<strong>
{ __(
'Merchant ID:',
'woocommerce-paypal-payments'
) }
</strong>
<span>{ connectionData.merchantId }</span>
</div>
<div className="ppcp-r-connection-status__status-row">
<strong>
{ __(
'Client ID:',
'woocommerce-paypal-payments'
) }
</strong>
<span>{ connectionData.clientId }</span>
</div>
</>
) }
</div>
);
};

View file

@ -1,65 +0,0 @@
import { Button } from '@wordpress/components';
import PaymentMethodIcon from './PaymentMethodIcon';
import { PayPalCheckbox } from './Fields';
import { useState } from '@wordpress/element';
import { ToggleControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import data from '../../utils/data';
const PaymentMethodItem = ( props ) => {
const [ paymentMethodState, setPaymentMethodState ] = useState();
const [ modalIsVisible, setModalIsVisible ] = useState( false );
let Modal = null;
if ( props?.modal ) {
Modal = props.modal;
}
const handleCheckboxState = ( checked ) => {
if ( checked ) {
setPaymentMethodState( props.payment_method_id );
} else {
setPaymentMethodState( null );
}
};
return (
<>
<div className="ppcp-r-payment-method-item">
<div className="ppcp-r-payment-method-item__wrap">
<div className="ppcp-r-payment-method-item__title-wrap">
<PaymentMethodIcon
icons={ [ props.icon ] }
type={ props.icon }
/>
<span className="ppcp-r-payment-method-item__title">
{ props.title }
</span>
</div>
<div className="ppcp-r-payment-method-item__content">
<p>{ props.description }</p>
</div>
<div className="ppcp-r-payment-method-item__footer">
<ToggleControl
__nextHasNoMarginBottom={ true }
checked={
props.payment_method_id === paymentMethodState
}
onChange={ ( newValue ) =>
handleCheckboxState( newValue )
}
/>
<div
className="ppcp-r-payment-method-item__settings-button"
onClick={ () => setModalIsVisible( true ) }
>
{ Modal && data().getImage( 'icon-settings.svg' ) }
</div>
</div>
</div>
</div>
{ Modal && modalIsVisible && (
<Modal setModalIsVisible={ setModalIsVisible } />
) }
</>
);
};
export default PaymentMethodItem;

View file

@ -1,146 +0,0 @@
import { Button, ToggleControl, TextControl } from '@wordpress/components';
import data from '../../utils/data';
import { useState } from '@wordpress/element';
import Select, { components } from 'react-select';
export const SETTINGS_BLOCK_TYPE_EMPTY = 'empty';
export const SETTINGS_BLOCK_TYPE_TOGGLE = 'toggle';
export const SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT = 'toggle-content';
export const SETTINGS_BLOCK_TYPE_INPUT = 'input';
export const SETTINGS_BLOCK_TYPE_BUTTON = 'button';
export const SETTINGS_BLOCK_TYPE_SELECT = 'select';
export const SETTINGS_BLOCK_STYLING_TYPE_PRIMARY = 'primary';
export const SETTINGS_BLOCK_STYLING_TYPE_SECONDARY = 'secondary';
export const SETTINGS_BLOCK_STYLING_TYPE_TERTIARY = 'tertiary';
const SettingsBlock = ( {
className,
title,
description,
children,
style,
actionProps,
tag,
} ) => {
const [ toggleContentVisible, setToggleContentVisible ] = useState(
actionProps?.type !== SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT
);
const toggleContent = () => {
if ( actionProps?.type !== SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT ) {
return;
}
setToggleContentVisible( ! toggleContentVisible );
};
const blockClassName = [ 'ppcp-r-settings-block' ];
blockClassName.push( 'ppcp-r-settings-block--' + style );
blockClassName.push( 'ppcp-r-settings-block--' + actionProps?.type );
if ( className ) {
blockClassName.push( className );
}
if (
toggleContentVisible &&
actionProps?.type === SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT
) {
blockClassName.push( 'ppcp-r-settings-block--content-visible' );
}
return (
<div className={ blockClassName.join( ' ' ) }>
<div
className="ppcp-r-settings-block__header"
onClick={ () => toggleContent() }
>
<div className="ppcp-r-settings-block__header-inner">
<span className="ppcp-r-settings-block__title">
{ title }
{ tag && tag }
</span>
<p
className="ppcp-r-settings-block__description"
dangerouslySetInnerHTML={ { __html: description } }
/>
</div>
{ actionProps?.type !== SETTINGS_BLOCK_TYPE_EMPTY && (
<div className="ppcp-r-settings-block__action">
{ actionProps?.type === SETTINGS_BLOCK_TYPE_TOGGLE && (
<ToggleControl
className="ppcp-r-settings-block__toggle"
__nextHasNoMarginBottom={ true }
checked={ actionProps?.value }
onChange={ ( newValue ) =>
actionProps?.callback(
actionProps?.key,
newValue
)
}
/>
) }
{ actionProps?.type === SETTINGS_BLOCK_TYPE_INPUT && (
<>
<TextControl
className="ppcp-r-vertical-text-control"
placeholder={ actionProps?.placeholder }
value={ actionProps?.value }
onChange={ ( newValue ) =>
actionProps?.callback(
actionProps?.key,
newValue
)
}
/>
</>
) }
{ actionProps?.type === SETTINGS_BLOCK_TYPE_BUTTON && (
<Button
variant={ actionProps.buttonType }
onClick={
actionProps?.callback
? () => actionProps.callback()
: undefined
}
>
{ actionProps.value }
</Button>
) }
{ actionProps?.type ===
SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT && (
<div className="ppcp-r-settings-block__toggle-content">
{ data().getImage( 'icon-arrow-down.svg' ) }
</div>
) }
{ actionProps?.type === SETTINGS_BLOCK_TYPE_SELECT && (
<Select
className="ppcp-r-multiselect"
classNamePrefix="ppcp-r"
isMulti={ actionProps?.isMulti }
options={ actionProps?.options }
components={ { DropdownIndicator } }
/>
) }
</div>
) }
</div>
{ children && toggleContentVisible && (
<div className="ppcp-r-settings-block__content">
{ children }
</div>
) }
</div>
);
};
const DropdownIndicator = ( props ) => {
return (
<components.DropdownIndicator { ...props }>
{ data().getImage( 'icon-arrow-down.svg' ) }
</components.DropdownIndicator>
);
};
export default SettingsBlock;

View file

@ -0,0 +1,56 @@
import { useState } from '@wordpress/element';
import data from '../../../utils/data';
import SettingsBlock from './SettingsBlock';
import {
Header,
Title,
Action,
Description,
TitleWrapper,
} from './SettingsBlockElements';
const AccordionSettingsBlock = ( { title, description, ...props } ) => {
const [ isVisible, setIsVisible ] = useState( false );
return (
<SettingsBlock
{ ...props }
className={ `ppcp-r-settings-block__accordion ${
isVisible ? 'ppcp-r-settings-block--content-visible' : ''
}` }
components={ [
() => (
<>
<Header className="ppcp-r-settings-block--accordion__header">
<TitleWrapper>
<Title className="ppcp-r-settings-block--accordion__title">
{ title }
</Title>
<Action>
<div
className="ppcp-r-settings-block__toggle-content"
onClick={ () =>
setIsVisible( ! isVisible )
}
>
{ data().getImage(
'icon-arrow-down.svg'
) }
</div>
</Action>
</TitleWrapper>
<Description className="ppcp-r-settings-block--accordion__description">
{ description }
</Description>
</Header>
{ isVisible && props.children && (
<>{ props.children }</>
) }
</>
),
] }
/>
);
};
export default AccordionSettingsBlock;

View file

@ -0,0 +1,34 @@
import { Button } from '@wordpress/components';
import SettingsBlock from './SettingsBlock';
import { Header, Title, Action, Description } from './SettingsBlockElements';
const ButtonSettingsBlock = ( { title, description, ...props } ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__button"
components={ [
() => (
<>
<Header>
<Title>{ title }</Title>
<Description>{ description }</Description>
</Header>
<Action>
<Button
variant={ props.actionProps?.buttonType }
onClick={
props.actionProps?.callback
? () => props.actionProps.callback()
: undefined
}
>
{ props.actionProps.value }
</Button>
</Action>
</>
),
] }
/>
);
export default ButtonSettingsBlock;

View file

@ -0,0 +1,67 @@
import { Button } from '@wordpress/components';
import SettingsBlock from './SettingsBlock';
import { Header, Title, Action, Description } from './SettingsBlockElements';
import TitleBadge from '../TitleBadge';
const FeatureSettingsBlock = ( { title, description, ...props } ) => {
const printNotes = () => {
const notes = props.actionProps?.notes;
if ( ! notes || ( Array.isArray( notes ) && notes.length === 0 ) ) {
return null;
}
return (
<>
<span className="ppcp-r-feature-item__notes">
{ notes.map( ( note, index ) => (
<span key={ index }>{ note }</span>
) ) }
</span>
</>
);
};
return (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__feature"
components={ [
() => (
<>
<Header>
<Title>
{ title }
{ props.actionProps?.featureStatus && (
<TitleBadge
{ ...props.actionProps?.badge }
/>
) }
</Title>
<Description className="ppcp-r-settings-block__feature__description">
{ description }
{ printNotes() }
</Description>
</Header>
<Action>
<div className="ppcp-r-feature-item__buttons">
{ props.actionProps?.buttons.map(
( button ) => (
<Button
href={ button.url }
key={ button.text }
variant={ button.type }
>
{ button.text }
</Button>
)
) }
</div>
</Action>
</>
),
] }
/>
);
};
export default FeatureSettingsBlock;

View file

@ -0,0 +1,69 @@
import { TextControl } from '@wordpress/components';
import SettingsBlock from './SettingsBlock';
import {
Title,
Action,
Description,
SupplementaryLabel,
} from './SettingsBlockElements';
const DEFAULT_ELEMENT_ORDER = [ 'title', 'action', 'description' ];
const ELEMENT_RENDERERS = {
title: ( { title, supplementaryLabel } ) => (
<Title>
{ title }
{ supplementaryLabel && (
<SupplementaryLabel>{ supplementaryLabel }</SupplementaryLabel>
) }
</Title>
),
action: ( { actionProps } ) => (
<Action>
<TextControl
className="ppcp-r-vertical-text-control"
placeholder={ actionProps?.placeholder }
value={ actionProps?.value }
onChange={ ( newValue ) =>
actionProps?.callback( actionProps?.key, newValue )
}
/>
</Action>
),
description: ( { description } ) => (
<Description>{ description }</Description>
),
};
const InputSettingsBlock = ( {
title,
description,
supplementaryLabel,
order = DEFAULT_ELEMENT_ORDER,
...props
} ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__input"
components={ [
() => (
<>
{ order.map( ( elementKey ) => {
const RenderElement = ELEMENT_RENDERERS[ elementKey ];
return RenderElement ? (
<RenderElement
key={ elementKey }
title={ title }
description={ description }
supplementaryLabel={ supplementaryLabel }
actionProps={ props.actionProps }
/>
) : null;
} ) }
</>
),
] }
/>
);
export default InputSettingsBlock;

View file

@ -0,0 +1,65 @@
import { useState } from '@wordpress/element';
import { ToggleControl } from '@wordpress/components';
import SettingsBlock from './SettingsBlock';
import PaymentMethodIcon from '../PaymentMethodIcon';
import data from '../../../utils/data';
const PaymentMethodItemBlock = ( props ) => {
const [ paymentMethodState, setPaymentMethodState ] = useState();
const [ modalIsVisible, setModalIsVisible ] = useState( false );
const Modal = props?.modal;
const handleCheckboxState = ( checked ) => {
setPaymentMethodState( checked ? props.id : null );
};
return (
<>
<SettingsBlock
className="ppcp-r-settings-block__payment-methods__item"
components={ [
() => (
<div className="ppcp-r-settings-block__payment-methods__item__inner">
<div className="ppcp-r-settings-block__payment-methods__item__title-wrapper">
<PaymentMethodIcon
icons={ [ props.icon ] }
type={ props.icon }
/>
<span className="ppcp-r-settings-block__payment-methods__item__title">
{ props.title }
</span>
</div>
<p className="ppcp-r-settings-block__payment-methods__item__description">
{ props.description }
</p>
<div className="ppcp-r-settings-block__payment-methods__item__footer">
<ToggleControl
__nextHasNoMarginBottom={ true }
checked={ props.id === paymentMethodState }
onChange={ handleCheckboxState }
/>
{ Modal && (
<div
className="ppcp-r-settings-block__payment-methods__item__settings"
onClick={ () =>
setModalIsVisible( true )
}
>
{ data().getImage(
'icon-settings.svg'
) }
</div>
) }
</div>
</div>
),
] }
/>
{ Modal && modalIsVisible && (
<Modal setModalIsVisible={ setModalIsVisible } />
) }
</>
);
};
export default PaymentMethodItemBlock;

View file

@ -0,0 +1,28 @@
import SettingsBlock from './SettingsBlock';
import PaymentMethodItemBlock from './PaymentMethodItemBlock';
const PaymentMethodsBlock = ( { paymentMethods, className = '' } ) => {
if ( paymentMethods.length === 0 ) {
return null;
}
return (
<SettingsBlock
className={ `ppcp-r-settings-block__payment-methods ${ className }` }
components={ [
() => (
<>
{ paymentMethods.map( ( paymentMethod ) => (
<PaymentMethodItemBlock
key={ paymentMethod.id }
{ ...paymentMethod }
/>
) ) }
</>
),
] }
/>
);
};
export default PaymentMethodsBlock;

View file

@ -0,0 +1,47 @@
import SettingsBlock from './SettingsBlock';
import { Header, Title, Description } from './SettingsBlockElements';
import { PayPalRdbWithContent } from '../Fields';
const RadioSettingsBlock = ( {
title,
description,
options = [],
...props
} ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__radio ppcp-r-settings-block--expert-rdb"
components={ [
() => (
<>
<Header>
<Title>{ title }</Title>
<Description>{ description }</Description>
</Header>
{ options.map( ( option ) => (
<PayPalRdbWithContent
key={ option.id }
id={ option.id }
name={ props.actionProps?.name }
value={ option.value }
currentValue={ props.actionProps?.currentValue }
handleRdbState={ ( newValue ) =>
props.actionProps?.callback(
props.actionProps?.key,
newValue
)
}
label={ option.label }
description={ option.description }
toggleAdditionalContent={ true }
>
{ option.additionalContent }
</PayPalRdbWithContent>
) ) }
</>
),
] }
/>
);
export default RadioSettingsBlock;

View file

@ -0,0 +1,61 @@
import Select, { components } from 'react-select';
import data from '../../../utils/data';
import SettingsBlock from './SettingsBlock';
import { Title, Action, Description } from './SettingsBlockElements';
const DEFAULT_ELEMENT_ORDER = [ 'title', 'action', 'description' ];
const DropdownIndicator = ( props ) => (
<components.DropdownIndicator { ...props }>
{ data().getImage( 'icon-arrow-down.svg' ) }
</components.DropdownIndicator>
);
const ELEMENT_RENDERERS = {
title: ( { title } ) => <Title>{ title }</Title>,
action: ( { actionProps } ) => (
<Action>
<Select
className="ppcp-r-multiselect"
classNamePrefix="ppcp-r"
isMulti={ actionProps?.isMulti }
options={ actionProps?.options }
components={ { DropdownIndicator } }
/>
</Action>
),
description: ( { description } ) => (
<Description>{ description }</Description>
),
};
const SelectSettingsBlock = ( {
title,
description,
order = DEFAULT_ELEMENT_ORDER,
...props
} ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__select"
components={ [
() => (
<>
{ order.map( ( elementKey ) => {
const RenderElement = ELEMENT_RENDERERS[ elementKey ];
return RenderElement ? (
<RenderElement
key={ elementKey }
title={ title }
description={ description }
actionProps={ props.actionProps }
/>
) : null;
} ) }
</>
),
] }
/>
);
export default SelectSettingsBlock;

View file

@ -0,0 +1,15 @@
const SettingsBlock = ( { className, components = [] } ) => {
const blockClassName = [ 'ppcp-r-settings-block', className ].filter(
Boolean
);
return (
<div className={ blockClassName.join( ' ' ) }>
{ components.map( ( Component, index ) => (
<Component key={ index } />
) ) }
</div>
);
};
export default SettingsBlock;

View file

@ -0,0 +1,42 @@
// Block Elements
export const Title = ( { children, className = '' } ) => (
<span className={ `ppcp-r-settings-block__title ${ className }`.trim() }>
{ children }
</span>
);
export const TitleWrapper = ( { children } ) => (
<span className="ppcp-r-settings-block__title-wrapper">{ children }</span>
);
export const SupplementaryLabel = ( { children } ) => (
<span className="ppcp-r-settings-block__supplementary-title-label">
{ children }
</span>
);
export const Description = ( { children, className = '' } ) => (
<span
className={ `ppcp-r-settings-block__description ${ className }`.trim() }
>
{ children }
</span>
);
export const Action = ( { children } ) => (
<div className="ppcp-r-settings-block__action">{ children }</div>
);
export const Header = ( { children, className = '' } ) => (
<div className={ `ppcp-r-settings-block__header ${ className }`.trim() }>
{ children }
</div>
);
// Card Elements
export const Content = ( { children } ) => (
<div className="ppcp-r-settings-card__content">{ children }</div>
);
export const ContentWrapper = ( { children } ) => (
<div className="ppcp-r-settings-card__content-wrapper">{ children }</div>
);

View file

@ -0,0 +1,69 @@
import { PayPalCheckbox, handleCheckboxState } from '../Fields';
import data from '../../../utils/data';
const TodoSettingsBlock = ( {
todos,
setTodos,
todosData,
setTodosData,
className = '',
} ) => {
if ( todosData.length === 0 ) {
return null;
}
return (
<div
className={ `ppcp-r-settings-block__todo ppcp-r-todo-items ${ className }` }
>
{ todosData.map( ( todo ) => (
<TodoItem
name="todo_items"
key={ todo.value }
value={ todo.value }
currentValue={ todos }
changeCallback={ setTodos }
description={ todo.description }
changeTodos={ setTodosData }
todosData={ todosData }
/>
) ) }
</div>
);
};
const TodoItem = ( props ) => {
return (
<div className="ppcp-r-todo-item">
<div className="ppcp-r-todo-item__inner">
<PayPalCheckbox
{ ...{
...props,
handleCheckboxState,
} }
/>
<div className="ppcp-r-todo-item__description">
{ props.description }
</div>
</div>
<div
className="ppcp-r-todo-item__close"
onClick={ () =>
removeTodo(
props.value,
props.todosData,
props.changeTodos
)
}
>
{ data().getImage( 'icon-close.svg' ) }
</div>
</div>
);
};
const removeTodo = ( todoValue, todosData, changeTodos ) => {
changeTodos( todosData.filter( ( todo ) => todo.value !== todoValue ) );
};
export default TodoSettingsBlock;

View file

@ -0,0 +1,37 @@
import { ToggleControl } from '@wordpress/components';
import SettingsBlock from './SettingsBlock';
import { Header, Title, Action, Description } from './SettingsBlockElements';
const ToggleSettingsBlock = ( { title, description, ...props } ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__toggle"
components={ [
() => (
<Action>
<ToggleControl
className="ppcp-r-settings-block__toggle-control"
__nextHasNoMarginBottom={ true }
checked={ props.actionProps?.value }
onChange={ ( newValue ) =>
props.actionProps?.callback(
props.actionProps?.key,
newValue
)
}
/>
</Action>
),
() => (
<Header>
{ title && <Title>{ title }</Title> }
{ description && (
<Description>{ description }</Description>
) }
</Header>
),
] }
/>
);
export default ToggleSettingsBlock;

View file

@ -0,0 +1,20 @@
export { default as SettingsBlock } from './SettingsBlock';
export { default as ButtonSettingsBlock } from './ButtonSettingsBlock';
export { default as InputSettingsBlock } from './InputSettingsBlock';
export { default as SelectSettingsBlock } from './SelectSettingsBlock';
export { default as AccordionSettingsBlock } from './AccordionSettingsBlock';
export { default as ToggleSettingsBlock } from './ToggleSettingsBlock';
export { default as RadioSettingsBlock } from './RadioSettingsBlock';
export { default as PaymentMethodsBlock } from './PaymentMethodsBlock';
export { default as PaymentMethodItemBlock } from './PaymentMethodItemBlock';
export {
Title,
TitleWrapper,
SupplementaryLabel,
Description,
Action,
Content,
ContentWrapper,
Header,
} from './SettingsBlockElements';

View file

@ -1,26 +1,50 @@
import data from '../../utils/data';
import { Content, ContentWrapper } from './SettingsBlocks';
const SettingsCard = ( props ) => {
let className = 'ppcp-r-settings-card';
const SettingsCard = ( {
className: extraClassName,
title,
description,
children,
contentItems,
contentContainer = true,
} ) => {
const className = [ 'ppcp-r-settings-card', extraClassName ]
.filter( Boolean )
.join( ' ' );
const renderContent = () => {
// If contentItems array is provided, wrap each item in Content component
if ( contentItems ) {
return (
<ContentWrapper>
{ contentItems.map( ( item, index ) => (
<Content key={ index }>{ item }</Content>
) ) }
</ContentWrapper>
);
}
// Otherwise handle regular children with contentContainer prop
if ( contentContainer ) {
return <Content>{ children }</Content>;
}
return children;
};
if ( props?.className ) {
className += ' ' + props.className;
}
return (
<div className={ className }>
<div className="ppcp-r-settings-card__header">
<div className="ppcp-r-settings-card__content-inner">
<span className="ppcp-r-settings-card__title">
{ props.title }
{ title }
</span>
<p className="ppcp-r-settings-card__description">
{ props.description }
{ description }
</p>
</div>
</div>
<div className="ppcp-r-settings-card__content">
{ props.children }
</div>
{ renderContent() }
</div>
);
};

View file

@ -1,11 +1,13 @@
const TitleBadge = ( { text, type } ) => {
const className = 'ppcp-r-title-badge ' + `ppcp-r-title-badge--${ type }`;
return <span
className={ className }
dangerouslySetInnerHTML={{
__html: text,
}}
></span>;
return (
<span
className={ className }
dangerouslySetInnerHTML={ {
__html: text,
} }
></span>
);
};
export const TITLE_BADGE_POSITIVE = 'positive';

View file

@ -1,19 +1,11 @@
import SettingsCard from '../../ReusableComponents/SettingsCard';
import { __ } from '@wordpress/i18n';
import {
PayPalCheckbox,
handleCheckboxState,
} from '../../ReusableComponents/Fields';
import { useState } from '@wordpress/element';
import data from '../../../utils/data';
import { Button } from '@wordpress/components';
import TitleBadge, {
TITLE_BADGE_NEGATIVE,
TITLE_BADGE_POSITIVE,
} from '../../ReusableComponents/TitleBadge';
import ConnectionInfo, {
connectionStatusDataDefault,
} from '../../ReusableComponents/ConnectionInfo';
import SettingsCard from '../../ReusableComponents/SettingsCard';
import TodoSettingsBlock from '../../ReusableComponents/SettingsBlocks/TodoSettingsBlock';
import FeatureSettingsBlock from '../../ReusableComponents/SettingsBlocks/FeatureSettingsBlock';
import { TITLE_BADGE_POSITIVE } from '../../ReusableComponents/TitleBadge';
import data from '../../../utils/data';
const TabOverview = () => {
const [ todos, setTodos ] = useState( [] );
@ -33,200 +25,52 @@ const TabOverview = () => {
'woocommerce-paypal-payments'
) }
>
<div className="ppcp-r-todo-items">
{ todosData.map( ( todo ) => (
<TodoItem
name="todo_items"
key={ todo.value }
value={ todo.value }
currentValue={ todos }
changeCallback={ setTodos }
description={ todo.description }
changeTodos={ setTodosData }
todosData={ todosData }
/>
) ) }
</div>
<TodoSettingsBlock
todos={ todos }
setTodos={ setTodos }
todosData={ todosData }
setTodosData={ setTodosData }
/>
</SettingsCard>
) }
<SettingsCard
className="ppcp-r-tab-overview-support"
title={ __( 'Status', 'woocommerce-paypal-payments' ) }
description={ __(
'Your PayPal account connection details, along with available products and features.',
'woocommerce-paypal-payments'
) }
>
<ConnectionStatus
connectionData={ connectionStatusDataDefault }
/>
<FeaturesRefresh />
{ featuresDefault.map( ( feature ) => {
return (
<FeatureItem key={ feature.id } feature={ feature } />
);
} ) }
</SettingsCard>
</div>
);
};
const ConnectionStatus = ( { connectionData } ) => {
return (
<div className="ppcp-r-connection-status">
<div className="ppcp-r-connection-status__status">
<div className="ppcp-r-connection-status__status-status">
<strong>
{ __( 'Connection', 'woocommerce-paypal-payments' ) }
</strong>
{ connectionData.connectionStatus ? (
<TitleBadge
type={ TITLE_BADGE_POSITIVE }
text={ __(
'Activated',
'woocommerce-paypal-payments'
) }
/>
) : (
<TitleBadge
type={ TITLE_BADGE_NEGATIVE }
text={ __(
'Not Activated',
'woocommerce-paypal-payments'
) }
/>
) }
</div>
<div className="ppcp-r-connection-status__status-label">
<span>
{ __(
'PayPal Account Details',
'woocommerce-paypal-payments'
) }
</span>
</div>
</div>
{ connectionData.connectionStatus && (
<ConnectionInfo
connectionStatusDataDefault={ connectionStatusDataDefault }
/>
) }
</div>
);
};
const FeaturesRefresh = () => {
return (
<div className="ppcp-r-feature-refresh">
<div className="ppcp-r-feature-refresh__content">
<span className="ppcp-r-feature-refresh__content-title">
{ __( 'Features', 'woocommerce-paypal-payments' ) }
</span>
<p>
{ __(
'After making changes to your PayPal account, click Refresh to update your store features.',
'woocommerce-paypal-payments'
) }
</p>
</div>
<Button variant="tertiary">
{ data().getImage( 'icon-refresh.svg' ) }
{ __( 'Refresh', 'woocommerce-paypal-payments' ) }
</Button>
</div>
);
};
const TodoItem = ( props ) => {
return (
<div className="ppcp-r-todo-item">
<div className="ppcp-r-todo-item__inner">
<PayPalCheckbox
{ ...{
...props,
handleCheckboxState,
} }
/>{ ' ' }
<p>{ props.description }</p>
</div>
<div
className="ppcp-r-todo-item__close"
onClick={ () =>
removeTodo(
props.value,
props.todosData,
props.changeTodos
)
}
>
{ data().getImage( 'icon-close.svg' ) }
</div>
</div>
);
};
const FeatureItem = ( { feature } ) => {
const printNotes = () => {
if ( ! feature?.notes ) {
return null;
}
if ( Array.isArray( feature.notes ) && feature.notes.length === 0 ) {
return null;
}
return (
<>
<br />
<br />
<span className="ppcp-r-feature-item__notes">
{ feature.notes.map( ( note, index ) => {
return <span key={ index }>{ note }</span>;
} ) }
</span>
</>
);
};
return (
<div className="ppcp-r-feature-item">
<span className="ppcp-r-feature-item__title">
{ feature.title }
{ feature?.featureStatus && (
<TitleBadge
text={ __(
'Activated',
'woocommerce-paypal-payments'
) }
type={ TITLE_BADGE_POSITIVE }
/>
) }
</span>
<p className="ppcp-r-feature-item__description">
{ feature.description }
{ printNotes() }
</p>
<div className="ppcp-r-feature-item__buttons">
{ feature.buttons.map( ( button ) => {
return (
<Button
href={ button.url }
key={ button.text }
variant={ button.type }
>
{ button.text }
className="ppcp-r-tab-overview-features"
title={ __( 'Features', 'woocommerce-paypal-payments' ) }
description={
<div>
<p>{ __( 'Enable additional features…' ) }</p>
<p>{ __( 'Click Refresh…' ) }</p>
<Button variant="tertiary">
{ data().getImage( 'icon-refresh.svg' ) }
{ __( 'Refresh', 'woocommerce-paypal-payments' ) }
</Button>
);
} ) }
</div>
</div>
}
contentItems={ featuresDefault.map( ( feature ) => (
<FeatureSettingsBlock
key={ feature.id }
title={ feature.title }
description={ feature.description }
actionProps={ {
buttons: feature.buttons,
featureStatus: feature.featureStatus,
notes: feature.notes,
badge: {
text: __(
'Active',
'woocommerce-paypal-payments'
),
type: TITLE_BADGE_POSITIVE,
},
} }
/>
) ) }
/>
</div>
);
};
const removeTodo = ( todoValue, todosData, changeTodos ) => {
changeTodos( todosData.filter( ( todo ) => todo.value !== todoValue ) );
};
const todosDataDefault = [
{
value: 'paypal_later_messaging',
@ -272,12 +116,12 @@ const featuresDefault = [
),
buttons: [
{
type: 'primary',
type: 'secondary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
type: 'tertiary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
@ -296,12 +140,12 @@ const featuresDefault = [
),
buttons: [
{
type: 'primary',
type: 'secondary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
type: 'tertiary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
@ -319,12 +163,12 @@ const featuresDefault = [
),
buttons: [
{
type: 'primary',
type: 'secondary',
text: __( 'Apply', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
type: 'tertiary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
@ -340,12 +184,12 @@ const featuresDefault = [
featureStatus: true,
buttons: [
{
type: 'primary',
type: 'secondary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
type: 'tertiary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
@ -363,7 +207,7 @@ const featuresDefault = [
),
buttons: [
{
type: 'primary',
type: 'secondary',
text: __(
'Domain registration',
'woocommerce-paypal-payments'
@ -371,7 +215,7 @@ const featuresDefault = [
url: '#',
},
{
type: 'secondary',
type: 'tertiary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
@ -386,16 +230,17 @@ const featuresDefault = [
),
buttons: [
{
type: 'primary',
type: 'secondary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
type: 'tertiary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
],
},
];
export default TabOverview;

View file

@ -1,24 +1,11 @@
import SettingsCard from '../../ReusableComponents/SettingsCard';
import { __ } from '@wordpress/i18n';
import PaymentMethodItem from '../../ReusableComponents/PaymentMethodItem';
import SettingsCard from '../../ReusableComponents/SettingsCard';
import PaymentMethodsBlock from '../../ReusableComponents/SettingsBlocks/PaymentMethodsBlock';
import ModalPayPal from './Modals/ModalPayPal';
import ModalFastlane from './Modals/ModalFastlane';
import ModalAcdc from './Modals/ModalAcdc';
const TabPaymentMethods = () => {
const renderPaymentMethods = ( data ) => {
return (
<div className="ppcp-r-payment-method-item-list">
{ data.map( ( paymentMethod ) => (
<PaymentMethodItem
key={ paymentMethod.id }
{ ...paymentMethod }
/>
) ) }
</div>
);
};
return (
<div className="ppcp-r-payment-methods">
<SettingsCard
@ -28,8 +15,11 @@ const TabPaymentMethods = () => {
'woocommerce-paypal-payments'
) }
icon="icon-checkout-standard.svg"
contentContainer={ false }
>
{ renderPaymentMethods( paymentMethodsPayPalCheckoutDefault ) }
<PaymentMethodsBlock
paymentMethods={ paymentMethodsPayPalCheckoutDefault }
/>
</SettingsCard>
<SettingsCard
title={ __(
@ -41,10 +31,11 @@ const TabPaymentMethods = () => {
'woocommerce-paypal-payments'
) }
icon="icon-checkout-online-methods.svg"
contentContainer={ false }
>
{ renderPaymentMethods(
paymentMethodsOnlineCardPaymentsDefault
) }
<PaymentMethodsBlock
paymentMethods={ paymentMethodsOnlineCardPaymentsDefault }
/>
</SettingsCard>
<SettingsCard
title={ __(
@ -56,8 +47,11 @@ const TabPaymentMethods = () => {
'woocommerce-paypal-payments'
) }
icon="icon-checkout-alternative-methods.svg"
contentContainer={ false }
>
{ renderPaymentMethods( paymentMethodsAlternativeDefault ) }
<PaymentMethodsBlock
paymentMethods={ paymentMethodsAlternativeDefault }
/>
</SettingsCard>
</div>
);
@ -124,7 +118,7 @@ const paymentMethodsOnlineCardPaymentsDefault = [
id: 'fastlane',
title: __( 'Fastlane by PayPal', 'woocommerce-paypal-payments' ),
description: __(
'Tap into the scale and trust of PayPals customer network to recognize shoppers and make guest checkout more seamless than ever.',
"Tap into the scale and trust of PayPal's customer network to recognize shoppers and make guest checkout more seamless than ever.",
'woocommerce-paypal-payments'
),
icon: 'payment-method-fastlane',

View file

@ -1,4 +1,5 @@
import { useState } from '@wordpress/element';
import ConnectionStatus from './TabSettingsElements/ConnectionStatus';
import CommonSettings from './TabSettingsElements/CommonSettings';
import ExpertSettings from './TabSettingsElements/ExpertSettings';
@ -31,6 +32,7 @@ const TabSettings = () => {
return (
<>
<div className="ppcp-r-settings">
<ConnectionStatus />
<CommonSettings
settings={ settings }
updateFormValue={ updateFormValue }

View file

@ -1,58 +1,63 @@
import { __ } from '@wordpress/i18n';
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_TYPE_EMPTY,
SETTINGS_BLOCK_TYPE_TOGGLE,
} from '../../../../ReusableComponents/SettingsBlock';
import {
Header,
SettingsBlock,
Title,
Description,
ToggleSettingsBlock,
} from '../../../../ReusableComponents/SettingsBlocks';
const OrderIntent = ( { updateFormValue, settings } ) => {
return (
<SettingsBlock
title={ __( 'Order Intent', 'woocommerce-paypal-payments' ) }
description={ __(
'Choose between immediate capture or authorization-only, with manual capture in the Orders section.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
className="ppcp-r-settings-block--order-intent"
actionProps={ {
type: SETTINGS_BLOCK_TYPE_EMPTY,
} }
>
<SettingsBlock
title={ __( 'Authorize Only', 'woocommerce-paypal-payments' ) }
description={ __(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc pellentesque libero vitae mattis tempor.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE,
callback: updateFormValue,
key: 'authorizeOnly',
value: settings.authorizeOnly,
} }
/>
components={ [
() => (
<>
<Header>
<Title>
{ __(
'Order Intent',
'woocommerce-paypal-payments'
) }
</Title>
<Description>
{ __(
'Choose between immediate capture or authorization-only, with manual capture in the Order section.',
'woocommerce-paypal-payments'
) }
</Description>
</Header>
</>
),
() => (
<>
<ToggleSettingsBlock
title={ __(
'Authorize Only',
'woocommerce-paypal-payments'
) }
actionProps={ {
callback: updateFormValue,
key: 'authorizeOnly',
value: settings.authorizeOnly,
} }
/>
<SettingsBlock
title={ __(
'Capture Virtual-Only Orders',
'woocommerce-paypal-payments'
) }
description={ __(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc pellentesque libero vitae mattis tempor.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE,
callback: updateFormValue,
key: 'captureVirtualOnlyOrders',
value: settings.captureVirtualOnlyOrders,
} }
/>
</SettingsBlock>
<ToggleSettingsBlock
title={ __(
'Capture Virtual-Only Orders',
'woocommerce-paypal-payments'
) }
actionProps={ {
callback: updateFormValue,
key: 'captureVirtualOnlyOrders',
value: settings.captureVirtualOnlyOrders,
} }
/>
</>
),
] }
/>
);
};

View file

@ -1,49 +1,8 @@
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_TYPE_SELECT,
SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
} from '../../../../ReusableComponents/SettingsBlock';
import { __ } from '@wordpress/i18n';
const OtherSettings = ( { settings, updateFormValue } ) => {
return (
<SettingsBlock
title={ __(
'Other payment method settings',
'woocommerce-paypal-payments'
) }
description={ __(
'Modify the checkout experience for alternative payment methods, credit cards, and digital wallets',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
} }
>
<SettingsBlock
title={ __(
'Disable specific credit cards',
'woocommerce-paypal-payments'
) }
description={ __(
'If left blank, PayPal and other buttons will present in the users detected language. Enter a language here to force all buttons to display in that language.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_SELECT,
options: creditCardExamples,
value: settings.buttonLanguage,
callback: updateFormValue,
key: 'buttonLanguage',
isMulti: true,
} }
/>
</SettingsBlock>
);
};
import {
AccordionSettingsBlock,
SelectSettingsBlock,
} from '../../../../ReusableComponents/SettingsBlocks';
const creditCardExamples = [
{ value: '', label: __( 'Select', 'woocommerce-paypal-payments' ) },
@ -63,4 +22,38 @@ const creditCardExamples = [
},
];
const OtherSettings = ( { settings, updateFormValue } ) => {
return (
<AccordionSettingsBlock
title={ __(
'Other payment method settings',
'woocommerce-paypal-payments'
) }
description={ __(
'Modify the checkout experience for alternative payment methods, credit cards, and digital wallets.',
'woocommerce-paypal-payments'
) }
>
<SelectSettingsBlock
title={ __(
'Disable specific credit cards',
'woocommerce-paypal-payments'
) }
description={ __(
"If left blank, PayPal and other buttons will present in the user's detected language. Enter a language here to force all buttons to display in that language.",
'woocommerce-paypal-payments'
) }
actionProps={ {
options: creditCardExamples,
value: settings.buttonLanguage,
callback: updateFormValue,
key: 'buttonLanguage',
isMulti: true,
} }
order={ [ 'title', 'description', 'action' ] }
/>
</AccordionSettingsBlock>
);
};
export default OtherSettings;

View file

@ -1,33 +1,28 @@
import { __ } from '@wordpress/i18n';
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_TYPE_EMPTY,
SETTINGS_BLOCK_TYPE_INPUT,
SETTINGS_BLOCK_TYPE_SELECT,
SETTINGS_BLOCK_TYPE_TOGGLE,
SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
} from '../../../../ReusableComponents/SettingsBlock';
import { PayPalRdbWithContent } from '../../../../ReusableComponents/Fields';
import {
AccordionSettingsBlock,
RadioSettingsBlock,
ToggleSettingsBlock,
InputSettingsBlock,
SelectSettingsBlock,
} from '../../../../ReusableComponents/SettingsBlocks';
const PaypalSettings = ( { updateFormValue, settings } ) => {
return (
<SettingsBlock
<AccordionSettingsBlock
className="ppcp-r-settings-block--settings"
title={ __( 'PayPal Settings', 'woocommerce-paypal-payments' ) }
description={ __(
'Modify the PayPal checkout experience',
'Modify the PayPal checkout experience.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
actionProps={ {
callback: updateFormValue,
type: SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
key: 'payNowExperience',
value: settings.payNowExperience,
} }
>
<SettingsBlock
<RadioSettingsBlock
title={ __(
'Subtotal mismatch fallback',
'woocommerce-paypal-payments'
@ -36,56 +31,41 @@ const PaypalSettings = ( { updateFormValue, settings } ) => {
'Due to differences in how WooCommerce and PayPal calculates taxes, some transactions may fail due to a rounding error. This settings determines the fallback behavior.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_EMPTY,
} }
>
<div className="ppcp-r-settings-block--mismatch-wrapper ppcp-r-settings-block--expert-rdb">
<PayPalRdbWithContent
id="add_a_correction"
name="paypal_settings_mismatch"
value="add_a_correction"
currentValue={ settings.subtotalMismatchFallback }
handleRdbState={ ( newValue ) =>
updateFormValue(
'subtotalMismatchFallback',
newValue
)
}
label={ __(
options={ [
{
id: 'add_a_correction',
value: 'add_a_correction',
label: __(
'Add a correction',
'woocommerce-paypal-payments'
) }
description={ __(
),
description: __(
'Adds an additional line item with the missing amount.',
'woocommerce-paypal-payments'
) }
/>
<PayPalRdbWithContent
id="do_not_send_line_items"
name="paypal_settings_mismatch"
value="do_not_send_line_items"
currentValue={ settings.subtotalMismatchFallback }
handleRdbState={ ( newValue ) =>
updateFormValue(
'subtotalMismatchFallback',
newValue
)
}
label={ __(
),
},
{
id: 'do_not_send_line_items',
value: 'do_not_send_line_items',
label: __(
'Do not send line items',
'woocommerce-paypal-payments'
) }
description={ __(
'Resubmit the transaction without line item details',
),
description: __(
'Resubmit the transaction without line item details.',
'woocommerce-paypal-payments'
) }
/>
</div>
</SettingsBlock>
),
},
] }
actionProps={ {
name: 'paypal_settings_mismatch',
key: 'subtotalMismatchFallback',
currentValue: settings.subtotalMismatchFallback,
callback: updateFormValue,
} }
/>
<SettingsBlock
<ToggleSettingsBlock
title={ __(
'Instant payments only',
'woocommerce-paypal-payments'
@ -94,23 +74,20 @@ const PaypalSettings = ( { updateFormValue, settings } ) => {
'If enabled, PayPal will not allow buyers to use funding sources that take additional time to complete, such as eChecks.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE,
value: settings.savePaypalAndVenmo,
callback: updateFormValue,
key: 'savePaypalAndVenmo',
} }
/>
<SettingsBlock
<InputSettingsBlock
title={ __( 'Brand name', 'woocommerce-paypal-payments' ) }
description={ __(
'What business name to show to your buyers during checkout and on receipts.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_INPUT,
value: settings.brandName,
callback: updateFormValue,
key: 'brandName',
@ -119,16 +96,16 @@ const PaypalSettings = ( { updateFormValue, settings } ) => {
'woocommerce-paypal-payments'
),
} }
order={ [ 'title', 'description', 'action' ] }
/>
<SettingsBlock
<InputSettingsBlock
title={ __( 'Soft Descriptor', 'woocommerce-paypal-payments' ) }
description={ __(
"The dynamic text used to construct the statement descriptor that appears on a payer's card statement. Applies to PayPal and Credit Card transactions. Max value of 22 characters.",
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_INPUT,
value: settings.softDescriptor,
callback: updateFormValue,
key: 'softDescriptor',
@ -137,8 +114,10 @@ const PaypalSettings = ( { updateFormValue, settings } ) => {
'woocommerce-paypal-payments'
),
} }
order={ [ 'title', 'description', 'action' ] }
/>
<SettingsBlock
<RadioSettingsBlock
title={ __(
'PayPal landing page',
'woocommerce-paypal-payments'
@ -147,74 +126,59 @@ const PaypalSettings = ( { updateFormValue, settings } ) => {
'Determine which experience a buyer sees when they click the PayPal button.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_EMPTY,
} }
>
<div className="ppcp-r-settings-block--landing ppcp-r-settings-block--expert-rdb">
<PayPalRdbWithContent
id="no_perference"
name="paypal_settings_landing"
value="no_reference"
currentValue={ settings.paypalLandingPage }
handleRdbState={ ( newValue ) =>
updateFormValue( 'paypalLandingPage', newValue )
}
label={ __(
options={ [
{
id: 'no_preference',
value: 'no_reference',
label: __(
'No preference',
'woocommerce-paypal-payments'
) }
description={ __(
),
description: __(
'Shows the buyer the PayPal login for a recognized PayPal buyer.',
'woocommerce-paypal-payments'
) }
/>
<PayPalRdbWithContent
id="login_page"
name="paypal_settings_landing"
value="login_page"
currentValue={ settings.paypalLandingPage }
handleRdbState={ ( newValue ) =>
updateFormValue( 'paypalLandingPage', newValue )
}
label={ __(
),
},
{
id: 'login_page',
value: 'login_page',
label: __(
'Login page',
'woocommerce-paypal-payments'
) }
description={ __(
),
description: __(
'Always show the buyer the PayPal login screen.',
'woocommerce-paypal-payments'
) }
/>
<PayPalRdbWithContent
id="guest_checkout_page"
name="paypal_settings_landing"
value="guest_checkout_page"
currentValue={ settings.paypalLandingPage }
handleRdbState={ ( newValue ) =>
updateFormValue( 'paypalLandingPage', newValue )
}
label={ __(
),
},
{
id: 'guest_checkout_page',
value: 'guest_checkout_page',
label: __(
'Guest checkout page',
'woocommerce-paypal-payments'
) }
description={ __(
),
description: __(
'Always show the buyer the guest checkout fields first.',
'woocommerce-paypal-payments'
) }
/>
</div>
</SettingsBlock>
<SettingsBlock
),
},
] }
actionProps={ {
name: 'paypal_settings_landing',
key: 'paypalLandingPage',
currentValue: settings.paypalLandingPage,
callback: updateFormValue,
} }
/>
<SelectSettingsBlock
title={ __( 'Button Language', 'woocommerce-paypal-payments' ) }
description={ __(
'If left blank, PayPal and other buttons will present in the users detected language. Enter a language here to force all buttons to display in that language.',
"If left blank, PayPal and other buttons will present in the user's detected language. Enter a language here to force all buttons to display in that language.",
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_SELECT,
value: settings.buttonLanguage,
callback: updateFormValue,
options: languagesExample,
@ -224,8 +188,9 @@ const PaypalSettings = ( { updateFormValue, settings } ) => {
'woocommerce-paypal-payments'
),
} }
order={ [ 'title', 'description', 'action' ] }
/>
</SettingsBlock>
</AccordionSettingsBlock>
);
};
@ -235,4 +200,5 @@ const languagesExample = [
{ value: 'es', label: 'Spanish' },
{ value: 'it', label: 'Italian' },
];
export default PaypalSettings;

View file

@ -1,43 +1,40 @@
import { __, sprintf } from '@wordpress/i18n';
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_STYLING_TYPE_TERTIARY,
SETTINGS_BLOCK_TYPE_EMPTY,
SETTINGS_BLOCK_TYPE_TOGGLE,
SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
} from '../../../../ReusableComponents/SettingsBlock';
import { Button } from '@wordpress/components';
import {
AccordionSettingsBlock,
ButtonSettingsBlock,
RadioSettingsBlock,
ToggleSettingsBlock,
InputSettingsBlock,
} from '../../../../ReusableComponents/SettingsBlocks';
import TitleBadge, {
TITLE_BADGE_POSITIVE,
} from '../../../../ReusableComponents/TitleBadge';
import ConnectionInfo, {
connectionStatusDataDefault,
} from '../../../../ReusableComponents/ConnectionInfo';
import { Button, TextControl } from '@wordpress/components';
import { PayPalRdbWithContent } from '../../../../ReusableComponents/Fields';
const Sandbox = ( { settings, updateFormValue } ) => {
const className = settings.sandboxConnected
? 'ppcp-r-settings-block--sandbox-connected'
: 'ppcp-r-settings-block--sandbox-disconnected';
return (
<SettingsBlock
<AccordionSettingsBlock
title={ __( 'Sandbox', 'woocommerce-paypal-payments' ) }
className={ className }
description={ __(
"Test your site in PayPal's Sandbox environment.<br /><strong>Note</strong>: No real payments/money movement occur in Sandbox mode. Do not ship orders made in this mode.",
"Test your site in PayPal's Sandbox environment.",
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
callback: updateFormValue,
key: 'payNowExperience',
value: settings.payNowExperience,
} }
>
{ settings.sandboxConnected && (
<SettingsBlock
<ButtonSettingsBlock
title={ __(
'Sandbox account credentials',
'woocommerce-paypal-payments'
@ -55,23 +52,14 @@ const Sandbox = ( { settings, updateFormValue } ) => {
) }
/>
}
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_EMPTY,
callback: updateFormValue,
key: 'sandboxAccountCredentials',
value: settings.sandboxAccountCredentials,
} }
>
<div className="ppcp-r-settings-block--sandbox">
<SettingsBlock
<ToggleSettingsBlock
title={ __(
'Enable sandbox mode',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_TERTIARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE,
callback: updateFormValue,
key: 'sandboxEnabled',
value: settings.sandboxEnabled,
@ -94,10 +82,10 @@ const Sandbox = ( { settings, updateFormValue } ) => {
) }
</Button>
</div>
</SettingsBlock>
</ButtonSettingsBlock>
) }
{ ! settings.sandboxConnected && (
<SettingsBlock
<RadioSettingsBlock
title={ __(
'Connect Sandbox Account',
'woocommerce-paypal-payments'
@ -106,92 +94,109 @@ const Sandbox = ( { settings, updateFormValue } ) => {
'Connect a PayPal Sandbox account in order to test your website. Transactions made will not result in actual money movement. Do not fulfil orders completed in Sandbox mode.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_EMPTY,
callback: updateFormValue,
key: 'sandboxAccountCredentials',
value: settings.sandboxAccountCredentials,
} }
>
<div className="ppcp-r-settings-block--connect-sandbox ppcp-r-settings-block--expert-rdb">
<PayPalRdbWithContent
id="sandbox_mode"
name="paypal_connect_sandbox"
value="sandbox_mode"
currentValue={ settings.sandboxMode }
toggleAdditionalContent={ true }
handleRdbState={ ( newValue ) =>
updateFormValue( 'sandboxMode', newValue )
}
label={ __(
options={ [
{
id: 'sandbox_mode',
value: 'sandbox_mode',
label: __(
'Sandbox Mode',
'woocommerce-paypal-payments'
) }
description={ __(
),
description: __(
'Activate Sandbox mode to safely test PayPal with sample data. Once your store is ready to go live, you can easily switch to your production account.',
'woocommerce-paypal-payments'
) }
>
<Button
variant="primary"
onClick={ () =>
updateFormValue( 'sandboxConnected', true )
}
>
{ __(
'Connect Sandbox Account',
'woocommerce-paypal-payments'
) }
</Button>
</PayPalRdbWithContent>
<PayPalRdbWithContent
id="manual_connect"
name="paypal_connect_sandbox"
value="manual_connect"
currentValue={ settings.sandboxMode }
toggleAdditionalContent={ true }
handleRdbState={ ( newValue ) =>
updateFormValue( 'sandboxMode', newValue )
}
label={ __(
),
additionalContent: (
<Button
variant="primary"
onClick={ () =>
updateFormValue(
'sandboxConnected',
true
)
}
>
{ __(
'Connect Sandbox Account',
'woocommerce-paypal-payments'
) }
</Button>
),
},
{
id: 'manual_connect',
value: 'manual_connect',
label: __(
'Manual Connect',
'woocommerce-paypal-payments'
) }
description={ sprintf(
// translators: %s: Link to creating PayPal REST application
),
description: sprintf(
__(
'For advanced users: Connect a custom PayPal REST app for full control over your integration. For more information on creating a PayPal REST application, <a target="_blank" href="%s">click here</a>.',
'woocommerce-paypal-payments'
),
'#'
) }
>
<TextControl
className="ppcp-r-vertical-text-control"
label={ __(
'Sandbox Client ID',
'woocommerce-paypal-payments'
) }
/>
<TextControl
className="ppcp-r-vertical-text-control"
label={ __(
'Sandbox Secrey Key',
'woocommerce-paypal-payments'
) }
/>
<Button variant="primary">
{ __(
'Connect Account',
'woocommerce-paypal-payments'
) }
</Button>
</PayPalRdbWithContent>
</div>
</SettingsBlock>
),
additionalContent: (
<>
<InputSettingsBlock
title={ __(
'Sandbox Client ID',
'woocommerce-paypal-payments'
) }
actionProps={ {
value: settings.sandboxClientId, // Add this to settings if not present
callback: updateFormValue,
key: 'sandboxClientId',
placeholder: __(
'Enter Client ID',
'woocommerce-paypal-payments'
),
} }
/>
<InputSettingsBlock
title={ __(
'Sandbox Secret Key',
'woocommerce-paypal-payments'
) }
actionProps={ {
value: settings.sandboxSecretKey, // Add this to settings if not present
callback: updateFormValue,
key: 'sandboxSecretKey',
placeholder: __(
'Enter Secret Key',
'woocommerce-paypal-payments'
),
} }
/>
<Button
variant="primary"
onClick={ () =>
updateFormValue(
'sandboxManuallyConnected',
true
)
} // Add this handler if needed
>
{ __(
'Connect Account',
'woocommerce-paypal-payments'
) }
</Button>
</>
),
},
] }
actionProps={ {
name: 'paypal_connect_sandbox',
key: 'sandboxMode',
currentValue: settings.sandboxMode,
callback: updateFormValue,
} }
/>
) }
</SettingsBlock>
</AccordionSettingsBlock>
);
};
export default Sandbox;

View file

@ -1,75 +1,83 @@
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_TYPE_EMPTY,
SETTINGS_BLOCK_TYPE_TOGGLE,
} from '../../../../ReusableComponents/SettingsBlock';
import { __, sprintf } from '@wordpress/i18n';
import {
SettingsBlock,
ToggleSettingsBlock,
Title,
Description,
} from '../../../../ReusableComponents/SettingsBlocks';
import { Header } from '../../../../ReusableComponents/SettingsBlocks/SettingsBlockElements';
const SavePaymentMethods = ( { updateFormValue, settings } ) => {
return (
<SettingsBlock
className="ppcp-r-settings-block--save-payment-methods"
title={ __(
'Save Payment Methods',
'woocommerce-paypal-payments'
) }
description={ sprintf(
// translators: first %s: Link to Future payments, second %s: Link to subscriptions
__(
'Securely store customers payment methods for <a target="_blank" href="%1$s">future payments[MISSING_LINK]</a> and <a target="_blank" href="%2$s">subscriptions[MISSING_LINK]</a>, simplifying checkout and enabling recurring transactions.',
'woocommerce-paypal-payments'
components={ [
() => (
<>
<Header>
<Title>
{ __(
'Save payment methods',
'woocommerce-paypal-payments'
) }
</Title>
<Description>
{ __(
'Securely store customers payment methods for future payments and subscriptions, simplifying checkout and enabling recurring transactions.',
'woocommerce-paypal-payments'
) }
</Description>
</Header>
</>
),
'#',
'#'
) }
type={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
style={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_EMPTY,
} }
>
<SettingsBlock
title={ __(
'Save PayPal and Venmo',
'woocommerce-paypal-payments'
) }
description={ sprintf(
// translators: first %s: Link to Pay Later, second %s: Link to Alternative Payment Methods
__(
'Securely store your customers PayPal accounts for a seamless checkout experience. <br />This will disable all <a target="_blank" href="%1$s">Pay Later</a> features and <a target="_blank" href="%2$s">Alternative Payment Methods</a> on your site.',
'woocommerce-paypal-payments'
),
'https://woocommerce.com/document/woocommerce-paypal-payments/#pay-later',
'https://woocommerce.com/document/woocommerce-paypal-payments/#alternative-payment-methods'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
value={ settings.savePaypalAndVenmo }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE,
value: settings.savePaypalAndVenmo,
callback: updateFormValue,
key: 'savePaypalAndVenmo',
} }
/>
<SettingsBlock
title={ __(
'Save Credit and Debit Cards',
'woocommerce-paypal-payments'
) }
description={ __(
"Securely store your customer's credit card.",
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: { SETTINGS_BLOCK_TYPE_TOGGLE },
callback: updateFormValue,
key: 'saveCreditCardAndDebitCard',
value: settings.saveCreditCardAndDebitCard,
} }
/>
</SettingsBlock>
() => (
<ToggleSettingsBlock
title={ __(
'Save PayPal and Venmo',
'woocommerce-paypal-payments'
) }
description={
<div
dangerouslySetInnerHTML={ {
__html: sprintf(
/* translators: 1: URL to Pay Later documentation, 2: URL to Alternative Payment Methods documentation */
__(
'Securely store your customers\' PayPal accounts for a seamless checkout experience. <br />This will disable all <a target="_blank" rel="noreferrer" href="%1$s">Pay Later</a> features and <a target="_blank" rel="noreferrer" href="%2$s">Alternative Payment Methods</a> on your site.',
'woocommerce-paypal-payments'
),
'https://woocommerce.com/document/woocommerce-paypal-payments/#pay-later',
'https://woocommerce.com/document/woocommerce-paypal-payments/#alternative-payment-methods'
),
} }
/>
}
actionProps={ {
value: settings.savePaypalAndVenmo,
callback: updateFormValue,
key: 'savePaypalAndVenmo',
} }
/>
),
() => (
<ToggleSettingsBlock
title={ __(
'Save Credit and Debit Cards',
'woocommerce-paypal-payments'
) }
description={ __(
"Securely store your customer's credit card.",
'woocommerce-paypal-payments'
) }
actionProps={ {
callback: updateFormValue,
key: 'saveCreditCardAndDebitCard',
value: settings.saveCreditCardAndDebitCard,
} }
/>
),
] }
/>
);
};
export default SavePaymentMethods;

View file

@ -1,65 +1,73 @@
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_TYPE_BUTTON,
SETTINGS_BLOCK_TYPE_EMPTY,
SETTINGS_BLOCK_TYPE_TOGGLE,
SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
} from '../../../../ReusableComponents/SettingsBlock';
import { __ } from '@wordpress/i18n';
import {
Header,
Title,
Description,
AccordionSettingsBlock,
ToggleSettingsBlock,
ButtonSettingsBlock,
} from '../../../../ReusableComponents/SettingsBlocks';
import SettingsBlock from '../../../../ReusableComponents/SettingsBlocks/SettingsBlock';
const Troubleshooting = ( { updateFormValue, settings } ) => {
return (
<SettingsBlock
<AccordionSettingsBlock
className="ppcp-r-settings-block--troubleshooting"
title={ __( 'Troubleshooting', 'woocommerce-paypal-payments' ) }
description={ __(
'Access tools to help debug and resolve issues.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
callback: updateFormValue,
key: 'payNowExperience',
value: settings.payNowExperience,
} }
>
<SettingsBlock
<ToggleSettingsBlock
title={ __( 'Logging', 'woocommerce-paypal-payments' ) }
description={ __(
'Log additional debugging information in the WooCommerce logs that can assist technical staff to determine issues.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE,
callback: updateFormValue,
key: 'logging',
value: settings.logging,
} }
/>
<SettingsBlock
title={ __(
'Subscribed PayPal webhooks',
'woocommerce-paypal-payments'
) }
description={ __(
'The following PayPal webhooks are subscribed. More information about the webhooks is available in the Webhook Status documentation.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_EMPTY,
callback: updateFormValue,
key: 'logging',
value: settings.logging,
} }
>
<HooksTable data={ hooksExampleData() } />
</SettingsBlock>
components={ [
() => (
<>
<Header>
<Title>
{ __(
'Subscribed PayPal webhooks',
'woocommerce-paypal-payments'
) }
</Title>
<Description>
{ __(
'The following PayPal webhooks are subscribed. More information about the webhooks is available in the',
'woocommerce-paypal-payments'
) }{ ' ' }
<a href="https://woocommerce.com/document/woocommerce-paypal-payments/#webhook-status">
{ __(
'Webhook Status documentation',
'woocommerce-paypal-payments'
) }
</a>
.
</Description>
</Header>
<HooksTable data={ hooksExampleData() } />
</>
),
] }
/>
<SettingsBlock
<ButtonSettingsBlock
title={ __(
'Resubscribe webhooks',
'woocommerce-paypal-payments'
@ -68,9 +76,7 @@ const Troubleshooting = ( { updateFormValue, settings } ) => {
'Click to remove the current webhook subscription and subscribe again, for example, if the website domain or URL structure changed.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_BUTTON,
buttonType: 'secondary',
callback: () =>
console.log(
@ -83,14 +89,13 @@ const Troubleshooting = ( { updateFormValue, settings } ) => {
),
} }
/>
<SettingsBlock
<ButtonSettingsBlock
title={ __(
'Simulate webhooks',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_BUTTON,
buttonType: 'secondary',
callback: () =>
console.log(
@ -103,7 +108,7 @@ const Troubleshooting = ( { updateFormValue, settings } ) => {
),
} }
/>
</SettingsBlock>
</AccordionSettingsBlock>
);
};

View file

@ -1,10 +1,8 @@
import { __ } from '@wordpress/i18n';
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_TYPE_INPUT,
SETTINGS_BLOCK_TYPE_TOGGLE,
} from '../../../ReusableComponents/SettingsBlock';
import {
InputSettingsBlock,
ToggleSettingsBlock,
} from '../../../ReusableComponents/SettingsBlocks';
import SettingsCard from '../../../ReusableComponents/SettingsCard';
import OrderIntent from './Blocks/OrderIntent';
import SavePaymentMethods from './Blocks/SavePaymentMethods';
@ -13,19 +11,21 @@ const CommonSettings = ( { updateFormValue, settings } ) => {
return (
<SettingsCard
icon="icon-settings-common.svg"
title={ __( 'Common Settings', 'woocommerce-paypal-payments' ) }
title={ __( 'Common settings', 'woocommerce-paypal-payments' ) }
className="ppcp-r-settings-card ppcp-r-settings-card--common-settings"
description={ __(
'Customize key features to tailor your PayPal experience.',
'woocommerce-paypal-payments'
) }
>
<SettingsBlock
<InputSettingsBlock
title="Invoice Prefix"
supplementaryLabel={ __(
'(Recommended)',
'woocommerce-paypal-payments'
) }
description="Add a unique prefix to invoice numbers for site-specific tracking (recommended)."
style={ SETTINGS_BLOCK_STYLING_TYPE_PRIMARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_INPUT,
callback: updateFormValue,
key: 'invoicePrefix',
value: settings.invoicePrefix,
@ -35,15 +35,18 @@ const CommonSettings = ( { updateFormValue, settings } ) => {
),
} }
/>
<OrderIntent
settings={ settings }
updateFormValue={ updateFormValue }
/>
<SavePaymentMethods
updateFormValue={ updateFormValue }
settings={ settings }
/>
<SettingsBlock
<ToggleSettingsBlock
title={ __(
'Pay Now Experience',
'woocommerce-paypal-payments'
@ -52,9 +55,7 @@ const CommonSettings = ( { updateFormValue, settings } ) => {
'Let PayPal customers skip the Order Review page by selecting shipping options directly within PayPal.',
'woocommerce-paypal-payments'
) }
style={ SETTINGS_BLOCK_STYLING_TYPE_SECONDARY }
actionProps={ {
type: SETTINGS_BLOCK_TYPE_TOGGLE,
callback: updateFormValue,
key: 'payNowExperience',
value: settings.payNowExperience,

View file

@ -0,0 +1,53 @@
import { __ } from '@wordpress/i18n';
import SettingsCard from '../../../ReusableComponents/SettingsCard';
import ConnectionInfo, {
connectionStatusDataDefault,
} from '../../../ReusableComponents/ConnectionInfo';
import TitleBadge, {
TITLE_BADGE_NEGATIVE,
TITLE_BADGE_POSITIVE,
} from '../../../ReusableComponents/TitleBadge';
const ConnectionStatus = () => {
return (
<SettingsCard
className="ppcp-r-tab-overview-support"
title={ __( 'Connection status', 'woocommerce-paypal-payments' ) }
description={ __(
'Your PayPal account connection details',
'woocommerce-paypal-payments'
) }
>
<div className="ppcp-r-connection-status">
<div className="ppcp-r-connection-status__status">
<div className="ppcp-r-connection-status__status-status">
{ connectionStatusDataDefault.connectionStatus ? (
<TitleBadge
type={ TITLE_BADGE_POSITIVE }
text={ __(
'Active',
'woocommerce-paypal-payments'
) }
/>
) : (
<TitleBadge
type={ TITLE_BADGE_NEGATIVE }
text={ __(
'Not Activated',
'woocommerce-paypal-payments'
) }
/>
) }
</div>
</div>
{ connectionStatusDataDefault.connectionStatus && (
<ConnectionInfo
connectionStatusDataDefault={
connectionStatusDataDefault
}
/>
) }
</div>
</SettingsCard>
);
};
export default ConnectionStatus;

View file

@ -1,11 +1,9 @@
import { __ } from '@wordpress/i18n';
import SettingsBlock, {
SETTINGS_BLOCK_STYLING_TYPE_PRIMARY,
SETTINGS_BLOCK_STYLING_TYPE_SECONDARY,
SETTINGS_BLOCK_TYPE_SELECT,
SETTINGS_BLOCK_TYPE_TOGGLE_CONTENT,
} from '../../../ReusableComponents/SettingsBlock';
import SettingsCard from '../../../ReusableComponents/SettingsCard';
import {
Content,
ContentWrapper,
} from '../../../ReusableComponents/SettingsBlocks';
import Sandbox from './Blocks/Sandbox';
import Troubleshooting from './Blocks/Troubleshooting';
import PaypalSettings from './Blocks/PaypalSettings';
@ -25,25 +23,37 @@ const ExpertSettings = ( { updateFormValue, settings } ) => {
callback: updateFormValue,
key: 'payNowExperience',
} }
contentContainer={ false }
>
<Sandbox
updateFormValue={ updateFormValue }
settings={ settings }
/>
<ContentWrapper>
<Content>
<Sandbox
updateFormValue={ updateFormValue }
settings={ settings }
/>
</Content>
<Troubleshooting
updateFormValue={ updateFormValue }
settings={ settings }
/>
<Content>
<Troubleshooting
updateFormValue={ updateFormValue }
settings={ settings }
/>
</Content>
<PaypalSettings
updateFormValue={ updateFormValue }
settings={ settings }
/>
<OtherSettings
updateFormValue={ updateFormValue }
settings={ settings }
/>
<Content>
<PaypalSettings
updateFormValue={ updateFormValue }
settings={ settings }
/>
</Content>
<Content>
<OtherSettings
updateFormValue={ updateFormValue }
settings={ settings }
/>
</Content>
</ContentWrapper>
</SettingsCard>
);
};