* Remove old payment gateway task components

* Move PaymentGatewaySuggestions up one directory

* Add feature check to tasks array

* Turn on payment gateway suggestions in all environments

* Handle PR feedback

* Use gateway suggestions from REST API in help panel

* Fix component path

* Remove BACS test due to SlotFill testing bug

* Await button selector

* Handle PR feedback round 2
This commit is contained in:
Joshua T Flowers 2021-06-28 14:18:42 -04:00 committed by GitHub
parent 5918c8ff1e
commit 41f3d8e99a
55 changed files with 103 additions and 4051 deletions

View File

@ -23,7 +23,6 @@ import { recordEvent } from '@woocommerce/tracks';
*/
import ActivityHeader from '../activity-header';
import { getCountryCode } from '../../../dashboard/utils';
import { getPaymentMethods } from '../../../task-list/tasks/payments/methods';
export const SETUP_TASK_HELP_ITEMS_FILTER =
'woocommerce_admin_setup_task_help_items';
@ -90,29 +89,8 @@ function getAppearanceItems() {
];
}
function getPaymentsItems( props ) {
const { countryCode, onboardingStatus, profileItems } = props;
const paymentMethods = props.getPaymentMethods( {
activePlugins: [],
countryCode,
onboardingStatus,
options: {},
profileItems,
} );
const methodIsVisible = ( methodKey ) =>
Boolean(
paymentMethods.find( ( method ) => method.key === methodKey )
);
const showWCPay = methodIsVisible( 'wcpay' );
const showStripe = methodIsVisible( 'stripe' );
const showKlarnaCheckout = methodIsVisible( 'klarna_checkout' );
const showKlarnaPayments = methodIsVisible( 'klarna_payments' );
const showPayPal = methodIsVisible( 'paypal' );
const showSquare = methodIsVisible( 'square' );
const showPayFast = methodIsVisible( 'payfast' );
const showEway = methodIsVisible( 'eway' );
function getPaymentGatewaySuggestions( props ) {
const { paymentGatewaySuggestions } = props;
return [
{
@ -123,7 +101,7 @@ function getPaymentsItems( props ) {
link:
'https://docs.woocommerce.com/document/premium-payment-gateway-extensions/?utm_source=help_panel',
},
showWCPay && {
paymentGatewaySuggestions.woocommerce_payments && {
title: __(
'WooCommerce Payments Start Up Guide',
'woocommerce-admin'
@ -131,17 +109,17 @@ function getPaymentsItems( props ) {
link:
'https://docs.woocommerce.com/document/payments//?utm_source=help_panel',
},
showWCPay && {
paymentGatewaySuggestions.woocommerce_payments && {
title: __( 'WooCommerce Payments FAQs', 'woocommerce-admin' ),
link:
'https://docs.woocommerce.com/documentation/woocommerce-payments/woocommerce-payments-faqs/?utm_source=help_panel',
},
showStripe && {
paymentGatewaySuggestions.stripe && {
title: __( 'Stripe Setup and Configuration', 'woocommerce-admin' ),
link:
'https://docs.woocommerce.com/document/stripe/?utm_source=help_panel',
},
showPayPal && {
paymentGatewaySuggestions[ 'ppcp-gateway' ] && {
title: __(
'PayPal Checkout Setup and Configuration',
'woocommerce-admin'
@ -149,27 +127,27 @@ function getPaymentsItems( props ) {
link:
'https://docs.woocommerce.com/document/2-0/woocommerce-paypal-payments/#section-3',
},
showSquare && {
paymentGatewaySuggestions.square_credit_card && {
title: __( 'Square - Get started', 'woocommerce-admin' ),
link:
'https://docs.woocommerce.com/document/woocommerce-square/?utm_source=help_panel',
},
showKlarnaCheckout && {
paymentGatewaySuggestions.kco && {
title: __( 'Klarna - Introduction', 'woocommerce-admin' ),
link:
'https://docs.woocommerce.com/document/klarna-checkout/?utm_source=help_panel',
},
showKlarnaPayments && {
paymentGatewaySuggestions.klarna_payments && {
title: __( 'Klarna - Introduction', 'woocommerce-admin' ),
link:
'https://docs.woocommerce.com/document/klarna-payments/?utm_source=help_panel',
},
showPayFast && {
paymentGatewaySuggestions.payfast && {
title: __( 'PayFast Setup and Configuration', 'woocommerce-admin' ),
link:
'https://docs.woocommerce.com/document/payfast-payment-gateway/?utm_source=help_panel',
},
showEway && {
paymentGatewaySuggestions.eway && {
title: __( 'eWAY Setup and Configuration', 'woocommerce-admin' ),
link:
'https://docs.woocommerce.com/document/eway/?utm_source=help_panel',
@ -301,7 +279,7 @@ function getItems( props ) {
case 'tax':
return getTaxItems( props );
case 'payments':
return getPaymentsItems( props );
return getPaymentGatewaySuggestions( props );
default:
return getHomeItems();
}
@ -397,22 +375,23 @@ export const HelpPanel = ( props ) => {
};
HelpPanel.defaultProps = {
getPaymentMethods,
getSetting,
recordEvent,
};
export default compose(
withSelect( ( select ) => {
const { getProfileItems, getTasksStatus } = select(
ONBOARDING_STORE_NAME
);
const { getSettings } = select( SETTINGS_STORE_NAME );
const { getActivePlugins } = select( PLUGINS_STORE_NAME );
const { general: generalSettings = {} } = getSettings( 'general' );
const activePlugins = getActivePlugins();
const onboardingStatus = getTasksStatus();
const profileItems = getProfileItems();
const paymentGatewaySuggestions = select( ONBOARDING_STORE_NAME )
.getPaymentGatewaySuggestions()
.reduce( ( suggestions, suggestion ) => {
const { id } = suggestion;
suggestions[ id ] = true;
return suggestions;
}, {} );
const countryCode = getCountryCode(
generalSettings.woocommerce_default_country
@ -421,8 +400,7 @@ export default compose(
return {
activePlugins,
countryCode,
onboardingStatus,
profileItems,
paymentGatewaySuggestions,
};
} )
)( HelpPanel );

View File

@ -11,49 +11,52 @@ import { HelpPanel, SETUP_TASK_HELP_ITEMS_FILTER } from '../panels/help';
describe( 'Activity Panels', () => {
describe( 'Help', () => {
it( 'only shows links for available payment methods', () => {
it( 'only shows links for suggested payment gateways', () => {
const fixtures = [
{
key: 'wcpay',
id: 'woocommerce_payments',
text: 'WooCommerce Payments',
},
{
key: 'stripe',
id: 'stripe',
text: 'Stripe',
},
{
key: 'klarna_checkout',
id: 'kco',
text: 'Klarna',
},
{
key: 'klarna_payments',
id: 'klarna_payments',
text: 'Klarna',
},
{
key: 'paypal',
id: 'ppcp-gateway',
text: 'PayPal Checkout',
},
{
key: 'square',
id: 'square_credit_card',
text: 'Square',
},
{
key: 'payfast',
id: 'payfast',
text: 'PayFast',
},
{
key: 'eway',
id: 'eway',
text: 'eWAY',
},
];
const noMethods = render(
<HelpPanel getPaymentMethods={ () => [] } taskName="payments" />
const noSuggestions = render(
<HelpPanel
paymentGatewaySuggestions={ () => [] }
taskName="payments"
/>
);
fixtures.forEach( ( method ) => {
expect(
noMethods.queryAllByText( ( text ) =>
noSuggestions.queryAllByText( ( text ) =>
text.includes( method.text )
)
).toHaveLength( 0 );
@ -62,7 +65,7 @@ describe( 'Activity Panels', () => {
fixtures.forEach( ( method ) => {
const { queryAllByText } = render(
<HelpPanel
getPaymentMethods={ () => [ method ] }
paymentGatewaySuggestions={ { [ method.id ]: true } }
taskName="payments"
/>
);

View File

@ -38,7 +38,7 @@ const StoreAlerts = lazy( () =>
const WCPayUsageModal = lazy( () =>
import(
/* webpackChunkName: "wcpay-usage-modal" */ '../task-list/tasks/payments/methods/wcpay/wcpay-usage-modal'
/* webpackChunkName: "wcpay-usage-modal" */ '../task-list/tasks/PaymentGatewaySuggestions/components/WCPay/UsageModal'
)
);

View File

@ -32,7 +32,7 @@ import './payment-recommendations.scss';
import { getCountryCode } from '../dashboard/utils';
import { getAdminLink } from '../wc-admin-settings';
import { createNoticesFromResponse } from '../lib/notices';
import { isWCPaySupported } from '../task-list/tasks/payments/methods/wcpay';
import { isWCPaySupported } from '~/task-list/tasks/PaymentGatewaySuggestions/components/WCPay';
const SEE_MORE_LINK =
'https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations';

View File

@ -19,7 +19,7 @@ import {
import PaymentRecommendations, {
getPaymentRecommendationData,
} from '../payment-recommendations';
import { isWCPaySupported } from '../../task-list/tasks/payments/methods/wcpay';
import { isWCPaySupported } from '~/task-list/tasks/PaymentGatewaySuggestions/components/WCPay';
import { getAdminLink } from '../../wc-admin-settings';
import { createNoticesFromResponse } from '~/lib/notices';
@ -54,9 +54,12 @@ jest.mock( '@woocommerce/components', () => ( {
</div>
),
} ) );
jest.mock( '../../task-list/tasks/payments/methods/wcpay', () => ( {
isWCPaySupported: jest.fn(),
} ) );
jest.mock(
'../../task-list/tasks/PaymentGatewaySuggestions/components/WCPay',
() => ( {
isWCPaySupported: jest.fn(),
} )
);
jest.mock( '../../wc-admin-settings', () => ( {
getAdminLink: jest

View File

@ -20,7 +20,7 @@ import { AppIllustration } from '../app-illustration';
import './style.scss';
import { setAllPropsToValue } from '~/lib/collections';
import { getCountryCode } from '~/dashboard/utils';
import { isWCPaySupported } from '~/task-list/tasks/payments/methods/wcpay';
import { isWCPaySupported } from '~/task-list/tasks/PaymentGatewaySuggestions/components/WCPay';
const generatePluginDescriptionWithLink = (
description,

View File

@ -20,11 +20,11 @@ import { getCategorizedOnboardingProducts } from '../dashboard/utils';
import { Products } from './tasks/products';
import Shipping from './tasks/shipping';
import Tax from './tasks/tax';
import Payments from './tasks/payments';
import { PaymentGatewaySuggestions } from './tasks/PaymentGatewaySuggestions';
import {
installActivateAndConnectWcpay,
isWCPaySupported,
} from './tasks/payments/methods/wcpay';
} from './tasks/PaymentGatewaySuggestions/components/WCPay';
import { groupListOfObjectsBy } from '../lib/collections';
import { getLinkTypeAndHref } from '~/store-management-links';
@ -266,16 +266,17 @@ export function getAllTasks( {
'Choose payment providers and enable payment methods at checkout.',
'woocommerce-admin'
),
container: <Payments />,
container: <PaymentGatewaySuggestions query={ query } />,
completed: hasPaymentGateway,
onClick: () => {
onTaskSelect( 'payments' );
updateQueryString( { task: 'payments' } );
},
visible:
! woocommercePaymentsInstalled ||
! woocommercePaymentsSelectedInProfiler ||
! isWCPaySupported( countryCode ),
window.wcAdminFeatures[ 'payment-gateway-suggestions' ] &&
( ! woocommercePaymentsInstalled ||
! woocommercePaymentsSelectedInProfiler ||
! isWCPaySupported( countryCode ) ),
time: __( '2 minutes', 'woocommerce-admin' ),
type: 'setup',
},

View File

@ -7,7 +7,7 @@ import { updateQueryString } from '@woocommerce/navigation';
import { recordEvent } from '@woocommerce/tracks';
import { useState } from '@wordpress/element';
export const PaymentAction = ( {
export const Action = ( {
hasSetup = false,
needsSetup = true,
id,

View File

@ -11,8 +11,7 @@ import { Text, useSlot } from '@woocommerce/experimental';
/**
* Internal dependencies
*/
import { PaymentAction } from '../PaymentAction';
import { Action } from '../Action';
import './List.scss';
export const Item = ( {
@ -77,7 +76,7 @@ export const Item = ( {
</div>
</div>
<div className="woocommerce-task-payment__footer">
<PaymentAction
<Action
manageUrl={ manageUrl }
id={ id }
hasSetup={ hasSetup }

View File

@ -18,7 +18,7 @@ import {
* Internal dependencies
*/
import { PaymentAction } from '../PaymentGatewaySuggestions/components/PaymentAction';
import { Action } from '../Action';
const TosPrompt = () =>
interpolateComponents( {
@ -37,10 +37,7 @@ const TosPrompt = () =>
},
} );
export const WCPaySuggestion = ( {
paymentGateway,
onSetupCallback = null,
} ) => {
export const Suggestion = ( { paymentGateway, onSetupCallback = null } ) => {
const {
description,
id,
@ -72,7 +69,7 @@ export const WCPaySuggestion = ( {
<Text lineHeight="1.5em">
<TosPrompt />
</Text>
<PaymentAction
<Action
id={ id }
hasSetup={ true }
needsSetup={ needsSetup }

View File

@ -10,9 +10,9 @@ import { Link } from '@woocommerce/components';
/**
* Internal dependencies
*/
import UsageModal from '~/profile-wizard/steps/usage-modal';
import Modal from '~/profile-wizard/steps/usage-modal';
const WCPayUsageModal = () => {
export const UsageModal = () => {
const query = getQuery();
const shouldDisplayModal = query[ 'wcpay-connection-success' ] === '1';
const [ isOpen, setIsOpen ] = useState( shouldDisplayModal );
@ -47,7 +47,7 @@ const WCPayUsageModal = () => {
} );
return (
<UsageModal
<Modal
isDismissible={ false }
title={ title }
message={ trackingMessage }
@ -59,4 +59,4 @@ const WCPayUsageModal = () => {
);
};
export default WCPayUsageModal;
export default UsageModal;

View File

@ -0,0 +1,3 @@
export * from './utils';
export { Suggestion as WCPaySuggestion } from './Suggestion';
export { UsageModal as WCPayUsageModal } from './UsageModal';

View File

@ -48,3 +48,24 @@ export function installActivateAndConnectWcpay(
reject();
} );
}
export function isWCPaySupported( countryCode ) {
const supportedCountries = [ 'US', 'PR' ];
if (
window.wcAdminFeatures &&
window.wcAdminFeatures[ 'wcpay/support-international-countries' ]
) {
supportedCountries.push(
'AU',
'CA',
'DE',
'ES',
'FR',
'GB',
'IE',
'IT',
'NZ'
);
}
return supportedCountries.includes( countryCode );
}

View File

@ -17,7 +17,7 @@ import { useMemo, useCallback } from '@wordpress/element';
*/
import { List, Placeholder as ListPlaceholder } from './components/List';
import { Setup, Placeholder as SetupPlaceholder } from './components/Setup';
import { WCPaySuggestion } from '../components/WCPaySuggestion';
import { WCPaySuggestion } from './components/WCPay';
import './plugins/Bacs';
const RECOMMENDED_GATEWAY_IDS = [

View File

@ -1,262 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useDispatch, useSelect } from '@wordpress/data';
import { getHistory, getNewPath } from '@woocommerce/navigation';
import {
ONBOARDING_STORE_NAME,
OPTIONS_STORE_NAME,
PLUGINS_STORE_NAME,
SETTINGS_STORE_NAME,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useMemo, useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import { PaymentMethodList } from './components/PaymentMethodList';
import { WCPaySuggestion } from './components/WCPaySuggestion';
import { getCountryCode } from '../../../dashboard/utils';
import { getPaymentMethods } from './methods';
import { PaymentSetup } from './components/PaymentSetup';
import { sift } from '~/utils';
export const setMethodEnabledOption = async (
optionName,
value,
{ clearTaskStatusCache, updateOptions, options }
) => {
const methodOptions = options[ optionName ];
// Don't update the option if it already has the same value.
if ( methodOptions.enabled !== value ) {
await updateOptions( {
[ optionName ]: {
...methodOptions,
enabled: value,
},
} );
clearTaskStatusCache();
}
};
export const LocalPayments = ( { query } ) => {
const { createNotice } = useDispatch( 'core/notices' );
const {
installAndActivatePlugins,
invalidateResolutionForStoreSelector: invalidatePluginStoreSelector,
} = useDispatch( PLUGINS_STORE_NAME );
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
const {
invalidateResolution,
invalidateResolutionForStoreSelector,
} = useDispatch( ONBOARDING_STORE_NAME );
const { methods, options } = useSelect( ( select ) => {
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
const { getOption } = select( OPTIONS_STORE_NAME );
const {
getActivePlugins,
isJetpackConnected,
getPaypalOnboardingStatus,
hasFinishedResolution,
} = select( PLUGINS_STORE_NAME );
const { getSettings } = select( SETTINGS_STORE_NAME );
const { general: generalSettings = {} } = getSettings( 'general' );
const { getTasksStatus } = select( ONBOARDING_STORE_NAME );
const activePlugins = getActivePlugins();
const onboardingStatus = getTasksStatus();
const profileItems = getProfileItems();
const optionNames = [
'woocommerce_woocommerce_payments_settings',
'woocommerce_stripe_settings',
'woocommerce-ppcp-settings',
'woocommerce_ppcp-gateway_settings',
'woocommerce_payfast_settings',
'woocommerce_square_credit_card_settings',
'woocommerce_klarna_payments_settings',
'woocommerce_kco_settings',
'wc_square_refresh_tokens',
'woocommerce_cod_settings',
'woocommerce_bacs_settings',
'woocommerce_bacs_accounts',
'woocommerce_eway_settings',
'woocommerce_razorpay_settings',
'woocommerce_mollie_payments_settings',
'woocommerce_payubiz_settings',
'woocommerce_paystack_settings',
'woocommerce_woo-mercado-pago-basic_settings',
];
const retrievedOptions = optionNames.reduce( ( result, name ) => {
result[ name ] = getOption( name );
return result;
}, {} );
const countryCode = getCountryCode(
generalSettings.woocommerce_default_country
);
const paypalOnboardingStatus = activePlugins.includes(
'woocommerce-paypal-payments'
)
? getPaypalOnboardingStatus()
: null;
return {
methods: getPaymentMethods( {
activePlugins,
countryCode,
createNotice,
installAndActivatePlugins,
isJetpackConnected: isJetpackConnected(),
onboardingStatus,
options: retrievedOptions,
profileItems,
paypalOnboardingStatus,
loadingPaypalStatus:
! hasFinishedResolution( 'getPaypalOnboardingStatus' ) &&
! paypalOnboardingStatus,
} ),
options: retrievedOptions,
};
} );
const recommendedMethod = useMemo( () => {
const method = methods.find(
( m ) =>
( m.key === 'wcpay' && m.visible ) ||
( m.key === 'mercadopago' && m.visible )
);
if ( ! method ) {
return 'stripe';
}
return method.key;
}, [ methods ] );
const markConfigured = async ( methodKey, queryParams = {} ) => {
const method = methods.find( ( option ) => option.key === methodKey );
if ( ! method ) {
throw `Method ${ methodKey } not found in available methods list`;
}
setEnabledMethods( {
...enabledMethods,
[ methodKey ]: true,
} );
const clearTaskStatusCache = () => {
invalidateResolution( 'getProfileItems', [] );
invalidateResolution( 'getTasksStatus', [] );
invalidateResolutionForStoreSelector( 'getTasksStatus' );
invalidatePluginStoreSelector( 'getPaypalOnboardingStatus' );
};
await setMethodEnabledOption( method.optionName, 'yes', {
clearTaskStatusCache,
updateOptions,
options,
} );
recordEvent( 'tasklist_payment_connect_method', {
payment_method: methodKey,
} );
getHistory().push( getNewPath( { ...queryParams }, '/', {} ) );
};
const recordConnectStartEvent = ( methodName ) => {
recordEvent( 'tasklist_payment_connect_start', {
payment_method: methodName,
} );
};
const currentMethod = useMemo( () => {
if ( ! query.id ) {
return null;
}
const method = methods.find( ( m ) => m.key === query.id );
if ( ! method ) {
throw `Current method ${ query.id } not found in available methods list`;
}
return method;
}, [ query ] );
const [ enabledMethods, setEnabledMethods ] = useState(
methods.reduce( ( acc, method ) => {
acc[ method.key ] = method.isEnabled;
return acc;
}, {} )
);
if ( currentMethod ) {
return (
<PaymentSetup
method={ currentMethod }
markConfigured={ markConfigured }
recordConnectStartEvent={ recordConnectStartEvent }
/>
);
}
const [ enabledCardMethods, additionalCardMethods ] = sift(
methods,
( method ) => method.isEnabled && method.isConfigured
);
const wcPayIndex = additionalCardMethods.findIndex(
( m ) => m.key === 'wcpay'
);
const wcPayMethod =
wcPayIndex === -1
? null
: additionalCardMethods.splice( wcPayIndex, 1 )[ 0 ];
return (
<div className="woocommerce-task-payments">
{ !! wcPayMethod && (
<WCPaySuggestion
onSetupCallback={ wcPayMethod.onClick }
paymentGateway={ {
...wcPayMethod,
description: __(
'Try the new way to get paid. Securely accept credit and debit cards on your site. Manage transactions without leaving your WordPress dashboard. Only with WooCommerce Payments.',
'wc-admin'
),
enabled: wcPayMethod.isEnabled,
installed: wcPayMethod.isEnabled,
needsSetup: ! wcPayMethod.isConfigured,
} }
/>
) }
{ !! enabledCardMethods.length && (
<PaymentMethodList
recommendedMethod={ recommendedMethod }
heading={ __( 'Enabled payment methods', 'wc-admin' ) }
methods={ enabledCardMethods }
/>
) }
{ !! additionalCardMethods.length && (
<PaymentMethodList
recommendedMethod={ recommendedMethod }
heading={ __( 'Additional payment methods', 'wc-admin' ) }
methods={ additionalCardMethods }
markConfigured={ markConfigured }
/>
) }
</div>
);
};
export default LocalPayments;

View File

@ -1,114 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Button, Spinner } from '@wordpress/components';
import { updateQueryString } from '@woocommerce/navigation';
import { recordEvent } from '@woocommerce/tracks';
import { useState } from '@wordpress/element';
export const PaymentAction = ( {
hasSetup = false,
needsSetup = true,
id,
isEnabled = false,
isLoading = false,
isRecommended = false,
manageUrl = null,
markConfigured,
onSetUp = () => {},
onSetupCallback,
setupButtonText = __( 'Set up', 'woocommerce-admin' ),
} ) => {
const [ isBusy, setIsBusy ] = useState( false );
const classes = 'woocommerce-task-payment__action';
if ( isLoading ) {
return <Spinner />;
}
const handleClick = async () => {
onSetUp( id );
if ( onSetupCallback ) {
setIsBusy( true );
await new Promise( onSetupCallback )
.then( () => {
setIsBusy( false );
} )
.catch( () => {
setIsBusy( false );
} );
return;
}
updateQueryString( {
id,
} );
};
const ManageButton = () => (
<Button
className={ classes }
isSecondary
href={ manageUrl }
onClick={ () => recordEvent( 'tasklist_payment_manage', { id } ) }
>
{ __( 'Manage', 'woocommerce-admin' ) }
</Button>
);
if ( ! hasSetup ) {
if ( ! isEnabled ) {
return (
<Button
className={ classes }
isSecondary
onClick={ () => markConfigured( id ) }
>
{ __( 'Enable', 'woocommerce-admin' ) }
</Button>
);
}
return <ManageButton />;
}
if ( ! isEnabled ) {
return (
<div>
<Button
className={ classes }
isPrimary={ isRecommended }
isSecondary={ ! isRecommended }
isBusy={ isBusy }
disabled={ isBusy }
onClick={ () => handleClick() }
>
{ setupButtonText }
</Button>
</div>
);
}
if ( needsSetup ) {
return (
<div>
<Button
className={ classes }
isPrimary={ isRecommended }
isSecondary={ ! isRecommended }
isBusy={ isBusy }
disabled={ isBusy }
onClick={ () => handleClick() }
>
{ __( 'Finish setup', 'woocommerce-admin' ) }
</Button>
</div>
);
}
return <ManageButton />;
};

View File

@ -1,108 +0,0 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { Fragment } from '@wordpress/element';
import {
Card,
CardBody,
CardMedia,
CardHeader,
CardDivider,
} from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
import { recordEvent } from '@woocommerce/tracks';
import { RecommendedRibbon, SetupRequired } from '@woocommerce/onboarding';
/**
* Internal dependencies
*/
import { PaymentAction } from '../PaymentActionLocal';
import './PaymentMethodList.scss';
export const PaymentMethodList = ( {
recommendedMethod,
heading,
methods,
markConfigured,
} ) => (
<Card>
<CardHeader as="h2">{ heading }</CardHeader>
{ methods.map( ( method, index ) => {
const {
before,
content,
isEnabled,
isConfigured,
key,
title,
visible,
loading,
manageUrl,
} = method;
if ( ! visible ) {
return null;
}
const classes = classnames(
'woocommerce-task-payment',
'woocommerce-task-card',
! isConfigured && 'woocommerce-task-payment-not-configured',
'woocommerce-task-payment-' + key
);
const isRecommended = key === recommendedMethod && ! isConfigured;
const showRecommendedRibbon = isRecommended;
return (
<Fragment key={ key }>
{ index !== 0 && <CardDivider /> }
<CardBody
style={ { paddingLeft: 0, marginBottom: 0 } }
className={ classes }
>
<CardMedia isBorderless>{ before }</CardMedia>
<div className="woocommerce-task-payment__description">
{ showRecommendedRibbon && <RecommendedRibbon /> }
<Text
as="h3"
className="woocommerce-task-payment__title"
>
{ title }
{ isEnabled && ! isConfigured && (
<SetupRequired />
) }
</Text>
<div className="woocommerce-task-payment__content">
{ content }
</div>
</div>
<div className="woocommerce-task-payment__footer">
<PaymentAction
manageUrl={ manageUrl }
id={ key }
hasSetup={ !! method.container }
needsSetup={ ! isConfigured }
isEnabled={ method.isEnabled }
isRecommended={ isRecommended }
isLoading={ loading }
markConfigured={ markConfigured }
onSetup={ () =>
recordEvent( 'tasklist_payment_setup', {
options: methods.map(
( option ) => option.key
),
selected: key,
} )
}
onSetupCallback={ method.onClick }
/>
</div>
</CardBody>
</Fragment>
);
} ) }
</Card>
);

View File

@ -1,81 +0,0 @@
.woocommerce-task-payment {
display: flex;
flex-direction: row;
align-items: center;
position: relative;
overflow: hidden;
.components-card__media {
width: 170px;
flex-shrink: 0;
img,
svg {
margin: auto;
max-width: 100px;
display: block;
}
}
> .components-form-toggle {
min-width: 52px;
}
.woocommerce-task-payment__title {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 500;
color: $studio-gray-80;
margin-top: 0;
margin-bottom: $gap-smaller;
}
.woocommerce-task-payment__content {
font-size: 14px;
color: $studio-gray-60;
margin: 0;
margin-right: $gap-larger;
.text-style-strong {
font-weight: bold;
}
p {
font-size: 12px;
}
}
.woocommerce-task-payment__description {
flex: 1;
}
@include breakpoint( '<600px' ) {
flex-wrap: wrap;
.woocommerce-task-payment__content {
margin: 0;
}
.components-card__media {
> svg,
> img {
margin: 0 0 0 $gap-large;
}
order: 1;
flex-basis: 50%;
}
.woocommerce-task-payment__description {
order: 3;
padding: $gap-large 0 0 $gap-large;
}
.woocommerce-task-payment__footer {
flex-basis: 50%;
align-self: flex-start;
order: 2;
text-align: right;
}
}
}

View File

@ -1 +0,0 @@
export { PaymentMethodList } from './PaymentMethodList';

View File

@ -1,93 +0,0 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { Card, CardBody } from '@wordpress/components';
import { cloneElement, useEffect, useMemo } from '@wordpress/element';
import { Plugins } from '@woocommerce/components';
import { PLUGINS_STORE_NAME, pluginNames } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { createNoticesFromResponse } from '~/lib/notices';
export const PaymentSetup = ( {
method,
markConfigured,
query,
recordConnectStartEvent,
} ) => {
useEffect( () => {
recordEvent( 'payments_task_stepper_view', {
payment_method: method.key,
} );
}, [] );
const { activePlugins } = useSelect( ( select ) => {
const { getActivePlugins } = select( PLUGINS_STORE_NAME );
return {
activePlugins: getActivePlugins(),
};
} );
const installStep = useMemo( () => {
if ( ! method.plugins || ! method.plugins.length ) {
return;
}
const pluginsToInstall = method.plugins.filter(
( m ) => ! activePlugins.includes( m )
);
const pluginNamesString = method.plugins
.map( ( pluginSlug ) => pluginNames[ pluginSlug ] )
.join( ' ' + __( 'and', 'woocommerce-admin' ) + ' ' );
return {
key: 'install',
label: sprintf(
/* translators: %s = one or more plugin names joined by "and" */
__( 'Install %s', 'woocommerce-admin' ),
pluginNamesString
),
content: (
<Plugins
onComplete={ ( plugins, response ) => {
createNoticesFromResponse( response );
recordEvent( 'tasklist_payment_install_method', {
plugins: method.plugins,
} );
} }
onError={ ( errors, response ) =>
createNoticesFromResponse( response )
}
autoInstall
pluginSlugs={ method.plugins }
/>
),
isComplete: ! pluginsToInstall.length,
};
}, [ activePlugins, method.plugins ] );
if ( ! method.container ) {
return null;
}
return (
<Card className="woocommerce-task-payment-method woocommerce-task-card">
<CardBody>
{ cloneElement( method.container, {
methodConfig: method,
query,
installStep,
markConfigured,
recordConnectStartEvent,
hasCbdIndustry: method.hasCbdIndustry,
} ) }
</CardBody>
</Card>
);
};

View File

@ -1,172 +0,0 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import interpolateComponents from 'interpolate-components';
import { useDispatch, useSelect } from '@wordpress/data';
import { Form, Link, Stepper, TextControl } from '@woocommerce/components';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
export function GenericPaymentStep( {
installStep,
markConfigured,
methodConfig,
recordConnectStartEvent,
} ) {
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
const { createNotice } = useDispatch( 'core/notices' );
const isOptionsRequesting = useSelect( ( select ) => {
const { isOptionsUpdating } = select( OPTIONS_STORE_NAME );
return isOptionsUpdating();
} );
const getInitialConfigValues = () => {
if ( methodConfig && methodConfig.fields ) {
return methodConfig.fields.reduce( ( data, field ) => {
return {
...data,
[ field.name ]: '',
};
}, {} );
}
};
const validate = ( values ) => {
if ( methodConfig && methodConfig.fields ) {
return methodConfig.fields.reduce( ( errors, field ) => {
if ( ! values[ field.name ] ) {
// Matches any word that is capitalized aside from abrevitions like ID.
const title = field.title.replace(
/([A-Z][a-z]+)/,
( val ) => val.toLowerCase()
);
return {
...errors,
[ field.name ]: __( 'Please enter your ' ) + title,
};
}
return errors;
}, {} );
}
return {};
};
const updateSettings = async ( values ) => {
// Because the GenericPaymentStep extension only works with the South African Rand
// currency, force the store to use it while setting the GenericPaymentStep settings
const options = methodConfig.getOptions
? methodConfig.getOptions( values )
: null;
if ( ! options ) {
return;
}
const update = await updateOptions( {
...options,
} );
if ( update.success ) {
markConfigured( methodConfig.key );
createNotice(
'success',
methodConfig.title +
__( ' connected successfully', 'woocommerce-admin' )
);
} else {
createNotice(
'error',
__(
'There was a problem saving your payment settings',
'woocommerce-admin'
)
);
}
};
const renderConnectStep = () => {
const helpText = interpolateComponents( {
mixedString: __(
'Your API details can be obtained from your {{link/}}',
'woocommerce-admin'
),
components: {
link: (
<Link
href={ methodConfig.apiDetailsLink }
target="_blank"
type="external"
>
{ sprintf(
__( '%(title)s account', 'woocommerce-admin' ),
{
title: methodConfig.title,
}
) }
</Link>
),
},
} );
return (
<Form
initialValues={ getInitialConfigValues() }
onSubmit={ updateSettings }
validate={ validate }
>
{ ( { getInputProps, handleSubmit } ) => {
return (
<>
{ ( methodConfig.fields || [] ).map( ( field ) => (
<TextControl
key={ field.name }
label={ field.title }
required
{ ...getInputProps( field.name ) }
/>
) ) }
<Button
isPrimary
isBusy={ isOptionsRequesting }
onClick={ ( event ) => {
recordConnectStartEvent( methodConfig.key );
handleSubmit( event );
} }
>
{ __( 'Proceed', 'woocommerce-admin' ) }
</Button>
<p>{ helpText }</p>
</>
);
} }
</Form>
);
};
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete || isOptionsRequesting }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: sprintf(
__(
'Connect your %(title)s account',
'woocommerce-admin'
),
{
title: methodConfig.title,
}
),
content: renderConnectStep(),
},
] }
/>
);
}

View File

@ -1,74 +0,0 @@
export default () => (
<svg
width="96"
height="32"
viewBox="0 0 96 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="32" height="32" rx="16" fill="#8E9196" />
<mask
id="bacs0"
mask-type="alpha"
maskUnits="userSpaceOnUse"
x="8"
y="8"
width="16"
height="16"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.875 12.25L16 8.5L23.125 12.25V13.75H8.875V12.25ZM16 10.195L19.9075 12.25H12.0925L16 10.195ZM10.75 15.25H12.25V20.5H10.75V15.25ZM15.25 20.5V15.25H16.75V20.5H15.25ZM23.125 23.5V22H8.875V23.5H23.125ZM19.75 15.25H21.25V20.5H19.75V15.25Z"
fill="white"
/>
</mask>
<g mask="url(#bacs0)">
<rect x="7" y="7" width="18" height="18" fill="white" />
</g>
<mask
id="bacs1"
mask-type="alpha"
maskUnits="userSpaceOnUse"
x="39"
y="10"
width="18"
height="12"
>
<path
d="M39 17L53.17 17L49.59 20.59L51 22L57 16L51 10L49.59 11.41L53.17 15L39 15L39 17Z"
fill="white"
/>
</mask>
<g mask="url(#bacs1)">
<rect
x="60"
y="28"
width="24"
height="24"
transform="rotate(-180 60 28)"
fill="#8E9196"
/>
</g>
<rect x="64" width="32" height="32" rx="16" fill="#8E9196" />
<mask
id="bacs2"
mask-type="alpha"
maskUnits="userSpaceOnUse"
x="72"
y="8"
width="16"
height="16"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M72.875 12.25L80 8.5L87.125 12.25V13.75H72.875V12.25ZM80 10.195L83.9075 12.25H76.0925L80 10.195ZM74.75 15.25H76.25V20.5H74.75V15.25ZM79.25 20.5V15.25H80.75V20.5H79.25ZM87.125 23.5V22H72.875V23.5H87.125ZM83.75 15.25H85.25V20.5H83.75V15.25Z"
fill="white"
/>
</mask>
<g mask="url(#bacs2)">
<rect x="71" y="7" width="18" height="18" fill="white" />
</g>
</svg>
);

View File

@ -1,15 +0,0 @@
export const PayUIndiaLogo = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1333.333"
version="1"
viewBox="0 0 1000 1000"
>
<path
d="M8987 7472c-15-16-17-45-17-194 0-157 2-177 18-191s44-17 189-17c152 0 172 2 186 18 15 16 17 45 17 194 0 157-2 177-18 191s-44 17-189 17c-152 0-172-2-186-18zM9413 7046l-28-24v-520l24-26 24-26h518l24 25 25 24v250c0 162-4 259-11 274-20 43-45 47-304 47-243 0-244 0-272-24zM8623 6435c-44-19-64-54-70-123l-6-59-106-6c-182-11-261-50-293-145-9-28-14-251-18-912l-5-875-29-62c-47-102-124-160-256-194-83-21-356-19-440 4-131 36-203 90-249 187l-26 55-5 875c-5 669-9 884-19 913-20 62-75 115-140 135-82 25-431 25-513-1-70-21-110-54-134-109-18-41-19-90-22-888-2-567 1-877 8-942 45-397 254-684 606-832 100-41 240-81 369-103 156-27 570-24 725 5 224 41 398 107 541 202 92 62 216 193 273 288 27 45 64 126 82 179 61 180 64 217 64 936v647h165c128 0 173 3 195 15 61 31 60 27 60 398 0 377-2 386-65 413-49 20-645 20-692-1zM322 6230c-114-24-221-100-268-192-55-108-54-73-54-1379V3453l23-34c29-44 72-58 172-58s143 14 172 58l23 34v935l473 5c379 4 489 8 557 21 374 72 570 244 656 573 36 135 45 410 20 562-64 379-252 580-626 667-65 15-141 18-590 20-283 1-534-2-558-6zm1107-388c75-27 103-44 154-91 88-82 127-217 127-438-1-343-95-479-370-529-56-10-188-13-513-14H389l3 503c3 457 5 505 21 534 35 64 26 63 512 60 429-2 442-3 504-25zM2665 5600c-114-13-234-38-274-58-62-31-76-61-76-167 0-79 3-98 21-121 32-43 65-49 163-30 175 33 251 40 441 40 272 0 384-28 473-121 62-63 78-123 84-309l6-162-369-5c-387-5-459-12-604-58-155-49-291-151-353-263-56-102-72-176-71-341 0-135 3-158 27-231 64-192 211-329 422-393 123-38 231-52 407-51 526 0 804 152 895 490 16 59 18 123 18 650v585l-23 75c-52 167-144 281-288 357-168 88-292 113-594 118-124 2-261 0-305-5zm832-1452c-7-243-17-288-83-358-49-52-106-81-211-106-89-22-373-25-453-5-198 49-277 155-268 355 3 80 8 99 34 146 50 87 142 139 289 160 27 4 196 8 374 9l324 1-6-202zM4073 5535c-46-20-67-57-59-105 9-57 420-1575 458-1690 42-130 91-221 152-283 64-64 123-94 228-115 68-13 95-14 171-4 50 6 93 10 95 8 7-7-80-211-113-266-37-61-97-122-155-157-48-29-155-60-232-68-130-14-162-36-160-115 2-84 30-166 69-200 32-28 38-30 121-30 98 0 228 26 318 63 229 93 393 294 499 613 53 161 565 2215 565 2269 0 50-21 80-64 91-14 3-70 4-125 2-116-4-142-16-179-89-14-27-95-348-212-837-104-437-198-812-209-835-37-83-92-117-188-117-113 0-163 31-204 126-9 23-106 367-214 765-245 906-247 910-285 943-17 14-47 30-68 36-52 14-171 12-209-5z"
transform="matrix(.1 0 0 -.1 0 1000)"
></path>
</svg>
);
};

View File

@ -1,15 +0,0 @@
/**
* Internal dependencies
*/
import { LocalPayments } from './LocalPayments';
import { PaymentGatewaySuggestions } from './PaymentGatewaySuggestions';
export const Payments = ( { query } ) => {
if ( window.wcAdminFeatures[ 'payment-gateway-suggestions' ] ) {
return <PaymentGatewaySuggestions query={ query } />;
}
return <LocalPayments query={ query } />;
};
export default Payments;

View File

@ -1,171 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { Button } from '@wordpress/components';
import { compose } from '@wordpress/compose';
import { withDispatch, withSelect } from '@wordpress/data';
import { Form, H, TextControl } from '@woocommerce/components';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
class Bacs extends Component {
getInitialConfigValues = () => {
return {
account_name: '',
account_number: '',
bank_name: '',
sort_code: '',
iban: '',
bic: '',
};
};
validate = ( values ) => {
const errors = {};
if ( ! values.account_number && ! values.iban ) {
errors.account_number = errors.iban = __(
'Please enter an account number or IBAN',
'woocommerce-admin'
);
}
return errors;
};
updateSettings = async ( values ) => {
const { updateOptions, createNotice, markConfigured } = this.props;
const update = await updateOptions( {
woocommerce_bacs_settings: {
enabled: 'yes',
},
woocommerce_bacs_accounts: [ values ],
} );
if ( update.success ) {
markConfigured( 'bacs' );
createNotice(
'success',
__(
'Direct bank transfer details added successfully',
'woocommerce-admin'
)
);
} else {
createNotice(
'error',
__(
'There was a problem saving your payment settings',
'woocommerce-admin'
)
);
}
};
render() {
const { isOptionsRequesting } = this.props;
return (
<Form
initialValues={ this.getInitialConfigValues() }
onSubmit={ this.updateSettings }
validate={ this.validate }
>
{ ( { getInputProps, handleSubmit } ) => {
return (
<Fragment>
<H>
{ __(
'Add your bank details',
'woocommerce-admin'
) }
</H>
<p>
{ __(
'These details are required to receive payments via bank transfer',
'woocommerce-admin'
) }
</p>
<div className="woocommerce-task-payment-method__fields">
<TextControl
label={ __(
'Account name',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'account_name' ) }
/>
<TextControl
label={ __(
'Account number',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'account_number' ) }
/>
<TextControl
label={ __(
'Bank name',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'bank_name' ) }
/>
<TextControl
label={ __(
'Sort code',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'sort_code' ) }
/>
<TextControl
label={ __( 'IBAN', 'woocommerce-admin' ) }
required
{ ...getInputProps( 'iban' ) }
/>
<TextControl
label={ __(
'BIC / Swift',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'bic' ) }
/>
</div>
<Button
isPrimary
isBusy={ isOptionsRequesting }
onClick={ handleSubmit }
>
{ __( 'Save', 'woocommerce-admin' ) }
</Button>
</Fragment>
);
} }
</Form>
);
}
}
export default compose(
withSelect( ( select ) => {
const { isOptionsUpdating } = select( OPTIONS_STORE_NAME );
const isOptionsRequesting = isOptionsUpdating();
return {
isOptionsRequesting,
};
} ),
withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
return {
createNotice,
updateOptions,
};
} )
)( Bacs );

View File

@ -1,173 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { Button } from '@wordpress/components';
import interpolateComponents from 'interpolate-components';
import { compose } from '@wordpress/compose';
import { withDispatch, withSelect } from '@wordpress/data';
import { Form, Link, Stepper, TextControl } from '@woocommerce/components';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
class EWay extends Component {
getInitialConfigValues = () => {
return {
customer_api: '',
customer_password: '',
};
};
validate = ( values ) => {
const errors = {};
if ( ! values.customer_api ) {
errors.customer_api = __(
'Please enter your customer API key ',
'woocommerce-admin'
);
}
if ( ! values.customer_password ) {
errors.customer_password = __(
'Please enter your customer password',
'woocommerce-admin'
);
}
return errors;
};
updateSettings = async ( values ) => {
const { updateOptions, createNotice, markConfigured } = this.props;
const update = await updateOptions( {
woocommerce_eway_settings: {
customer_api: values.customer_api,
customer_password: values.customer_password,
enabled: 'yes',
},
} );
if ( update.success ) {
markConfigured( 'eway' );
createNotice(
'success',
__( 'eWAY connected successfully', 'woocommerce-admin' )
);
} else {
createNotice(
'error',
__(
'There was a problem saving your payment settings',
'woocommerce-admin'
)
);
}
};
renderConnectStep() {
const { isOptionsRequesting, recordConnectStartEvent } = this.props;
const helpText = interpolateComponents( {
mixedString: __(
'Your API details can be obtained from your {{link}}eWAY account{{/link}}',
'woocommerce-admin'
),
components: {
link: (
<Link
href="https://www.eway.com.au/"
target="_blank"
type="external"
/>
),
},
} );
return (
<Form
initialValues={ this.getInitialConfigValues() }
onSubmit={ this.updateSettings }
validate={ this.validate }
>
{ ( { getInputProps, handleSubmit } ) => {
return (
<Fragment>
<TextControl
label={ __(
'Customer API Key',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'customer_api' ) }
/>
<TextControl
label={ __(
'Customer Password',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'customer_password' ) }
/>
<Button
isPrimary
isBusy={ isOptionsRequesting }
onClick={ ( event ) => {
recordConnectStartEvent( 'eway' );
handleSubmit( event );
} }
>
{ __( 'Proceed', 'woocommerce-admin' ) }
</Button>
<p>{ helpText }</p>
</Fragment>
);
} }
</Form>
);
}
render() {
const { installStep, isOptionsRequesting } = this.props;
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete || isOptionsRequesting }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: __(
'Connect your eWAY account',
'woocommerce-admin'
),
content: this.renderConnectStep(),
},
] }
/>
);
}
}
export default compose(
withSelect( ( select ) => {
const { isOptionsUpdating } = select( OPTIONS_STORE_NAME );
const isOptionsRequesting = isOptionsUpdating();
return {
isOptionsRequesting,
};
} ),
withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
return {
createNotice,
updateOptions,
};
} )
)( EWay );

View File

@ -1,608 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import {
getAdminLink,
getSetting,
WC_ASSET_URL as wcAssetUrl,
} from '@woocommerce/wc-admin-settings';
/**
* Internal dependencies
*/
import Bacs from './bacs';
import BacsLogo from '../images/bacs';
import { PayUIndiaLogo } from '../images/payu-india';
import Stripe from './stripe';
import Square from './square';
import {
WCPay,
WCPayUsageModal,
installActivateAndConnectWcpay,
isWCPaySupported,
} from './wcpay';
import PayPal, { PAYPAL_PLUGIN } from './paypal';
import { MercadoPago, MERCADOPAGO_PLUGIN } from './mercadopago';
import Klarna from './klarna';
import EWay from './eway';
import Razorpay from './razorpay';
import { Mollie } from './mollie';
import { PayUIndia } from './payu-india';
import { GenericPaymentStep } from '../generic-payment-step';
const wcAdminAssetUrl = getSetting( 'wcAdminAssetUrl', '' );
const getPaymentsSettingsUrl = ( methodKey ) => {
return getAdminLink(
'admin.php?page=wc-settings&tab=checkout&section=' + methodKey
);
};
const methodDefaults = { isConfigured: true };
export function getPaymentMethods( {
activePlugins,
countryCode,
createNotice,
installAndActivatePlugins,
onboardingStatus,
options,
profileItems,
paypalOnboardingStatus,
loadingPaypalStatus,
} ) {
const {
stripeSupportedCountries = [],
wcPayIsConnected = false,
enabledPaymentGateways = [],
} = onboardingStatus;
const hasCbdIndustry = ( profileItems.industry || [] ).some(
( { slug } ) => {
return slug === 'cbd-other-hemp-derived-products';
}
);
// Whether publishable and secret keys are filled for given mode.
const isStripeConfigured =
options.woocommerce_stripe_settings &&
( options.woocommerce_stripe_settings.testmode === 'no'
? options.woocommerce_stripe_settings.publishable_key &&
options.woocommerce_stripe_settings.secret_key
: options.woocommerce_stripe_settings.test_publishable_key &&
options.woocommerce_stripe_settings.test_secret_key );
const methods = [
{
key: 'stripe',
title: __(
'Credit cards - powered by Stripe',
'woocommerce-admin'
),
content: (
<>
{ __(
'Accept debit and credit cards in 135+ currencies, methods such as Alipay, ' +
'and one-touch checkout with Apple Pay.',
'woocommerce-admin'
) }
</>
),
before: (
<img
src={ wcAssetUrl + 'images/stripe.png' }
alt={ __( 'Stripe Logo', 'woocommerce-admin' ) }
/>
),
visible:
stripeSupportedCountries.includes( countryCode ) &&
! hasCbdIndustry,
plugins: [ 'woocommerce-gateway-stripe' ],
container: <Stripe />,
isConfigured: isStripeConfigured,
isEnabled:
options.woocommerce_stripe_settings &&
options.woocommerce_stripe_settings.enabled === 'yes',
optionName: 'woocommerce_stripe_settings',
manageUrl: getPaymentsSettingsUrl( 'stripe' ),
},
{
key: 'paystack',
title: __( 'Paystack', 'woocommerce-admin' ),
content: (
<>
{ __(
'Paystack helps African merchants accept one-time and recurring payments online with a modern, safe, and secure payment gateway.',
'woocommerce-admin'
) }
</>
),
before: (
<img
src={ wcAdminAssetUrl + 'onboarding/paystack.png' }
alt={ __( 'Paystack Logo', 'woocommerce-admin' ) }
/>
),
visible:
[ 'ZA', 'GH', 'NG' ].includes( countryCode ) &&
! hasCbdIndustry,
plugins: [ 'woo-paystack' ],
container: <GenericPaymentStep />,
isConfigured:
options.woocommerce_paystack_settings &&
options.woocommerce_paystack_settings.live_public_key &&
options.woocommerce_paystack_settings.live_secret_key,
isEnabled: enabledPaymentGateways.includes( 'paystack' ),
optionName: 'woocommerce_paystack_settings',
apiDetailsLink:
'https://dashboard.paystack.com/#/settings/developer',
fields: [
{
name: 'live_public_key',
title: __( 'Live Public Key', 'woocommerce-admin' ),
},
{
name: 'live_secret_key',
title: __( 'Live Secret Key', 'woocommerce-admin' ),
},
],
getOptions: ( values ) => {
// Paystack only supports NGN (₦), GHS (₵), USD ($) or ZAR (R)
return {
woocommerce_currency: 'ZAR',
woocommerce_paystack_settings: {
...values,
testmode: 'no',
},
};
},
manageUrl: getPaymentsSettingsUrl( 'paystack' ),
},
{
key: 'payfast',
title: __( 'PayFast', 'woocommerce-admin' ),
content: (
<>
{ __(
'The PayFast extension for WooCommerce enables you to accept payments by Credit Card and EFT via one of South Africas most popular payment gateways. No setup fees or monthly subscription costs.',
'woocommerce-admin'
) }
<p>
{ __(
'Selecting this extension will configure your store to use South African rands as the selected currency.',
'woocommerce-admin'
) }
</p>
</>
),
before: (
<img
src={ wcAssetUrl + 'images/payfast.png' }
alt={ __( 'PayFast Logo', 'woocommerce-admin' ) }
/>
),
visible: [ 'ZA' ].includes( countryCode ) && ! hasCbdIndustry,
plugins: [ 'woocommerce-payfast-gateway' ],
container: <GenericPaymentStep />,
isConfigured:
options.woocommerce_payfast_settings &&
options.woocommerce_payfast_settings.merchant_id &&
options.woocommerce_payfast_settings.merchant_key &&
options.woocommerce_payfast_settings.pass_phrase,
isEnabled:
options.woocommerce_payfast_settings &&
options.woocommerce_payfast_settings.enabled === 'yes',
optionName: 'woocommerce_payfast_settings',
apiDetailsLink: 'https://www.payfast.co.za/',
fields: [
{
name: 'merchant_id',
title: __( 'Merchant ID', 'woocommerce-admin' ),
},
{
name: 'merchant_key',
title: __( 'Merchant Key', 'woocommerce-admin' ),
},
{
name: 'pass_phrase',
title: __( 'Passphrase', 'woocommerce-admin' ),
},
],
getOptions: ( values ) => {
return {
woocommerce_currency: 'ZAR',
woocommerce_payfast_settings: {
...values,
testmode: 'no',
},
};
},
manageUrl: getPaymentsSettingsUrl( 'stripe' ),
},
{
key: 'mercadopago',
title: __(
'Mercado Pago Checkout Pro & Custom',
'woocommerce-admin'
),
content: (
<>
{ __(
'Accept credit and debit cards, offline (cash or bank transfer) and logged-in payments with money in Mercado Pago. Safe and secure payments with the leading payment processor in LATAM.',
'woocommerce-admin'
) }
</>
),
before: (
<img
src={ wcAdminAssetUrl + 'onboarding/mercadopago.png' }
alt={ __( 'Mercado Pago Logo', 'woocommerce-admin' ) }
/>
),
visible: [ 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ].includes(
countryCode
),
plugins: [ MERCADOPAGO_PLUGIN ],
container: <MercadoPago />,
isConfigured: activePlugins.includes( MERCADOPAGO_PLUGIN ),
isEnabled:
options[ 'woocommerce_woo-mercado-pago-basic_settings' ] &&
options[ 'woocommerce_woo-mercado-pago-basic_settings' ]
.enabled === 'yes',
optionName: 'woocommerce_woo-mercado-pago-basic_settings',
manageUrl: getPaymentsSettingsUrl( 'woo-mercado-pago-basic' ),
},
{
key: 'paypal',
title: __( 'PayPal Payments', 'woocommerce-admin' ),
content: (
<>
{ __(
"Safe and secure payments using credit cards or your customer's PayPal account.",
'woocommerce-admin'
) }
</>
),
before: (
<img
src={ wcAssetUrl + 'images/paypal.png' }
alt={ __( 'PayPal Logo', 'woocommerce-admin' ) }
/>
),
visible: countryCode !== 'IN' && ! hasCbdIndustry,
plugins: [ PAYPAL_PLUGIN ],
container: <PayPal />,
isConfigured:
paypalOnboardingStatus &&
paypalOnboardingStatus.production &&
paypalOnboardingStatus.production.onboarded,
isEnabled: enabledPaymentGateways.includes( 'ppcp-gateway' ),
optionName: 'woocommerce_ppcp-gateway_settings',
loading: activePlugins.includes( PAYPAL_PLUGIN )
? loadingPaypalStatus
: false,
manageUrl: getPaymentsSettingsUrl( 'ppcp-gateway' ),
},
{
key: 'klarna_checkout',
title: __( 'Klarna Checkout', 'woocommerce-admin' ),
content: __(
'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries.',
'woocommerce-admin'
),
before: (
<img
src={ wcAssetUrl + 'images/klarna-black.png' }
alt={ __( 'Klarna Logo', 'woocommerce-admin' ) }
/>
),
visible:
[ 'SE', 'FI', 'NO' ].includes( countryCode ) &&
! hasCbdIndustry,
plugins: [ 'klarna-checkout-for-woocommerce' ],
container: <Klarna plugin={ 'checkout' } />,
// @todo This should check actual Klarna connection information.
isConfigured: activePlugins.includes(
'klarna-checkout-for-woocommerce'
),
isEnabled:
options.woocommerce_kco_settings &&
options.woocommerce_kco_settings.enabled === 'yes',
optionName: 'woocommerce_kco_settings',
manageUrl: getPaymentsSettingsUrl( 'kco' ),
},
{
key: 'klarna_payments',
title: __( 'Klarna Payments', 'woocommerce-admin' ),
content: __(
'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries.',
'woocommerce-admin'
),
before: (
<img
src={ wcAssetUrl + 'images/klarna-black.png' }
alt={ __( 'Klarna Logo', 'woocommerce-admin' ) }
/>
),
visible:
[
'DK',
'DE',
'AT',
'NL',
'CH',
'BE',
'SP',
'PL',
'FR',
'IT',
'GB',
].includes( countryCode ) && ! hasCbdIndustry,
plugins: [ 'klarna-payments-for-woocommerce' ],
container: <Klarna plugin={ 'payments' } />,
// @todo This should check actual Klarna connection information.
isConfigured: activePlugins.includes(
'klarna-payments-for-woocommerce'
),
isEnabled:
options.woocommerce_klarna_payments_settings &&
options.woocommerce_klarna_payments_settings.enabled === 'yes',
optionName: 'woocommerce_klarna_payments_settings',
manageUrl: getPaymentsSettingsUrl( 'klarna_payments' ),
},
{
key: 'mollie',
title: __( 'Mollie Payments for WooCommerce', 'woocommerce-admin' ),
before: (
<img
src={ wcAdminAssetUrl + '/onboarding/mollie.svg' }
alt={ __(
'Mollie Payments for WooCommerce logo',
'woocommerce-admin'
) }
/>
),
plugins: [ 'mollie-payments-for-woocommerce' ],
isConfigured: activePlugins.includes(
'mollie-payments-for-woocommerce'
),
content: (
<>
{ __(
'Effortless payments by Mollie: Offer global and local payment methods, get onboarded in minutes, and supported in your language.',
'woocommerce-admin'
) }
</>
),
visible: [
'FR',
'DE',
'GB',
'AT',
'CH',
'ES',
'IT',
'PL',
'FI',
'NL',
'BE',
].includes( countryCode ),
container: <Mollie />,
isEnabled:
options.woocommerce_mollie_payments_settings &&
options.woocommerce_mollie_payments_settings.enabled === 'yes',
optionName: 'woocommerce_mollie_payments_settings',
manageUrl: getPaymentsSettingsUrl( 'mollie_wc_gateway_creditcard' ),
},
{
key: 'square',
title: __( 'Square', 'woocommerce-admin' ),
content: (
<>
{ __(
'Securely accept credit and debit cards with one low rate, no surprise fees (custom rates available). ' +
'Sell online and in store and track sales and inventory in one place.',
'woocommerce-admin'
) }
{ hasCbdIndustry && (
<span className="text-style-strong">
{ __(
' Selling CBD products is only supported by Square.',
'woocommerce-admin'
) }
</span>
) }
</>
),
before: (
<img
src={ `${ wcAssetUrl }images/square-black.png` }
alt={ __( 'Square Logo', 'woocommerce-admin' ) }
/>
),
visible:
( hasCbdIndustry && [ 'US' ].includes( countryCode ) ) ||
( [ 'brick-mortar', 'brick-mortar-other' ].includes(
profileItems.selling_venues
) &&
[ 'US', 'CA', 'JP', 'GB', 'AU', 'IE' ].includes(
countryCode
) ),
plugins: [ 'woocommerce-square' ],
container: <Square />,
isConfigured:
options.wc_square_refresh_tokens &&
options.wc_square_refresh_tokens.length,
isEnabled:
options.woocommerce_square_credit_card_settings &&
options.woocommerce_square_credit_card_settings.enabled ===
'yes',
optionName: 'woocommerce_square_credit_card_settings',
hasCbdIndustry,
manageUrl: getPaymentsSettingsUrl( 'square_credit_card' ),
},
{
key: 'eway',
title: __( 'eWAY', 'woocommerce-admin' ),
content: (
<>
{ __(
'The eWAY extension for WooCommerce allows you to take credit card payments directly on your store without redirecting your customers to a third party site to make payment.',
'woocommerce-admin'
) }
</>
),
before: (
<img
src={ wcAssetUrl + 'images/eway-logo.jpg' }
alt={ __( 'eWAY Logo', 'woocommerer-admin' ) }
/>
),
visible: [ 'AU', 'NZ' ].includes( countryCode ) && ! hasCbdIndustry,
plugins: [ 'woocommerce-gateway-eway' ],
container: <EWay />,
isConfigured:
options.woocommerce_eway_settings &&
options.woocommerce_eway_settings.customer_api &&
options.woocommerce_eway_settings.customer_password,
isEnabled:
options.woocommerce_eway_settings &&
options.woocommerce_eway_settings.enabled === 'yes',
optionName: 'woocommerce_eway_settings',
manageUrl: getPaymentsSettingsUrl( 'eway' ),
},
{
key: 'razorpay',
title: __( 'Razorpay', 'woocommerce-admin' ),
content: (
<>
{ __(
'The official Razorpay extension for WooCommerce allows you to accept credit cards, debit cards, netbanking, wallet, and UPI payments.',
'woocommerce-admin'
) }
</>
),
before: (
<img
src={ wcAdminAssetUrl + 'onboarding/razorpay.svg' }
alt={ __( 'Razorpay', 'woocommerce-admin' ) }
/>
),
visible: countryCode === 'IN' && ! hasCbdIndustry,
plugins: [ 'woo-razorpay' ],
container: <Razorpay />,
isConfigured:
options.woocommerce_razorpay_settings &&
options.woocommerce_razorpay_settings.key_id &&
options.woocommerce_razorpay_settings.key_secret,
isEnabled:
options.woocommerce_razorpay_settings &&
options.woocommerce_razorpay_settings.enabled === 'yes',
optionName: 'woocommerce_razorpay_settings',
manageUrl: getPaymentsSettingsUrl( 'razorpay' ),
},
{
key: 'payubiz',
title: __( 'PayU for WooCommerce', 'woocommerce-admin' ),
content: (
<>
{ __(
'Enable PayUs exclusive plugin for WooCommerce to start accepting payments in 100+ payment methods available in India including credit cards, debit cards, UPI, & more!',
'woocommerce-admin'
) }
</>
),
before: <PayUIndiaLogo />,
visible: countryCode === 'IN' && ! hasCbdIndustry,
plugins: [ 'payu-india' ],
container: <PayUIndia />,
isConfigured: activePlugins.includes( 'payu-india' ),
isEnabled: enabledPaymentGateways.includes( 'payubiz' ),
optionName: 'woocommerce_payubiz_settings',
manageUrl: getPaymentsSettingsUrl( 'payubiz' ),
},
{
key: 'cod',
title: __( 'Cash on delivery', 'woocommerce-admin' ),
content: __(
'Take payments in cash upon delivery.',
'woocommerce-admin'
),
before: (
<img
src={ wcAdminAssetUrl + 'onboarding/cod.svg' }
alt={ __( 'Cash on Delivery Logo', 'woocommerce-admin' ) }
/>
),
visible: ! hasCbdIndustry,
isEnabled:
options.woocommerce_cod_settings &&
options.woocommerce_cod_settings.enabled === 'yes',
optionName: 'woocommerce_cod_settings',
manageUrl: getPaymentsSettingsUrl( 'cod' ),
},
{
key: 'bacs',
title: __( 'Direct bank transfer', 'woocommerce-admin' ),
content: __(
'Take payments via bank transfer.',
'woocommerce-admin'
),
before: <BacsLogo />,
visible: ! hasCbdIndustry,
container: <Bacs />,
isConfigured:
options.woocommerce_bacs_accounts &&
options.woocommerce_bacs_accounts.length,
isEnabled:
options.woocommerce_bacs_settings &&
options.woocommerce_bacs_settings.enabled === 'yes',
optionName: 'woocommerce_bacs_settings',
manageUrl: getPaymentsSettingsUrl( 'bacs' ),
},
];
if ( window.wcAdminFeatures.wcpay ) {
methods.unshift( {
key: 'wcpay',
title: __( 'WooCommerce Payments', 'woocommerce-admin' ),
content: (
<>
{ __(
'Manage transactions without leaving your WordPress Dashboard. Only with WooCommerce Payments.',
'woocommerce-admin'
) }
<WCPayUsageModal />
</>
),
before: (
<img
src={ wcAdminAssetUrl + 'onboarding/wcpay.svg' }
alt={ __( 'WooCommerce Payments', 'woocommerce-admin' ) }
/>
),
onClick: ( resolve, reject ) => {
return installActivateAndConnectWcpay(
reject,
createNotice,
installAndActivatePlugins
);
},
visible: isWCPaySupported( countryCode ) && ! hasCbdIndustry,
plugins: [ 'woocommerce-payments' ],
container: <WCPay />,
isConfigured: wcPayIsConnected,
isEnabled:
options.woocommerce_woocommerce_payments_settings &&
options.woocommerce_woocommerce_payments_settings.enabled ===
'yes',
optionName: 'woocommerce_woocommerce_payments_settings',
manageUrl: getPaymentsSettingsUrl( 'woocommerce_payments' ),
} );
}
return methods
.filter( ( method ) => method.visible )
.map( ( method ) => ( { ...methodDefaults, ...method } ) );
}

View File

@ -1,101 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { Button } from '@wordpress/components';
import interpolateComponents from 'interpolate-components';
import { ADMIN_URL as adminUrl } from '@woocommerce/wc-admin-settings';
import { Link, Stepper } from '@woocommerce/components';
class Klarna extends Component {
constructor( props ) {
super( props );
this.continue = this.continue.bind( this );
}
continue() {
const { markConfigured, plugin } = this.props;
const slug =
plugin === 'checkout' ? 'klarna_checkout' : 'klarna_payments';
markConfigured( slug );
}
renderConnectStep() {
const { plugin } = this.props;
const slug =
plugin === 'checkout' ? 'klarna-checkout' : 'klarna-payments';
const section = plugin === 'checkout' ? 'kco' : 'klarna_payments';
const link = (
<Link
href={
adminUrl +
'admin.php?page=wc-settings&tab=checkout&section=' +
section
}
target="_blank"
type="external"
/>
);
const helpLink = (
<Link
href={
'https://docs.woocommerce.com/document/' +
slug +
'/#section-3'
}
target="_blank"
type="external"
/>
);
const configureText = interpolateComponents( {
mixedString: __(
'Klarna can be configured under your {{link}}store settings{{/link}}. Figure out {{helpLink}}what you need{{/helpLink}}.',
'woocommerce-admin'
),
components: {
link,
helpLink,
},
} );
return (
<Fragment>
<p>{ configureText }</p>
<Button isPrimary onClick={ this.continue }>
{ __( 'Continue', 'woocommerce-admin' ) }
</Button>
</Fragment>
);
}
render() {
const { installStep } = this.props;
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: __(
'Connect your Klarna account',
'woocommerce-admin'
),
content: this.renderConnectStep(),
},
] }
/>
);
}
}
export default Klarna;

View File

@ -1,101 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { ADMIN_URL as adminUrl } from '@woocommerce/wc-admin-settings';
import { Stepper, Link } from '@woocommerce/components';
import { Button } from '@wordpress/components';
import interpolateComponents from 'interpolate-components';
import { useSelect } from '@wordpress/data';
import { SETTINGS_STORE_NAME } from '@woocommerce/data';
/**
* Internal dependencies
*/
import { getCountryCode } from '~/dashboard/utils';
export const MERCADOPAGO_PLUGIN = 'woocommerce-mercadopago';
export const MercadoPago = ( { installStep, markConfigured } ) => {
const { countryCode } = useSelect( ( select ) => {
const { getSettings } = select( SETTINGS_STORE_NAME );
const { general: generalSettings = {} } = getSettings( 'general' );
return {
countryCode: getCountryCode(
generalSettings.woocommerce_default_country
),
};
} );
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: __(
'Connect to your Mercado Pago account',
'woocommerce-admin'
),
content: (
<MercadoPagoCredentialsStep
countryCode={ countryCode }
onFinish={ () => markConfigured( 'mercadopago' ) }
/>
),
},
] }
/>
);
};
const MercadoPagoCredentialsStep = ( { countryCode, onFinish } ) => {
const getRegistrationURL = () => {
const mercadoPagoURL = 'https://www.mercadopago.com';
if (
! [ 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ].includes(
countryCode
)
) {
return mercadoPagoURL;
}
// As each country has its own domain, we will return the correct one. Otherwise, for example, a Spanish speaker could be redirected to a Mercado Pago page in Portuguese, etc.
return `${ mercadoPagoURL }.${ countryCode.toLowerCase() }/registration-company?confirmation_url=${ mercadoPagoURL }.${ countryCode.toLowerCase() }%2Fcomo-cobrar`;
};
const settingsLink = (
<Link
href={ `${ adminUrl }admin.php?page=wc-settings&tab=checkout` }
target="_blank"
type="external"
/>
);
const accountLink = (
<Link href={ getRegistrationURL() } target="_blank" type="external" />
);
const configureText = interpolateComponents( {
mixedString: __(
'Mercado Pago can be configured under your {{settingsLink}}store settings.{{/settingsLink}} Create your Mercado Pago account {{accountLink}}here.{{/accountLink}}',
'woocommerce-admin'
),
components: {
accountLink,
settingsLink,
},
} );
return (
<>
<p>{ configureText }</p>
<Button isPrimary onClick={ onFinish }>
{ __( 'Continue', 'woocommerce-admin' ) }
</Button>
</>
);
};

View File

@ -1,73 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { ADMIN_URL as adminUrl } from '@woocommerce/wc-admin-settings';
import { Stepper, Link } from '@woocommerce/components';
import { Button } from '@wordpress/components';
import interpolateComponents from 'interpolate-components';
export const Mollie = ( { installStep, markConfigured } ) => {
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: __(
'Connect your Mollie account',
'woocommerce-admin'
),
content: (
<MollieConnectStep
onFinish={ () => {
markConfigured( 'mollie' );
} }
/>
),
},
] }
/>
);
};
const MollieConnectStep = ( { onFinish } ) => {
const settingsLink = (
<Link
href={ `${ adminUrl }admin.php?page=wc-settings&tab=mollie_settings#mollie-payments-for-woocommerce` }
target="_blank"
type="external"
/>
);
const accountLink = (
<Link
href={ 'https://www.mollie.com/dashboard/signup' }
target="_blank"
type="external"
/>
);
const configureText = interpolateComponents( {
mixedString: __(
'Create a {{accountLink}}Mollie account{{/accountLink}} and finish the configuration in the {{settingsLink}}Mollie settings.{{/settingsLink}}',
'woocommerce-admin'
),
components: {
accountLink,
settingsLink,
},
} );
return (
<>
<p>{ configureText }</p>
<Button isPrimary onClick={ onFinish }>
{ __( 'Continue', 'woocommerce-admin' ) }
</Button>
</>
);
};

View File

@ -1,535 +0,0 @@
/* global ppcp_onboarding */
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import apiFetch from '@wordpress/api-fetch';
import { Button } from '@wordpress/components';
import { Component, Fragment, useEffect } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import interpolateComponents from 'interpolate-components';
import { withDispatch, withSelect } from '@wordpress/data';
import { isEmail } from '@wordpress/url';
import { Form, Link, TextControl, Stepper } from '@woocommerce/components';
import { getQuery } from '@woocommerce/navigation';
import { PLUGINS_STORE_NAME, OPTIONS_STORE_NAME } from '@woocommerce/data';
const PAYPAL_PLUGIN = 'woocommerce-paypal-payments';
const WC_PAYPAL_NAMESPACE = '/wc-paypal/v1';
/**
* Loads the onboarding script file into the dom on the fly.
*
* @param {string} url of the onboarding js file.
* @param {Object} data required for the onboarding script, labeled as PayPalCommerceGatewayOnboarding
* @param {Function} onLoad callback for when the script is loaded.
*/
function loadOnboardingScript( url, data, onLoad ) {
try {
// eslint-disable-next-line camelcase
if ( ppcp_onboarding ) {
onLoad();
}
} catch ( e ) {
const script = document.createElement( 'script' );
script.src = url;
document.body.append( script );
// Callback after scripts have loaded.
script.onload = function () {
onLoad();
};
window.PayPalCommerceGatewayOnboarding = data;
}
}
function PaypalConnectButton( { connectUrl, recordConnectStartEvent } ) {
useEffect( () => {
// eslint-disable-next-line camelcase
if ( ppcp_onboarding ) {
// Makes sure the onboarding is hooked up to the Connect button rendered.
ppcp_onboarding.reload();
}
}, [] );
return (
<a
className="button-primary"
target="_blank"
rel="noreferrer"
href={ connectUrl }
data-paypal-onboard-button="true"
data-paypal-button="true"
data-paypal-onboard-complete="ppcp_onboarding_productionCallback"
onClick={ () => recordConnectStartEvent( 'paypal' ) }
>
{ __( 'Connect', 'woocommerce-admin' ) }
</a>
);
}
class PayPal extends Component {
constructor( props ) {
super( props );
this.state = {
autoConnectFailed: false,
connectURL: '',
};
this.enablePaypalPlugin = this.enablePaypalPlugin.bind( this );
this.setCredentials = this.setCredentials.bind( this );
this.validate = this.validate.bind( this );
}
componentDidMount() {
const { createNotice } = this.props;
const query = getQuery();
// Handle redirect back from PayPal
if ( query.onboarding ) {
if (
query.onboarding === 'complete' &&
! query[ 'ppcp-onboarding-error' ]
) {
this.enablePaypalPlugin();
return;
}
if ( query[ 'ppcp-onboarding-error' ] ) {
/* eslint-disable react/no-did-mount-set-state */
this.setState( {
autoConnectFailed: true,
} );
createNotice(
'error',
__(
'There was a problem saving your payment settings through the onboarding, please fill the fields in manually.',
'woocommerce-admin'
)
);
}
return;
}
this.fetchOAuthConnectURLAndOnboardingSetup();
}
componentDidUpdate( prevProps ) {
const { activePlugins } = this.props;
if (
! prevProps.activePlugins.includes( PAYPAL_PLUGIN ) &&
activePlugins.includes( PAYPAL_PLUGIN )
) {
this.fetchOAuthConnectURLAndOnboardingSetup();
}
}
async fetchOAuthConnectURLAndOnboardingSetup() {
const { activePlugins, createNotice } = this.props;
if ( ! activePlugins.includes( PAYPAL_PLUGIN ) ) {
return;
}
this.setState( { isPending: true } );
try {
const result = await apiFetch( {
path: WC_PAYPAL_NAMESPACE + '/onboarding/get-params',
method: 'POST',
data: {
environment: 'production',
returnUrlArgs: {
ppcpobw: '1',
},
},
} );
if ( ! result || ! result.signupLink ) {
this.setState( {
autoConnectFailed: true,
isPending: false,
} );
return;
}
loadOnboardingScript( result.scriptURL, result.scriptData, () => {
this.setState( {
connectURL: result.signupLink,
isPending: false,
} );
} );
} catch ( error ) {
if ( error && error.data && error.data.status === 500 ) {
createNotice(
'error',
__(
'There was a problem with the Paypal onboarding setup, please fill the fields in manually.',
'woocommerce-admin'
)
);
}
this.setState( {
autoConnectFailed: true,
isPending: false,
} );
}
}
async enablePaypalPlugin( skipPpcpSettingsUpdate ) {
const {
createNotice,
updateOptions,
markConfigured,
options,
} = this.props;
const updatedOptions = {
'woocommerce_ppcp-gateway_settings': {
enabled: 'yes',
},
};
if ( ! skipPpcpSettingsUpdate ) {
updatedOptions[ 'woocommerce-ppcp-settings' ] = {
...options,
enabled: true,
};
}
const update = await updateOptions( updatedOptions );
if ( update.success ) {
createNotice(
'success',
__( 'PayPal connected successfully.', 'woocommerce-admin' )
);
markConfigured( 'paypal' );
} else {
createNotice(
'error',
__(
'There was a problem saving your payment settings.',
'woocommerce-admin'
)
);
}
}
async setCredentials( values ) {
const { createNotice } = this.props;
try {
const result = await apiFetch( {
path: WC_PAYPAL_NAMESPACE + '/onboarding/set-credentials',
method: 'POST',
data: {
environment: 'production',
...values,
},
} );
if ( result && result.data ) {
createNotice(
'error',
__(
'There was a problem updating the credentials.',
'woocommerce-admin'
)
);
} else {
await this.enablePaypalPlugin( true );
}
} catch ( error ) {
if ( error && error.data && error.data.status === 404 ) {
await this.updateManualSettings( values );
}
}
}
async updateManualSettings( values ) {
const {
createNotice,
options,
updateOptions,
markConfigured,
} = this.props;
const productionValues = Object.keys( values ).reduce(
( vals, key ) => {
const prodKey = key + '_production';
return {
...vals,
[ prodKey ]: values[ key ],
};
},
{}
);
/**
* merchant data can be the same across sandbox and production, that's why we set it as
* standalone as well.
*/
const optionValues = {
...options,
enabled: true,
sandbox_on: false,
merchant_email: values.merchant_email,
merchant_id: values.merchant_id,
...productionValues,
};
const update = await updateOptions( {
'woocommerce-ppcp-settings': optionValues,
'woocommerce_ppcp-gateway_settings': {
enabled: 'yes',
},
} );
if ( update.success ) {
createNotice(
'success',
__( 'PayPal connected successfully.', 'woocommerce-admin' )
);
markConfigured( 'paypal' );
} else {
createNotice(
'error',
__(
'There was a problem saving your payment settings.',
'woocommerce-admin'
)
);
}
}
getInitialConfigValues() {
const { options } = this.props;
return [
'merchant_email',
'merchant_id',
'client_id',
'client_secret',
].reduce( ( initialVals, key ) => {
return {
...initialVals,
[ key ]:
options && options[ key + '_production' ]
? options[ key + '_production' ]
: '',
};
}, {} );
}
validate( values ) {
const errors = {};
if ( ! values.merchant_email ) {
errors.merchant_email = __(
'Please enter your Merchant email',
'woocommerce-admin'
);
}
if ( ! isEmail( values.merchant_email ) ) {
errors.merchant_email = __(
'Please enter a valid email address',
'woocommerce-admin'
);
}
if ( ! values.merchant_id ) {
errors.merchant_id = __(
'Please enter your Merchant Id',
'woocommerce-admin'
);
}
if ( ! values.client_id ) {
errors.client_id = __(
'Please enter your Client Id',
'woocommerce-admin'
);
}
if ( ! values.client_secret ) {
errors.client_secret = __(
'Please enter your Client Secret',
'woocommerce-admin'
);
}
return errors;
}
renderManualConfig() {
const { isOptionsUpdating } = this.props;
const stripeHelp = interpolateComponents( {
mixedString: __(
'Your API details can be obtained from your {{docsLink}}Paypal developer account{{/docsLink}}, and your Merchant Id from your {{merchantLink}}Paypal Business account{{/merchantLink}}. Dont have a Paypal account? {{registerLink}}Create one.{{/registerLink}}',
'woocommerce-admin'
),
components: {
docsLink: (
<Link
href="https://developer.paypal.com/docs/api-basics/manage-apps/#create-or-edit-sandbox-and-live-apps"
target="_blank"
type="external"
/>
),
merchantLink: (
<Link
href="https://www.paypal.com/ca/smarthelp/article/FAQ3850"
target="_blank"
type="external"
/>
),
registerLink: (
<Link
href="https://www.paypal.com/us/business"
target="_blank"
type="external"
/>
),
},
} );
return (
<Form
initialValues={ this.getInitialConfigValues() }
onSubmit={ this.setCredentials }
validate={ this.validate }
>
{ ( { getInputProps, handleSubmit } ) => {
return (
<Fragment>
<TextControl
label={ __(
'Email address',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'merchant_email' ) }
/>
<TextControl
label={ __(
'Merchant Id',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'merchant_id' ) }
/>
<TextControl
label={ __( 'Client Id', 'woocommerce-admin' ) }
required
{ ...getInputProps( 'client_id' ) }
/>
<TextControl
label={ __(
'Secret Key',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'client_secret' ) }
/>
<Button
isPrimary
isBusy={ isOptionsUpdating }
onClick={ handleSubmit }
>
{ __( 'Proceed', 'woocommerce-admin' ) }
</Button>
<p>{ stripeHelp }</p>
</Fragment>
);
} }
</Form>
);
}
renderConnectFields() {
const { autoConnectFailed, connectURL } = this.state;
const { recordConnectStartEvent } = this.props;
if ( ! autoConnectFailed && connectURL ) {
return (
<>
<PaypalConnectButton
connectUrl={ connectURL }
recordConnectStartEvent={ recordConnectStartEvent }
/>
<p>
{ __(
'You will be redirected to the PayPal website to create the connection.',
'woocommerce-admin'
) }
</p>
</>
);
}
if ( autoConnectFailed ) {
return this.renderManualConfig();
}
}
getConnectStep() {
const { isRequestingOptions } = this.props;
return {
key: 'connect',
label: __( 'Connect your PayPal account', 'woocommerce-admin' ),
description: __(
'A PayPal account is required to process payments. Connect your store to your PayPal account.',
'woocommerce-admin'
),
content: isRequestingOptions ? null : this.renderConnectFields(),
};
}
render() {
const {
installStep,
isRequestingOptions,
isOptionsUpdating,
} = this.props;
const { isPending } = this.state;
return (
<Stepper
isVertical
isPending={
! installStep.isComplete ||
isPending ||
isRequestingOptions ||
isOptionsUpdating
}
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [ installStep, this.getConnectStep() ] }
/>
);
}
}
PayPal.defaultProps = {
manualConfig: false, // WCS is not required for the PayPal OAuth flow, so we can default to smooth connection.
};
export default compose(
withSelect( ( select ) => {
const { getOption, isOptionsUpdating, hasFinishedResolution } = select(
OPTIONS_STORE_NAME
);
const { getActivePlugins } = select( PLUGINS_STORE_NAME );
const paypalOptions = getOption( 'woocommerce-ppcp-settings' );
const isRequestingOptions = ! hasFinishedResolution( 'getOption', [
'woocommerce-ppcp-settings',
] );
const activePlugins = getActivePlugins();
return {
activePlugins,
isOptionsUpdating: isOptionsUpdating(),
options: paypalOptions,
isRequestingOptions,
};
} ),
withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
return {
createNotice,
updateOptions,
};
} )
)( PayPal );
export { PayPal, PAYPAL_PLUGIN };

View File

@ -1,73 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { ADMIN_URL as adminUrl } from '@woocommerce/wc-admin-settings';
import { Stepper, Link } from '@woocommerce/components';
import { Button } from '@wordpress/components';
import interpolateComponents from 'interpolate-components';
export const PayUIndia = ( { installStep, markConfigured } ) => {
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: __(
'Connect to your PayU account',
'woocommerce-admin'
),
content: (
<PayUCredentialsStep
onFinish={ () => {
markConfigured( 'payubiz' );
} }
/>
),
},
] }
/>
);
};
const PayUCredentialsStep = ( { onFinish } ) => {
const settingsLink = (
<Link
href={ `${ adminUrl }admin.php?page=wc-settings&tab=checkout&section=payubiz` }
target="_blank"
type="external"
/>
);
const accountLink = (
<Link
href={ 'https://onboarding.payu.in/app/account' }
target="_blank"
type="external"
/>
);
const configureText = interpolateComponents( {
mixedString: __(
'PayU can be configured under your {{settingsLink}}store settings.{{/settingsLink}} Create your PayU account {{accountLink}}here.{{/accountLink}}',
'woocommerce-admin'
),
components: {
accountLink,
settingsLink,
},
} );
return (
<>
<p>{ configureText }</p>
<Button isPrimary onClick={ onFinish }>
{ __( 'Continue', 'woocommerce-admin' ) }
</Button>
</>
);
};

View File

@ -1,173 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import interpolateComponents from 'interpolate-components';
import { useDispatch, useSelect } from '@wordpress/data';
import { Form, Link, Stepper, TextControl } from '@woocommerce/components';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
const INITIAL_CONFIG = {
key_id: '',
key_secret: '',
};
const validate = ( values ) => {
const errors = {};
if ( ! values.key_id ) {
errors.key_id = __( 'Please enter your Key ID', 'woocommerce-admin' );
}
if ( ! values.key_secret ) {
errors.key_secret = __(
'Please enter your Key Secret',
'woocommerce-admin'
);
}
return errors;
};
const updateSettings = async (
values,
createNotice,
markConfigured,
updateOptions
) => {
const update = await updateOptions( {
woocommerce_razorpay_settings: {
key_id: values.key_id,
key_secret: values.key_secret,
enabled: 'yes',
},
} );
if ( update.success ) {
markConfigured( 'razorpay' );
createNotice(
'success',
__( 'Razorpay connected successfully', 'woocommerce-admin' )
);
} else {
createNotice(
'error',
__(
'There was a problem saving your payment settings',
'woocommerce-admin'
)
);
}
};
const renderConnectStep = ( {
createNotice,
isOptionsRequesting,
markConfigured,
updateOptions,
} ) => {
const helpText = interpolateComponents( {
mixedString: __(
'Your key details can be obtained from your {{link}}Razorpay account{{/link}}',
'woocommerce-admin'
),
components: {
link: (
<Link
href="https://dashboard.razorpay.com/#/access/signin"
target="_blank"
type="external"
/>
),
},
} );
const onSubmit = ( values ) =>
updateSettings( values, createNotice, markConfigured, updateOptions );
return (
<Form
initialValues={ INITIAL_CONFIG }
onSubmit={ onSubmit }
validate={ validate }
>
{ ( { getInputProps, handleSubmit } ) => {
return (
<>
<TextControl
label={ __( 'Key ID', 'woocommerce-admin' ) }
required
{ ...getInputProps( 'key_id' ) }
/>
<TextControl
label={ __( 'Key Secret', 'woocommerce-admin' ) }
required
{ ...getInputProps( 'key_secret' ) }
/>
<Button
isPrimary
isBusy={ isOptionsRequesting }
onClick={ handleSubmit }
>
{ __( 'Proceed', 'woocommerce-admin' ) }
</Button>
<p>{ helpText }</p>
</>
);
} }
</Form>
);
};
export const Razorpay = ( {
createNotice,
installStep,
isOptionsRequesting,
markConfigured,
updateOptions,
} ) => {
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete || isOptionsRequesting }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: __(
'Connect your Razorpay account',
'woocommerce-admin'
),
content: renderConnectStep( {
createNotice,
isOptionsRequesting,
markConfigured,
updateOptions,
} ),
},
] }
/>
);
};
export default ( { installStep, markConfigured } ) => {
const isOptionsUpdating = useSelect(
( select ) => select( OPTIONS_STORE_NAME ).isOptionsUpdating
);
const isOptionsRequesting = isOptionsUpdating();
const { createNotice } = useDispatch( 'core/notices' );
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
return (
<Razorpay
createNotice={ createNotice }
installStep={ installStep }
isOptionsRequesting={ isOptionsRequesting }
markConfigured={ markConfigured }
updateOptions={ updateOptions }
/>
);
};

View File

@ -1,164 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { Button } from '@wordpress/components';
import { withDispatch, withSelect } from '@wordpress/data';
import { getQuery } from '@woocommerce/navigation';
import { compose } from '@wordpress/compose';
import { Stepper } from '@woocommerce/components';
import { getAdminLink } from '@woocommerce/wc-admin-settings';
import { OPTIONS_STORE_NAME, WC_ADMIN_NAMESPACE } from '@woocommerce/data';
class Square extends Component {
constructor( props ) {
super( props );
this.state = {
isPending: false,
};
this.connect = this.connect.bind( this );
}
componentDidMount() {
const { createNotice, markConfigured } = this.props;
const query = getQuery();
// Handle redirect back from Square
if ( query[ 'square-connect' ] ) {
if ( query[ 'square-connect' ] === '1' ) {
createNotice(
'success',
__( 'Square connected successfully.', 'woocommerce-admin' )
);
markConfigured( 'square' );
}
}
}
async connect() {
const {
createNotice,
hasCbdIndustry,
options,
recordConnectStartEvent,
updateOptions,
} = this.props;
this.setState( { isPending: true } );
updateOptions( {
woocommerce_square_credit_card_settings: {
...options.woocommerce_square_credit_card_settings,
enabled: 'yes',
},
} );
const errorMessage = __(
'There was an error connecting to Square. Please try again or skip to connect later in store settings.',
'woocommerce-admin'
);
recordConnectStartEvent( 'square' );
try {
let newWindow = null;
if ( hasCbdIndustry ) {
// It's necessary to declare the new tab before the async call,
// otherwise, it won't be possible to open it.
newWindow = window.open( '/', '_blank' );
}
const result = await apiFetch( {
path: WC_ADMIN_NAMESPACE + '/plugins/connect-square',
method: 'POST',
} );
if ( ! result || ! result.connectUrl ) {
this.setState( { isPending: false } );
createNotice( 'error', errorMessage );
if ( hasCbdIndustry ) {
newWindow.close();
}
return;
}
this.setState( { isPending: true } );
this.redirect( result.connectUrl, newWindow );
} catch ( error ) {
this.setState( { isPending: false } );
createNotice( 'error', errorMessage );
}
}
redirect( connectUrl, newWindow ) {
if ( newWindow ) {
newWindow.location.href = connectUrl;
window.location = getAdminLink( 'admin.php?page=wc-admin' );
} else {
window.location = connectUrl;
}
}
render() {
const { installStep } = this.props;
const { isPending } = this.state;
return (
<Stepper
isVertical
isPending={ ! installStep.isComplete || isPending }
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [
installStep,
{
key: 'connect',
label: __(
'Connect your Square account',
'woocommerce-admin'
),
description: __(
'A Square account is required to process payments. You will be redirected to the Square website to create the connection.',
'woocommerce-admin'
),
content: (
<Fragment>
<Button
isPrimary
isBusy={ isPending }
onClick={ this.connect }
>
{ __( 'Connect', 'woocommerce-admin' ) }
</Button>
</Fragment>
),
},
] }
/>
);
}
}
export default compose(
withSelect( ( select ) => {
const { getOption, isResolving } = select( OPTIONS_STORE_NAME );
const options = getOption( 'woocommerce_square_credit_card_settings' );
const optionsIsRequesting = isResolving( 'getOption', [
'woocommerce_square_credit_card_settings',
] );
return {
options,
optionsIsRequesting,
};
} ),
withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
return {
createNotice,
updateOptions,
};
} )
)( Square );

View File

@ -1,365 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { compose } from '@wordpress/compose';
import apiFetch from '@wordpress/api-fetch';
import { withDispatch, withSelect } from '@wordpress/data';
import interpolateComponents from 'interpolate-components';
import { Button } from '@wordpress/components';
import { Form, Link, Stepper, TextControl } from '@woocommerce/components';
import { getAdminLink } from '@woocommerce/wc-admin-settings';
import { getQuery } from '@woocommerce/navigation';
import {
PLUGINS_STORE_NAME,
OPTIONS_STORE_NAME,
WCS_NAMESPACE,
} from '@woocommerce/data';
class Stripe extends Component {
constructor( props ) {
super( props );
this.state = {
oAuthConnectFailed: false,
connectURL: null,
isPending: false,
};
this.updateSettings = this.updateSettings.bind( this );
}
componentDidMount() {
const { oAuthConnectFailed } = this.state;
const { stripeSettings } = this.props;
const query = getQuery();
// Handle redirect back from Stripe.
if ( query[ 'stripe-connect' ] && query[ 'stripe-connect' ] === '1' ) {
const isStripeConnected =
stripeSettings.publishable_key && stripeSettings.secret_key;
if ( isStripeConnected ) {
this.completeMethod();
return;
}
}
if ( ! oAuthConnectFailed ) {
this.fetchOAuthConnectURL();
}
}
componentDidUpdate( prevProps ) {
const { activePlugins } = this.props;
if (
! prevProps.activePlugins.includes(
'woocommerce-gateway-stripe'
) &&
activePlugins.includes( 'woocommerce-gateway-stripe' )
) {
this.fetchOAuthConnectURL();
}
}
completeMethod() {
const { createNotice, markConfigured } = this.props;
this.setState( { isPending: false } );
createNotice(
'success',
__( 'Stripe connected successfully.', 'woocommerce-admin' )
);
markConfigured( 'stripe' );
}
async fetchOAuthConnectURL() {
const { activePlugins } = this.props;
if ( ! activePlugins.includes( 'woocommerce-gateway-stripe' ) ) {
return;
}
try {
this.setState( { isPending: true } );
const result = await apiFetch( {
path: WCS_NAMESPACE + '/connect/stripe/oauth/init',
method: 'POST',
data: {
returnUrl: getAdminLink(
'admin.php?page=wc-admin&task=payments&id=stripe&stripe-connect=1'
),
},
} );
if ( ! result || ! result.oauthUrl ) {
this.setState( {
oAuthConnectFailed: true,
isPending: false,
} );
return;
}
this.setState( {
connectURL: result.oauthUrl,
isPending: false,
} );
} catch ( error ) {
this.setState( {
oAuthConnectFailed: true,
isPending: false,
} );
}
}
renderConnectButton() {
const { connectURL } = this.state;
return (
<Button isPrimary href={ connectURL }>
{ __( 'Connect', 'woocommerce-admin' ) }
</Button>
);
}
async updateSettings( values ) {
const { updateOptions, stripeSettings, createNotice } = this.props;
const prefix = values.publishable_key.match( /^pk_live_/ )
? ''
: 'test_';
const update = await updateOptions( {
woocommerce_stripe_settings: {
...stripeSettings,
[ prefix + 'publishable_key' ]: values.publishable_key,
[ prefix + 'secret_key' ]: values.secret_key,
testmode: prefix === 'test_' ? 'yes' : 'no',
enabled: 'yes',
},
} );
if ( update.success ) {
this.completeMethod();
} else {
createNotice(
'error',
__(
'There was a problem saving your payment settings',
'woocommerce-admin'
)
);
}
}
getInitialConfigValues() {
return {
publishable_key: '',
secret_key: '',
};
}
validateManualConfig( values ) {
const errors = {};
if (
values.publishable_key.match( /^pk_(live|test)_[a-zA-Z0-9_]+/ ) ===
null
) {
errors.publishable_key = __(
'Please enter a valid publishable key (starting with "pk_").',
'woocommerce-admin'
);
}
if (
values.secret_key.match( /^[rs]k_(live|test)_[a-zA-Z0-9_]+/ ) ===
null
) {
errors.secret_key = __(
'Please enter a valid secret key (starting with "sk_" or "rk_").',
'woocommerce-admin'
);
} else if (
values.secret_key.slice( 3, 7 ) !==
values.publishable_key.slice( 3, 7 )
) {
errors.secret_key = __(
'Please enter a secret key in the same mode as the publishable key.',
'woocommerce-admin'
);
}
return errors;
}
renderManualConfig() {
const { isOptionsUpdating, recordConnectStartEvent } = this.props;
const stripeHelp = interpolateComponents( {
mixedString: __(
'Your API details can be obtained from your {{docsLink}}Stripe account{{/docsLink}}. Dont have a Stripe account? {{registerLink}}Create one.{{/registerLink}}',
'woocommerce-admin'
),
components: {
docsLink: (
<Link
href="https://stripe.com/docs/keys"
target="_blank"
type="external"
/>
),
registerLink: (
<Link
href="https://dashboard.stripe.com/register"
target="_blank"
type="external"
/>
),
},
} );
return (
<Form
initialValues={ this.getInitialConfigValues() }
onSubmit={ this.updateSettings }
validate={ this.validateManualConfig }
>
{ ( { getInputProps, handleSubmit } ) => {
return (
<Fragment>
<TextControl
label={ __(
'Publishable Key',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'publishable_key' ) }
/>
<TextControl
label={ __(
'Secret Key',
'woocommerce-admin'
) }
required
{ ...getInputProps( 'secret_key' ) }
/>
<Button
isPrimary
isBusy={ isOptionsUpdating }
onClick={ ( event ) => {
recordConnectStartEvent( 'stripe' );
handleSubmit( event );
} }
>
{ __( 'Proceed', 'woocommerce-admin' ) }
</Button>
<p>{ stripeHelp }</p>
</Fragment>
);
} }
</Form>
);
}
renderOauthConfig() {
const { recordConnectStartEvent } = this.props;
const tosPrompt = interpolateComponents( {
mixedString: __(
'By clicking "Connect," you agree to the {{tosLink}}Terms of Service{{/tosLink}}. Or {{manualConfigLink}}manually enter your Stripe API details{{/manualConfigLink}} instead.',
'woocommerce-admin'
),
components: {
tosLink: (
<Link
href="https://wordpress.com/tos"
target="_blank"
type="external"
/>
),
manualConfigLink: (
<Button
isLink
onClick={ () => {
this.setState( {
connectURL: null,
} );
recordConnectStartEvent( 'stripe' );
} }
/>
),
},
} );
return (
<Fragment>
<p>{ this.renderConnectButton() }</p>
{ tosPrompt }
</Fragment>
);
}
getConnectStep() {
const { connectURL, isPending, oAuthConnectFailed } = this.state;
const connectStep = {
key: 'connect',
label: __( 'Connect your Stripe account', 'woocommerce-admin' ),
};
if ( isPending ) {
return connectStep;
}
if ( ! oAuthConnectFailed && connectURL ) {
return {
...connectStep,
description: __(
'A Stripe account is required to process payments.',
'woocommerce-admin'
),
content: this.renderOauthConfig(),
};
}
return {
...connectStep,
content: this.renderManualConfig(),
};
}
render() {
const { installStep, isOptionsUpdating } = this.props;
const { isPending } = this.state;
return (
<Stepper
isVertical
isPending={
! installStep.isComplete || isOptionsUpdating || isPending
}
currentStep={ installStep.isComplete ? 'connect' : 'install' }
steps={ [ installStep, this.getConnectStep() ] }
/>
);
}
}
export default compose(
withSelect( ( select ) => {
const { getOption, isOptionsUpdating } = select( OPTIONS_STORE_NAME );
const { getActivePlugins } = select( PLUGINS_STORE_NAME );
return {
activePlugins: getActivePlugins(),
isOptionsUpdating: isOptionsUpdating(),
stripeSettings: getOption( 'woocommerce_stripe_settings' ) || [],
};
} ),
withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
return {
createNotice,
updateOptions,
};
} )
)( Stripe );

View File

@ -1,10 +0,0 @@
/**
* Internal dependencies
*/
import WCPayUsageModal from './wcpay-usage-modal';
import WCPay from './wcpay';
export * from './is-supported';
export * from './install-activate-and-connect';
export { WCPay, WCPayUsageModal };

View File

@ -1,20 +0,0 @@
export function isWCPaySupported( countryCode ) {
const supportedCountries = [ 'US', 'PR' ];
if (
window.wcAdminFeatures &&
window.wcAdminFeatures[ 'wcpay/support-international-countries' ]
) {
supportedCountries.push(
'AU',
'CA',
'DE',
'ES',
'FR',
'GB',
'IE',
'IT',
'NZ'
);
}
return supportedCountries.includes( countryCode );
}

View File

@ -1,36 +0,0 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Component } from '@wordpress/element';
import { withDispatch } from '@wordpress/data';
import { getQuery } from '@woocommerce/navigation';
class WCPay extends Component {
componentDidMount() {
const { createNotice, markConfigured } = this.props;
const query = getQuery();
// Handle redirect back from WCPay on-boarding
if ( query[ 'wcpay-connection-success' ] ) {
createNotice(
'success',
__(
'WooCommerce Payments connected successfully.',
'woocommerce-admin'
)
);
markConfigured( 'wcpay', { 'wcpay-connection-success': '1' } );
}
}
render() {
return null;
}
}
export default withDispatch( ( dispatch ) => {
const { createNotice } = dispatch( 'core/notices' );
return {
createNotice,
};
} )( WCPay );

View File

@ -1,417 +0,0 @@
/**
* External dependencies
*/
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import apiFetch from '@wordpress/api-fetch';
/**
* Internal dependencies
*/
import { PayPal, PAYPAL_PLUGIN } from '../tasks/payments/methods/paypal';
import { getPaymentMethods } from '../tasks/payments/methods';
import { setMethodEnabledOption } from '../../task-list/tasks/payments/LocalPayments';
import { GenericPaymentStep } from '../tasks/payments/generic-payment-step';
jest.mock( '@wordpress/api-fetch' );
describe( 'TaskList > Payments', () => {
describe( 'Payments', () => {
const optionName = 'woocommerce_mollie_payments_settings';
it( 'does not update an option if the value is the same as the current one', async () => {
const mockProps = {
clearTaskStatusCache: jest.fn(),
updateOptions: jest.fn(),
options: {
woocommerce_klarna_payments_settings: false,
woocommerce_mollie_payments_settings: { enabled: 'yes' },
},
};
await setMethodEnabledOption( optionName, 'yes', mockProps );
expect( mockProps.updateOptions ).not.toHaveBeenCalled();
} );
it( 'does update an option if the value is different to the current one', async () => {
const mockProps = {
clearTaskStatusCache: jest.fn(),
updateOptions: jest.fn(),
options: {
woocommerce_klarna_payments_settings: false,
woocommerce_mollie_payments_settings: { enabled: 'no' },
},
};
await setMethodEnabledOption( optionName, 'yes', mockProps );
expect( mockProps.updateOptions ).toHaveBeenCalledWith( {
woocommerce_mollie_payments_settings: { enabled: 'yes' },
} );
} );
} );
describe( 'Methods', () => {
const params = {
activePlugins: [],
countryCode: 'SE',
onboardingStatus: {},
options: [],
profileItems: { industry: [] },
};
it( 'includes Klarna Checkout for SE, NO, and FI', () => {
[ 'SE', 'NO', 'FI' ].forEach( ( countryCode ) => {
params.countryCode = countryCode;
const methods = getPaymentMethods( params );
expect(
methods.some(
( method ) => method.key === 'klarna_checkout'
)
).toBe( true );
} );
} );
it( 'includes Klarna Payment for EU countries', () => {
const supportedCountryCodes = [
'DK',
'DE',
'AT',
'NL',
'CH',
'BE',
'SP',
'PL',
'FR',
'IT',
'GB',
];
supportedCountryCodes.forEach( ( countryCode ) => {
params.countryCode = countryCode;
const methods = getPaymentMethods( params );
expect(
methods.some( ( e ) => e.key === 'klarna_payments' )
).toBe( true );
} );
} );
describe( 'Mollie', () => {
it( 'Detects the plugin is enabled based on the options passed', () => {
const mollieParams = {
...params,
options: {
woocommerce_mollie_payments_settings: {
enabled: 'yes',
},
},
};
const mollieMethod = getPaymentMethods( mollieParams ).find(
( method ) => method.key === 'mollie'
);
expect( mollieMethod.isEnabled ).toBe( true );
} );
it( 'is enabled for supported countries', () => {
[
'FR',
'DE',
'GB',
'AT',
'CH',
'ES',
'IT',
'PL',
'FI',
'NL',
'BE',
].forEach( ( countryCode ) => {
const methods = getPaymentMethods( {
...params,
countryCode,
} );
expect(
methods.filter( ( method ) => method.key === 'mollie' )
.length
).toBe( 1 );
} );
} );
} );
it( 'is marked as `isConfigured` if the plugin is active', () => {
expect(
getPaymentMethods( {
...params,
activePlugins: [ 'mollie-payments-for-woocommerce' ],
} ).find( ( method ) => method.key === 'mollie' ).isConfigured
).toBe( true );
} );
describe( 'MercadoPago', () => {
it( 'Is enabled for supported countries', () => {
[ 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ].forEach(
( countryCode ) => {
params.countryCode = countryCode;
const methods = getPaymentMethods( params );
expect(
methods.some(
( method ) => method.key === 'mercadopago'
)
).toBe( true );
}
);
} );
it( 'Detects whether the plugin is enabled based on the received options', () => {
const mercadoPagoParams = {
...params,
options: {
...params.options,
'woocommerce_woo-mercado-pago-basic_settings': {
enabled: 'yes',
},
},
};
const mercadoPagoMethod = getPaymentMethods(
mercadoPagoParams
).find( ( method ) => method.key === 'mercadopago' );
expect( mercadoPagoMethod.isEnabled ).toBe( true );
} );
} );
it( 'If the plugin is active `mercadopago` is marked as `isConfigured`', () => {
expect(
getPaymentMethods( {
...params,
activePlugins: [ 'woocommerce-mercadopago' ],
} ).find( ( method ) => method.key === 'mercadopago' )
.isConfigured
).toBe( true );
} );
} );
describe( 'PayPal', () => {
afterEach( () => jest.clearAllMocks() );
const mockInstallStep = {
isComplete: true,
key: 'install',
label: 'Install',
};
it( 'shows API credential inputs when "create account" opted out and OAuth fetch fails', async () => {
apiFetch.mockResolvedValue( false );
render(
<PayPal
activePlugins={ [
'jetpack',
PAYPAL_PLUGIN,
'woocommerce-services',
] }
isRequestingOptions={ false }
options={ {} }
installStep={ mockInstallStep }
/>
);
// Since the oauth response failed, we should have the API credentials form.
expect(
await screen.findByText( 'Proceed', { selector: 'button' } )
).toBeDefined();
expect(
screen.queryByLabelText( 'Email address', {
selector: 'input',
} )
).toBeDefined();
expect(
screen.getByLabelText( 'Merchant Id', { selector: 'input' } )
).toBeDefined();
expect(
screen.getByLabelText( 'Client Id', { selector: 'input' } )
).toBeDefined();
expect(
screen.getByLabelText( 'Secret Key', { selector: 'input' } )
).toBeDefined();
} );
it( 'shows OAuth connect button', async () => {
global.ppcp_onboarding = {
reload: () => {},
};
const mockConnectUrl = 'https://connect.woocommerce.test/paypal';
apiFetch.mockResolvedValue( {
signupLink: mockConnectUrl,
} );
render(
<PayPal
activePlugins={ [ PAYPAL_PLUGIN ] }
installStep={ mockInstallStep }
isRequestingOptions={ false }
options={ {} }
/>
);
// Since the oauth response was mocked, we should have a "connect" button.
const oauthButton = await screen.findByText( 'Connect', {
selector: 'a',
} );
expect( oauthButton ).toBeDefined();
expect( oauthButton.href ).toEqual( mockConnectUrl );
expect( oauthButton.dataset.paypalButton ).toEqual( 'true' );
expect( oauthButton.dataset.paypalOnboardButton ).toEqual( 'true' );
} );
} );
describe( 'Payfast', () => {
const params = {
activePlugins: [],
countryCode: 'ZA',
onboardingStatus: {},
options: [],
profileItems: { industry: [] },
};
const mockInstallStep = {
isComplete: true,
key: 'install',
label: 'Install',
};
it( 'Detects the plugin is enabled based on the options passed', () => {
const payfastParams = {
...params,
options: {
woocommerce_payfast_settings: {
enabled: 'yes',
},
},
};
const payfastMethod = getPaymentMethods( payfastParams ).find(
( method ) => method.key === 'payfast'
);
expect( payfastMethod.isEnabled ).toBe( true );
} );
it( 'is enabled for supported countries', () => {
[ 'ZA' ].forEach( ( countryCode ) => {
const methods = getPaymentMethods( {
...params,
countryCode,
} );
expect(
methods.filter( ( method ) => method.key === 'payfast' )
.length
).toBe( 1 );
} );
} );
it( 'shows API credential inputs', async () => {
const payfastMethod = getPaymentMethods( params ).find(
( method ) => method.key === 'payfast'
);
render(
<GenericPaymentStep
isRequestingOptions={ false }
options={ {} }
installStep={ mockInstallStep }
methodConfig={ payfastMethod }
/>
);
// Since the oauth response failed, we should have the API credentials form.
expect(
await screen.findByText( 'Proceed', { selector: 'button' } )
).toBeDefined();
expect(
screen.getByLabelText( 'Merchant ID', { selector: 'input' } )
).toBeDefined();
expect(
screen.getByLabelText( 'Merchant Key', { selector: 'input' } )
).toBeDefined();
expect(
screen.getByLabelText( 'Passphrase', { selector: 'input' } )
).toBeDefined();
} );
} );
describe( 'Paystack', () => {
const params = {
activePlugins: [],
countryCode: 'ZA',
onboardingStatus: {},
options: [],
profileItems: { industry: [] },
};
const mockInstallStep = {
isComplete: true,
key: 'install',
label: 'Install',
};
it( 'Detects the plugin is enabled based on the enabled gateways', () => {
const paystackParams = {
...params,
onboardingStatus: {
enabledPaymentGateways: [ 'paystack' ],
},
};
const paystackMethod = getPaymentMethods( paystackParams ).find(
( method ) => method.key === 'paystack'
);
expect( paystackMethod.isEnabled ).toBe( true );
} );
it( 'is enabled for supported countries', () => {
[ 'ZA', 'GH', 'NG' ].forEach( ( countryCode ) => {
const methods = getPaymentMethods( {
...params,
countryCode,
} );
expect(
methods.filter( ( method ) => method.key === 'paystack' )
.length
).toBe( 1 );
} );
} );
it( 'shows API credential inputs', async () => {
const payfastMethod = getPaymentMethods( params ).find(
( method ) => method.key === 'paystack'
);
render(
<GenericPaymentStep
isRequestingOptions={ false }
options={ {} }
installStep={ mockInstallStep }
methodConfig={ payfastMethod }
/>
);
// Since the oauth response failed, we should have the API credentials form.
expect(
await screen.findByText( 'Proceed', { selector: 'button' } )
).toBeDefined();
expect(
screen.getByLabelText( 'Live Public Key', {
selector: 'input',
} )
).toBeDefined();
expect(
screen.getByLabelText( 'Live Secret Key', {
selector: 'input',
} )
).toBeDefined();
} );
} );
} );

View File

@ -14,7 +14,7 @@
"onboarding": true,
"remote-inbox-notifications": true,
"remote-extensions-list": true,
"payment-gateway-suggestions": false,
"payment-gateway-suggestions": true,
"settings": false,
"shipping-label-banner": true,
"store-alerts": true,

View File

@ -14,7 +14,7 @@
"onboarding": true,
"remote-inbox-notifications": true,
"remote-extensions-list": true,
"payment-gateway-suggestions": false,
"payment-gateway-suggestions": true,
"settings": false,
"shipping-label-banner": true,
"store-alerts": true,

View File

@ -75,26 +75,27 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt
== Unreleased ==
- Add: SlotFill to Abbreviated Notification panel #7091
- Add: Add unit tests around extended payment gateway controller #7133
- Add: Add payment gateway suggestion unit tests #7142
- Add: Feature toggle to disable Analytics UI #7168
- Fix: WCPay not working in local payments task #7151
- Fix: Include onboarding settings on the analytic pages #7109
- Fix: RemoteFreeExtension hide bundle when all of its plugins are not visible #7182
- Fix: Fixing button state logic for remote payment gateways #7200
- Fix: Skip schedule customer data deletion on site deletion #7214
- Fix: Fix obsolete key property in gateway defaults #7229
- Fix: Load Analytics API only when feature is turned on #7193
- Tweak: Revert Card component removal #7167
- Add: SlotFill to Abbreviated Notification panel #7091
- Dev: Add `woocommerce_admin_export_id` filter for customizing the export file name #7178
- Dev: Remove old payment gateway task components #7224
- Fix: Currency display on Orders activity card on homescreen #7181
- Fix: Report export filtering bug. #7165
- Fix: Fix obsolete key property in gateway defaults #7229
- Fix: Fixing button state logic for remote payment gateways #7200
- Fix: Include onboarding settings on the analytic pages #7109
- Fix: Load Analytics API only when feature is turned on #7193
- Fix: Localize string for description #7219
- Fix: RemoteFreeExtension hide bundle when all of its plugins are not visible #7182
- Fix: Report export filtering bug. #7165
- Fix: Use tab char for the CSV injection prevention. #7154
- Fix: Use saved form values if available when switching tabs #7226
- Fix: Skip schedule customer data deletion on site deletion #7214
- Fix: The use of gridicons for Analytics section controls. #7237
- Fix: WCPay not working in local payments task #7151
- Fix: WordPress 5.8 compatibility UI fixes #7255
- Dev: Add `woocommerce_admin_export_id` filter for customizing the export file name #7178
- Tweak: Revert Card component removal #7167
- Update: Notes to use a date range. #7222
== 2.4.0 6/10/2021 ==

View File

@ -28,6 +28,7 @@ export class PaymentsSetup extends BasePage {
async goToPaymentMethodSetup( method: PaymentMethodWithSetupButton ) {
const selector = `.woocommerce-task-payment-${ method } button`;
await this.page.waitForSelector( selector );
const button = await this.page.$( selector );
if ( ! button ) {