initial commit

This commit is contained in:
2021-12-10 12:03:04 +00:00
commit c46c7ddbf0
3643 changed files with 582794 additions and 0 deletions

View File

@ -0,0 +1,4 @@
export const ACTION_TYPES = {
SET_QUERY_KEY_VALUE: 'SET_QUERY_KEY_VALUE',
SET_QUERY_CONTEXT_VALUE: 'SET_QUERY_CONTEXT_VALUE',
};

View File

@ -0,0 +1,38 @@
/**
* Internal dependencies
*/
import { ACTION_TYPES as types } from './action-types';
/**
* Action creator for setting a single query-state value for a given context.
*
* @param {string} context Context for query state being stored.
* @param {string} queryKey Key for query item.
* @param {*} value The value for the query item.
*
* @return {Object} The action object.
*/
export const setQueryValue = ( context, queryKey, value ) => {
return {
type: types.SET_QUERY_KEY_VALUE,
context,
queryKey,
value,
};
};
/**
* Action creator for setting query-state for a given context.
*
* @param {string} context Context for query state being stored.
* @param {*} value Query state being stored for the given context.
*
* @return {Object} The action object.
*/
export const setValueForQueryContext = ( context, value ) => {
return {
type: types.SET_QUERY_CONTEXT_VALUE,
context,
value,
};
};

View File

@ -0,0 +1 @@
export const STORE_KEY = 'wc/store/query-state';

View File

@ -0,0 +1,20 @@
/**
* External dependencies
*/
import { registerStore } from '@wordpress/data';
/**
* Internal dependencies
*/
import { STORE_KEY } from './constants';
import * as selectors from './selectors';
import * as actions from './actions';
import reducer from './reducers';
registerStore( STORE_KEY, {
reducer,
actions,
selectors,
} );
export const QUERY_STATE_STORE_KEY = STORE_KEY;

View File

@ -0,0 +1,46 @@
/**
* Internal dependencies
*/
import { ACTION_TYPES as types } from './action-types';
import { getStateForContext } from './utils';
/**
* Reducer for processing actions related to the query state store.
*
* @param {Object} state Current state in store.
* @param {Object} action Action being processed.
*/
const queryStateReducer = ( state = {}, action ) => {
const { type, context, queryKey, value } = action;
const prevState = getStateForContext( state, context );
let newState;
switch ( type ) {
case types.SET_QUERY_KEY_VALUE:
const prevStateObject =
prevState !== null ? JSON.parse( prevState ) : {};
// mutate it and JSON.stringify to compare
prevStateObject[ queryKey ] = value;
newState = JSON.stringify( prevStateObject );
if ( prevState !== newState ) {
state = {
...state,
[ context ]: newState,
};
}
break;
case types.SET_QUERY_CONTEXT_VALUE:
newState = JSON.stringify( value );
if ( prevState !== newState ) {
state = {
...state,
[ context ]: newState,
};
}
break;
}
return state;
};
export default queryStateReducer;

View File

@ -0,0 +1,51 @@
/**
* Internal dependencies
*/
import { getStateForContext } from './utils';
/**
* Selector for retrieving a specific query-state for the given context.
*
* @param {Object} state Current state.
* @param {string} context Context for the query-state being retrieved.
* @param {string} queryKey Key for the specific query-state item.
* @param {*} defaultValue Default value for the query-state key if it doesn't
* currently exist in state.
*
* @return {*} The currently stored value or the defaultValue if not present.
*/
export const getValueForQueryKey = (
state,
context,
queryKey,
defaultValue = {}
) => {
let stateContext = getStateForContext( state, context );
if ( stateContext === null ) {
return defaultValue;
}
stateContext = JSON.parse( stateContext );
return typeof stateContext[ queryKey ] !== 'undefined'
? stateContext[ queryKey ]
: defaultValue;
};
/**
* Selector for retrieving the query-state for the given context.
*
* @param {Object} state The current state.
* @param {string} context The context for the query-state being retrieved.
* @param {*} defaultValue The default value to return if there is no state for
* the given context.
*
* @return {*} The currently stored query-state for the given context or
* defaultValue if not present in state.
*/
export const getValueForQueryContext = (
state,
context,
defaultValue = {}
) => {
const stateContext = getStateForContext( state, context );
return stateContext === null ? defaultValue : JSON.parse( stateContext );
};

View File

@ -0,0 +1,136 @@
/**
* External dependencies
*/
import deepFreeze from 'deep-freeze';
/**
* Internal dependencies
*/
import queryStateReducer from '../reducers';
import { setQueryValue, setValueForQueryContext } from '../actions';
describe( 'queryStateReducer', () => {
const originalState = deepFreeze( {
contexta: JSON.stringify( {
foo: 'bar',
cheese: 'pizza',
} ),
} );
it(
'returns original state when the action is not of the type being ' +
'processed',
() => {
expect(
queryStateReducer( originalState, { type: 'invalid' } )
).toBe( originalState );
}
);
describe( 'SET_QUERY_KEY_VALUE action', () => {
it(
'returns original state when incoming query-state key value ' +
'matches what is already in the state',
() => {
expect(
queryStateReducer(
originalState,
setQueryValue( 'contexta', 'foo', 'bar' )
)
).toBe( originalState );
}
);
it(
'returns new state when incoming query-state key exist ' +
'but the value is a new value',
() => {
const newState = queryStateReducer(
originalState,
setQueryValue( 'contexta', 'foo', 'zed' )
);
expect( newState ).not.toBe( originalState );
expect( newState ).toEqual( {
contexta: JSON.stringify( {
foo: 'zed',
cheese: 'pizza',
} ),
} );
}
);
it(
'returns new state when incoming query-state key does not ' +
'exist',
() => {
const newState = queryStateReducer(
originalState,
setQueryValue( 'contexta', 'burger', 'pizza' )
);
expect( newState ).not.toBe( originalState );
expect( newState ).toEqual( {
contexta: JSON.stringify( {
foo: 'bar',
cheese: 'pizza',
burger: 'pizza',
} ),
} );
}
);
} );
describe( 'SET_QUERY_CONTEXT_VALUE action', () => {
it(
'returns original state when incoming context value matches ' +
'what is already in the state',
() => {
expect(
queryStateReducer(
originalState,
setValueForQueryContext( 'contexta', {
foo: 'bar',
cheese: 'pizza',
} )
)
).toBe( originalState );
}
);
it(
'returns new state when incoming context value is different ' +
'than what is already in the state',
() => {
const newState = queryStateReducer(
originalState,
setValueForQueryContext( 'contexta', {
bar: 'foo',
pizza: 'cheese',
} )
);
expect( newState ).not.toBe( originalState );
expect( newState ).toEqual( {
contexta: JSON.stringify( {
bar: 'foo',
pizza: 'cheese',
} ),
} );
}
);
it(
'returns new state when incoming context does not exist in the ' +
'state',
() => {
const newState = queryStateReducer(
originalState,
setValueForQueryContext( 'contextb', {
foo: 'bar',
} )
);
expect( newState ).not.toBe( originalState );
expect( newState ).toEqual( {
contexta: JSON.stringify( {
foo: 'bar',
cheese: 'pizza',
} ),
contextb: JSON.stringify( {
foo: 'bar',
} ),
} );
}
);
} );
} );

View File

@ -0,0 +1,63 @@
/**
* External dependencies
*/
import deepFreeze from 'deep-freeze';
/**
* Internal dependencies
*/
import { getValueForQueryKey, getValueForQueryContext } from '../selectors';
const testState = deepFreeze( {
contexta: JSON.stringify( {
foo: 'bar',
cheese: 'pizza',
} ),
} );
describe( 'getValueForQueryKey', () => {
it(
'returns provided default value when there is no state for the ' +
'given context',
() => {
expect(
getValueForQueryKey( testState, 'invalid', 'foo', 42 )
).toBe( 42 );
}
);
it(
'returns provided default value when there is no value for the ' +
'given context and queryKey',
() => {
expect(
getValueForQueryKey( testState, 'contexta', 'pizza', 42 )
).toBe( 42 );
}
);
it( 'returns expected value when context and queryKey exist', () => {
expect( getValueForQueryKey( testState, 'contexta', 'foo', 42 ) ).toBe(
'bar'
);
} );
} );
describe( 'getValueForQueryContext', () => {
it(
'returns provided default value when there is no state for the ' +
'given context',
() => {
expect( getValueForQueryContext( testState, 'invalid', 42 ) ).toBe(
42
);
}
);
it(
'returns expected value when selecting a context that exists in ' +
'state',
() => {
expect(
getValueForQueryContext( testState, 'contexta', 42 )
).toEqual( JSON.parse( testState.contexta ) );
}
);
} );

View File

@ -0,0 +1,3 @@
export const getStateForContext = ( state, context ) => {
return typeof state[ context ] === 'undefined' ? null : state[ context ];
};