Try add payment method selector to onboarding store (https://github.com/woocommerce/woocommerce-admin/pull/6921)
* Added payment method to onboarding data store * Add reducer test * Address feedback on reducer naming convention, isResolving, enabledMethods * Move out types to live in its own island * Add a comment to remind ourselves for utilizing payments data store for enabled payment gateways * Update changelog
This commit is contained in:
parent
f515ed5b6e
commit
de9cfb210d
|
@ -2,12 +2,11 @@
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import apiFetch from '@wordpress/api-fetch';
|
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
import { getHistory, getNewPath } from '@woocommerce/navigation';
|
import { getHistory, getNewPath } from '@woocommerce/navigation';
|
||||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
import { OPTIONS_STORE_NAME, ONBOARDING_STORE_NAME } from '@woocommerce/data';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
import { useEffect, useMemo, useState } from '@wordpress/element';
|
import { useMemo, useState } from '@wordpress/element';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
@ -19,27 +18,22 @@ import { sift } from '../../../../utils';
|
||||||
|
|
||||||
export const RemotePayments = ( { query } ) => {
|
export const RemotePayments = ( { query } ) => {
|
||||||
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
|
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
|
||||||
const { getOption } = useSelect( ( select ) => {
|
const {
|
||||||
|
getOption,
|
||||||
|
getPaymentMethodRecommendations,
|
||||||
|
isResolving,
|
||||||
|
} = useSelect( ( select ) => {
|
||||||
return {
|
return {
|
||||||
getOption: select( OPTIONS_STORE_NAME ).getOption,
|
getOption: select( OPTIONS_STORE_NAME ).getOption,
|
||||||
|
getPaymentMethodRecommendations: select( ONBOARDING_STORE_NAME )
|
||||||
|
.getPaymentMethodRecommendations,
|
||||||
|
isResolving: select( ONBOARDING_STORE_NAME ).isResolving(
|
||||||
|
'getPaymentMethodRecommendations'
|
||||||
|
),
|
||||||
};
|
};
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const [ methods, setMethods ] = useState( [] );
|
const methods = getPaymentMethodRecommendations();
|
||||||
const [ isFetching, setIsFetching ] = useState( true );
|
|
||||||
|
|
||||||
useEffect( () => {
|
|
||||||
apiFetch( {
|
|
||||||
path: '/wc-admin/onboarding/payments',
|
|
||||||
} )
|
|
||||||
.then( ( results ) => {
|
|
||||||
setMethods( results );
|
|
||||||
setIsFetching( false );
|
|
||||||
} )
|
|
||||||
.catch( () => {
|
|
||||||
setIsFetching( false );
|
|
||||||
} );
|
|
||||||
}, [] );
|
|
||||||
|
|
||||||
const recommendedMethod = useMemo( () => {
|
const recommendedMethod = useMemo( () => {
|
||||||
const method = methods.find(
|
const method = methods.find(
|
||||||
|
@ -73,6 +67,29 @@ export const RemotePayments = ( { query } ) => {
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getInitiallyEnabledMethods = () =>
|
||||||
|
methods.reduce( ( acc, method ) => {
|
||||||
|
acc[ method.key ] = method.isEnabled;
|
||||||
|
return acc;
|
||||||
|
}, {} );
|
||||||
|
|
||||||
|
// TODO: Ideally when payments data store is merged https://github.com/woocommerce/woocommerce-admin/pull/6918
|
||||||
|
// we can utilize it for keeping track of enabled payment methods and optimistically update that
|
||||||
|
// store when enabling methods.
|
||||||
|
const [ enabledMethods, setEnabledMethods ] = useState(
|
||||||
|
getInitiallyEnabledMethods()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Keeps enabledMethods up to date with methods fetched from API.
|
||||||
|
useMemo(
|
||||||
|
() =>
|
||||||
|
setEnabledMethods( {
|
||||||
|
...getInitiallyEnabledMethods(),
|
||||||
|
...enabledMethods,
|
||||||
|
} ),
|
||||||
|
[ methods ]
|
||||||
|
);
|
||||||
|
|
||||||
const markConfigured = async ( methodKey, queryParams = {} ) => {
|
const markConfigured = async ( methodKey, queryParams = {} ) => {
|
||||||
const method = methods.find( ( option ) => option.key === methodKey );
|
const method = methods.find( ( option ) => option.key === methodKey );
|
||||||
|
|
||||||
|
@ -103,7 +120,7 @@ export const RemotePayments = ( { query } ) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentMethod = useMemo( () => {
|
const currentMethod = useMemo( () => {
|
||||||
if ( ! query.method || isFetching ) {
|
if ( ! query.method || isResolving ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,14 +131,7 @@ export const RemotePayments = ( { query } ) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return method;
|
return method;
|
||||||
}, [ isFetching, query ] );
|
}, [ isResolving, query, methods ] );
|
||||||
|
|
||||||
const [ enabledMethods, setEnabledMethods ] = useState(
|
|
||||||
methods.reduce( ( acc, method ) => {
|
|
||||||
acc[ method.key ] = method.isEnabled;
|
|
||||||
return acc;
|
|
||||||
}, {} )
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( currentMethod ) {
|
if ( currentMethod ) {
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,6 +3,7 @@ const TYPES = {
|
||||||
SET_IS_REQUESTING: 'SET_IS_REQUESTING',
|
SET_IS_REQUESTING: 'SET_IS_REQUESTING',
|
||||||
SET_PROFILE_ITEMS: 'SET_PROFILE_ITEMS',
|
SET_PROFILE_ITEMS: 'SET_PROFILE_ITEMS',
|
||||||
SET_TASKS_STATUS: 'SET_TASKS_STATUS',
|
SET_TASKS_STATUS: 'SET_TASKS_STATUS',
|
||||||
|
GET_PAYMENT_METHODS_SUCCESS: 'GET_PAYMENT_METHODS_SUCCESS',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TYPES;
|
export default TYPES;
|
||||||
|
|
|
@ -40,6 +40,13 @@ export function setTasksStatus( tasksStatus ) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setPaymentMethods( paymentMethods ) {
|
||||||
|
return {
|
||||||
|
type: TYPES.GET_PAYMENT_METHODS_SUCCESS,
|
||||||
|
paymentMethods,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function* updateProfileItems( items ) {
|
export function* updateProfileItems( items ) {
|
||||||
yield setIsRequesting( 'updateProfileItems', true );
|
yield setIsRequesting( 'updateProfileItems', true );
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,23 @@ export const defaultState = {
|
||||||
theme: null,
|
theme: null,
|
||||||
wccom_connected: null,
|
wccom_connected: null,
|
||||||
},
|
},
|
||||||
|
paymentMethods: [],
|
||||||
requesting: {},
|
requesting: {},
|
||||||
tasksStatus: {},
|
tasksStatus: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const onboarding = (
|
const onboarding = (
|
||||||
state = defaultState,
|
state = defaultState,
|
||||||
{ type, profileItems, replace, error, isRequesting, selector, tasksStatus }
|
{
|
||||||
|
type,
|
||||||
|
profileItems,
|
||||||
|
paymentMethods,
|
||||||
|
replace,
|
||||||
|
error,
|
||||||
|
isRequesting,
|
||||||
|
selector,
|
||||||
|
tasksStatus,
|
||||||
|
}
|
||||||
) => {
|
) => {
|
||||||
switch ( type ) {
|
switch ( type ) {
|
||||||
case TYPES.SET_PROFILE_ITEMS:
|
case TYPES.SET_PROFILE_ITEMS:
|
||||||
|
@ -57,6 +67,11 @@ const onboarding = (
|
||||||
[ selector ]: isRequesting,
|
[ selector ]: isRequesting,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
case TYPES.GET_PAYMENT_METHODS_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
paymentMethods,
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,12 @@ import { apiFetch } from '@wordpress/data-controls';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { WC_ADMIN_NAMESPACE } from '../constants';
|
import { WC_ADMIN_NAMESPACE } from '../constants';
|
||||||
import { setProfileItems, setError, setTasksStatus } from './actions';
|
import {
|
||||||
|
setProfileItems,
|
||||||
|
setError,
|
||||||
|
setTasksStatus,
|
||||||
|
setPaymentMethods,
|
||||||
|
} from './actions';
|
||||||
|
|
||||||
export function* getProfileItems() {
|
export function* getProfileItems() {
|
||||||
try {
|
try {
|
||||||
|
@ -34,3 +39,16 @@ export function* getTasksStatus() {
|
||||||
yield setError( 'getTasksStatus', error );
|
yield setError( 'getTasksStatus', error );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* getPaymentMethodRecommendations() {
|
||||||
|
try {
|
||||||
|
const results = yield apiFetch( {
|
||||||
|
path: WC_ADMIN_NAMESPACE + '/onboarding/payments',
|
||||||
|
method: 'GET',
|
||||||
|
} );
|
||||||
|
|
||||||
|
yield setPaymentMethods( results );
|
||||||
|
} catch ( error ) {
|
||||||
|
yield setError( 'getPaymentMethodRecommendations', error );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { WPDataSelectors } from '../types';
|
import { WPDataSelectors, RuleProcessor } from '../types';
|
||||||
|
|
||||||
export const getProfileItems = (
|
export const getProfileItems = (
|
||||||
state: OnboardingState
|
state: OnboardingState
|
||||||
|
@ -15,6 +15,12 @@ export const getTasksStatus = (
|
||||||
return state.tasksStatus || {};
|
return state.tasksStatus || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getPaymentMethodRecommendations = (
|
||||||
|
state: OnboardingState
|
||||||
|
): PaymentMethodsState[] => {
|
||||||
|
return state.paymentMethods || [];
|
||||||
|
};
|
||||||
|
|
||||||
export const getOnboardingError = (
|
export const getOnboardingError = (
|
||||||
state: OnboardingState,
|
state: OnboardingState,
|
||||||
selector: string
|
selector: string
|
||||||
|
@ -33,6 +39,9 @@ export const isOnboardingRequesting = (
|
||||||
export type OnboardingSelectors = {
|
export type OnboardingSelectors = {
|
||||||
getProfileItems: () => ReturnType< typeof getProfileItems >;
|
getProfileItems: () => ReturnType< typeof getProfileItems >;
|
||||||
getTasksStatus: () => ReturnType< typeof getTasksStatus >;
|
getTasksStatus: () => ReturnType< typeof getTasksStatus >;
|
||||||
|
getPaymentMethodRecommendations: () => ReturnType<
|
||||||
|
typeof getPaymentMethodRecommendations
|
||||||
|
>;
|
||||||
getOnboardingError: () => ReturnType< typeof getOnboardingError >;
|
getOnboardingError: () => ReturnType< typeof getOnboardingError >;
|
||||||
isOnboardingRequesting: () => ReturnType< typeof isOnboardingRequesting >;
|
isOnboardingRequesting: () => ReturnType< typeof isOnboardingRequesting >;
|
||||||
} & WPDataSelectors;
|
} & WPDataSelectors;
|
||||||
|
@ -40,6 +49,7 @@ export type OnboardingSelectors = {
|
||||||
export type OnboardingState = {
|
export type OnboardingState = {
|
||||||
profileItems: ProfileItemsState;
|
profileItems: ProfileItemsState;
|
||||||
tasksStatus: TasksStatusState;
|
tasksStatus: TasksStatusState;
|
||||||
|
paymentMethods: PaymentMethodsState[];
|
||||||
// TODO clarify what the error record's type is
|
// TODO clarify what the error record's type is
|
||||||
errors: Record< string, unknown >;
|
errors: Record< string, unknown >;
|
||||||
requesting: Record< string, boolean >;
|
requesting: Record< string, boolean >;
|
||||||
|
@ -112,3 +122,31 @@ export type ProfileItemsState = {
|
||||||
theme: string | null;
|
theme: string | null;
|
||||||
wccom_connected: boolean | null;
|
wccom_connected: boolean | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FieldLocale = {
|
||||||
|
locale: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MethodFields = {
|
||||||
|
name: string;
|
||||||
|
option?: string;
|
||||||
|
label?: string;
|
||||||
|
locales?: FieldLocale[];
|
||||||
|
type?: string;
|
||||||
|
value?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PaymentMethodsState = {
|
||||||
|
locale: string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
key: string;
|
||||||
|
image: string;
|
||||||
|
is_visible: boolean | RuleProcessor[];
|
||||||
|
plugins: string[];
|
||||||
|
is_configured: boolean | RuleProcessor[];
|
||||||
|
fields: MethodFields[];
|
||||||
|
api_details_url: string;
|
||||||
|
manage_url: string;
|
||||||
|
};
|
||||||
|
|
|
@ -47,6 +47,24 @@ describe( 'plugins reducer', () => {
|
||||||
expect( state.profileItems.propertyName ).toBe( 'value' );
|
expect( state.profileItems.propertyName ).toBe( 'value' );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
it( 'should handle GET_PAYMENT_METHODS_SUCCESS', () => {
|
||||||
|
const state = reducer(
|
||||||
|
{
|
||||||
|
paymentMethods: [ { previousItem: 'value' } ],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: TYPES.GET_PAYMENT_METHODS_SUCCESS,
|
||||||
|
paymentMethods: [ { newItem: 'changed' } ],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
expect( state.paymentMethods[ 0 ] ).not.toHaveProperty(
|
||||||
|
'previousItem'
|
||||||
|
);
|
||||||
|
expect( state.paymentMethods[ 0 ] ).toHaveProperty( 'newItem' );
|
||||||
|
expect( state.paymentMethods[ 0 ].newItem ).toBe( 'changed' );
|
||||||
|
} );
|
||||||
|
|
||||||
it( 'should handle SET_ERROR', () => {
|
it( 'should handle SET_ERROR', () => {
|
||||||
const state = reducer( defaultState, {
|
const state = reducer( defaultState, {
|
||||||
type: TYPES.SET_ERROR,
|
type: TYPES.SET_ERROR,
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './wp-data';
|
||||||
|
export * from './rule-processor';
|
|
@ -0,0 +1,45 @@
|
||||||
|
export type RuleProcessor = {
|
||||||
|
type: RuleType;
|
||||||
|
value?: string | number | boolean;
|
||||||
|
default?: string | number | boolean;
|
||||||
|
index?: string;
|
||||||
|
operation?: RuleOperation;
|
||||||
|
status?: string;
|
||||||
|
operand?: RuleProcessor;
|
||||||
|
operands?: RuleProcessor[] | RuleProcessor[][];
|
||||||
|
option_name?: string;
|
||||||
|
plugin?: string;
|
||||||
|
plugins?: string[];
|
||||||
|
publish_after?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RuleType =
|
||||||
|
| 'plugins_activated'
|
||||||
|
| 'publish_after_time'
|
||||||
|
| 'publish_before_time'
|
||||||
|
| 'not'
|
||||||
|
| 'or'
|
||||||
|
| 'fail'
|
||||||
|
| 'pass'
|
||||||
|
| 'plugin_version'
|
||||||
|
| 'stored_state'
|
||||||
|
| 'order_count'
|
||||||
|
| 'wcadmin_active_for'
|
||||||
|
| 'product_count'
|
||||||
|
| 'onboarding_profile'
|
||||||
|
| 'is_ecommerce'
|
||||||
|
| 'base_location_country'
|
||||||
|
| 'base_location_state'
|
||||||
|
| 'note_status'
|
||||||
|
| 'option'
|
||||||
|
| 'wca_updated';
|
||||||
|
|
||||||
|
export type RuleOperation =
|
||||||
|
| '='
|
||||||
|
| '<'
|
||||||
|
| '<='
|
||||||
|
| '>'
|
||||||
|
| '>='
|
||||||
|
| '!='
|
||||||
|
| 'contains'
|
||||||
|
| '!contains';
|
|
@ -90,6 +90,8 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt
|
||||||
- Dev: Fixed storybook build script #6875
|
- Dev: Fixed storybook build script #6875
|
||||||
- Dev: Removed allowed keys list for adding woocommerce_meta data. #6889 🎉 @xristos3490
|
- Dev: Removed allowed keys list for adding woocommerce_meta data. #6889 🎉 @xristos3490
|
||||||
- Dev: Delete all products when running product import tests, unskip previously skipped test. #6905
|
- Dev: Delete all products when running product import tests, unskip previously skipped test. #6905
|
||||||
|
- Dev: Add payment method selector to onboarding store #6921
|
||||||
|
- Dev: Add disabled prop to SelectControl #6902
|
||||||
- Dev: Do a git clean before the core release. #6945
|
- Dev: Do a git clean before the core release. #6945
|
||||||
- Enhancement: Add recommended payment methods in payment settings. #6760
|
- Enhancement: Add recommended payment methods in payment settings. #6760
|
||||||
- Enhancement: Add expand/collapse to extendable task list. #6910
|
- Enhancement: Add expand/collapse to extendable task list. #6910
|
||||||
|
@ -133,7 +135,6 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt
|
||||||
- Update: UI updates to Payment Task screen #6766
|
- Update: UI updates to Payment Task screen #6766
|
||||||
- Update: Adding setup required icon for non-configured payment methods #6811
|
- Update: Adding setup required icon for non-configured payment methods #6811
|
||||||
- Update: Task list component with new Experimental Task list. #6849
|
- Update: Task list component with new Experimental Task list. #6849
|
||||||
- Dev: Add disabled prop to SelectControl #6902
|
|
||||||
- Update: Redirect to WC Home after setting up a payment method #6891
|
- Update: Redirect to WC Home after setting up a payment method #6891
|
||||||
- Dev: Fix a bug where trying to load an asset registry causes a crash. #6951
|
- Dev: Fix a bug where trying to load an asset registry causes a crash. #6951
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue