Menu
Menu Sheet Overlay
Search
Search Sheet

Using the Integration Manager

    When using the Integration Manager in front end code (UI, components, etc.) you dispatch operations by importing the appropriate command and then dispatching it. There are often UI-level behaviours that need to be managed as part of dispatching the core action and so a common pattern when using the Integration Manager is to create an “event handler” action to connect to the UI and then dispatching the appropriate Integration Manager command from within that. This pattern allows the UI to present a spinner for the duration of the Integration Manager command, for example. The Integration Manager commands never modify the UI directly (or through UI-related actions) and so that must be handled in the event handler actions which are themselves redux thunk actions.

    Dispatching a command is only half of the equation though. Once the command is dispatched you’ll want to be notified when the command completes. Integration Manager commands always return a Promise which can be used to execute some behaviour when the command completes. This also provides a mechanism for handling error states that the Integration Manager and configured connector may encounter (network errors, server errors, etc). A complete example below shows how the UI would connect to an event handler action, dispatch a command to do the “real work”, and then clean up when the command completes.

    // product-details/index.jsx
    import {submitCartForm} from './actions'
    
    class ProductDetails({
        title,
        image,
        price
    }) => (
        <form onSubmit={handleSubmit(submitCartForm)}>
            ... render title, image, price...
        </form>
    )
    
    mapStateToProps = createStructuredSelector({
        title: getSelectedProductTitle,
        image: getSelectedProductImage,
        price: getSelectedProductPrice
    })
    
    mapDispatchToProps = {
        submitCartForm
    }
    
    export default connect(
        mapStateToProps,
        mapDispatchToProps
    )(ProductDetails)
    
    // product-details/actions.js
    import {addNotification} from 'progressive-web-sdk/dist/store/notifications/actions'
    import IntegrationManager from 'mobify-integration-manager/dist/'
    import {showSpinner, hideSpinner} from '../app/actions'
    import {PRODUCT_DETAILS_ITEM_ADDED_MODAL} from './constants'
    
    // A thunk action
    export const submitCartForm = (formValues) => (dispatch) => {
        const productId = formValues.product_id
        const quantity = formValues.quantity
    
        dispatch(showSpinner())
        dispatch(IntegrationManager.cart.addToCart(productId, quantity))
            .then(() => {
                dispatch(openModal(PRODUCT_DETAILS_ITEM_ADDED_MODAL))
            })
            .catch((error) => {
                dispatch(addNotification({
                    content: 'We couldn\'t add this item to your cart',
                    id: 'add-to-cart-error',
                    showRemoveButton: true)
                })
            })
            .finally(() => {
                dispatch(hideSpinner())
            })
    }
    

    There is a lot going on in that last thunk action. Let’s walk through what’s going on. At the top we have a typical JSX component. This component displays product details. Within that component we have an Add to Cart form that is bound to the submitCartForm action.

    The submitCartForm action is where things get interesting. The action takes a set of formValues that are managed by Redux Form. The method extracts the productId and quantity and then starts dispatching actions. First it shows the spinner so that the user knows that work is in progress. Then it dispatches the addToCart command which is an Integration Manager command. This command is implemented by the currently configured connector and calls out to whatever service the connector is built for (eg. Salesforce Commerce Cloud, Magento, etc).

    The addToCart command returns a Promise so we can chain on the end of it. If it completes successfully we show a modal (dispatch(openModal...)). In the event of an error, the .catch() block will be executed and we show a notification (dispatch(addNotification(...))).

    We want to make sure that we don’t leave the spinner showing regardless of the result of the command so we use a .finally() block to hide the spinner (dispatch(hideSpinner())).

    Connectors #

    Connectors implement the Integration Manager commands exposed to the front end. Each connector is simply a collection of thunk actions that do the work that the command represents. The thunk action implementation can do whatever is needed, including asynchronous calls. If the operation is asynchronous the connector must return a promise from the thunk action.

    Within the thunk action you can also import any selectors for data you need (in addition to parameters passed directly to the function). Despite thunk actions receiving the getState function, using it is discouraged as that binds you to the current shape of the Redux store, which may change between versions of the SDK. Using seletors shields your connector from these changes.

    As your thunk action completes its work, it returns data back to the app by dispatching Result actions You can find the list of currently supported results in integration-manager/results.

    API #

    The Integration Manager API is the set of commands, results, and types that it exports. You can view the API documentation by running the following command in a terminal window in your project directory:

    open node_modules/progressive-web-sdk/src/integration-manager/docs/index.html
    

    Connector specific data #

    Each connector will have its unique setups and requirements, when working with connector specific data or fields, keep in mind that there are common fields that apply to every connector, such as username and password in a user registration form. Also, there are fields that are dedicated to a particular connector, for example, Hybris connector requires a title field which should be one of the following values: Mr, Mrs, Miss, etc. The way to implement these kind of data is to pass an object opts that contains the necessary key and values. Each Integration Manager command will validate the data on behalf of the connector that you are using.

    Hybris connector

    /*
     *  Example:
     *  registerUser command takes a fifth parameter `opts`
     *  For Hybris connector, titleCode field is needed for registerUser
     *  opts = {
     *    titleCode: 'Mr'
     *  }
     *  You can fetch a list of avaiable titles from your Hybris OCC API
     *  [GET] endpoint: `/rest/v2/{site}/titles`
     */
    dispatch(registerUser(firstname, lastname, email, password, opts))