🔀 Merge branch 'trunk'

# Conflicts:
#	modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss
#	modules/ppcp-settings/resources/css/style.scss
#	modules/ppcp-settings/resources/js/Components/ReusableComponents/TabNavigation.js
#	modules/ppcp-settings/resources/js/Components/Screens/Dashboard/Dashboard.js
#	modules/ppcp-settings/resources/js/Components/Screens/Settings.js
This commit is contained in:
Philipp Stracker 2024-10-28 16:09:09 +01:00
commit 0c16bfeb93
No known key found for this signature in database
36 changed files with 1072 additions and 80 deletions

View file

@ -1,5 +1,18 @@
const Container = ( props ) => {
return <div className="ppcp-r-container">{ props.children }</div>;
export const PAGE_ONBOARDING = 'onboarding';
export const PAGE_SETTINGS = 'settings';
const Container = ( { isCard = true, page, children } ) => {
let className = 'ppcp-r-container';
if ( isCard ) {
className += ' ppcp-r-container--card';
}
if ( page ) {
className += ` ppcp-r-container--${ page }`;
}
return <div className={ className }>{ children }</div>;
};
export default Container;

View file

@ -0,0 +1,50 @@
import data from '../../utils/data';
export const PayPalCheckbox = ( props ) => {
return (
<div className="ppcp-r__checkbox">
<input
className="ppcp-r__checkbox-value"
type="checkbox"
checked={ props.currentValue.includes( props.value ) }
name={ props.name }
value={ props.value }
onChange={ ( e ) =>
props.handleCheckboxState( e.target.checked, props )
}
/>
<span className="ppcp-r__checkbox-presentation">
{ data().getImage( 'icon-checkbox.svg' ) }
</span>
</div>
);
};
export const PayPalRdb = ( props ) => {
return (
<div className="ppcp-r__radio">
<input
className="ppcp-r__radio-value"
type="radio"
checked={ props.value === props.currentValue }
name={ props.name }
value={ props.value }
onChange={ () => props.handleRdbState( props.value ) }
/>
<span className="ppcp-r__radio-presentation"></span>
</div>
);
};
export const handleCheckboxState = ( checked, props ) => {
let newValue = null;
if ( checked ) {
newValue = [ ...props.currentValue, props.value ];
props.changeCallback( newValue );
} else {
newValue = props.currentValue.filter(
( value ) => value !== props.value
);
}
props.changeCallback( newValue );
};

View file

@ -1,19 +1,7 @@
import data from '../../utils/data';
import { PayPalCheckbox, PayPalRdb, handleCheckboxState } from './Fields';
const SelectBox = ( props ) => {
const handleCheckboxState = ( checked ) => {
let newValue = null;
if ( checked ) {
newValue = [ ...props.currentValue, props.value ];
props.changeCallback( newValue );
} else {
newValue = props.currentValue.filter(
( value ) => value !== props.value
);
}
props.changeCallback( newValue );
};
let boxClassName = 'ppcp-r-select-box';
if (
@ -27,34 +15,20 @@ const SelectBox = ( props ) => {
return (
<div className={ boxClassName }>
{ props.type === 'radio' && (
<div className="ppcp-r-select-box__radio">
<input
className="ppcp-r-select-box__radio-value"
type="radio"
checked={ props.value === props.currentValue }
name={ props.name }
value={ props.value }
onChange={ () => props.changeCallback( props.value ) }
/>
<span className="ppcp-r-select-box__radio-presentation"></span>
</div>
<PayPalRdb
{ ...{
...props,
handleRdbState: props.changeCallback,
} }
/>
) }
{ props.type === 'checkbox' && (
<div className="ppcp-r-select-box__checkbox">
<input
className="ppcp-r-select-box__checkbox-value"
type="checkbox"
checked={ props.currentValue.includes( props.value ) }
name={ props.name }
value={ props.value }
onChange={ ( e ) =>
handleCheckboxState( e.target.checked )
}
/>
<span className="ppcp-r-select-box__checkbox-presentation">
{ data().getImage( 'icon-checkbox.svg' ) }
</span>
</div>
<PayPalCheckbox
{ ...{
...props,
handleCheckboxState,
} }
/>
) }
<div className="ppcp-r-select-box__content">
{ data().getImage( props.icon ) }

View file

@ -0,0 +1,29 @@
import data from '../../utils/data';
const SettingsCard = ( props ) => {
let className = 'ppcp-r-settings-card';
if ( props?.className ) {
className += ' ' + props.className;
}
return (
<div className={ className }>
<div className="ppcp-r-settings-card__header">
{ data().getImage( props.icon ) }
<div className="ppcp-r-settings-card__content-inner">
<span className="ppcp-r-settings-card__title">
{ props.title }
</span>
<p className="ppcp-r-settings-card__description">
{ props.description }
</p>
</div>
</div>
<div className="ppcp-r-settings-card__content">
{ props.children }
</div>
</div>
);
};
export default SettingsCard;

View file

@ -0,0 +1,8 @@
const TitleBadge = ( { text, type } ) => {
const className = 'ppcp-r-title-badge ' + `ppcp-r-title-badge--${ type }`;
return <span className={ className }>{ text }</span>;
};
export const TITLE_BADGE_POSITIVE = 'positive';
export const TITLE_BADGE_NEGATIVE = 'negative';
export default TitleBadge;

View file

@ -1,7 +0,0 @@
import TabNavigation from '../../ReusableComponents/TabNavigation';
const Dashboard = () => {
return <div>Settings Page</div>;
};
export default Dashboard;

View file

@ -0,0 +1,450 @@
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';
const TabDashboard = () => {
const [ todos, setTodos ] = useState( [] );
const [ todosData, setTodosData ] = useState( todosDataDefault );
const [ connectionData, setConnectionData ] = useState( {
connectionStatus: true,
showAllData: false,
email: 'bt_us@woocommerce.com',
merchantId: 'AT45V2DGMKLRY',
clientId: 'BAARTJLxtUNN4d2GMB6Eut3suMDYad72xQA-FntdIFuJ6FmFJITxAY8',
} );
const showAllData = () => {
setConnectionData( { ...connectionData, showAllData: true } );
};
return (
<div className="ppcp-r-tab-dashboard">
{ todosData.length > 0 && (
<SettingsCard
className="ppcp-r-tab-dashboard-todo"
icon="icon-dashboard-list.svg"
title={ __(
'Things to do next',
'woocommerce-paypal-payments'
) }
description={ __(
'Complete these tasks to keep your store updated with the latest products and services.',
'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>
</SettingsCard>
) }
<SettingsCard
className="ppcp-r-tab-dashboard-support"
icon="icon-dashboard-support.svg"
title={ __( 'Status', 'woocommerce-paypal-payments' ) }
description={ __(
'Your PayPal account connection details, along with available products and features.',
'woocommerce-paypal-payments'
) }
>
<ConnectionStatus
connectionData={ connectionData }
showAllData={ showAllData }
/>
<FeaturesRefresh />
{ featuresDefault.map( ( feature ) => {
return (
<FeatureItem key={ feature.id } feature={ feature } />
);
} ) }
</SettingsCard>
</div>
);
};
const ConnectionStatus = ( { connectionData, showAllData } ) => {
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 && (
<div className="ppcp-r-connection-status__data">
<div className="ppcp-r-connection-status__status-row">
<strong>
{ __(
'Email address:',
'woocommerce-paypal-payments'
) }
</strong>
<span>{ connectionData.email }</span>
{ ! connectionData.showAllData && (
<span onClick={ () => showAllData() }>
{ data().getImage(
'icon-arrow-down.svg',
'ppcp-r-connection-status__show-all-data'
) }
</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>
) }
</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 }
</Button>
);
} ) }
</div>
</div>
);
};
const removeTodo = ( todoValue, todosData, changeTodos ) => {
changeTodos( todosData.filter( ( todo ) => todo.value !== todoValue ) );
};
const todosDataDefault = [
{
value: 'paypal_later_messaging',
description: __(
'Enable Pay Later messaging',
'woocommerce-paypal-payments'
),
},
{
value: 'capture_authorized_payments',
description: __(
'Capture authorized payments',
'woocommerce-paypal-payments'
),
},
{
value: 'enable_google_pay',
description: __( 'Enable Google Pay', 'woocommerce-paypal-payments' ),
},
{
value: 'paypal_shortcut',
description: __(
'Add PayPal shortcut to the Cart page',
'woocommerce-paypal-payments'
),
},
{
value: 'advanced_cards',
description: __(
'Add Advanced Cards to Blocks Checkout',
'woocommerce-paypal-payments'
),
},
];
const featuresDefault = [
{
id: 'save_paypal_and_venmo',
title: __( 'Save PayPal and Venmo', 'woocommerce-paypal-payments' ),
description: __(
'Securely save PayPal and Venmo payment methods for subscriptions or return buyers.',
'woocommerce-paypal-payments'
),
buttons: [
{
type: 'primary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
],
},
{
id: 'advanced_credit_and_debit_cards',
title: __(
'Advanced Credit and Debit Cards',
'woocommerce-paypal-payments'
),
featureStatus: true,
description: __(
'Process major credit and debit cards including Visa, Mastercard, American Express and Discover.',
'woocommerce-paypal-payments'
),
buttons: [
{
type: 'primary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
],
},
{
id: 'alternative_payment_methods',
title: __(
'Alternative Payment Methods',
'woocommerce-paypal-payments'
),
description: __(
'Offer global, country-specific payment options for your customers.',
'woocommerce-paypal-payments'
),
buttons: [
{
type: 'primary',
text: __( 'Apply', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
],
},
{
id: 'google_pay',
title: __( 'Google Pay', 'woocommerce-paypal-payments' ),
description: __(
'Let customers pay using their Google Pay wallet.',
'woocommerce-paypal-payments'
),
featureStatus: true,
buttons: [
{
type: 'primary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
],
notes: [
__( '¹PayPal Q2 Earnings-2021.', 'woocommerce-paypal-payments' ),
],
},
{
id: 'apple_pay',
title: __( 'Apple Pay', 'woocommerce-paypal-payments' ),
description: __(
'Let customers pay using their Apple Pay wallet.',
'woocommerce-paypal-payments'
),
buttons: [
{
type: 'primary',
text: __(
'Domain registration',
'woocommerce-paypal-payments'
),
url: '#',
},
{
type: 'secondary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
],
},
{
id: 'pay_later_messaging',
title: __( 'Pay Later Messaging', 'woocommerce-paypal-payments' ),
description: __(
'Let customers know they can buy now and pay later with PayPal. Adding this messaging can boost conversion rates and increase cart sizes by 39%¹, with no extra cost to you—plus, you get paid up front.',
'woocommerce-paypal-payments'
),
buttons: [
{
type: 'primary',
text: __( 'Configure', 'woocommerce-paypal-payments' ),
url: '#',
},
{
type: 'secondary',
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
url: '#',
},
],
},
];
export default TabDashboard;

View file

@ -0,0 +1,5 @@
const TabPaymentMethods = () => {
return <div>PaymentMethods tab</div>;
};
export default TabPaymentMethods;

View file

@ -0,0 +1,5 @@
const TabSettings = () => {
return <div>Settings tab</div>;
};
export default TabSettings;

View file

@ -0,0 +1,5 @@
const TabStyling = () => {
return <div>Styling tab</div>;
};
export default TabStyling;

View file

@ -1,15 +1,16 @@
import Container from '../../ReusableComponents/Container.js';
import Container, {
PAGE_ONBOARDING,
} from '../../ReusableComponents/Container.js';
import StepWelcome from './StepWelcome.js';
import StepBusiness from './StepBusiness.js';
import StepProducts from './StepProducts.js';
import { useState } from '@wordpress/element';
import Dashboard from '../Dashboard/Dashboard';
const Onboarding = () => {
const [ step, setStep ] = useState( 0 );
return (
<Container>
<Container page={ PAGE_ONBOARDING }>
<div className="ppcp-r-card">
<Stepper currentStep={ step } setStep={ setStep } />
</div>

View file

@ -1,6 +1,9 @@
import { __ } from '@wordpress/i18n';
import Dashboard from './Dashboard/Dashboard';
import Onboarding from './Onboarding/Onboarding';
import TabDashboard from './Dashboard/TabDashboard';
import TabPaymentMethods from './Dashboard/TabPaymentMethods';
import TabSettings from './Dashboard/TabSettings';
import TabStyling from './Dashboard/TabStyling';
export const getSettingsTabs = () => {
const tabs = [];
@ -18,23 +21,25 @@ export const getSettingsTabs = () => {
tabs.push( {
name: 'dashboard',
title: __( 'Dashboard', 'woocommerce-paypal-payments' ),
component: <Dashboard />,
component: <TabDashboard />,
} );
tabs.push( {
name: 'payment-methods',
title: __( 'Payment Methods', 'woocommerce-paypal-payments' ),
component: <Dashboard />,
component: <TabPaymentMethods />,
} );
tabs.push( {
name: 'settings',
title: __( 'Settings', 'woocommerce-paypal-payments' ),
component: <TabSettings />,
} );
tabs.push( {
name: 'styling',
title: __( 'Styling', 'woocommerce-paypal-payments' ),
component: <TabStyling />,
} );
}