mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-31 06:52:50 +08:00
Merge pull request #3097 from woocommerce/PCP-4183-manual-connection-credentials-are-not-working
Manual Connection credentials are not working (4183)
This commit is contained in:
commit
8258c1c993
8 changed files with 87 additions and 46 deletions
|
@ -18,6 +18,7 @@ const DataStoreControl = React.forwardRef(
|
|||
control: ControlComponent,
|
||||
value: externalValue,
|
||||
onChange,
|
||||
onConfirm = null,
|
||||
delay = 300,
|
||||
...props
|
||||
},
|
||||
|
@ -25,7 +26,9 @@ const DataStoreControl = React.forwardRef(
|
|||
) => {
|
||||
const [ internalValue, setInternalValue ] = useState( externalValue );
|
||||
const onChangeRef = useRef( onChange );
|
||||
const onConfirmRef = useRef( onConfirm );
|
||||
onChangeRef.current = onChange;
|
||||
onConfirmRef.current = onConfirm;
|
||||
|
||||
const debouncedUpdate = useRef(
|
||||
debounce( ( value ) => {
|
||||
|
@ -36,7 +39,7 @@ const DataStoreControl = React.forwardRef(
|
|||
useEffect( () => {
|
||||
setInternalValue( externalValue );
|
||||
debouncedUpdate?.cancel();
|
||||
}, [ externalValue ] );
|
||||
}, [ debouncedUpdate, externalValue ] );
|
||||
|
||||
useEffect( () => {
|
||||
return () => debouncedUpdate?.cancel();
|
||||
|
@ -50,12 +53,25 @@ const DataStoreControl = React.forwardRef(
|
|||
[ debouncedUpdate ]
|
||||
);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
( event ) => {
|
||||
if ( onConfirmRef.current && event.key === 'Enter' ) {
|
||||
event.preventDefault();
|
||||
debouncedUpdate.flush();
|
||||
onConfirmRef.current();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
[ debouncedUpdate ]
|
||||
);
|
||||
|
||||
return (
|
||||
<ControlComponent
|
||||
ref={ ref }
|
||||
{ ...props }
|
||||
value={ internalValue }
|
||||
onChange={ handleChange }
|
||||
onKeyDown={ handleKeyDown }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -157,6 +157,7 @@ const ManualConnectionForm = () => {
|
|||
label={ clientIdLabel }
|
||||
value={ manualClientId }
|
||||
onChange={ setManualClientId }
|
||||
onConfirm={ handleManualConnect }
|
||||
className={ classNames( {
|
||||
'ppcp--has-error': ! clientValid,
|
||||
} ) }
|
||||
|
@ -173,6 +174,7 @@ const ManualConnectionForm = () => {
|
|||
label={ secretKeyLabel }
|
||||
value={ manualClientSecret }
|
||||
onChange={ setManualClientSecret }
|
||||
onConfirm={ handleManualConnect }
|
||||
type="password"
|
||||
/>
|
||||
<Button
|
||||
|
|
|
@ -12,6 +12,7 @@ export default {
|
|||
SET_PERSISTENT: 'ppcp/common/SET_PERSISTENT',
|
||||
RESET: 'ppcp/common/RESET',
|
||||
HYDRATE: 'ppcp/common/HYDRATE',
|
||||
SET_MERCHANT: 'ppcp/common/SET_MERCHANT',
|
||||
RESET_MERCHANT: 'ppcp/common/RESET_MERCHANT',
|
||||
|
||||
// Activity management (advanced solution that replaces the isBusy state).
|
||||
|
|
|
@ -110,6 +110,17 @@ export const setManualConnectionMode = ( useManualConnection ) =>
|
|||
export const setWebhooks = ( webhooks ) =>
|
||||
setPersistent( 'webhooks', webhooks );
|
||||
|
||||
/**
|
||||
* Replace merchant details in the store.
|
||||
*
|
||||
* @param {Object} merchant - The new merchant details.
|
||||
* @return {Action} The action.
|
||||
*/
|
||||
export const setMerchant = ( merchant ) => ( {
|
||||
type: ACTION_TYPES.SET_MERCHANT,
|
||||
payload: { merchant },
|
||||
} );
|
||||
|
||||
/**
|
||||
* Reset merchant details in the store.
|
||||
*
|
||||
|
|
|
@ -141,18 +141,27 @@ export const useWebhooks = () => {
|
|||
export const useMerchantInfo = () => {
|
||||
const { isReady, features } = useHooks();
|
||||
const merchant = useMerchant();
|
||||
const { refreshMerchantData } = useDispatch( STORE_NAME );
|
||||
const { refreshMerchantData, setMerchant } = useDispatch( STORE_NAME );
|
||||
|
||||
const verifyLoginStatus = useCallback( async () => {
|
||||
const result = await refreshMerchantData();
|
||||
|
||||
if ( ! result.success ) {
|
||||
if ( ! result.success || ! result.merchant ) {
|
||||
throw new Error( result?.message || result?.error?.message );
|
||||
}
|
||||
|
||||
const newMerchant = result.merchant;
|
||||
|
||||
// Verify if the server state is "connected" and we have a merchant ID.
|
||||
return merchant?.isConnected && merchant?.id;
|
||||
}, [ refreshMerchantData, merchant ] );
|
||||
if ( newMerchant?.isConnected && newMerchant?.id ) {
|
||||
// Update the verified merchant details in Redux.
|
||||
setMerchant( newMerchant );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}, [ refreshMerchantData, setMerchant ] );
|
||||
|
||||
return {
|
||||
isReady,
|
||||
|
@ -225,6 +234,8 @@ export const useBusyState = () => {
|
|||
);
|
||||
|
||||
return {
|
||||
startActivity,
|
||||
stopActivity,
|
||||
withActivity, // HOC
|
||||
isBusy, // Boolean.
|
||||
};
|
||||
|
|
|
@ -114,6 +114,10 @@ const commonReducer = createReducer( defaultTransient, defaultPersistent, {
|
|||
features: Object.freeze( { ...defaultTransient.features } ),
|
||||
} ),
|
||||
|
||||
[ ACTION_TYPES.SET_MERCHANT ]: ( state, payload ) => {
|
||||
return changePersistent( state, { merchant: payload.merchant } );
|
||||
},
|
||||
|
||||
[ ACTION_TYPES.HYDRATE ]: ( state, payload ) => {
|
||||
const newState = changePersistent( state, payload.data );
|
||||
|
||||
|
|
|
@ -10,19 +10,7 @@ const PAYPAL_PARTNER_SDK_URL =
|
|||
|
||||
const MESSAGES = {
|
||||
CONNECTED: __( 'Connected to PayPal', 'woocommerce-paypal-payments' ),
|
||||
POPUP_BLOCKED: __(
|
||||
'Popup blocked. Please allow popups for this site to connect to PayPal.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
SANDBOX_ERROR: __(
|
||||
'Could not generate a Sandbox login link.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
PRODUCTION_ERROR: __(
|
||||
'Could not generate a login link.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
MANUAL_ERROR: __(
|
||||
API_ERROR: __(
|
||||
'Could not connect to PayPal. Please make sure your Client ID and Secret Key are correct.',
|
||||
'woocommerce-paypal-payments'
|
||||
),
|
||||
|
@ -33,17 +21,16 @@ const MESSAGES = {
|
|||
};
|
||||
|
||||
const ACTIVITIES = {
|
||||
CONNECT_SANDBOX: 'ISU_LOGIN_SANDBOX',
|
||||
CONNECT_PRODUCTION: 'ISU_LOGIN_PRODUCTION',
|
||||
CONNECT_ISU: 'ISU_LOGIN',
|
||||
CONNECT_MANUAL: 'MANUAL_LOGIN',
|
||||
OAUTH_VERIFY: 'oauth/login',
|
||||
API_LOGIN: 'auth/api-login',
|
||||
API_VERIFY: 'auth/verify-login',
|
||||
};
|
||||
|
||||
export const useHandleOnboardingButton = ( isSandbox ) => {
|
||||
const { sandboxOnboardingUrl } = CommonHooks.useSandbox();
|
||||
const { productionOnboardingUrl } = CommonHooks.useProduction();
|
||||
const products = OnboardingHooks.useDetermineProducts();
|
||||
const { withActivity } = CommonHooks.useBusyState();
|
||||
const { withActivity, startActivity } = CommonHooks.useBusyState();
|
||||
const { authenticateWithOAuth } = CommonHooks.useAuthentication();
|
||||
const [ onboardingUrl, setOnboardingUrl ] = useState( '' );
|
||||
const [ scriptLoaded, setScriptLoaded ] = useState( false );
|
||||
|
@ -123,16 +110,15 @@ export const useHandleOnboardingButton = ( isSandbox ) => {
|
|||
* frame before the REST endpoint returns a value. Using "withActivity" is more of a
|
||||
* visual cue to the user that something is still processing in the background.
|
||||
*/
|
||||
await withActivity(
|
||||
ACTIVITIES.CONNECT_ISU,
|
||||
'Validating the connection details',
|
||||
async () => {
|
||||
await authenticateWithOAuth(
|
||||
sharedId,
|
||||
authCode,
|
||||
'sandbox' === environment
|
||||
);
|
||||
}
|
||||
startActivity(
|
||||
ACTIVITIES.OAUTH_VERIFY,
|
||||
'Validating the connection details'
|
||||
);
|
||||
|
||||
await authenticateWithOAuth(
|
||||
sharedId,
|
||||
authCode,
|
||||
'sandbox' === environment
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -168,11 +154,13 @@ export const useHandleOnboardingButton = ( isSandbox ) => {
|
|||
};
|
||||
};
|
||||
|
||||
// Base connection is only used for API login (manual connection).
|
||||
const useConnectionBase = () => {
|
||||
const { setCompleted } = OnboardingHooks.useSteps();
|
||||
const { createSuccessNotice, createErrorNotice } =
|
||||
useDispatch( noticesStore );
|
||||
const { verifyLoginStatus } = CommonHooks.useMerchantInfo();
|
||||
const { withActivity } = CommonHooks.useBusyState();
|
||||
|
||||
return {
|
||||
handleFailed: ( res, genericMessage ) => {
|
||||
|
@ -180,18 +168,26 @@ const useConnectionBase = () => {
|
|||
createErrorNotice( res?.message ?? genericMessage );
|
||||
},
|
||||
handleCompleted: async () => {
|
||||
try {
|
||||
const loginSuccessful = await verifyLoginStatus();
|
||||
await withActivity(
|
||||
ACTIVITIES.API_VERIFY,
|
||||
'Verifying Authentication',
|
||||
async () => {
|
||||
try {
|
||||
const loginSuccessful = await verifyLoginStatus();
|
||||
|
||||
if ( loginSuccessful ) {
|
||||
createSuccessNotice( MESSAGES.CONNECTED );
|
||||
await setCompleted( true );
|
||||
} else {
|
||||
createErrorNotice( MESSAGES.LOGIN_FAILED );
|
||||
if ( loginSuccessful ) {
|
||||
createSuccessNotice( MESSAGES.CONNECTED );
|
||||
await setCompleted( true );
|
||||
} else {
|
||||
createErrorNotice( MESSAGES.LOGIN_FAILED );
|
||||
}
|
||||
} catch ( error ) {
|
||||
createErrorNotice(
|
||||
error.message ?? MESSAGES.LOGIN_FAILED
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch ( error ) {
|
||||
createErrorNotice( error.message ?? MESSAGES.LOGIN_FAILED );
|
||||
}
|
||||
);
|
||||
},
|
||||
createErrorNotice,
|
||||
};
|
||||
|
@ -218,7 +214,7 @@ export const useDirectAuthentication = () => {
|
|||
|
||||
const handleDirectAuthentication = async ( connectionDetails ) => {
|
||||
return withActivity(
|
||||
ACTIVITIES.CONNECT_MANUAL,
|
||||
ACTIVITIES.API_LOGIN,
|
||||
'Connecting manually via Client ID and Secret',
|
||||
async () => {
|
||||
let data;
|
||||
|
@ -250,7 +246,7 @@ export const useDirectAuthentication = () => {
|
|||
if ( res.success ) {
|
||||
await handleCompleted();
|
||||
} else {
|
||||
handleFailed( res, MESSAGES.MANUAL_ERROR );
|
||||
handleFailed( res, MESSAGES.API_ERROR );
|
||||
}
|
||||
|
||||
return res.success;
|
||||
|
|
|
@ -175,7 +175,7 @@ class AuthenticationRestEndpoint extends RestEndpoint {
|
|||
}
|
||||
|
||||
$account = $this->authentication_manager->get_account_details();
|
||||
$response = $this->sanitize_for_javascript( $this->response_map, $account );
|
||||
$response = $this->sanitize_for_javascript( $account, $this->response_map );
|
||||
|
||||
return $this->return_success( $response );
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue