mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
🔀 Merge branch 'PCP-3793’
# Conflicts: # modules/ppcp-settings/resources/js/App.js
This commit is contained in:
commit
180df1001e
46 changed files with 957 additions and 35 deletions
12
modules/ppcp-settings/resources/css/_global.scss
Normal file
12
modules/ppcp-settings/resources/css/_global.scss
Normal file
|
@ -0,0 +1,12 @@
|
|||
* {
|
||||
font-family: "Inter", sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
a:not(.button) {
|
||||
color: $color-blueberry;
|
||||
}
|
||||
|
||||
.components-form-toggle.is-checked > .components-form-toggle__track {
|
||||
background-color: $color-blueberry;
|
||||
}
|
8
modules/ppcp-settings/resources/css/_mixins.scss
Normal file
8
modules/ppcp-settings/resources/css/_mixins.scss
Normal file
|
@ -0,0 +1,8 @@
|
|||
@mixin font($font-size, $line-height, $font-weight, $letter-spacing: false) {
|
||||
font-size: $font-size + px;
|
||||
line-height: calc($line-height / $font-size);
|
||||
font-weight: $font-weight;
|
||||
@if $letter-spacing {
|
||||
letter-spacing: $letter-spacing;
|
||||
}
|
||||
}
|
13
modules/ppcp-settings/resources/css/_variables.scss
Normal file
13
modules/ppcp-settings/resources/css/_variables.scss
Normal file
|
@ -0,0 +1,13 @@
|
|||
$color-white: #fff;
|
||||
$color-blue: #1D35B4;
|
||||
$color-blueberry: #3858E9;
|
||||
$color-gray-900: #1E1E1E;
|
||||
$color-gray-800: #2F2F2F;
|
||||
$color-gray-700: #757575;
|
||||
$color-gray-600: #949494;
|
||||
$color-gray-500: #BBBBBB;
|
||||
$color-gray-200: #E0E0E0;
|
||||
$color-gray: #646970;
|
||||
|
||||
$shadow-card: 0 3px 6px 0 rgba(0, 0, 0, 0.15);
|
||||
$gradient-header: linear-gradient(87.03deg, #003087 -0.49%, #001E51 29.22%, #001435 100%);
|
|
@ -0,0 +1,22 @@
|
|||
button.components-button {
|
||||
&.is-primary, &.is-secondary {
|
||||
background-color: $color-blueberry;
|
||||
border-radius: 2px;
|
||||
padding: 14px 17px;
|
||||
height: auto;
|
||||
&:hover {
|
||||
background: $gradient-header;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-primary {
|
||||
@include font(13, 16, 500);
|
||||
}
|
||||
|
||||
&.is-secondary {
|
||||
padding: 6px 12px;
|
||||
@include font(13, 20, 500);
|
||||
color: $color-white;
|
||||
border: none;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
.ppcp-r-onboarding-header{
|
||||
margin: 0 0 32px 0;
|
||||
|
||||
&__gradient {
|
||||
background: $gradient-header;
|
||||
width: 100%;
|
||||
height: 112px;
|
||||
position: relative;
|
||||
margin-bottom: 55px;
|
||||
}
|
||||
|
||||
&__logo-wrapper {
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
background-color: $color-white;
|
||||
border-radius: 110px;
|
||||
position: absolute;
|
||||
left: calc(50% - 55px);
|
||||
bottom: -55px;
|
||||
|
||||
img {
|
||||
width: 56px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
&__content {
|
||||
max-width: 458px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding:0 16px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include font(20, 28, 700);
|
||||
color: $color-blue;
|
||||
margin: 0 0 4px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__description {
|
||||
color: $color-gray-800;
|
||||
@include font(14, 20, 400);
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
.ppcp-r-payment-method-icons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
.ppcp-r-separator{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&__line {
|
||||
height: 1px;
|
||||
background-color: $color-gray-600;
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__text {
|
||||
color: $color-gray;
|
||||
@include font(12, 24, 500, 0.8px);
|
||||
text-transform: uppercase;
|
||||
padding: 0 23px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
.ppcp-r-toggle-block {
|
||||
&__wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
&__switch {
|
||||
.components-base-control__field > div {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&__content-label {
|
||||
@include font(14, 20, 600);
|
||||
display: block;
|
||||
margin: 0 0 4px 0;
|
||||
color: $color-gray-900;
|
||||
}
|
||||
|
||||
&__content-description {
|
||||
@include font(13, 18, 400);
|
||||
color: $color-gray-700;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&__toggled-content {
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
.ppcp-r {
|
||||
|
||||
&-inner-container {
|
||||
width: 652px;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
padding:0 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&-container {
|
||||
box-shadow: $shadow-card;
|
||||
max-width: 1024px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
&-card {
|
||||
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.15);
|
||||
background-color: $color-white;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
.components-base-control {
|
||||
&__label {
|
||||
color: $color-gray-900;
|
||||
@include font(13, 16, 600);
|
||||
margin: 0 0 8px 0;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
&__input {
|
||||
border: 1px solid $color-gray-700;
|
||||
border-radius: 2px;
|
||||
box-shadow: none;
|
||||
&:focus{
|
||||
border-color:$color-blueberry;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
.ppcp-r-page-welcome {
|
||||
.ppcp-r-inner-container {
|
||||
padding-bottom: 72px;
|
||||
@media screen and (max-width: 480px) {
|
||||
padding-bottom: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp-r-welcome-features {
|
||||
margin: 0 0 32px 0;
|
||||
}
|
||||
|
||||
.ppcp-r-payment-method-icons {
|
||||
margin: 0 0 12px 0;
|
||||
}
|
||||
|
||||
.ppcp-r-button-activate-paypal {
|
||||
display: block;
|
||||
margin: 0 auto 32px auto;
|
||||
}
|
||||
|
||||
.ppcp-r-page-welcome-or-separator {
|
||||
margin: 0 0 32px 0;
|
||||
}
|
||||
|
||||
.ppcp-r-page-welcome-mode-separator {
|
||||
margin: 32px 0;
|
||||
|
||||
.ppcp-r-separator__line {
|
||||
background-color: $color-gray-500;
|
||||
}
|
||||
}
|
||||
|
||||
.components-base-control__field {
|
||||
margin: 0 0 24px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ppcp-r-welcome-features {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
|
||||
&__col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
> span {
|
||||
@include font(11, 16, 600);
|
||||
text-transform: uppercase;
|
||||
color: $color-gray-800;
|
||||
}
|
||||
|
||||
> p {
|
||||
margin: 0;
|
||||
@include font(13, 16, 400);
|
||||
color: $color-gray-700;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
padding-right: 18px;
|
||||
border-right: 1px solid $color-gray-200;
|
||||
margin-right: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
flex-wrap: wrap;
|
||||
row-gap: 8px;
|
||||
&__col {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
||||
&:not(:last-child) {
|
||||
border-bottom: 1px solid $color-gray-200;
|
||||
border-right: 0;
|
||||
padding-right: 0;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1,14 @@
|
|||
.red {color:red;}
|
||||
@import 'variables';
|
||||
@import 'mixins';
|
||||
|
||||
#ppcp-settings-container {
|
||||
@import './global';
|
||||
@import './components/reusable-components/onboarding-header';
|
||||
@import './components/reusable-components/button';
|
||||
@import './components/reusable-components/settings-toggle-block';
|
||||
@import './components/reusable-components/text-control';
|
||||
@import './components/reusable-components/separator';
|
||||
@import './components/reusable-components/payment-method-icons';
|
||||
@import './components/reusable-components/settings-wrapper';
|
||||
@import './components/screens/onboarding/step-welcome';
|
||||
}
|
||||
|
|
|
@ -1,40 +1,9 @@
|
|||
import * as Store from './data';
|
||||
|
||||
const StoreTest = () => {
|
||||
const { isSaving, onboardingStep, setOnboardingStep } =
|
||||
Store.useOnboardingDetails();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<hr />
|
||||
<div>Onboarding Step: { onboardingStep }</div>
|
||||
<div>{ isSaving ? 'Saving...' : 'Not Saving' }</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type={ 'button' }
|
||||
onClick={ () => setOnboardingStep( onboardingStep - 1 ) }
|
||||
disabled={ onboardingStep < 1 }
|
||||
>
|
||||
Prev
|
||||
</button>
|
||||
<button
|
||||
type={ 'button' }
|
||||
onClick={ () => setOnboardingStep( onboardingStep + 1 ) }
|
||||
disabled={ onboardingStep > 3 }
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
import Onboarding from './components/screens/onboarding/onboarding.js';
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<div className="red">
|
||||
App
|
||||
<StoreTest />
|
||||
<div>
|
||||
<Onboarding />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
const Container = ( props ) => {
|
||||
return <div className="ppcp-r-container">{ props.children }</div>;
|
||||
};
|
||||
|
||||
export default Container;
|
|
@ -0,0 +1,25 @@
|
|||
import data from '../../utils/data';
|
||||
|
||||
const OnboardingHeader = ( props ) => {
|
||||
return (
|
||||
<section className="ppcp-r-onboarding-header">
|
||||
<div className="ppcp-r-onboarding-header__gradient">
|
||||
<div className="ppcp-r-onboarding-header__logo-wrapper">
|
||||
{ data().getImage( 'logo-paypal.svg' ) }
|
||||
</div>
|
||||
</div>
|
||||
<div className="ppcp-r-onboarding-header__content">
|
||||
<h1 className="ppcp-r-onboarding-header__title">
|
||||
{ props.title }
|
||||
</h1>
|
||||
{ props.description && (
|
||||
<p className="ppcp-r-onboarding-header__description">
|
||||
{ props.description }
|
||||
</p>
|
||||
) }
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default OnboardingHeader;
|
|
@ -0,0 +1,15 @@
|
|||
import data from '../../utils/data';
|
||||
|
||||
const PaymentMethodIcon = ( props ) => {
|
||||
if (
|
||||
( Array.isArray( props.icons ) &&
|
||||
props.icons.includes( props.type ) ) ||
|
||||
props.icons === 'all'
|
||||
) {
|
||||
return data().getImage( 'icon-button-' + props.type + '.svg' );
|
||||
}
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export default PaymentMethodIcon;
|
|
@ -0,0 +1,21 @@
|
|||
import PaymentMethodIcon from './payment-method-icon';
|
||||
|
||||
const PaymentMethodIcons = ( props ) => {
|
||||
return (
|
||||
<div className="ppcp-r-payment-method-icons">
|
||||
<PaymentMethodIcon type="paypal" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="venmo" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="visa" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="mastercard" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="amex" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="discover" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="apple-pay" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="google-pay" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="sepa" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="ideal" icons={ props.icons } />
|
||||
<PaymentMethodIcon type="bancontact" icons={ props.icons } />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PaymentMethodIcons;
|
|
@ -0,0 +1,26 @@
|
|||
const Separator = ( props ) => {
|
||||
let separatorClass = 'ppcp-r-separator';
|
||||
|
||||
if ( props?.className ) {
|
||||
separatorClass += ' ' + props.className;
|
||||
}
|
||||
|
||||
if ( props.text ) {
|
||||
return (
|
||||
<div className={ separatorClass }>
|
||||
<span className="ppcp-r-separator__line ppcp-r-separator__line--before"></span>
|
||||
|
||||
<span className="ppcp-r-separator__text">{ props.text }</span>
|
||||
<span className="ppcp-r-separator__line ppcp-r-separator__line--after"></span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={ separatorClass }>
|
||||
<span className="ppcp-r-separator__line ppcp-r-separator__line--before"></span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Separator;
|
|
@ -0,0 +1,43 @@
|
|||
import { useState } from '@wordpress/element';
|
||||
import { ToggleControl } from '@wordpress/components';
|
||||
|
||||
const SettingsToggleBlock = ( props ) => {
|
||||
const [ isToggled, setToggled ] = useState( false );
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-toggle-block">
|
||||
<div className="ppcp-r-toggle-block__wrapper">
|
||||
<div className="ppcp-r-toggle-block__content">
|
||||
{ props?.label && (
|
||||
<span className="ppcp-r-toggle-block__content-label">
|
||||
{ props.label }
|
||||
</span>
|
||||
) }
|
||||
{ props?.description && (
|
||||
<p
|
||||
className="ppcp-r-toggle-block__content-description"
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: props.description,
|
||||
} }
|
||||
></p>
|
||||
) }
|
||||
</div>
|
||||
<div className="ppcp-r-toggle-block__switch">
|
||||
<ToggleControl
|
||||
checked={ isToggled }
|
||||
onChange={ ( newValue ) => {
|
||||
setToggled( newValue );
|
||||
} }
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{ props.children && isToggled && (
|
||||
<div className="ppcp-r-toggle-block__toggled-content">
|
||||
{ props.children }
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsToggleBlock;
|
|
@ -0,0 +1,14 @@
|
|||
import Container from '../../reusable-components/container';
|
||||
import StepWelcome from './step-welcome.js';
|
||||
|
||||
const Onboarding = () => {
|
||||
return (
|
||||
<Container>
|
||||
<div className="ppcp-r-card">
|
||||
<StepWelcome />
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default Onboarding;
|
|
@ -0,0 +1,130 @@
|
|||
import OnboardingHeader from '../../reusable-components/onboarding-header.js';
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { Button, TextControl } from '@wordpress/components';
|
||||
import PaymentMethodIcons from '../../reusable-components/payment-method-icons';
|
||||
import SettingsToggleBlock from '../../reusable-components/settings-toggle-block';
|
||||
import Separator from '../../reusable-components/separator';
|
||||
|
||||
const StepWelcome = () => {
|
||||
return (
|
||||
<div className="ppcp-r-page-welcome">
|
||||
<OnboardingHeader
|
||||
title={ __(
|
||||
'Welcome to PayPal Payments',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
description={ __(
|
||||
'Your all-in-one checkout solution with PayPal, Venmo, Pay Later, all major credit/debit cards, Apple Pay, Google Pay, and more.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
/>
|
||||
<div className="ppcp-r-inner-container">
|
||||
<PaymentMethodIcons icons="all" />
|
||||
<WelcomeFeatures />
|
||||
<Button
|
||||
className="ppcp-r-button-activate-paypal"
|
||||
variant="primary"
|
||||
>
|
||||
{ __(
|
||||
'Activate PayPal Payments',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
</Button>
|
||||
<Separator
|
||||
className="ppcp-r-page-welcome-or-separator"
|
||||
text={ __( 'or', 'woocommerce-paypal-payments' ) }
|
||||
/>
|
||||
<WelcomeForm />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const WelcomeFeatures = () => {
|
||||
return (
|
||||
<div className="ppcp-r-welcome-features">
|
||||
<div className="ppcp-r-welcome-features__col">
|
||||
<span>{ __( 'Deposits', 'woocommerce-paypal-payments' ) }</span>
|
||||
<p>{ __( 'Instant', 'woocommerce-paypal-payments' ) }</p>
|
||||
</div>
|
||||
<div className="ppcp-r-welcome-features__col">
|
||||
<span>
|
||||
{ __( 'Payment Capture', 'woocommerce-paypal-payments' ) }
|
||||
</span>
|
||||
<p>
|
||||
{ __(
|
||||
'Authorize only or Capture',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
</p>
|
||||
</div>
|
||||
<div className="ppcp-r-welcome-features__col">
|
||||
<span>
|
||||
{ __(
|
||||
'Recurring payments',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
</span>
|
||||
<p>{ __( 'Supported', 'woocommerce-paypal-payments' ) }</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const WelcomeForm = () => {
|
||||
const advancedUsersDescription = sprintf(
|
||||
// translators: %s: Link to PayPal REST application guide
|
||||
__(
|
||||
'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 href="%s">click here</a>.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
'#'
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsToggleBlock
|
||||
label={ __(
|
||||
'Enable Sandbox Mode',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
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="secondary">
|
||||
{ __( 'Connect Account', 'woocommerce-paypal-payments' ) }
|
||||
</Button>
|
||||
</SettingsToggleBlock>
|
||||
<Separator className="ppcp-r-page-welcome-mode-separator" />
|
||||
<SettingsToggleBlock
|
||||
label={ __(
|
||||
'Manually Connect - TODO missing link',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
description={ advancedUsersDescription }
|
||||
>
|
||||
<TextControl
|
||||
label={ __(
|
||||
'Sandbox Client ID',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
></TextControl>
|
||||
|
||||
<TextControl
|
||||
label={ __(
|
||||
'Sandbox Secret Key',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
type="password"
|
||||
></TextControl>
|
||||
<Button variant="secondary">
|
||||
{ __( 'Connect Account', 'woocommerce-paypal-payments' ) }
|
||||
</Button>
|
||||
</SettingsToggleBlock>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StepWelcome;
|
18
modules/ppcp-settings/resources/js/utils/data.js
Normal file
18
modules/ppcp-settings/resources/js/utils/data.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
const data = () => {
|
||||
return {
|
||||
...global.ppcpSettings,
|
||||
getImage( imageName, className = '' ) {
|
||||
const pathToImages = global.ppcpSettings.assets.imagesUrl;
|
||||
|
||||
return (
|
||||
<img
|
||||
className={ className }
|
||||
alt=""
|
||||
src={ pathToImages + imageName }
|
||||
/>
|
||||
);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default data;
|
Loading…
Add table
Add a link
Reference in a new issue