mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-05 08:59:14 +08:00
🔀 Merge branch 'trunk'
# Conflicts: # modules/ppcp-settings/resources/js/data/common/hooks.js
This commit is contained in:
commit
ff81617b22
57 changed files with 817 additions and 725 deletions
|
@ -9,7 +9,13 @@ const OptionSelector = ( {
|
|||
} ) => (
|
||||
<div className="ppcp-r-select-box-wrapper">
|
||||
{ options.map(
|
||||
( { value: itemValue, title, description, contents } ) => {
|
||||
( {
|
||||
value: itemValue,
|
||||
title,
|
||||
description,
|
||||
contents,
|
||||
isDisabled = false,
|
||||
} ) => {
|
||||
let isSelected;
|
||||
|
||||
if ( Array.isArray( value ) ) {
|
||||
|
@ -27,6 +33,7 @@ const OptionSelector = ( {
|
|||
onChange={ onChange }
|
||||
isMulti={ multiSelect }
|
||||
isSelected={ isSelected }
|
||||
isDisabled={ isDisabled }
|
||||
>
|
||||
{ contents }
|
||||
</OptionItem>
|
||||
|
@ -46,13 +53,13 @@ const OptionItem = ( {
|
|||
isMulti,
|
||||
isSelected,
|
||||
children,
|
||||
isDisabled = false,
|
||||
} ) => {
|
||||
const boxClassName = classNames( 'ppcp-r-select-box', {
|
||||
'ppcp--selected': isSelected,
|
||||
'ppcp--multiselect': isMulti,
|
||||
'ppcp--no-title': ! itemTitle,
|
||||
} );
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/label-has-associated-control -- label has a nested input control.
|
||||
<label className={ boxClassName }>
|
||||
|
@ -61,6 +68,7 @@ const OptionItem = ( {
|
|||
isRadio={ ! isMulti }
|
||||
onChange={ onChange }
|
||||
isSelected={ isSelected }
|
||||
isDisabled={ isDisabled }
|
||||
/>
|
||||
|
||||
<div className="ppcp--box-content">
|
||||
|
@ -80,7 +88,7 @@ const OptionItem = ( {
|
|||
);
|
||||
};
|
||||
|
||||
const InputField = ( { value, onChange, isRadio, isSelected } ) => {
|
||||
const InputField = ( { value, onChange, isRadio, isSelected, isDisabled } ) => {
|
||||
if ( isRadio ) {
|
||||
return (
|
||||
<PayPalRdb
|
||||
|
@ -96,6 +104,7 @@ const InputField = ( { value, onChange, isRadio, isSelected } ) => {
|
|||
value={ value }
|
||||
onChange={ onChange }
|
||||
checked={ isSelected }
|
||||
disabled={ isDisabled }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -49,10 +49,10 @@ const TodoSettingsBlock = ( {
|
|||
await selectTab( tabId, todo.action.section );
|
||||
} else if ( todo.action.type === 'external' ) {
|
||||
window.open( todo.action.url, '_blank' );
|
||||
// If it has completeOnClick flag, trigger the action
|
||||
if ( todo.action.completeOnClick === true ) {
|
||||
await completeOnClick( todo.id );
|
||||
}
|
||||
}
|
||||
|
||||
if ( todo.action.completeOnClick === true ) {
|
||||
await completeOnClick( todo.id );
|
||||
}
|
||||
|
||||
if ( todo.action.modal ) {
|
||||
|
@ -63,10 +63,10 @@ const TodoSettingsBlock = ( {
|
|||
}
|
||||
};
|
||||
|
||||
// Filter out dismissed todos for display
|
||||
const visibleTodos = todosData.filter(
|
||||
( todo ) => ! dismissedTodos.includes( todo.id )
|
||||
);
|
||||
// Filter out dismissed todos for display and limit to 5.
|
||||
const visibleTodos = todosData
|
||||
.filter( ( todo ) => ! dismissedTodos.includes( todo.id ) )
|
||||
.slice( 0, 5 );
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -24,6 +24,26 @@ const StepBusiness = ( {} ) => {
|
|||
useEffect( () => {
|
||||
setIsCasualSeller( BUSINESS_TYPES.CASUAL_SELLER === businessChoice );
|
||||
}, [ businessChoice, setIsCasualSeller ] );
|
||||
const { canUseSubscriptions } = OnboardingHooks.useFlags();
|
||||
const businessChoices = [
|
||||
{
|
||||
value: BUSINESS_TYPES.BUSINESS,
|
||||
title: __( 'Business', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Recommended for individuals and organizations that primarily use PayPal to sell goods or services or receive donations, even if your business is not incorporated.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
},
|
||||
{
|
||||
value: BUSINESS_TYPES.CASUAL_SELLER,
|
||||
title: __( 'Personal Account', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Ideal for those who primarily make purchases or send personal transactions to family and friends.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
contents: canUseSubscriptions ? <DetailsAccountType /> : null,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-page-business">
|
||||
|
@ -45,23 +65,13 @@ const StepBusiness = ( {} ) => {
|
|||
);
|
||||
};
|
||||
|
||||
const businessChoices = [
|
||||
{
|
||||
value: BUSINESS_TYPES.BUSINESS,
|
||||
title: __( 'Business', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Recommended for individuals and organizations that primarily use PayPal to sell goods or services or receive donations, even if your business is not incorporated.',
|
||||
const DetailsAccountType = () => (
|
||||
<p>
|
||||
{ __(
|
||||
'* Business account is required for subscriptions.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
},
|
||||
{
|
||||
value: BUSINESS_TYPES.CASUAL_SELLER,
|
||||
title: __( 'Personal Account', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Ideal for those who primarily make purchases or send personal transactions to family and friends.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
},
|
||||
];
|
||||
) }
|
||||
</p>
|
||||
);
|
||||
|
||||
export default StepBusiness;
|
||||
|
|
|
@ -10,6 +10,7 @@ const StepProducts = () => {
|
|||
const { canUseSubscriptions } = OnboardingHooks.useFlags();
|
||||
const [ optionState, setOptionState ] = useState( null );
|
||||
const [ productChoices, setProductChoices ] = useState( [] );
|
||||
const { isCasualSeller } = OnboardingHooks.useBusiness();
|
||||
|
||||
useEffect( () => {
|
||||
const initChoices = () => {
|
||||
|
@ -48,7 +49,36 @@ const StepProducts = () => {
|
|||
|
||||
setProducts( getNewValue() );
|
||||
};
|
||||
|
||||
const productChoicesFull = [
|
||||
{
|
||||
value: PRODUCT_TYPES.VIRTUAL,
|
||||
title: __( 'Virtual', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Items do not require shipping.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
contents: <DetailsVirtual />,
|
||||
},
|
||||
{
|
||||
value: PRODUCT_TYPES.PHYSICAL,
|
||||
title: __( 'Physical Goods', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Items require shipping.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
contents: <DetailsPhysical />,
|
||||
},
|
||||
{
|
||||
value: PRODUCT_TYPES.SUBSCRIPTIONS,
|
||||
title: __( 'Subscriptions', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Recurring payments for either physical goods or services.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
isDisabled: isCasualSeller,
|
||||
contents: <DetailsSubscriptions showNotice={ isCasualSeller } />,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="ppcp-r-page-products">
|
||||
<OnboardingHeader
|
||||
|
@ -87,41 +117,21 @@ const DetailsPhysical = () => (
|
|||
</ul>
|
||||
);
|
||||
|
||||
const DetailsSubscriptions = () => (
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://woocommerce.com/document/woocommerce-paypal-payments/#subscriptions-faq"
|
||||
>
|
||||
{ __( 'WooCommerce Subscriptions', 'woocommerce-paypal-payments' ) }
|
||||
</a>
|
||||
const DetailsSubscriptions = ( { showNotice } ) => (
|
||||
<>
|
||||
<a
|
||||
target="__blank"
|
||||
href="https://woocommerce.com/document/woocommerce-paypal-payments/#subscriptions-faq"
|
||||
>
|
||||
{ __( 'WooCommerce Subscriptions', 'woocommerce-paypal-payments' ) }
|
||||
</a>
|
||||
{ showNotice && (
|
||||
<p>
|
||||
{ __(
|
||||
'* Business account is required for subscriptions.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
</p>
|
||||
) }
|
||||
</>
|
||||
);
|
||||
|
||||
const productChoicesFull = [
|
||||
{
|
||||
value: PRODUCT_TYPES.VIRTUAL,
|
||||
title: __( 'Virtual', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Items do not require shipping.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
contents: <DetailsVirtual />,
|
||||
},
|
||||
{
|
||||
value: PRODUCT_TYPES.PHYSICAL,
|
||||
title: __( 'Physical Goods', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Items require shipping.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
contents: <DetailsPhysical />,
|
||||
},
|
||||
{
|
||||
value: PRODUCT_TYPES.SUBSCRIPTIONS,
|
||||
title: __( 'Subscriptions', 'woocommerce-paypal-payments' ),
|
||||
description: __(
|
||||
'Recurring payments for either physical goods or services.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
contents: <DetailsSubscriptions />,
|
||||
},
|
||||
];
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { __ } from '@wordpress/i18n';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import SettingsCard from '../../../../ReusableComponents/SettingsCard';
|
||||
import { CommonHooks } from '../../../../../data';
|
||||
|
@ -8,11 +9,15 @@ import SettingsBlock from '../../../../ReusableComponents/SettingsBlock';
|
|||
import { ControlStaticValue } from '../../../../ReusableComponents/Controls';
|
||||
|
||||
const ConnectionStatus = () => {
|
||||
const { merchant } = CommonHooks.useMerchantInfo();
|
||||
const merchant = CommonHooks.useMerchant();
|
||||
const className = classNames( 'ppcp-connection-details ppcp--value-list', {
|
||||
'ppcp--type-business': merchant.isBusinessSeller,
|
||||
'ppcp--type-casual': merchant.isCasualSeller,
|
||||
} );
|
||||
|
||||
return (
|
||||
<SettingsCard
|
||||
className="ppcp-connection-details ppcp--value-list"
|
||||
className={ className }
|
||||
title={ __( 'Connection status', 'woocommerce-paypal-payments' ) }
|
||||
description={ <ConnectionDescription /> }
|
||||
>
|
||||
|
|
|
@ -16,6 +16,7 @@ import { useTodos } from '../../../../data/todos/hooks';
|
|||
import { useMerchantInfo } from '../../../../data/common/hooks';
|
||||
import { STORE_NAME as COMMON_STORE_NAME } from '../../../../data/common';
|
||||
import { STORE_NAME as TODOS_STORE_NAME } from '../../../../data/todos';
|
||||
import { CommonHooks, TodosHooks } from '../../../../data';
|
||||
|
||||
import { getFeatures } from '../Components/Overview/features-config';
|
||||
|
||||
|
@ -23,8 +24,16 @@ import {
|
|||
NOTIFICATION_ERROR,
|
||||
NOTIFICATION_SUCCESS,
|
||||
} from '../../../ReusableComponents/Icons';
|
||||
import SpinnerOverlay from '../../../ReusableComponents/SpinnerOverlay';
|
||||
|
||||
const TabOverview = () => {
|
||||
const { isReady: areTodosReady } = TodosHooks.useTodos();
|
||||
const { isReady: merchantIsReady } = CommonHooks.useMerchantInfo();
|
||||
|
||||
if ( ! areTodosReady || ! merchantIsReady ) {
|
||||
return <SpinnerOverlay asModal={ true } />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-tab-overview">
|
||||
<OverviewTodos />
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useCallback } from '@wordpress/element';
|
|||
|
||||
import SettingsCard from '../../../ReusableComponents/SettingsCard';
|
||||
import { PaymentMethodsBlock } from '../../../ReusableComponents/SettingsBlocks';
|
||||
import { PaymentHooks } from '../../../../data';
|
||||
import { CommonHooks, OnboardingHooks, PaymentHooks } from '../../../../data';
|
||||
import { useActiveModal } from '../../../../data/common/hooks';
|
||||
import Modal from '../Components/Payment/Modal';
|
||||
|
||||
|
@ -45,6 +45,9 @@ const TabPaymentMethods = () => {
|
|||
[ changePaymentSettings, setActiveModal, setPersistent ]
|
||||
);
|
||||
|
||||
const merchant = CommonHooks.useMerchant();
|
||||
const { canUseCardPayments } = OnboardingHooks.useFlags();
|
||||
|
||||
return (
|
||||
<div className="ppcp-r-payment-methods">
|
||||
<PaymentMethodCard
|
||||
|
@ -58,20 +61,22 @@ const TabPaymentMethods = () => {
|
|||
methods={ methods.paypal }
|
||||
onTriggerModal={ setActiveModal }
|
||||
/>
|
||||
<PaymentMethodCard
|
||||
id="ppcp-card-payments-card"
|
||||
title={ __(
|
||||
'Online Card Payments',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
description={ __(
|
||||
'Select your preferred card payment options for efficient payment processing.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
icon="icon-checkout-online-methods.svg"
|
||||
methods={ methods.cardPayment }
|
||||
onTriggerModal={ setActiveModal }
|
||||
/>
|
||||
{ merchant.isBusinessSeller && canUseCardPayments && (
|
||||
<PaymentMethodCard
|
||||
id="ppcp-card-payments-card"
|
||||
title={ __(
|
||||
'Online Card Payments',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
description={ __(
|
||||
'Select your preferred card payment options for efficient payment processing.',
|
||||
'woocommerce-paypal-payments'
|
||||
) }
|
||||
icon="icon-checkout-online-methods.svg"
|
||||
methods={ methods.cardPayment }
|
||||
onTriggerModal={ setActiveModal }
|
||||
/>
|
||||
) }
|
||||
<PaymentMethodCard
|
||||
id="ppcp-alternative-payments-card"
|
||||
title={ __(
|
||||
|
|
|
@ -5,6 +5,7 @@ import { getSettingsTabs } from './Tabs';
|
|||
const SettingsScreen = ( { activePanel, setActivePanel } ) => {
|
||||
const tabs = getSettingsTabs();
|
||||
const { Component } = tabs.find( ( tab ) => tab.name === activePanel );
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsNavigation
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
import { useCallback, useEffect, useState } from '@wordpress/element';
|
||||
import { useCallback, useEffect, useMemo, useState } from '@wordpress/element';
|
||||
|
||||
import { createHooksForStore } from '../utils';
|
||||
import { STORE_NAME } from './constants';
|
||||
|
@ -36,10 +36,6 @@ const useHooks = () => {
|
|||
const [ isManualConnectionMode, setManualConnectionMode ] = usePersistent(
|
||||
'useManualConnection'
|
||||
);
|
||||
const merchant = useSelect(
|
||||
( select ) => select( STORE_NAME ).merchant(),
|
||||
[]
|
||||
);
|
||||
|
||||
// Read-only properties.
|
||||
const wooSettings = useSelect(
|
||||
|
@ -78,7 +74,6 @@ const useHooks = () => {
|
|||
productionOnboardingUrl,
|
||||
authenticateWithCredentials,
|
||||
authenticateWithOAuth,
|
||||
merchant,
|
||||
wooSettings,
|
||||
features,
|
||||
webhooks,
|
||||
|
@ -144,7 +139,8 @@ export const useWebhooks = () => {
|
|||
};
|
||||
|
||||
export const useMerchantInfo = () => {
|
||||
const { isReady, merchant, features } = useHooks();
|
||||
const { isReady, features } = useHooks();
|
||||
const merchant = useMerchant();
|
||||
const { refreshMerchantData, setMerchant } = useDispatch( STORE_NAME );
|
||||
|
||||
const verifyLoginStatus = useCallback( async () => {
|
||||
|
@ -175,6 +171,29 @@ export const useMerchantInfo = () => {
|
|||
};
|
||||
};
|
||||
|
||||
// Read-only access to the sanitized merchant details.
|
||||
export const useMerchant = () => {
|
||||
const merchant = useSelect(
|
||||
( select ) => select( STORE_NAME ).merchant(),
|
||||
[]
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ( {
|
||||
isConnected: merchant.isConnected ?? false,
|
||||
isSandbox: merchant.isSandbox ?? true,
|
||||
id: merchant.id ?? '',
|
||||
email: merchant.email ?? '',
|
||||
clientId: merchant.clientId ?? '',
|
||||
clientSecret: merchant.clientSecret ?? '',
|
||||
isBusinessSeller: 'business' === merchant.sellerType,
|
||||
isCasualSeller: 'personal' === merchant.sellerType,
|
||||
} ),
|
||||
// the merchant object is stable, so a new memo is only generated when a merchant prop changes.
|
||||
[ merchant ]
|
||||
);
|
||||
};
|
||||
|
||||
export const useActiveModal = () => {
|
||||
const { activeModal, setActiveModal } = useHooks();
|
||||
return { activeModal, setActiveModal };
|
||||
|
|
|
@ -26,6 +26,7 @@ const defaultTransient = Object.freeze( {
|
|||
email: '',
|
||||
clientId: '',
|
||||
clientSecret: '',
|
||||
sellerType: 'unknown',
|
||||
} ),
|
||||
|
||||
wooSettings: Object.freeze( {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue