toggle-corp/react-store

View on GitHub
utils/redux-sync.js

Summary

Maintainability
A
1 hr
Test Coverage
import { isFalsy } from '@togglecorp/fujs';

const SYNC_KEY = 'ACTION_DISPATCHED';

// Start listening to actions from other tabs and synchronize.
export const startActionsSync = (store) => {
    // Local storage is, by definition, listened when changed from
    // other tabs.
    window.addEventListener('storage', (e) => {
        if (e.key === SYNC_KEY) {
            const event = JSON.parse(e.newValue);
            if (event.action) {
                store.dispatch(event.action);
            }
        }
    });
};

// Create a middleware that dispatches actions to other tabs.
export const createActionSyncMiddleware = (actionPrefixes, tabId) => () => next => (action) => {
    const {
        senderId,
        resenderId,
        type,
        retransmit,
    } = action;

    const containsPrefix = prefix => type.startsWith(prefix);

    // do not set to local storage
    if (
        !actionPrefixes.find(containsPrefix)
        || (!isFalsy(senderId, ['']) && !isFalsy(resenderId, ['']))
    ) {
        return next(action);
    }

    let timestampedAction;
    // Two successive actions with same body won't propagate twice.
    // So, we add timestamp to make sure the body is unique.

    if (isFalsy(senderId, [''])) {
        // this is original message to be sent
        timestampedAction = {
            action: {
                ...action,
                senderId: tabId,
            },
            time: Date.now(),
        };
    } else if (retransmit) {
        // this is retransmitted back
        timestampedAction = {
            action: {
                ...action,
                resenderId: tabId,
            },
            time: Date.now(),
        };
    } else {
        return next(action);
    }

    try {
        localStorage.setItem(SYNC_KEY, JSON.stringify(timestampedAction));
    } catch (e) {
        // NOTE: error occurs if size of timestampedAction is very large
        console.error(e);
    }
    return next(action);
};