2021-09-21 19:33:44 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import { useDispatch, useSelect } from '@wordpress/data';
|
|
|
|
import {
|
|
|
|
OPTIONS_STORE_NAME,
|
|
|
|
ONBOARDING_STORE_NAME,
|
|
|
|
PAYMENT_GATEWAYS_STORE_NAME,
|
2022-04-13 07:13:15 +00:00
|
|
|
SETTINGS_STORE_NAME,
|
2021-09-21 19:33:44 +00:00
|
|
|
} from '@woocommerce/data';
|
|
|
|
import { recordEvent } from '@woocommerce/tracks';
|
|
|
|
import { useMemo, useCallback, useEffect } from '@wordpress/element';
|
|
|
|
import { registerPlugin } from '@wordpress/plugins';
|
|
|
|
import { WooOnboardingTask } from '@woocommerce/onboarding';
|
2022-03-02 01:45:44 +00:00
|
|
|
import { getNewPath } from '@woocommerce/navigation';
|
2022-03-31 05:57:38 +00:00
|
|
|
import { Button } from '@wordpress/components';
|
|
|
|
import ExternalIcon from 'gridicons/dist/external';
|
2021-09-21 19:33:44 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { List, Placeholder as ListPlaceholder } from './components/List';
|
|
|
|
import { Setup, Placeholder as SetupPlaceholder } from './components/Setup';
|
2022-04-04 10:12:20 +00:00
|
|
|
import { Toggle } from './components/Toggle/Toggle';
|
2021-09-21 19:33:44 +00:00
|
|
|
import { WCPaySuggestion } from './components/WCPay';
|
2022-01-24 16:23:12 +00:00
|
|
|
import { getPluginSlug } from '~/utils';
|
2022-04-13 07:13:15 +00:00
|
|
|
import { getCountryCode } from '~/dashboard/utils';
|
2021-09-21 19:33:44 +00:00
|
|
|
import './plugins/Bacs';
|
2021-10-05 18:20:28 +00:00
|
|
|
import './payment-gateway-suggestions.scss';
|
2021-09-21 19:33:44 +00:00
|
|
|
|
2022-03-31 05:57:38 +00:00
|
|
|
const SEE_MORE_LINK =
|
|
|
|
'https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations';
|
|
|
|
|
2022-02-09 06:12:20 +00:00
|
|
|
const comparePaymentGatewaysByPriority = ( a, b ) =>
|
|
|
|
a.recommendation_priority - b.recommendation_priority;
|
|
|
|
|
2021-10-01 19:53:22 +00:00
|
|
|
export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
|
2021-09-21 19:33:44 +00:00
|
|
|
const { updatePaymentGateway } = useDispatch( PAYMENT_GATEWAYS_STORE_NAME );
|
|
|
|
const {
|
|
|
|
getPaymentGateway,
|
|
|
|
paymentGatewaySuggestions,
|
|
|
|
installedPaymentGateways,
|
|
|
|
isResolving,
|
2022-04-13 07:13:15 +00:00
|
|
|
countryCode,
|
2021-09-21 19:33:44 +00:00
|
|
|
} = useSelect( ( select ) => {
|
2022-04-13 07:13:15 +00:00
|
|
|
const { getSettings } = select( SETTINGS_STORE_NAME );
|
|
|
|
const { general: settings = {} } = getSettings( 'general' );
|
2021-09-21 19:33:44 +00:00
|
|
|
return {
|
|
|
|
getPaymentGateway: select( PAYMENT_GATEWAYS_STORE_NAME )
|
|
|
|
.getPaymentGateway,
|
|
|
|
getOption: select( OPTIONS_STORE_NAME ).getOption,
|
|
|
|
installedPaymentGateways: select(
|
|
|
|
PAYMENT_GATEWAYS_STORE_NAME
|
|
|
|
).getPaymentGateways(),
|
|
|
|
isResolving: select( ONBOARDING_STORE_NAME ).isResolving(
|
|
|
|
'getPaymentGatewaySuggestions'
|
|
|
|
),
|
|
|
|
paymentGatewaySuggestions: select(
|
|
|
|
ONBOARDING_STORE_NAME
|
|
|
|
).getPaymentGatewaySuggestions(),
|
2022-04-13 07:13:15 +00:00
|
|
|
countryCode: getCountryCode( settings.woocommerce_default_country ),
|
2021-09-21 19:33:44 +00:00
|
|
|
};
|
|
|
|
}, [] );
|
|
|
|
|
|
|
|
const getEnrichedPaymentGateways = () => {
|
|
|
|
const mappedPaymentGateways = installedPaymentGateways.reduce(
|
|
|
|
( map, gateway ) => {
|
|
|
|
map[ gateway.id ] = gateway;
|
|
|
|
return map;
|
|
|
|
},
|
|
|
|
{}
|
|
|
|
);
|
|
|
|
|
|
|
|
return paymentGatewaySuggestions.reduce( ( map, suggestion ) => {
|
2021-12-03 13:27:45 +00:00
|
|
|
// A colon ':' is used sometimes to have multiple configs for the same gateway ex: woocommerce_payments:us.
|
2022-01-24 16:23:12 +00:00
|
|
|
const id = getPluginSlug( suggestion.id );
|
2021-12-03 13:27:45 +00:00
|
|
|
const installedGateway = mappedPaymentGateways[ id ]
|
2021-09-21 19:33:44 +00:00
|
|
|
? mappedPaymentGateways[ id ]
|
|
|
|
: {};
|
|
|
|
|
|
|
|
const enrichedSuggestion = {
|
|
|
|
installed: !! mappedPaymentGateways[ id ],
|
|
|
|
postInstallScripts: installedGateway.post_install_scripts,
|
2022-03-02 01:45:44 +00:00
|
|
|
hasPlugins: !! (
|
|
|
|
suggestion.plugins && suggestion.plugins.length
|
|
|
|
),
|
2021-09-21 19:33:44 +00:00
|
|
|
enabled: installedGateway.enabled || false,
|
|
|
|
needsSetup: installedGateway.needs_setup,
|
|
|
|
settingsUrl: installedGateway.settings_url,
|
|
|
|
connectionUrl: installedGateway.connection_url,
|
|
|
|
setupHelpText: installedGateway.setup_help_text,
|
|
|
|
title: installedGateway.title,
|
|
|
|
requiredSettings: installedGateway.required_settings_keys
|
|
|
|
? installedGateway.required_settings_keys
|
|
|
|
.map(
|
|
|
|
( settingKey ) =>
|
|
|
|
installedGateway.settings[ settingKey ]
|
|
|
|
)
|
|
|
|
.filter( Boolean )
|
|
|
|
: [],
|
|
|
|
...suggestion,
|
|
|
|
};
|
|
|
|
|
2021-12-03 13:27:45 +00:00
|
|
|
map.set( suggestion.id, enrichedSuggestion );
|
2021-09-21 19:33:44 +00:00
|
|
|
return map;
|
|
|
|
}, new Map() );
|
|
|
|
};
|
|
|
|
|
|
|
|
const paymentGateways = useMemo( getEnrichedPaymentGateways, [
|
|
|
|
installedPaymentGateways,
|
|
|
|
paymentGatewaySuggestions,
|
|
|
|
] );
|
|
|
|
|
|
|
|
useEffect( () => {
|
|
|
|
if ( paymentGateways.size ) {
|
|
|
|
recordEvent( 'tasklist_payments_options', {
|
|
|
|
options: Array.from( paymentGateways.values() ).map(
|
|
|
|
( gateway ) => gateway.id
|
|
|
|
),
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
}, [ paymentGateways ] );
|
|
|
|
|
|
|
|
const enablePaymentGateway = ( id ) => {
|
|
|
|
if ( ! id ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gateway = getPaymentGateway( id );
|
|
|
|
|
2021-12-03 20:13:05 +00:00
|
|
|
if ( ! gateway ) {
|
2021-09-21 19:33:44 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
updatePaymentGateway( id, {
|
|
|
|
enabled: true,
|
|
|
|
} ).then( () => {
|
2022-03-02 01:45:44 +00:00
|
|
|
onComplete(
|
|
|
|
// use the paymentGateways variable.
|
|
|
|
// gateway variable doesn't have hasPlugins property.
|
|
|
|
! paymentGateways.get( id )?.hasPlugins
|
|
|
|
? {
|
|
|
|
redirectPath: getNewPath(
|
|
|
|
{ task: 'payments' },
|
|
|
|
{},
|
|
|
|
'/'
|
|
|
|
),
|
|
|
|
}
|
|
|
|
: {}
|
|
|
|
);
|
2021-09-21 19:33:44 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
const markConfigured = useCallback(
|
2021-10-01 19:53:22 +00:00
|
|
|
async ( id ) => {
|
2021-09-21 19:33:44 +00:00
|
|
|
if ( ! paymentGateways.get( id ) ) {
|
|
|
|
throw `Payment gateway ${ id } not found in available gateways list`;
|
|
|
|
}
|
|
|
|
|
|
|
|
recordEvent( 'tasklist_payment_connect_method', {
|
|
|
|
payment_method: id,
|
|
|
|
} );
|
|
|
|
|
2021-10-01 19:53:22 +00:00
|
|
|
enablePaymentGateway( id );
|
2021-09-21 19:33:44 +00:00
|
|
|
},
|
|
|
|
[ paymentGateways ]
|
|
|
|
);
|
|
|
|
|
|
|
|
const recommendation = useMemo(
|
|
|
|
() =>
|
|
|
|
Array.from( paymentGateways.values() )
|
|
|
|
.filter( ( gateway ) => gateway.recommendation_priority )
|
2022-02-09 06:12:20 +00:00
|
|
|
.sort( comparePaymentGatewaysByPriority )
|
2021-09-21 19:33:44 +00:00
|
|
|
.map( ( gateway ) => gateway.id )
|
|
|
|
.shift(),
|
|
|
|
[ paymentGateways ]
|
|
|
|
);
|
|
|
|
|
|
|
|
const currentGateway = useMemo( () => {
|
|
|
|
if ( ! query.id || isResolving || ! paymentGateways.size ) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gateway = paymentGateways.get( query.id );
|
|
|
|
|
|
|
|
if ( ! gateway ) {
|
|
|
|
throw `Current gateway ${ query.id } not found in available gateways list`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gateway;
|
|
|
|
}, [ isResolving, query, paymentGateways ] );
|
|
|
|
|
2022-04-13 07:13:15 +00:00
|
|
|
const isWCPayOrOtherCategory = useMemo( () => {
|
|
|
|
for ( const [ , gateway ] of paymentGateways.entries() ) {
|
|
|
|
if ( ! gateway.installed || gateway.needsSetup ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
gateway.plugins?.length === 1 &&
|
|
|
|
gateway.plugins[ 0 ] === 'woocommerce-payments'
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
gateway.category_other &&
|
|
|
|
gateway.category_other.indexOf( countryCode ) !== -1
|
|
|
|
) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}, [ countryCode, paymentGateways ] );
|
|
|
|
|
|
|
|
const isEligibleWCPay =
|
|
|
|
Array.from( paymentGateways.values() ).findIndex( ( gateway ) => {
|
|
|
|
return (
|
|
|
|
gateway.plugins?.length === 1 &&
|
|
|
|
gateway.plugins[ 0 ] === 'woocommerce-payments'
|
|
|
|
);
|
|
|
|
} ) !== -1;
|
|
|
|
|
2022-04-12 02:09:07 +00:00
|
|
|
const [ wcPayGateway, offlineGateways, additionalGateways ] = useMemo(
|
2021-09-21 19:33:44 +00:00
|
|
|
() =>
|
2022-02-09 06:12:20 +00:00
|
|
|
Array.from( paymentGateways.values() )
|
|
|
|
.sort( ( a, b ) => {
|
|
|
|
if ( a.hasPlugins === b.hasPlugins ) {
|
|
|
|
return comparePaymentGatewaysByPriority( a, b );
|
2021-09-21 19:33:44 +00:00
|
|
|
}
|
|
|
|
|
2022-02-09 06:12:20 +00:00
|
|
|
// hasPlugins payment first
|
|
|
|
if ( a.hasPlugins ) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
} )
|
|
|
|
.reduce(
|
|
|
|
( all, gateway ) => {
|
2022-04-12 02:09:07 +00:00
|
|
|
const [ wcPay, offline, additional ] = all;
|
2022-02-09 06:12:20 +00:00
|
|
|
|
|
|
|
// WCPay is handled separately when not installed and configured
|
|
|
|
if (
|
|
|
|
gateway.plugins?.length === 1 &&
|
|
|
|
gateway.plugins[ 0 ] === 'woocommerce-payments' &&
|
|
|
|
! ( gateway.installed && ! gateway.needsSetup )
|
|
|
|
) {
|
|
|
|
wcPay.push( gateway );
|
2022-03-31 04:23:26 +00:00
|
|
|
} else if ( gateway.is_offline ) {
|
|
|
|
offline.push( gateway );
|
2022-04-13 07:13:15 +00:00
|
|
|
} else if ( gateway.enabled ) {
|
|
|
|
// Enabled gateways should be ignored.
|
|
|
|
} else if (
|
|
|
|
isEligibleWCPay &&
|
|
|
|
isWCPayOrOtherCategory
|
|
|
|
) {
|
|
|
|
// If WCPay or "other" gateway is enabled in an WCPay-eligible country, only
|
|
|
|
// allow to list "additional" gateways or the ones without it defined.
|
|
|
|
if (
|
|
|
|
gateway.category_additional &&
|
|
|
|
gateway.category_additional.indexOf(
|
|
|
|
countryCode
|
|
|
|
) !== -1
|
|
|
|
) {
|
|
|
|
additional.push( gateway );
|
|
|
|
}
|
2022-02-09 06:12:20 +00:00
|
|
|
} else {
|
|
|
|
additional.push( gateway );
|
|
|
|
}
|
|
|
|
|
|
|
|
return all;
|
|
|
|
},
|
2022-04-12 02:09:07 +00:00
|
|
|
[ [], [], [] ]
|
2022-02-09 06:12:20 +00:00
|
|
|
),
|
2022-04-13 07:13:15 +00:00
|
|
|
[
|
|
|
|
countryCode,
|
|
|
|
isEligibleWCPay,
|
|
|
|
isWCPayOrOtherCategory,
|
|
|
|
paymentGateways,
|
|
|
|
]
|
2021-09-21 19:33:44 +00:00
|
|
|
);
|
|
|
|
|
2022-04-11 07:57:26 +00:00
|
|
|
const trackSeeMore = () => {
|
|
|
|
recordEvent( 'tasklist_payment_see_more', {} );
|
|
|
|
};
|
|
|
|
|
|
|
|
const trackToggle = ( isShow ) => {
|
|
|
|
recordEvent( 'tasklist_payment_show_toggle', {
|
|
|
|
toggle: isShow ? 'hide' : 'show',
|
|
|
|
payment_method_count:
|
|
|
|
offlineGateways.length + additionalGateways.length,
|
|
|
|
} );
|
|
|
|
};
|
2022-04-04 10:12:20 +00:00
|
|
|
|
2021-09-21 19:33:44 +00:00
|
|
|
if ( query.id && ! currentGateway ) {
|
|
|
|
return <SetupPlaceholder />;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( currentGateway ) {
|
|
|
|
return (
|
|
|
|
<Setup
|
|
|
|
paymentGateway={ currentGateway }
|
|
|
|
markConfigured={ markConfigured }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-04-04 10:12:20 +00:00
|
|
|
const additionalSection = !! additionalGateways.length && (
|
|
|
|
<List
|
|
|
|
heading={
|
2022-04-13 07:13:15 +00:00
|
|
|
! wcPayGateway.length &&
|
|
|
|
__( 'Choose a payment provider', 'woocommerce' )
|
2022-04-04 10:12:20 +00:00
|
|
|
}
|
|
|
|
recommendation={ recommendation }
|
|
|
|
paymentGateways={ additionalGateways }
|
|
|
|
markConfigured={ markConfigured }
|
|
|
|
footerLink={
|
2022-04-13 07:13:15 +00:00
|
|
|
! isWCPayOrOtherCategory && (
|
|
|
|
<Button
|
|
|
|
href={ SEE_MORE_LINK }
|
|
|
|
target="_blank"
|
|
|
|
onClick={ trackSeeMore }
|
|
|
|
isTertiary
|
|
|
|
>
|
|
|
|
{ __( 'See more', 'woocommerce' ) }
|
|
|
|
<ExternalIcon size={ 18 } />
|
|
|
|
</Button>
|
|
|
|
)
|
2022-04-04 10:12:20 +00:00
|
|
|
}
|
|
|
|
></List>
|
|
|
|
);
|
2021-09-21 19:33:44 +00:00
|
|
|
|
2022-04-04 10:12:20 +00:00
|
|
|
const offlineSection = !! offlineGateways.length && (
|
|
|
|
<List
|
|
|
|
heading={ __( 'Offline payment methods', 'woocommerce' ) }
|
|
|
|
recommendation={ recommendation }
|
|
|
|
paymentGateways={ offlineGateways }
|
|
|
|
markConfigured={ markConfigured }
|
|
|
|
/>
|
|
|
|
);
|
2021-09-21 19:33:44 +00:00
|
|
|
|
2022-04-04 10:12:20 +00:00
|
|
|
return (
|
|
|
|
<div className="woocommerce-task-payments">
|
|
|
|
{ ! paymentGateways.size && <ListPlaceholder /> }
|
2022-03-31 04:23:26 +00:00
|
|
|
|
2022-04-13 07:13:15 +00:00
|
|
|
{ wcPayGateway.length ? (
|
2022-04-04 10:12:20 +00:00
|
|
|
<>
|
|
|
|
<WCPaySuggestion paymentGateway={ wcPayGateway[ 0 ] } />
|
|
|
|
<Toggle
|
|
|
|
heading={ __( 'Other payment methods', 'woocommerce' ) }
|
2022-04-04 10:38:07 +00:00
|
|
|
onToggle={ trackToggle }
|
2022-04-04 10:12:20 +00:00
|
|
|
>
|
|
|
|
{ additionalSection }
|
|
|
|
{ offlineSection }
|
|
|
|
</Toggle>
|
|
|
|
</>
|
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
{ additionalSection }
|
|
|
|
{ offlineSection }
|
|
|
|
</>
|
2022-03-31 04:23:26 +00:00
|
|
|
) }
|
2021-09-21 19:33:44 +00:00
|
|
|
</div>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
registerPlugin( 'wc-admin-onboarding-task-payments', {
|
|
|
|
scope: 'woocommerce-tasks',
|
|
|
|
render: () => (
|
|
|
|
<WooOnboardingTask id="payments">
|
2021-10-01 19:53:22 +00:00
|
|
|
{ ( { onComplete, query } ) => (
|
|
|
|
<PaymentGatewaySuggestions
|
|
|
|
onComplete={ onComplete }
|
|
|
|
query={ query }
|
|
|
|
/>
|
|
|
|
) }
|
2021-09-21 19:33:44 +00:00
|
|
|
</WooOnboardingTask>
|
|
|
|
),
|
|
|
|
} );
|