mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Refactor the Overview tab > Features > Buttons
This commit is contained in:
parent
7a223de4a7
commit
e4e95de5f6
15 changed files with 602 additions and 239 deletions
|
@ -119,8 +119,6 @@
|
|||
background-color: $color-white;
|
||||
|
||||
&::before {
|
||||
transform: translate(3px, 3px);
|
||||
border-width: 6px;
|
||||
border-color: $color-blueberry;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,26 @@ const FeatureSettingsBlock = ( { title, description, ...props } ) => {
|
|||
);
|
||||
};
|
||||
|
||||
const renderButton = ( button ) => {
|
||||
const buttonElement = (
|
||||
<Button
|
||||
key={ button.text }
|
||||
variant={ button.type }
|
||||
onClick={ button.onClick }
|
||||
>
|
||||
{ button.text }
|
||||
</Button>
|
||||
);
|
||||
|
||||
return button.urls ? (
|
||||
<a href={ button.urls.live } key={ button.text }>
|
||||
{ buttonElement }
|
||||
</a>
|
||||
) : (
|
||||
buttonElement
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<SettingsBlock { ...props } className="ppcp-r-settings-block__feature">
|
||||
<Header>
|
||||
|
@ -35,15 +55,7 @@ const FeatureSettingsBlock = ( { title, description, ...props } ) => {
|
|||
</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>
|
||||
) ) }
|
||||
{ props.actionProps?.buttons.map( renderButton ) }
|
||||
</div>
|
||||
</Action>
|
||||
</SettingsBlock>
|
||||
|
|
|
@ -1,51 +1,50 @@
|
|||
import { useState } from '@wordpress/element';
|
||||
import { ToggleControl } from '@wordpress/components';
|
||||
import SettingsBlock from './SettingsBlock';
|
||||
import PaymentMethodIcon from '../PaymentMethodIcon';
|
||||
import data from '../../../utils/data';
|
||||
import { MODAL_CONFIG } from '../../Screens/Overview/Modals/Modal';
|
||||
|
||||
const PaymentMethodItemBlock = ( props ) => {
|
||||
const [ toggleIsChecked, setToggleIsChecked ] = useState( false );
|
||||
const [ modalIsVisible, setModalIsVisible ] = useState( false );
|
||||
const Modal = props?.modal;
|
||||
const PaymentMethodItemBlock = ( {
|
||||
id,
|
||||
title,
|
||||
description,
|
||||
icon,
|
||||
onTriggerModal,
|
||||
onSelect,
|
||||
isSelected,
|
||||
} ) => {
|
||||
// Only show settings icon if this method has a modal configured
|
||||
const hasModal = Boolean( MODAL_CONFIG[ id ] );
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsBlock className="ppcp-r-settings-block__payment-methods__item">
|
||||
<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={ toggleIsChecked }
|
||||
onChange={ setToggleIsChecked }
|
||||
/>
|
||||
{ Modal && (
|
||||
<div
|
||||
className="ppcp-r-settings-block__payment-methods__item__settings"
|
||||
onClick={ () => setModalIsVisible( true ) }
|
||||
>
|
||||
{ data().getImage( 'icon-settings.svg' ) }
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
<SettingsBlock className="ppcp-r-settings-block__payment-methods__item">
|
||||
<div className="ppcp-r-settings-block__payment-methods__item__inner">
|
||||
<div className="ppcp-r-settings-block__payment-methods__item__title-wrapper">
|
||||
<PaymentMethodIcon icons={ [ icon ] } type={ icon } />
|
||||
<span className="ppcp-r-settings-block__payment-methods__item__title">
|
||||
{ title }
|
||||
</span>
|
||||
</div>
|
||||
</SettingsBlock>
|
||||
{ Modal && modalIsVisible && (
|
||||
<Modal setModalIsVisible={ setModalIsVisible } />
|
||||
) }
|
||||
</>
|
||||
<p className="ppcp-r-settings-block__payment-methods__item__description">
|
||||
{ description }
|
||||
</p>
|
||||
<div className="ppcp-r-settings-block__payment-methods__item__footer">
|
||||
<ToggleControl
|
||||
__nextHasNoMarginBottom={ true }
|
||||
checked={ isSelected }
|
||||
onChange={ onSelect }
|
||||
/>
|
||||
{ hasModal && onTriggerModal && (
|
||||
<div
|
||||
className="ppcp-r-settings-block__payment-methods__item__settings"
|
||||
onClick={ onTriggerModal }
|
||||
>
|
||||
{ data().getImage( 'icon-settings.svg' ) }
|
||||
</div>
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
</SettingsBlock>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -2,7 +2,11 @@ import { useState, useCallback } from '@wordpress/element';
|
|||
import SettingsBlock from './SettingsBlock';
|
||||
import PaymentMethodItemBlock from './PaymentMethodItemBlock';
|
||||
|
||||
const PaymentMethodsBlock = ( { paymentMethods, className = '' } ) => {
|
||||
const PaymentMethodsBlock = ( {
|
||||
paymentMethods,
|
||||
className = '',
|
||||
onTriggerModal,
|
||||
} ) => {
|
||||
const [ selectedMethod, setSelectedMethod ] = useState( null );
|
||||
|
||||
const handleSelect = useCallback( ( methodId, isSelected ) => {
|
||||
|
@ -25,6 +29,9 @@ const PaymentMethodsBlock = ( { paymentMethods, className = '' } ) => {
|
|||
onSelect={ ( checked ) =>
|
||||
handleSelect( paymentMethod.id, checked )
|
||||
}
|
||||
onTriggerModal={ () =>
|
||||
onTriggerModal?.( paymentMethod.id )
|
||||
}
|
||||
/>
|
||||
) ) }
|
||||
</SettingsBlock>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Content, ContentWrapper } from './SettingsBlocks';
|
||||
|
||||
const SettingsCard = ( {
|
||||
id,
|
||||
className: extraClassName,
|
||||
title,
|
||||
description,
|
||||
|
@ -33,7 +34,7 @@ const SettingsCard = ( {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className={ className }>
|
||||
<div id={ id } className={ className }>
|
||||
<div className="ppcp-r-settings-card__header">
|
||||
<div className="ppcp-r-settings-card__content-inner">
|
||||
<span className="ppcp-r-settings-card__title">
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { useCallback, useEffect, useState } from '@wordpress/element';
|
||||
|
||||
// TODO: Migrate to Tabs (TabPanel v2) once its API is publicly available, as it provides programmatic tab switching support: https://github.com/WordPress/gutenberg/issues/52997
|
||||
import { TabPanel } from '@wordpress/components';
|
||||
|
||||
import { getQuery, updateQueryString } from '../../utils/navigation';
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import ModalPayPal from './ModalPayPal';
|
||||
import ModalFastlane from './ModalFastlane';
|
||||
import ModalAcdc from './ModalAcdc';
|
||||
import { useActiveModal } from '../../../../data/common/hooks';
|
||||
|
||||
export const MODAL_CONFIG = {
|
||||
paypal: {
|
||||
component: ModalPayPal,
|
||||
icon: 'payment-method-paypal-big',
|
||||
title: __( 'PayPal', 'woocommerce-paypal-payments' ),
|
||||
},
|
||||
fastlane: {
|
||||
component: ModalFastlane,
|
||||
icon: 'payment-method-fastlane-big',
|
||||
title: __( 'Fastlane by PayPal', 'woocommerce-paypal-payments' ),
|
||||
size: 'small',
|
||||
},
|
||||
advanced_credit_and_debit_card_payments: {
|
||||
component: ModalAcdc,
|
||||
icon: 'payment-method-cards-big',
|
||||
title: __(
|
||||
'Advanced Credit and Debit Card Payments',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
const Modal = () => {
|
||||
const { activeModal, setActiveModal } = useActiveModal();
|
||||
|
||||
const handleCloseModal = () => {
|
||||
setActiveModal( '' );
|
||||
};
|
||||
|
||||
if ( ! activeModal || ! MODAL_CONFIG[ activeModal ] ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { component: ModalComponent, ...modalProps } =
|
||||
MODAL_CONFIG[ activeModal ];
|
||||
|
||||
return (
|
||||
<ModalComponent
|
||||
setModalIsVisible={ handleCloseModal }
|
||||
{ ...modalProps }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
|
@ -1,5 +1,5 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import { useState } from '@wordpress/element';
|
||||
import { useState, useMemo } from '@wordpress/element';
|
||||
import { Button, Icon } from '@wordpress/components';
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
import { reusableBlock } from '@wordpress/icons';
|
||||
|
@ -10,6 +10,7 @@ import FeatureSettingsBlock from '../../ReusableComponents/SettingsBlocks/Featur
|
|||
import { TITLE_BADGE_POSITIVE } from '../../ReusableComponents/TitleBadge';
|
||||
import { useMerchantInfo } from '../../../data/common/hooks';
|
||||
import { STORE_NAME } from '../../../data/common';
|
||||
import Features from './TabSettingsElements/Blocks/Features';
|
||||
|
||||
const TabOverview = () => {
|
||||
const [ todos, setTodos ] = useState( [] );
|
||||
|
@ -17,32 +18,39 @@ const TabOverview = () => {
|
|||
const [ isRefreshing, setIsRefreshing ] = useState( false );
|
||||
|
||||
const { merchant } = useMerchantInfo();
|
||||
const { refreshFeatureStatuses } = useDispatch( STORE_NAME );
|
||||
const { refreshFeatureStatuses, setActiveModal } =
|
||||
useDispatch( STORE_NAME );
|
||||
|
||||
const features = featuresDefault.map( ( feature ) => {
|
||||
const merchantFeature = merchant?.features?.[ feature.id ];
|
||||
return {
|
||||
...feature,
|
||||
enabled: merchantFeature?.enabled ?? false,
|
||||
};
|
||||
} );
|
||||
// Get the features data with access to setActiveModal
|
||||
const featuresData = useMemo(
|
||||
() => Features.getFeatures( setActiveModal ),
|
||||
[ setActiveModal ]
|
||||
);
|
||||
|
||||
// Map merchant features status to our config
|
||||
const features = useMemo( () => {
|
||||
return featuresData.map( ( feature ) => {
|
||||
const merchantFeature = merchant?.features?.[ feature.id ];
|
||||
return {
|
||||
...feature,
|
||||
enabled: merchantFeature?.enabled ?? false,
|
||||
};
|
||||
} );
|
||||
}, [ featuresData, merchant?.features ] );
|
||||
|
||||
const refreshHandler = async () => {
|
||||
setIsRefreshing( true );
|
||||
|
||||
const result = await refreshFeatureStatuses();
|
||||
|
||||
// TODO: Implement the refresh logic, remove this debug code -- PCP-4024
|
||||
if ( result && ! result.success ) {
|
||||
console.error(
|
||||
'Failed to refresh features:',
|
||||
result.message || 'Unknown error'
|
||||
);
|
||||
} else {
|
||||
console.log( 'Features refreshed successfully.' );
|
||||
try {
|
||||
const result = await refreshFeatureStatuses();
|
||||
if ( result && ! result.success ) {
|
||||
console.error(
|
||||
'Failed to refresh features:',
|
||||
result.message || 'Unknown error'
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
setIsRefreshing( false );
|
||||
}
|
||||
|
||||
setIsRefreshing( false );
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -103,27 +111,46 @@ const TabOverview = () => {
|
|||
</Button>
|
||||
</>
|
||||
}
|
||||
contentItems={ features.map( ( feature ) => (
|
||||
<FeatureSettingsBlock
|
||||
key={ feature.id }
|
||||
title={ feature.title }
|
||||
description={ feature.description }
|
||||
actionProps={ {
|
||||
buttons: feature.buttons,
|
||||
enabled: feature.enabled,
|
||||
notes: feature.notes,
|
||||
badge: feature.enabled
|
||||
? {
|
||||
text: __(
|
||||
'Active',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
type: TITLE_BADGE_POSITIVE,
|
||||
}
|
||||
: undefined,
|
||||
} }
|
||||
/>
|
||||
) ) }
|
||||
contentItems={ features.map( ( feature ) => {
|
||||
return (
|
||||
<FeatureSettingsBlock
|
||||
key={ feature.id }
|
||||
title={ feature.title }
|
||||
description={ feature.description }
|
||||
actionProps={ {
|
||||
buttons: feature.buttons
|
||||
.filter(
|
||||
( button ) =>
|
||||
! button.showWhen || // Learn more buttons
|
||||
( feature.enabled &&
|
||||
button.showWhen ===
|
||||
'enabled' ) ||
|
||||
( ! feature.enabled &&
|
||||
button.showWhen === 'disabled' )
|
||||
)
|
||||
.map( ( button ) => ( {
|
||||
...button,
|
||||
url: button.urls
|
||||
? merchant?.isSandbox
|
||||
? button.urls.sandbox
|
||||
: button.urls.live
|
||||
: button.url,
|
||||
} ) ),
|
||||
enabled: feature.enabled,
|
||||
notes: feature.notes,
|
||||
badge: feature.enabled
|
||||
? {
|
||||
text: __(
|
||||
'Active',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
type: TITLE_BADGE_POSITIVE,
|
||||
}
|
||||
: undefined,
|
||||
} }
|
||||
/>
|
||||
);
|
||||
} ) }
|
||||
/>
|
||||
|
||||
<SettingsCard
|
||||
|
@ -219,140 +246,4 @@ const todosDataDefault = [
|
|||
},
|
||||
];
|
||||
|
||||
// TODO: Hardcoding this list here is not the best idea. Can we move this to a REST API response?
|
||||
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: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
url: '#',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
url: '#',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'advanced_credit_and_debit_cards',
|
||||
title: __(
|
||||
'Advanced Credit and Debit Cards',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
description: __(
|
||||
'Process major credit and debit cards including Visa, Mastercard, American Express and Discover.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
url: '#',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
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: 'secondary',
|
||||
text: __( 'Apply', 'woocommerce-paypal-payments' ),
|
||||
url: '#',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
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'
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
url: '#',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
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: 'secondary',
|
||||
text: __(
|
||||
'Domain registration',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
url: '#',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
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: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
url: '#',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
url: '#',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default TabOverview;
|
||||
|
|
|
@ -4,12 +4,12 @@ import { useMemo } from '@wordpress/element';
|
|||
import SettingsCard from '../../ReusableComponents/SettingsCard';
|
||||
import PaymentMethodsBlock from '../../ReusableComponents/SettingsBlocks/PaymentMethodsBlock';
|
||||
import { CommonHooks } from '../../../data';
|
||||
import ModalPayPal from './Modals/ModalPayPal';
|
||||
import ModalFastlane from './Modals/ModalFastlane';
|
||||
import ModalAcdc from './Modals/ModalAcdc';
|
||||
import { useActiveModal } from '../../../data/common/hooks';
|
||||
import Modal from './Modals/Modal';
|
||||
|
||||
const TabPaymentMethods = () => {
|
||||
const { storeCountry, storeCurrency } = CommonHooks.useWooSettings();
|
||||
const { setActiveModal } = useActiveModal();
|
||||
|
||||
const filteredPaymentMethods = useMemo( () => {
|
||||
const contextProps = { storeCountry, storeCurrency };
|
||||
|
@ -33,6 +33,7 @@ const TabPaymentMethods = () => {
|
|||
return (
|
||||
<div className="ppcp-r-payment-methods">
|
||||
<SettingsCard
|
||||
id="ppcp-paypal-checkout-card"
|
||||
title={ __( 'PayPal Checkout', 'woocommerce-paypal-payments' ) }
|
||||
description={ __(
|
||||
'Select your preferred checkout option with PayPal for easy payment processing.',
|
||||
|
@ -43,9 +44,11 @@ const TabPaymentMethods = () => {
|
|||
>
|
||||
<PaymentMethodsBlock
|
||||
paymentMethods={ filteredPaymentMethods.payPalCheckout }
|
||||
onTriggerModal={ setActiveModal }
|
||||
/>
|
||||
</SettingsCard>
|
||||
<SettingsCard
|
||||
id="ppcp-card-payments-card"
|
||||
title={ __(
|
||||
'Online Card Payments',
|
||||
'woocommerce-paypal-payments'
|
||||
|
@ -59,9 +62,11 @@ const TabPaymentMethods = () => {
|
|||
>
|
||||
<PaymentMethodsBlock
|
||||
paymentMethods={ filteredPaymentMethods.onlineCardPayments }
|
||||
onTriggerModal={ setActiveModal }
|
||||
/>
|
||||
</SettingsCard>
|
||||
<SettingsCard
|
||||
id="ppcp-alternative-payments-card"
|
||||
title={ __(
|
||||
'Alternative Payment Methods',
|
||||
'woocommerce-paypal-payments'
|
||||
|
@ -75,8 +80,11 @@ const TabPaymentMethods = () => {
|
|||
>
|
||||
<PaymentMethodsBlock
|
||||
paymentMethods={ filteredPaymentMethods.alternative }
|
||||
onTriggerModal={ setActiveModal }
|
||||
/>
|
||||
</SettingsCard>
|
||||
|
||||
<Modal />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -98,7 +106,6 @@ const paymentMethodsPayPalCheckout = [
|
|||
'woocommerce-paypal-payments'
|
||||
),
|
||||
icon: 'payment-method-paypal',
|
||||
modal: ModalPayPal,
|
||||
},
|
||||
{
|
||||
id: 'venmo',
|
||||
|
@ -144,7 +151,6 @@ const paymentMethodsOnlineCardPayments = [
|
|||
'woocommerce-paypal-payments'
|
||||
),
|
||||
icon: 'payment-method-advanced-cards',
|
||||
modal: ModalAcdc,
|
||||
},
|
||||
{
|
||||
id: 'fastlane',
|
||||
|
@ -154,7 +160,6 @@ const paymentMethodsOnlineCardPayments = [
|
|||
'woocommerce-paypal-payments'
|
||||
),
|
||||
icon: 'payment-method-fastlane',
|
||||
modal: ModalFastlane,
|
||||
},
|
||||
{
|
||||
id: 'apply_pay',
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import { TAB_IDS, selectTab } from '../../../../../utils/tabSelector';
|
||||
|
||||
const Features = {
|
||||
getFeatures: ( setActiveModal ) => [
|
||||
{
|
||||
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: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
onClick: () => {
|
||||
selectTab(
|
||||
TAB_IDS.PAYMENT_METHODS,
|
||||
'ppcp-paypal-checkout-card'
|
||||
).then( () => {
|
||||
setActiveModal( 'paypal' );
|
||||
} );
|
||||
},
|
||||
showWhen: 'enabled',
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Apply', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox:
|
||||
'https://www.sandbox.paypal.com/bizsignup/entry?product=ADVANCED_VAULTING',
|
||||
live: 'https://www.paypal.com/bizsignup/entry?product=ADVANCED_VAULTING',
|
||||
},
|
||||
showWhen: 'disabled',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'advanced_credit_and_debit_cards',
|
||||
title: __(
|
||||
'Advanced Credit and Debit Cards',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
description: __(
|
||||
'Process major credit and debit cards including Visa, Mastercard, American Express and Discover.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
onClick: () => {
|
||||
selectTab(
|
||||
TAB_IDS.PAYMENT_METHODS,
|
||||
'ppcp-card-payments-card'
|
||||
).then( () => {
|
||||
setActiveModal(
|
||||
'advanced_credit_and_debit_card_payments'
|
||||
);
|
||||
} );
|
||||
},
|
||||
showWhen: 'enabled',
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Apply', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox:
|
||||
'https://www.sandbox.paypal.com/bizsignup/entry?product=ppcp',
|
||||
live: 'https://www.paypal.com/bizsignup/entry?product=ppcp',
|
||||
},
|
||||
showWhen: 'disabled',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
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: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
onClick: () => {
|
||||
selectTab(
|
||||
TAB_IDS.PAYMENT_METHODS,
|
||||
'ppcp-alternative-payments-card'
|
||||
);
|
||||
},
|
||||
showWhen: 'enabled',
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Apply', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
showWhen: 'disabled',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'google_pay',
|
||||
title: __( 'Google Pay', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Let customers pay using their Google Pay wallet.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
buttons: [
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
onClick: () => {
|
||||
selectTab(
|
||||
TAB_IDS.PAYMENT_METHODS,
|
||||
'ppcp-card-payments-card'
|
||||
).then( () => {
|
||||
setActiveModal( 'google_pay' );
|
||||
} );
|
||||
},
|
||||
showWhen: 'enabled',
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Apply', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox:
|
||||
'https://www.sandbox.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=GOOGLE_PAY',
|
||||
live: 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=GOOGLE_PAY',
|
||||
},
|
||||
showWhen: 'disabled',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
},
|
||||
],
|
||||
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: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
onClick: () => {
|
||||
selectTab(
|
||||
TAB_IDS.PAYMENT_METHODS,
|
||||
'ppcp-card-payments-card'
|
||||
).then( () => {
|
||||
setActiveModal( 'apple_pay' );
|
||||
} );
|
||||
},
|
||||
showWhen: 'enabled',
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __(
|
||||
'Domain registration',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
urls: {
|
||||
sandbox:
|
||||
'https://www.sandbox.paypal.com/uccservicing/apm/applepay',
|
||||
live: 'https://www.paypal.com/uccservicing/apm/applepay',
|
||||
},
|
||||
showWhen: 'enabled',
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Apply', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox:
|
||||
'https://www.sandbox.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=APPLE_PAY',
|
||||
live: 'https://www.paypal.com/bizsignup/add-product?product=payment_methods&capabilities=APPLE_PAY',
|
||||
},
|
||||
showWhen: 'disabled',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
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: 'secondary',
|
||||
text: __( 'Configure', 'woocommerce-paypal-payments' ),
|
||||
onClick: () => {
|
||||
selectTab(
|
||||
TAB_IDS.PAYMENT_METHODS,
|
||||
'ppcp-paypal-checkout-card'
|
||||
).then( () => {
|
||||
setActiveModal( 'paypal' );
|
||||
} );
|
||||
},
|
||||
showWhen: 'enabled',
|
||||
},
|
||||
{
|
||||
type: 'secondary',
|
||||
text: __( 'Apply', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
showWhen: 'disabled',
|
||||
},
|
||||
{
|
||||
type: 'tertiary',
|
||||
text: __( 'Learn more', 'woocommerce-paypal-payments' ),
|
||||
urls: {
|
||||
sandbox: '#',
|
||||
live: '#',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default Features;
|
|
@ -47,6 +47,17 @@ export const setIsReady = ( isReady ) => ( {
|
|||
payload: { isReady },
|
||||
} );
|
||||
|
||||
/**
|
||||
* Transient. Sets the active settings tab.
|
||||
*
|
||||
* @param {string} activeModal
|
||||
* @return {Action} The action.
|
||||
*/
|
||||
export const setActiveModal = ( activeModal ) => ( {
|
||||
type: ACTION_TYPES.SET_TRANSIENT,
|
||||
payload: { activeModal },
|
||||
} );
|
||||
|
||||
/**
|
||||
* Transient. Changes the "saving" flag.
|
||||
*
|
||||
|
|
|
@ -34,10 +34,12 @@ const useHooks = () => {
|
|||
connectToSandbox,
|
||||
connectToProduction,
|
||||
connectViaIdAndSecret,
|
||||
setActiveModal,
|
||||
} = useDispatch( STORE_NAME );
|
||||
|
||||
// Transient accessors.
|
||||
const isReady = useTransient( 'isReady' );
|
||||
const activeModal = useTransient( 'activeModal' );
|
||||
|
||||
// Persistent accessors.
|
||||
const clientId = usePersistent( 'clientId' );
|
||||
|
@ -61,6 +63,8 @@ const useHooks = () => {
|
|||
|
||||
return {
|
||||
isReady,
|
||||
activeModal,
|
||||
setActiveModal,
|
||||
isSandboxMode,
|
||||
setSandboxMode: ( state ) => {
|
||||
return savePersistent( setSandboxMode, state );
|
||||
|
@ -146,6 +150,11 @@ export const useMerchantInfo = () => {
|
|||
};
|
||||
};
|
||||
|
||||
export const useActiveModal = () => {
|
||||
const { activeModal, setActiveModal } = useHooks();
|
||||
return { activeModal, setActiveModal };
|
||||
};
|
||||
|
||||
// -- Not using the `useHooks()` data provider --
|
||||
|
||||
export const useBusyState = () => {
|
||||
|
|
|
@ -15,6 +15,7 @@ import ACTION_TYPES from './action-types';
|
|||
const defaultTransient = Object.freeze( {
|
||||
isReady: false,
|
||||
activities: new Map(),
|
||||
activeModal: '',
|
||||
|
||||
// Read only values, provided by the server via hydrate.
|
||||
merchant: Object.freeze( {
|
||||
|
|
59
modules/ppcp-settings/resources/js/utils/tabSelector.js
Normal file
59
modules/ppcp-settings/resources/js/utils/tabSelector.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Tab panel IDs
|
||||
export const TAB_IDS = {
|
||||
OVERVIEW: 'tab-panel-0-overview',
|
||||
PAYMENT_METHODS: 'tab-panel-0-payment-methods',
|
||||
SETTINGS: 'tab-panel-0-settings',
|
||||
STYLING: 'tab-panel-0-styling',
|
||||
};
|
||||
|
||||
/**
|
||||
* Select a tab by simulating a click event and scroll to specified element,
|
||||
* accounting for navigation container height
|
||||
*
|
||||
* TODO: Once the TabPanel gets migrated to Tabs (TabPanel v2) we need to remove this in favor of programmatic tab switching: https://github.com/WordPress/gutenberg/issues/52997
|
||||
*
|
||||
* @param {string} tabId - The ID of the tab to select
|
||||
* @param {string} [scrollToId] - Optional ID of the element to scroll to
|
||||
* @return {Promise} - Resolves when tab switch and scroll are complete
|
||||
*/
|
||||
export const selectTab = ( tabId, scrollToId ) => {
|
||||
return new Promise( ( resolve ) => {
|
||||
const tab = document.getElementById( tabId );
|
||||
if ( tab ) {
|
||||
tab.click();
|
||||
setTimeout( () => {
|
||||
const scrollTarget = scrollToId
|
||||
? document.getElementById( scrollToId )
|
||||
: document.getElementById( 'ppcp-settings-container' );
|
||||
|
||||
if ( scrollTarget ) {
|
||||
const navContainer = document.querySelector(
|
||||
'.ppcp-r-navigation-container'
|
||||
);
|
||||
const navHeight = navContainer
|
||||
? navContainer.offsetHeight
|
||||
: 0;
|
||||
|
||||
// Get the current scroll position and element's position relative to viewport
|
||||
const rect = scrollTarget.getBoundingClientRect();
|
||||
|
||||
// Calculate the final position with offset
|
||||
const scrollPosition =
|
||||
rect.top + window.scrollY - ( navHeight + 55 );
|
||||
|
||||
window.scrollTo( {
|
||||
top: scrollPosition,
|
||||
behavior: 'smooth',
|
||||
} );
|
||||
|
||||
// Resolve after scroll animation
|
||||
setTimeout( resolve, 300 );
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
}, 100 );
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
} );
|
||||
};
|
|
@ -192,6 +192,40 @@ class CommonRestEndpoint extends RestEndpoint {
|
|||
return $this->return_success( $js_data, $extra_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mocked merchant data until real data fetching is implemented.
|
||||
*
|
||||
* @return array Mocked merchant details including connection status, features, etc.
|
||||
*/
|
||||
protected function get_mocked_merchant_data(): array {
|
||||
return array(
|
||||
'isConnected' => true,
|
||||
'isSandbox' => false,
|
||||
'id' => '',
|
||||
'email' => '',
|
||||
'features' => array(
|
||||
'save_paypal_and_venmo' => array(
|
||||
'enabled' => true,
|
||||
),
|
||||
'advanced_credit_and_debit_cards' => array(
|
||||
'enabled' => true,
|
||||
),
|
||||
'alternative_payment_methods' => array(
|
||||
'enabled' => true,
|
||||
),
|
||||
'google_pay' => array(
|
||||
'enabled' => true,
|
||||
),
|
||||
'apple_pay' => array(
|
||||
'enabled' => true,
|
||||
),
|
||||
'pay_later_messaging' => array(
|
||||
'enabled' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the "merchant" attribute to the extra_data collection, which
|
||||
* contains details about the merchant's PayPal account, like the merchant ID.
|
||||
|
@ -200,7 +234,7 @@ class CommonRestEndpoint extends RestEndpoint {
|
|||
*
|
||||
* @return array Updated extra_data collection.
|
||||
*/
|
||||
protected function add_merchant_info( array $extra_data ) : array {
|
||||
protected function add_merchant_info( array $extra_data ): array {
|
||||
$extra_data['merchant'] = $this->sanitize_for_javascript(
|
||||
$this->settings->to_array(),
|
||||
$this->merchant_info_map
|
||||
|
@ -211,6 +245,11 @@ class CommonRestEndpoint extends RestEndpoint {
|
|||
$extra_data['merchant'],
|
||||
);
|
||||
|
||||
// If no real data is available yet, use mock data.
|
||||
if ( empty( $extra_data['merchant'] ) || ( empty( $extra_data['merchant']['id'] ) && empty( $extra_data['merchant']['email'] ) ) ) {
|
||||
$extra_data['merchant'] = $this->get_mocked_merchant_data();
|
||||
}
|
||||
|
||||
return $extra_data;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue