Create helpers to simplify reducer logic

This commit is contained in:
Philipp Stracker 2024-11-18 17:43:15 +01:00
parent f272da5a5a
commit 81f45692f4
No known key found for this signature in database
2 changed files with 102 additions and 32 deletions

View file

@ -1,22 +1,13 @@
import { createReducer, createSetters } from '../utils';
import ACTION_TYPES from './action-types'; import ACTION_TYPES from './action-types';
const defaultState = { // Store structure.
const defaultTransient = {
isReady: false, isReady: false,
isSaving: false, isSaving: false,
isManualConnectionBusy: false, isManualConnectionBusy: false,
// Data persisted to the server.
data: {
completed: false,
step: 0,
useSandbox: false,
useManualConnection: false,
clientId: '',
clientSecret: '',
isCasualSeller: null, // null value will uncheck both options in the UI.
products: [],
},
// Read only values, provided by the server. // Read only values, provided by the server.
flags: { flags: {
canUseCasualSelling: false, canUseCasualSelling: false,
@ -25,29 +16,33 @@ const defaultState = {
}, },
}; };
const defaultPersistent = {
completed: false,
step: 0,
useSandbox: false,
useManualConnection: false,
clientId: '',
clientSecret: '',
isCasualSeller: null, // null value will uncheck both options in the UI.
products: [],
};
// Reducer logic.
const [ setTransient, setPersistent ] = createSetters(
defaultTransient,
defaultPersistent
);
const defaultState = {
...defaultTransient,
data: { ...defaultPersistent },
};
export const onboardingReducer = ( export const onboardingReducer = (
state = defaultState, state = defaultState,
{ type, ...action } { type, ...action }
) => { ) => {
const setTransient = ( changes ) => {
const { data, ...transientChanges } = changes;
return { ...state, ...transientChanges };
};
const setPersistent = ( changes ) => {
const validChanges = Object.keys( changes ).reduce( ( acc, key ) => {
if ( key in defaultState.data ) {
acc[ key ] = changes[ key ];
}
return acc;
}, {} );
return {
...state,
data: { ...state.data, ...validChanges },
};
};
switch ( type ) { switch ( type ) {
// Reset store to initial state. // Reset store to initial state.
case ACTION_TYPES.RESET_ONBOARDING: case ACTION_TYPES.RESET_ONBOARDING:

View file

@ -0,0 +1,75 @@
/**
* Updates an object with new values, filtering based on allowed keys.
*
* Helper method used by createSetters.
*
* @param {Object} oldObject The original object to update.
* @param {Object} newValues The new values to apply.
* @param {Object} allowedKeys An object whose keys define the allowed keys to update.
* @return {Object} A new object with the allowed updates applied.
*/
const updateObject = ( oldObject, newValues, allowedKeys = {} ) => ( {
...oldObject,
...Object.keys( newValues ).reduce( ( acc, key ) => {
if ( key in allowedKeys ) {
acc[ key ] = newValues[ key ];
}
return acc;
}, {} ),
} );
/**
* Creates setter functions for updating state.
*
* Only properties that are present in the "defaultTransient" or "defaultPersistent"
* arguments can be updated by the setters. Make sure that the default state defines
* ALL possible properties.
*
* @param {Object} defaultTransient Object defining initial transient values.
* @param {Object} defaultPersistent Object defining initial persistent values.
* @return {[Function, Function]} An array containing setTransient and setPersistent functions.
*/
export const createSetters = ( defaultTransient, defaultPersistent ) => {
const setTransient = ( oldState, newValues ) =>
updateObject( oldState, newValues, defaultTransient );
const setPersistent = ( oldState, newValues ) => ( {
...oldState,
data: updateObject( oldState.data, newValues, defaultPersistent ),
} );
return [ setTransient, setPersistent ];
};
/**
* Creates a reducer function with predefined action handlers.
*
* @param {Object} defaultTransient Object defining initial transient values.
* @param {Object} defaultPersistent Object defining initial persistent values.
* @param {Object} handlers An object mapping action types to handler functions.
* @return {Function} A reducer function.
*/
export const createReducer = (
defaultTransient,
defaultPersistent,
handlers
) => {
if ( Object.hasOwnProperty.call( defaultTransient, 'data' ) ) {
throw new Error(
'The transient state cannot contain a "data" property.'
);
}
const initialState = {
...defaultTransient,
data: defaultPersistent,
};
return function reducer( state = initialState, action ) {
if ( Object.hasOwnProperty.call( handlers, action.type ) ) {
return handlers[ action.type ]( state, action.data );
}
return state;
};
};