2021-02-05 23:41:26 +00:00
/* global ppcp_onboarding */
2019-10-03 16:03:29 +00:00
/ * *
* External dependencies
* /
import { _ _ } from '@wordpress/i18n' ;
import apiFetch from '@wordpress/api-fetch' ;
2021-02-05 23:41:26 +00:00
import { Button } from '@wordpress/components' ;
import { Component , Fragment , useEffect } from '@wordpress/element' ;
2019-10-03 16:03:29 +00:00
import { compose } from '@wordpress/compose' ;
import interpolateComponents from 'interpolate-components' ;
2020-06-10 23:49:27 +00:00
import { withDispatch , withSelect } from '@wordpress/data' ;
2020-07-15 12:10:21 +00:00
import { isEmail } from '@wordpress/url' ;
2021-02-05 23:41:26 +00:00
import { Form , Link , TextControl , Stepper } from '@woocommerce/components' ;
2019-12-02 17:39:22 +00:00
import { getQuery } from '@woocommerce/navigation' ;
2021-02-05 23:41:26 +00:00
import { PLUGINS _STORE _NAME , OPTIONS _STORE _NAME } from '@woocommerce/data' ;
2020-08-13 02:05:22 +00:00
2021-02-05 23:41:26 +00:00
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 } ) {
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"
>
{ _ _ ( 'Connect' , 'woocommerce-admin' ) }
< / a >
) ;
}
class PayPal extends Component {
2019-10-03 16:03:29 +00:00
constructor ( props ) {
super ( props ) ;
this . state = {
2020-03-15 21:45:19 +00:00
autoConnectFailed : false ,
2019-10-03 16:03:29 +00:00
connectURL : '' ,
} ;
2021-02-05 23:41:26 +00:00
this . enablePaypalPlugin = this . enablePaypalPlugin . bind ( this ) ;
this . setCredentials = this . setCredentials . bind ( this ) ;
2020-07-15 12:10:21 +00:00
this . validate = this . validate . bind ( this ) ;
2019-10-03 16:03:29 +00:00
}
componentDidMount ( ) {
2021-02-05 23:41:26 +00:00
const { createNotice } = this . props ;
2019-10-03 16:03:29 +00:00
const query = getQuery ( ) ;
// Handle redirect back from PayPal
2021-02-05 23:41:26 +00:00
if ( query . onboarding ) {
if (
query . onboarding === 'complete' &&
! query [ 'ppcp-onboarding-error' ]
) {
this . enablePaypalPlugin ( ) ;
2019-10-03 16:03:29 +00:00
return ;
}
2021-02-05 23:41:26 +00:00
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'
)
) ;
}
2019-10-03 16:03:29 +00:00
return ;
}
2021-02-05 23:41:26 +00:00
this . fetchOAuthConnectURLAndOnboardingSetup ( ) ;
2020-03-16 11:09:29 +00:00
}
componentDidUpdate ( prevProps ) {
const { activePlugins } = this . props ;
if (
2021-02-05 23:41:26 +00:00
! prevProps . activePlugins . includes ( PAYPAL _PLUGIN ) &&
activePlugins . includes ( PAYPAL _PLUGIN )
2020-03-16 11:09:29 +00:00
) {
2021-02-05 23:41:26 +00:00
this . fetchOAuthConnectURLAndOnboardingSetup ( ) ;
2019-10-03 16:03:29 +00:00
}
}
2021-02-05 23:41:26 +00:00
async fetchOAuthConnectURLAndOnboardingSetup ( ) {
const { activePlugins , createNotice } = this . props ;
2020-07-15 12:10:21 +00:00
2021-02-05 23:41:26 +00:00
if ( ! activePlugins . includes ( PAYPAL _PLUGIN ) ) {
2020-03-16 11:09:29 +00:00
return ;
}
2020-03-15 21:45:19 +00:00
this . setState ( { isPending : true } ) ;
2019-10-03 16:03:29 +00:00
try {
const result = await apiFetch ( {
2021-02-05 23:41:26 +00:00
path : WC _PAYPAL _NAMESPACE + '/onboarding/get-params' ,
2019-10-03 16:03:29 +00:00
method : 'POST' ,
2021-02-05 23:41:26 +00:00
data : {
environment : 'production' ,
returnUrlArgs : {
ppcpobw : '1' ,
} ,
} ,
2019-10-03 16:03:29 +00:00
} ) ;
2021-02-05 23:41:26 +00:00
if ( ! result || ! result . signupLink ) {
2019-10-03 16:03:29 +00:00
this . setState ( {
2020-03-15 21:45:19 +00:00
autoConnectFailed : true ,
2020-07-15 12:10:21 +00:00
isPending : false ,
2019-10-03 16:03:29 +00:00
} ) ;
return ;
}
2021-02-05 23:41:26 +00:00
loadOnboardingScript ( result . scriptURL , result . scriptData , ( ) => {
this . setState ( {
connectURL : result . signupLink ,
isPending : false ,
} ) ;
2019-10-03 16:03:29 +00:00
} ) ;
} catch ( error ) {
2021-02-05 23:41:26 +00:00
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'
)
) ;
}
2019-10-03 16:03:29 +00:00
this . setState ( {
2020-03-15 21:45:19 +00:00
autoConnectFailed : true ,
isPending : false ,
2019-10-03 16:03:29 +00:00
} ) ;
}
}
2021-02-05 23:41:26 +00:00
async enablePaypalPlugin ( skipPpcpSettingsUpdate ) {
2020-02-14 02:23:21 +00:00
const {
createNotice ,
updateOptions ,
markConfigured ,
2021-02-05 23:41:26 +00:00
options ,
2020-02-14 02:23:21 +00:00
} = this . props ;
2021-02-05 23:41:26 +00:00
const updatedOptions = {
'woocommerce_ppcp-gateway_settings' : {
enabled : 'yes' ,
} ,
2020-07-15 12:10:21 +00:00
} ;
2021-02-05 23:41:26 +00:00
if ( ! skipPpcpSettingsUpdate ) {
updatedOptions [ 'woocommerce-ppcp-settings' ] = {
... options ,
enabled : true ,
} ;
}
const update = await updateOptions ( updatedOptions ) ;
2020-07-15 12:10:21 +00:00
2021-02-05 23:41:26 +00:00
if ( update . success ) {
createNotice (
'success' ,
_ _ ( 'PayPal connected successfully.' , 'woocommerce-admin' )
) ;
markConfigured ( 'paypal' ) ;
2020-07-15 12:10:21 +00:00
} else {
2021-02-05 23:41:26 +00:00
createNotice (
'error' ,
_ _ (
'There was a problem saving your payment settings.' ,
'woocommerce-admin'
)
) ;
2020-07-15 12:10:21 +00:00
}
2021-02-05 23:41:26 +00:00
}
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 ,
} ;
2020-07-15 12:10:21 +00:00
2020-06-10 23:49:27 +00:00
const update = await updateOptions ( {
2021-02-05 23:41:26 +00:00
'woocommerce-ppcp-settings' : optionValues ,
'woocommerce_ppcp-gateway_settings' : {
enabled : 'yes' ,
} ,
2019-10-03 16:03:29 +00:00
} ) ;
2020-06-10 23:49:27 +00:00
if ( update . success ) {
2020-03-15 21:45:19 +00:00
createNotice (
2019-10-03 16:03:29 +00:00
'success' ,
_ _ ( 'PayPal connected successfully.' , 'woocommerce-admin' )
) ;
2020-03-15 21:45:19 +00:00
markConfigured ( 'paypal' ) ;
2019-10-03 16:03:29 +00:00
} else {
createNotice (
'error' ,
2020-02-14 02:23:21 +00:00
_ _ (
'There was a problem saving your payment settings.' ,
'woocommerce-admin'
)
2019-10-03 16:03:29 +00:00
) ;
}
}
getInitialConfigValues ( ) {
2021-02-05 23:41:26 +00:00
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' ]
: '' ,
} ;
} , { } ) ;
2019-10-03 16:03:29 +00:00
}
validate ( values ) {
const errors = { } ;
2021-02-05 23:41:26 +00:00
if ( ! values . merchant _email ) {
errors . merchant _email = _ _ (
'Please enter your Merchant email' ,
2020-02-14 02:23:21 +00:00
'woocommerce-admin'
) ;
2019-10-03 16:03:29 +00:00
}
2021-02-05 23:41:26 +00:00
if ( ! isEmail ( values . merchant _email ) ) {
errors . merchant _email = _ _ (
'Please enter a valid email address' ,
2020-02-14 02:23:21 +00:00
'woocommerce-admin'
) ;
2019-10-03 16:03:29 +00:00
}
2021-02-05 23:41:26 +00:00
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' ,
2020-07-15 12:10:21 +00:00
'woocommerce-admin'
) ;
}
2019-10-03 16:03:29 +00:00
return errors ;
}
2021-02-05 23:41:26 +00:00
renderManualConfig ( ) {
2020-06-10 23:49:27 +00:00
const { isOptionsUpdating } = this . props ;
2021-02-05 23:41:26 +00:00
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}}. Don’ t 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"
/ >
) ,
} ,
} ) ;
2019-10-03 16:03:29 +00:00
return (
< Form
2021-02-05 23:41:26 +00:00
initialValues = { this . getInitialConfigValues ( ) }
onSubmitCallback = { this . setCredentials }
2019-10-03 16:03:29 +00:00
validate = { this . validate }
>
2021-02-05 23:41:26 +00:00
{ ( { getInputProps , handleSubmit } ) => {
2019-10-03 16:03:29 +00:00
return (
< Fragment >
2021-02-05 23:41:26 +00:00
< TextControl
label = { _ _ (
'Email address' ,
'woocommerce-admin'
2020-02-14 02:23:21 +00:00
) }
2021-02-05 23:41:26 +00:00
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'
2020-02-14 02:23:21 +00:00
) }
2021-02-05 23:41:26 +00:00
required
{ ... getInputProps ( 'client_secret' ) }
/ >
< Button
isPrimary
isBusy = { isOptionsUpdating }
onClick = { handleSubmit }
>
{ _ _ ( 'Proceed' , 'woocommerce-admin' ) }
< / B u t t o n >
< p > { stripeHelp } < / p >
2019-10-03 16:03:29 +00:00
< / F r a g m e n t >
) ;
} }
< / F o r m >
) ;
}
2021-02-05 23:41:26 +00:00
renderConnectFields ( ) {
const { autoConnectFailed , connectURL } = this . state ;
if ( ! autoConnectFailed && connectURL ) {
return (
< >
< PaypalConnectButton connectUrl = { connectURL } / >
< p >
{ _ _ (
'You will be redirected to the PayPal website to create the connection.' ,
'woocommerce-admin'
) }
< / p >
< / >
) ;
}
if ( autoConnectFailed ) {
return this . renderManualConfig ( ) ;
}
}
2020-03-15 21:45:19 +00:00
getConnectStep ( ) {
2021-02-05 23:41:26 +00:00
const { isRequestingOptions } = this . props ;
2020-07-15 12:10:21 +00:00
return {
2020-03-15 21:45:19 +00:00
key : 'connect' ,
label : _ _ ( 'Connect your PayPal account' , 'woocommerce-admin' ) ,
description : _ _ (
2020-11-02 02:22:50 +00:00
'A PayPal account is required to process payments. Connect your store to your PayPal account.' ,
2020-03-15 21:45:19 +00:00
'woocommerce-admin'
) ,
2021-02-05 23:41:26 +00:00
content : isRequestingOptions ? null : this . renderConnectFields ( ) ,
2020-03-15 21:45:19 +00:00
} ;
}
render ( ) {
2021-02-05 23:41:26 +00:00
const {
installStep ,
isRequestingOptions ,
isOptionsUpdating ,
} = this . props ;
2020-03-15 21:45:19 +00:00
const { isPending } = this . state ;
return (
< Stepper
isVertical
2021-02-05 23:41:26 +00:00
isPending = {
! installStep . isComplete ||
isPending ||
isRequestingOptions ||
isOptionsUpdating
}
2020-03-15 21:45:19 +00:00
currentStep = { installStep . isComplete ? 'connect' : 'install' }
steps = { [ installStep , this . getConnectStep ( ) ] }
/ >
) ;
2019-10-03 16:03:29 +00:00
}
}
PayPal . defaultProps = {
manualConfig : false , // WCS is not required for the PayPal OAuth flow, so we can default to smooth connection.
} ;
export default compose (
2020-02-14 02:23:21 +00:00
withSelect ( ( select ) => {
2021-02-05 23:41:26 +00:00
const { getOption , isOptionsUpdating , hasFinishedResolution } = select (
OPTIONS _STORE _NAME
2020-07-15 12:10:21 +00:00
) ;
2021-02-05 23:41:26 +00:00
const { getActivePlugins } = select ( PLUGINS _STORE _NAME ) ;
const paypalOptions = getOption ( 'woocommerce-ppcp-settings' ) ;
const isRequestingOptions = ! hasFinishedResolution ( 'getOption' , [
'woocommerce-ppcp-settings' ,
] ) ;
2020-03-16 11:09:29 +00:00
const activePlugins = getActivePlugins ( ) ;
2019-10-03 16:03:29 +00:00
return {
2020-03-16 11:09:29 +00:00
activePlugins ,
2020-06-10 23:49:27 +00:00
isOptionsUpdating : isOptionsUpdating ( ) ,
2020-07-15 12:10:21 +00:00
options : paypalOptions ,
2021-02-05 23:41:26 +00:00
isRequestingOptions ,
2019-10-03 16:03:29 +00:00
} ;
} ) ,
2020-02-14 02:23:21 +00:00
withDispatch ( ( dispatch ) => {
2019-10-03 16:03:29 +00:00
const { createNotice } = dispatch ( 'core/notices' ) ;
2020-06-10 23:49:27 +00:00
const { updateOptions } = dispatch ( OPTIONS _STORE _NAME ) ;
2019-10-03 16:03:29 +00:00
return {
createNotice ,
updateOptions ,
} ;
} )
) ( PayPal ) ;
2021-02-05 23:41:26 +00:00
export { PayPal , PAYPAL _PLUGIN } ;