Migrate @woocommerce/data settings store to TS (#34184)

* Migrate wc.data.settings to TS

* Correct data.settings type

* Fix wc admin client type errors

* Add changelog

* Add changelog

* Update types

* Update RawSetting type
This commit is contained in:
Chi-Hsuan Huang 2022-08-08 13:25:46 +08:00 committed by GitHub
parent 3bbee139ed
commit af97aaf410
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 310 additions and 201 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Migrate setting store to TS

View File

@ -4,6 +4,6 @@ const TYPES = {
CLEAR_SETTINGS: 'CLEAR_SETTINGS',
SET_IS_REQUESTING: 'SET_IS_REQUESTING',
CLEAR_IS_DIRTY: 'CLEAR_IS_DIRTY',
};
} as const;
export default TYPES;

View File

@ -6,6 +6,7 @@ import { __ } from '@wordpress/i18n';
import { apiFetch, select } from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
import { concat } from 'lodash';
import { DispatchFromMap } from '@automattic/data-stores';
/**
* Internal dependencies
@ -13,12 +14,17 @@ import { concat } from 'lodash';
import { NAMESPACE } from '../constants';
import { STORE_NAME } from './constants';
import TYPES from './action-types';
import { Settings } from './types';
// Can be removed in WP 5.9, wp.data is supported in >5.7.
const resolveSelect =
controls && controls.resolveSelect ? controls.resolveSelect : select;
export function updateSettingsForGroup( group, data, time = new Date() ) {
export function updateSettingsForGroup(
group: string,
data: Settings,
time = new Date()
) {
return {
type: TYPES.UPDATE_SETTINGS_FOR_GROUP,
group,
@ -27,7 +33,12 @@ export function updateSettingsForGroup( group, data, time = new Date() ) {
};
}
export function updateErrorForGroup( group, data, error, time = new Date() ) {
export function updateErrorForGroup(
group: string,
data: Settings | null,
error: unknown,
time = new Date()
) {
return {
type: TYPES.UPDATE_ERROR_FOR_GROUP,
group,
@ -37,7 +48,7 @@ export function updateErrorForGroup( group, data, error, time = new Date() ) {
};
}
export function setIsRequesting( group, isRequesting ) {
export function setIsRequesting( group: string, isRequesting: boolean ) {
return {
type: TYPES.SET_IS_REQUESTING,
group,
@ -45,25 +56,23 @@ export function setIsRequesting( group, isRequesting ) {
};
}
export function clearIsDirty( group ) {
export function clearIsDirty( group: string ) {
return {
type: TYPES.CLEAR_IS_DIRTY,
group,
};
}
// allows updating and persisting immediately in one action.
export function* updateAndPersistSettingsForGroup( group, data ) {
yield updateSettingsForGroup( group, data );
yield* persistSettingsForGroup( group );
}
// this would replace setSettingsForGroup
export function* persistSettingsForGroup( group ) {
export function* persistSettingsForGroup( group: string ) {
// first dispatch the is persisting action
yield setIsRequesting( group, true );
// get all dirty keys with select control
const dirtyKeys = yield resolveSelect( STORE_NAME, 'getDirtyKeys', group );
const dirtyKeys: string[] = yield resolveSelect(
STORE_NAME,
'getDirtyKeys',
group
);
// if there is nothing dirty, bail
if ( dirtyKeys.length === 0 ) {
yield setIsRequesting( group, false );
@ -71,22 +80,27 @@ export function* persistSettingsForGroup( group ) {
}
// get data slice for keys
const dirtyData = yield resolveSelect(
const dirtyData: {
[ key: string ]: Record< string, unknown >;
} = yield resolveSelect(
STORE_NAME,
'getSettingsForGroup',
group,
dirtyKeys
);
const url = `${ NAMESPACE }/settings/${ group }/batch`;
const update = dirtyKeys.reduce( ( updates, key ) => {
const update = dirtyKeys.reduce< Array< { id: string; value: unknown } > >(
( updates, key ) => {
const u = Object.keys( dirtyData[ key ] ).map( ( k ) => {
return { id: k, value: dirtyData[ key ][ k ] };
} );
return concat( updates, u );
}, [] );
},
[]
);
try {
const results = yield apiFetch( {
const results: unknown = yield apiFetch( {
path: url,
method: 'POST',
data: { update },
@ -112,8 +126,30 @@ export function* persistSettingsForGroup( group ) {
}
}
// allows updating and persisting immediately in one action.
export function* updateAndPersistSettingsForGroup(
group: string,
data: Settings
) {
yield updateSettingsForGroup( group, data );
yield* persistSettingsForGroup( group );
}
export function clearSettings() {
return {
type: TYPES.CLEAR_SETTINGS,
};
}
export type Actions = ReturnType<
| typeof updateSettingsForGroup
| typeof updateErrorForGroup
| typeof setIsRequesting
| typeof clearIsDirty
| typeof clearSettings
>;
export type ActionDispatchers = DispatchFromMap< {
createProduct: typeof persistSettingsForGroup;
updateProduct: typeof updateAndPersistSettingsForGroup;
} >;

View File

@ -1 +1 @@
export const STORE_NAME = 'wc/admin/settings';
export const STORE_NAME = 'wc/admin/settings' as const;

View File

@ -1,25 +0,0 @@
/**
* External dependencies
*/
import { registerStore } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
/**
* Internal dependencies
*/
import { STORE_NAME } from './constants';
import * as selectors from './selectors';
import * as actions from './actions';
import * as resolvers from './resolvers';
import reducer from './reducer';
registerStore( STORE_NAME, {
reducer,
actions,
controls,
selectors,
resolvers,
} );
export const SETTINGS_STORE_NAME = STORE_NAME;

View File

@ -0,0 +1,40 @@
/**
* External dependencies
*/
import { registerStore } from '@wordpress/data';
import { controls } from '@wordpress/data-controls';
import { Reducer } from 'redux';
import { SelectFromMap, DispatchFromMap } from '@automattic/data-stores';
/**
* Internal dependencies
*/
import { WPDataSelectors } from '../types';
import { STORE_NAME } from './constants';
import * as selectors from './selectors';
import * as actions from './actions';
import * as resolvers from './resolvers';
import reducer, { State } from './reducer';
import { SettingsState } from './types';
export * from './types';
export type { State };
registerStore< State >( STORE_NAME, {
reducer: reducer as Reducer< SettingsState >,
actions,
controls,
selectors,
resolvers,
} );
export const SETTINGS_STORE_NAME = STORE_NAME;
declare module '@wordpress/data' {
function dispatch(
key: typeof STORE_NAME
): DispatchFromMap< typeof actions >;
function select(
key: typeof STORE_NAME
): SelectFromMap< typeof selectors > & WPDataSelectors;
}

View File

@ -2,16 +2,31 @@
* External dependencies
*/
import { union } from 'lodash';
import { Reducer } from 'redux';
/**
* Internal dependencies
*/
import TYPES from './action-types';
import { getResourceName } from '../utils';
import { Actions } from './actions';
import { Settings, SettingsState } from './types';
const updateGroupDataInNewState = (
newState,
{ group, groupIds, data, time, error }
newState: SettingsState,
{
group,
groupIds,
data,
time,
error,
}: {
group: string;
groupIds: string[];
data: Settings;
time: Date;
error: unknown;
}
) => {
groupIds.forEach( ( id ) => {
newState[ getResourceName( group, id ) ] = {
@ -23,33 +38,35 @@ const updateGroupDataInNewState = (
return newState;
};
const receiveSettings = (
state = {},
{ type, group, data, error, time, isRequesting }
) => {
const reducer: Reducer< SettingsState, Actions > = ( state = {}, action ) => {
const newState = {};
switch ( type ) {
switch ( action.type ) {
case TYPES.SET_IS_REQUESTING:
state = {
...state,
[ group ]: {
...state[ group ],
isRequesting,
[ action.group ]: {
...state[ action.group ],
isRequesting: action.isRequesting,
},
};
break;
case TYPES.CLEAR_IS_DIRTY:
state = {
...state,
[ group ]: {
...state[ group ],
[ action.group ]: {
...state[ action.group ],
dirty: [],
},
};
break;
case TYPES.UPDATE_SETTINGS_FOR_GROUP:
case TYPES.UPDATE_ERROR_FOR_GROUP:
const { data, group, time } = action;
const groupIds = data ? Object.keys( data ) : [];
const error =
action.type === TYPES.UPDATE_ERROR_FOR_GROUP
? action.error
: null;
if ( data === null ) {
state = {
...state,
@ -60,12 +77,15 @@ const receiveSettings = (
},
};
} else {
const stateGroup = state[ group ];
state = {
...state,
[ group ]: {
data:
state[ group ] && state[ group ].data
? [ ...state[ group ].data, ...groupIds ]
stateGroup &&
stateGroup.data &&
Array.isArray( stateGroup.data )
? [ ...stateGroup.data, ...groupIds ]
: groupIds,
error,
lastReceived: time,
@ -91,4 +111,5 @@ const receiveSettings = (
return state;
};
export default receiveSettings;
export type State = ReturnType< typeof reducer >;
export default reducer;

View File

@ -1,48 +0,0 @@
/**
* External dependencies
*/
import {
apiFetch,
dispatch as depreciatedDispatch,
} from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
/**
* Internal dependencies
*/
import { NAMESPACE } from '../constants';
import { STORE_NAME } from './constants';
import { updateSettingsForGroup, updateErrorForGroup } from './actions';
// Can be removed in WP 5.9.
const dispatch =
controls && controls.dispatch ? controls.dispatch : depreciatedDispatch;
function settingsToSettingsResource( settings ) {
return settings.reduce( ( resource, setting ) => {
resource[ setting.id ] = setting.value;
return resource;
}, {} );
}
export function* getSettings( group ) {
yield dispatch( STORE_NAME, 'setIsRequesting', group, true );
try {
const url = NAMESPACE + '/settings/' + group;
const results = yield apiFetch( {
path: url,
method: 'GET',
} );
const resource = settingsToSettingsResource( results );
return updateSettingsForGroup( group, { [ group ]: resource } );
} catch ( error ) {
return updateErrorForGroup( group, null, error.message );
}
}
export function* getSettingsForGroup( group ) {
return getSettings( group );
}

View File

@ -0,0 +1,78 @@
/**
* External dependencies
*/
import {
apiFetch,
dispatch as depreciatedDispatch,
} from '@wordpress/data-controls';
import { controls } from '@wordpress/data';
/**
* Internal dependencies
*/
import { NAMESPACE } from '../constants';
import { STORE_NAME } from './constants';
import { updateSettingsForGroup, updateErrorForGroup } from './actions';
import { isRestApiError } from '../types';
// Can be removed in WP 5.9.
const dispatch =
controls && controls.dispatch ? controls.dispatch : depreciatedDispatch;
// [class-wc-rest-setting-options-controller.php](https://github.com/woocommerce/woocommerce/blob/28926968bdcd2b504e16761a483388f85ee0c151/plugins/woocommerce/includes/rest-api/Controllers/Version3/class-wc-rest-setting-options-controller.php#L158-L248)
type RawSetting = {
id: string;
group_id: string;
label: string;
description: string;
tip?: string;
type:
| 'text'
| 'email'
| 'number'
| 'color'
| 'password'
| 'textarea'
| 'select'
| 'multiselect'
| 'radio'
| 'image_width'
| 'checkbox';
default: unknown;
value: unknown;
options: {
[ key: string ]: string;
};
placeholder?: string;
};
function settingsToSettingsResource( settings: RawSetting[] ) {
return settings.reduce< {
[ id: string ]: unknown;
} >( ( resource, setting ) => {
resource[ setting.id ] = setting.value;
return resource;
}, {} );
}
export function* getSettings( group: string ) {
yield dispatch( STORE_NAME, 'setIsRequesting', group, true );
try {
const url = NAMESPACE + '/settings/' + group;
const results: RawSetting[] = yield apiFetch( {
path: url,
method: 'GET',
} );
const resource = settingsToSettingsResource( results );
return updateSettingsForGroup( group, { [ group ]: resource } );
} catch ( error ) {
if ( error instanceof Error || isRestApiError( error ) ) {
return updateErrorForGroup( group, null, error.message );
}
throw `Unexpected error ${ error }`;
}
}
export function* getSettingsForGroup( group: string ) {
return getSettings( group );
}

View File

@ -2,8 +2,9 @@
* Internal dependencies
*/
import { getResourceName, getResourcePrefix } from '../utils';
import { SettingsState, Settings } from './types';
export const getSettingsGroupNames = ( state ) => {
export const getSettingsGroupNames = ( state: SettingsState ) => {
const groupNames = new Set(
Object.keys( state ).map( ( resourceName ) => {
return getResourcePrefix( resourceName );
@ -12,10 +13,10 @@ export const getSettingsGroupNames = ( state ) => {
return [ ...groupNames ];
};
export const getSettings = ( state, group ) => {
const settings = {};
export const getSettings = ( state: SettingsState, group: string ) => {
const settings: Settings = {};
const settingIds = ( state[ group ] && state[ group ].data ) || [];
if ( settingIds.length === 0 ) {
if ( ! Array.isArray( settingIds ) || settingIds.length === 0 ) {
return settings;
}
settingIds.forEach( ( id ) => {
@ -24,11 +25,15 @@ export const getSettings = ( state, group ) => {
return settings;
};
export const getDirtyKeys = ( state, group ) => {
export const getDirtyKeys = ( state: SettingsState, group: string ) => {
return state[ group ].dirty || [];
};
export const getIsDirty = ( state, group, keys = [] ) => {
export const getIsDirty = (
state: SettingsState,
group: string,
keys: string[] = []
) => {
const dirtyMap = getDirtyKeys( state, group );
// if empty array bail
if ( dirtyMap.length === 0 ) {
@ -39,15 +44,22 @@ export const getIsDirty = ( state, group, keys = [] ) => {
return keys.some( ( key ) => dirtyMap.includes( key ) );
};
export const getSettingsForGroup = ( state, group, keys ) => {
export const getSettingsForGroup = (
state: SettingsState,
group: string,
keys: string[]
) => {
const allSettings = getSettings( state, group );
return keys.reduce( ( accumulator, key ) => {
return keys.reduce< Settings >( ( accumulator, key ) => {
accumulator[ key ] = allSettings[ key ] || {};
return accumulator;
}, {} );
};
export const isUpdateSettingsRequesting = ( state, group ) => {
export const isUpdateSettingsRequesting = (
state: SettingsState,
group: string
) => {
return state[ group ] && Boolean( state[ group ].isRequesting );
};
@ -70,11 +82,12 @@ export const isUpdateSettingsRequesting = ( state, group ) => {
* name.
*/
export function getSetting(
state,
group,
name,
state: SettingsState,
group: string,
name: string,
fallback = false,
filter = ( val ) => val
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- _fallback in default filter is unused.
filter = ( val: unknown, _fallback: unknown | boolean ) => val
) {
const resourceName = getResourceName( group, name );
const value =
@ -82,15 +95,22 @@ export function getSetting(
return filter( value, fallback );
}
export const getLastSettingsErrorForGroup = ( state, group ) => {
export const getLastSettingsErrorForGroup = (
state: SettingsState,
group: string
) => {
const settingsIds = state[ group ].data;
if ( settingsIds.length === 0 ) {
if ( ! Array.isArray( settingsIds ) || settingsIds.length === 0 ) {
return state[ group ].error;
}
return [ ...settingsIds ].pop().error;
};
export const getSettingsError = ( state, group, id ) => {
export const getSettingsError = (
state: SettingsState,
group: string,
id: string
) => {
if ( ! id ) {
return ( state[ group ] && state[ group ].error ) || false;
}

View File

@ -0,0 +1,20 @@
export type Settings = {
[ key: string ]: unknown;
} & {
general?: {
[ key: string ]: string;
};
tax?: {
[ key: string ]: string;
};
};
export type SettingsState = {
[ key: string ]: {
data?: unknown;
lastReceived?: Date;
error?: unknown;
isRequesting?: boolean;
dirty?: string[];
};
};

View File

@ -9,7 +9,7 @@ import { useCallback } from '@wordpress/element';
*/
import { STORE_NAME } from './constants';
export const useSettings = ( group, settingsKeys = [] ) => {
export const useSettings = ( group: string, settingsKeys: string[] = [] ) => {
const { requestedSettings, settingsError, isRequesting, isDirty } =
useSelect(
( select ) => {

View File

@ -2,20 +2,22 @@
* External dependencies
*/
import { createHigherOrderComponent } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { useSelect, select as wpSelect } from '@wordpress/data';
import { createElement, useRef } from '@wordpress/element';
/**
* Internal dependencies
*/
import { STORE_NAME } from './constants';
import { Settings } from './types';
export const withSettingsHydration = ( group, settings ) =>
createHigherOrderComponent(
export const withSettingsHydration = ( group: string, settings: Settings ) =>
createHigherOrderComponent< Record< string, unknown > >(
( OriginalComponent ) => ( props ) => {
const settingsRef = useRef( settings );
useSelect( ( select, registry ) => {
// @ts-expect-error registry is not defined in the wp.data typings
useSelect( ( select: typeof wpSelect, registry ) => {
if ( ! settingsRef.current ) {
return;
}

View File

@ -12,7 +12,7 @@ import { fetchWithHeaders } from './controls';
export function getResourceName(
prefix: string,
identifier: Record< string, unknown >
identifier: Record< string, unknown > | string
) {
const identifierString = JSON.stringify(
identifier,

View File

@ -25,11 +25,7 @@ const ShippingRecommendations: React.FC = () => {
isJetpackConnected,
isSellingDigitalProductsOnly,
} = useSelect( ( select ) => {
const settings = select( SETTINGS_STORE_NAME ).getSettings< {
general?: {
woocommerce_default_country: string;
};
} >( 'general' );
const settings = select( SETTINGS_STORE_NAME ).getSettings( 'general' );
const {
getActivePlugins,

View File

@ -64,9 +64,7 @@ export const Products = () => {
const { isStoreInUS } = useSelect( ( select ) => {
const { getSettings } = select( SETTINGS_STORE_NAME );
const { general: settings = {} } = getSettings< {
general?: { [ key: string ]: unknown };
} >( 'general' );
const { general: settings = {} } = getSettings( 'general' );
const country =
typeof settings.woocommerce_default_country === 'string'

View File

@ -10,7 +10,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
* Internal dependencies
*/
import { getCountryCode } from '~/dashboard/utils';
import { hasCompleteAddress, SettingsSelector } from '../../tax/utils';
import { hasCompleteAddress } from '../../tax/utils';
import { default as StoreLocationForm } from '~/tasks/fills/steps/location';
export const StoreLocation: React.FC< {
@ -21,9 +21,8 @@ export const StoreLocation: React.FC< {
const { updateAndPersistSettingsForGroup } =
useDispatch( SETTINGS_STORE_NAME );
const { generalSettings, isResolving } = useSelect( ( select ) => {
const { getSettings, hasFinishedResolution } = select(
SETTINGS_STORE_NAME
) as SettingsSelector;
const { getSettings, hasFinishedResolution } =
select( SETTINGS_STORE_NAME );
return {
generalSettings: getSettings( 'general' )?.general,
@ -34,7 +33,7 @@ export const StoreLocation: React.FC< {
} );
useEffect( () => {
if ( isResolving || ! hasCompleteAddress( generalSettings ) ) {
if ( isResolving || ! hasCompleteAddress( generalSettings || {} ) ) {
return;
}
onLocationComplete();

View File

@ -14,15 +14,12 @@ import { compose } from '@wordpress/compose';
/**
* Internal dependencies
*/
import { SettingsSelector } from '../tax/utils';
import { ShippingRecommendation } from './shipping-recommendation';
import { TaskProps } from './types';
const ShippingRecommendationWrapper = compose(
withSelect( ( select ) => {
const { getSettings } = select(
SETTINGS_STORE_NAME
) as SettingsSelector;
const { getSettings } = select( SETTINGS_STORE_NAME );
const { hasFinishedResolution } = select( OPTIONS_STORE_NAME );
const { getActivePlugins } = select( PLUGINS_STORE_NAME );

View File

@ -11,7 +11,7 @@ import { useSelect, useDispatch } from '@wordpress/data';
* Internal dependencies
*/
import { getCountryCode } from '~/dashboard/utils';
import { hasCompleteAddress, SettingsSelector } from '../utils';
import { hasCompleteAddress } from '../utils';
import { default as StoreLocationForm } from '~/tasks/fills/steps/location';
export const StoreLocation: React.FC< {
@ -21,9 +21,8 @@ export const StoreLocation: React.FC< {
const { updateAndPersistSettingsForGroup } =
useDispatch( SETTINGS_STORE_NAME );
const { generalSettings, isResolving } = useSelect( ( select ) => {
const { getSettings, hasFinishedResolution } = select(
SETTINGS_STORE_NAME
) as SettingsSelector;
const { getSettings, hasFinishedResolution } =
select( SETTINGS_STORE_NAME );
return {
generalSettings: getSettings( 'general' )?.general,
@ -34,7 +33,7 @@ export const StoreLocation: React.FC< {
} );
useEffect( () => {
if ( isResolving || ! hasCompleteAddress( generalSettings ) ) {
if ( isResolving || ! hasCompleteAddress( generalSettings || {} ) ) {
return;
}
nextStep();

View File

@ -24,11 +24,7 @@ import { WooOnboardingTask } from '@woocommerce/onboarding';
/**
* Internal dependencies
*/
import {
redirectToTaxSettings,
SettingsSelector,
supportsAvalara,
} from './utils';
import { redirectToTaxSettings, supportsAvalara } from './utils';
import { Card as AvalaraCard } from './avalara/card';
import { Card as WooCommerceTaxCard } from './woocommerce-tax/card';
import { createNoticesFromResponse } from '../../../lib/notices';
@ -59,10 +55,8 @@ const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => {
useDispatch( SETTINGS_STORE_NAME );
const { generalSettings, isResolving, taxSettings } = useSelect(
( select ) => {
const { getSettings, hasFinishedResolution } = select(
SETTINGS_STORE_NAME
) as SettingsSelector;
const { getSettings, hasFinishedResolution } =
select( SETTINGS_STORE_NAME );
return {
generalSettings: getSettings( 'general' ).general,
isResolving: ! hasFinishedResolution( 'getSettings', [
@ -75,7 +69,7 @@ const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => {
const onManual = useCallback( async () => {
setIsPending( true );
if ( generalSettings.woocommerce_calc_taxes !== 'yes' ) {
if ( generalSettings?.woocommerce_calc_taxes !== 'yes' ) {
updateAndPersistSettingsForGroup( 'tax', {
tax: {
...taxSettings,
@ -88,7 +82,6 @@ const Tax: React.FC< TaxProps > = ( { onComplete, query, task } ) => {
woocommerce_calc_taxes: 'yes',
},
} )
// @ts-expect-error updateAndPersistSettingsForGroup returns a Promise, but it is not typed in source.
.then( () => redirectToTaxSettings() )
.catch( ( error: unknown ) => {
setIsPending( false );

View File

@ -12,15 +12,13 @@ import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { SettingsSelector, TaxChildProps } from '../utils';
import { TaxChildProps } from '../utils';
export const Configure: React.FC<
Pick< TaxChildProps, 'isPending' | 'onManual' >
> = ( { isPending, onManual } ) => {
const { generalSettings } = useSelect( ( select ) => {
const { getSettings } = select(
SETTINGS_STORE_NAME
) as SettingsSelector;
const { getSettings } = select( SETTINGS_STORE_NAME );
return {
generalSettings: getSettings( 'general' )?.general,
@ -41,7 +39,7 @@ export const Configure: React.FC<
{ __( 'Configure', 'woocommerce' ) }
</Button>
<p>
{ generalSettings.woocommerce_calc_taxes !== 'yes' &&
{ generalSettings?.woocommerce_calc_taxes !== 'yes' &&
interpolateComponents( {
mixedString: __(
/*eslint-disable max-len*/

View File

@ -2,7 +2,7 @@
* External dependencies
*/
import { getAdminLink } from '@woocommerce/settings';
import { WPDataSelectors, TaskType } from '@woocommerce/data';
import { TaskType } from '@woocommerce/data';
/**
* Plugins required to automate taxes.
@ -17,11 +17,9 @@ export const AUTOMATION_PLUGINS = [ 'jetpack', 'woocommerce-services' ];
* @param {Object} generalSettings.woocommerce_default_country Store default country.
* @param {Object} generalSettings.woocommerce_store_postcode Store postal code.
*/
export const hasCompleteAddress = ( generalSettings: {
woocommerce_store_address?: string;
woocommerce_default_country?: string;
woocommerce_store_postcode?: string;
} ): boolean => {
export const hasCompleteAddress = (
generalSettings: Record< string, string >
): boolean => {
const {
woocommerce_store_address: storeAddress,
woocommerce_default_country: defaultCountry,
@ -39,22 +37,6 @@ export const redirectToTaxSettings = (): void => {
);
};
/**
* Types for settings selectors.
*/
export type SettingsSelector = WPDataSelectors & {
getSettings: ( type: string ) => {
general: {
woocommerce_default_country?: string;
woocommerce_calc_taxes?: string;
};
tax: { [ key: string ]: string };
};
getOption: ( type: string ) => {
tos_accepted?: boolean;
};
};
/**
* Types for child tax components.
*/

View File

@ -13,7 +13,6 @@ import { PLUGINS_STORE_NAME, SETTINGS_STORE_NAME } from '@woocommerce/data';
import {
AUTOMATION_PLUGINS,
hasCompleteAddress,
SettingsSelector,
TaxChildProps,
} from '../utils';
import { AutomatedTaxes } from './automated-taxes';
@ -31,9 +30,7 @@ export const WooCommerceTax: React.FC< TaxChildProps > = ( {
isResolving,
pluginsToActivate,
} = useSelect( ( select ) => {
const { getSettings } = select(
SETTINGS_STORE_NAME
) as SettingsSelector;
const { getSettings } = select( SETTINGS_STORE_NAME );
const { getActivePlugins, hasFinishedResolution } =
select( PLUGINS_STORE_NAME );
const activePlugins = getActivePlugins();
@ -55,7 +52,7 @@ export const WooCommerceTax: React.FC< TaxChildProps > = ( {
const canAutomateTaxes = () => {
return (
hasCompleteAddress( generalSettings ) &&
hasCompleteAddress( generalSettings || {} ) &&
! pluginsToActivate.length &&
isJetpackConnected
);

View File

@ -15,7 +15,7 @@ import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { AUTOMATION_PLUGINS, SettingsSelector } from '../utils';
import { AUTOMATION_PLUGINS } from '../utils';
import { Connect } from './connect';
import { Plugins } from './plugins';
import { StoreLocation } from '../components/store-location';
@ -48,9 +48,7 @@ export const Setup: React.FC< SetupProps > = ( {
[]
);
const { activePlugins, isResolving } = useSelect( ( select ) => {
const { getSettings } = select(
SETTINGS_STORE_NAME
) as SettingsSelector;
const { getSettings } = select( SETTINGS_STORE_NAME );
const { hasFinishedResolution } = select( OPTIONS_STORE_NAME );
const { getActivePlugins } = select( PLUGINS_STORE_NAME );

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Fix typescript errors for setting selector