allBlogsList

Implementing a Custom State in Optimizely B2B Spire Front End

Introduction

During an Optimizely Commerce Spire implementation additional data may need to be consumed that isn’t available out of the box. This can be accomplished by adding a Custom Data State, which will facilitate the reading and writing of custom data anywhere in the front end. Here is how to implement a scalable and maintainable Custom State on top of the Commerce Application State.

Implementing a Custom State

First, create a custom reducer. Optimizely provides a guide for this here. You can use traditional reducers, however using immer removes some boilerplate, and is consistent with the out-of-the-box commerce reducers. Below is a very basic custom reducer using immer.

CustomReducer.ts 

import { createTypedReducerWithImmer } from "@insite/client-framework/Common/CreateTypedReducer"; 
import ApplicationState from "@insite/client-framework/Store/ApplicationState"; 
import { AnyAction, reducers } from "@insite/client-framework/Store/Reducers"; 
import { Draft } from "immer";  

type CustomDataState = Readonly<{ 
    customProperty: string; 
}>;   

const initialCustomDataState: CustomDataState = { customProperty: "" };  

const customData = createTypedReducerWithImmer(initialCustomDataState, { 
    "CustomData/SetCustomProperty": (draft: Draft<CustomDataState>, action: { customProperty: string }) => { 
        draft.customProperty = action.customProperty; 
    }, 
}); 
  
(reducers as any).customData = customData;   

export type CustomState = { 
    customData: CustomDataState ; 
} & ApplicationState;   

type Reducers = { 
    customData: typeof customData; 
};   

export type CustomActions = Parameters<Reducers[keyof Reducers]>[1] | AnyAction;

Based on the volume of custom data, you may want to nest multiple states into CustomDataState to maintain readability, or even into multiple reducers. If you do use multiple custom reducers, make sure you import each in your blueprint’s Start.tsx file.

Start.tsx 

import "@blueprint/Store/CustomReducer"; 

Now the customData will be available in the store, which is confirmable using redux dev tools. Next, create a Handler that sets customProperty. Setting the DispatchProp to CustomActions will allow dispatching of actions on the custom reducer. 

SetCustomProperty.ts 

import { createHandlerChainRunner, Handler } from "@insite/client-framework/HandlerCreator"; 
import { CustomActions } from "@blueprint/Store/CustomReducer"; 
import { DispatchProp } from "react-redux"; 

type Props = DispatchProp<CustomActions>; 

type HandlerType = Handler<{ customProperty?: string }, Props>; 

export const DispatchSetCustomProperty: HandlerType = props => { 
    const customProperty = props.parameter.customProperty ?? ""; 
    props.dispatch({ 
        type: "CustomData/SetCustomProperty ", 
        customProperty, 
    })  
}; 

export const chain = [DispatchSetCustomProperty]; 

const setCustomProperty = createHandlerChainRunner(chain, "setCustomProperty"); 
export default setCustomProperty;

Read the custom State to a component by changing the type of state from ApplicationState to CustomState in mapStateToProps. Include any needed custom actions in mapDispatchToProps, then call them from a component to update the custom state. 

const mapStateToProps = (state: CustomState) => { 
    return { 
        customProperty: state.customData.customProperty, 
    }; 
}; 

const mapDispatchToProps = { 
    setUpsCollect 
}; 

You can also read from the custom state when modifying commerce handler chains by casting props.getState() to the CustomState type. 

type CommerceHandlerProps = Parameters<typeof "NameOfCommerceHandlerChain }>[0]; 

function SetCustomProperty(props: CommerceHandlerProps) { 
    const state = props.getState() as CustomState; 
    props.commerceData = { 
        ...props.commerceData, 
        commerceField: state.customData.customProperty, 
    }; 
} 

If you have any questions about implementing a custom state in your B2B Commerce solution, feel free to reach out to Kevin.Marks@xcentium.com