diff --git a/src/options/data/action-types.js b/src/options/data/action-types.js index 92b72ab3d58..e0763d223c4 100644 --- a/src/options/data/action-types.js +++ b/src/options/data/action-types.js @@ -1,5 +1,6 @@ const TYPES = { SET_OPTIONS: 'SET_OPTIONS', + SET_IS_LOADING: 'SET_IS_LOADING', DELETE_OPTION_BY_ID: 'DELETE_OPTION_BY_ID', }; diff --git a/src/options/data/actions.js b/src/options/data/actions.js index 2db057d6542..dff16e2205d 100644 --- a/src/options/data/actions.js +++ b/src/options/data/actions.js @@ -21,6 +21,13 @@ export function setOptions( options ) { }; } +export function setLoadingState( isLoading ) { + return { + type: TYPES.SET_IS_LOADING, + isLoading, + }; +} + export function* deleteOptionById( optionId ) { try { yield apiFetch( { diff --git a/src/options/data/reducer.js b/src/options/data/reducer.js index 805cdcc13d0..80a09e2e898 100644 --- a/src/options/data/reducer.js +++ b/src/options/data/reducer.js @@ -5,16 +5,22 @@ import TYPES from './action-types'; const DEFAULT_STATE = { options: [], + isLoading: true, }; const reducer = ( state = DEFAULT_STATE, action ) => { switch ( action.type ) { + case TYPES.SET_IS_LOADING: + return { + ...state, + isLoading: action.isLoading, + }; case TYPES.SET_OPTIONS: return { ...state, options: action.options, + isLoading: false, }; - case TYPES.DELETE_OPTION_BY_ID: return { ...state, diff --git a/src/options/data/resolvers.js b/src/options/data/resolvers.js index 6f9f6aad8ae..5058069e543 100644 --- a/src/options/data/resolvers.js +++ b/src/options/data/resolvers.js @@ -7,7 +7,7 @@ import { apiFetch } from '@wordpress/data-controls'; * Internal dependencies */ import { API_NAMESPACE } from './constants'; -import { setOptions } from './actions'; +import { setLoadingState, setOptions } from './actions'; export function* getOptions( search ) { let path = `${ API_NAMESPACE }/options?`; @@ -15,6 +15,8 @@ export function* getOptions( search ) { path += `search=${ search }`; } + yield setLoadingState( true ); + try { const response = yield apiFetch( { path, diff --git a/src/options/data/selectors.js b/src/options/data/selectors.js index 2d9024eed82..0bc9bd720a4 100644 --- a/src/options/data/selectors.js +++ b/src/options/data/selectors.js @@ -1,3 +1,7 @@ export function getOptions( state ) { return state.options; } + +export function isLoading( state ) { + return state.isLoading; +} diff --git a/src/options/index.js b/src/options/index.js index 923cd49bc49..86fc47ee9e6 100644 --- a/src/options/index.js +++ b/src/options/index.js @@ -14,7 +14,8 @@ function Options( { options, getOptions, deleteOptionById, - invalidateResolutionForStoreSelector, + isLoading, + invalidateResolution, } ) { const deleteOption = function ( optionId ) { // eslint-disable-next-line no-alert @@ -23,7 +24,27 @@ function Options( { } }; + const renderLoading = function () { + return ( + + + Loading... + + + ); + }; + const renderTableData = function () { + if ( options.length === 0 ) { + return ( + + + No Options Found + + + ); + } + return options.map( ( option ) => { // eslint-disable-next-line camelcase const { option_id, option_name, autoload } = option; @@ -53,14 +74,13 @@ function Options( { const searchOption = function ( event ) { event.preventDefault(); - let keyword = event.target.search.value; - if ( keyword === '' ) { - keyword = undefined; - } - getOptions( keyword ); + const keyword = event.target.search.value; - // force invlidation of the cached selector resolvers - invalidateResolutionForStoreSelector( 'getOptions' ); + // Invalidate resolution of the same selector + arg + // so that entering the same keyword always works + invalidateResolution( STORE_KEY, 'getOptions', [ keyword ] ); + + getOptions( keyword ); }; return ( @@ -100,7 +120,9 @@ function Options( { - { renderTableData() } + + { isLoading ? renderLoading() : renderTableData() } + ); @@ -108,15 +130,15 @@ function Options( { export default compose( withSelect( ( select ) => { - const { getOptions } = select( STORE_KEY ); + const { getOptions, isLoading } = select( STORE_KEY ); const options = getOptions(); - return { options, getOptions }; + + return { options, getOptions, isLoading: isLoading() }; } ), withDispatch( ( dispatch ) => { - const { - deleteOptionById, - invalidateResolutionForStoreSelector, - } = dispatch( STORE_KEY ); - return { deleteOptionById, invalidateResolutionForStoreSelector }; + const { deleteOptionById } = dispatch( STORE_KEY ); + const { invalidateResolution } = dispatch( 'core/data' ); + + return { deleteOptionById, invalidateResolution }; } ) )( Options );