/ common / features / store.ts
store.ts
 1  import { bindActionCreators } from 'redux';
 2  
 3  import { shepherdProvider, getShepherdPending, getShepherdOffline } from 'libs/nodes';
 4  import { setOffline, setOnline, getOffline } from 'features/config';
 5  import { notificationsActions } from 'features/notifications';
 6  import handleMetaMaskPolling, { METAMASK_POLLING_INTERVAL } from './handleMetaMaskPolling';
 7  import configureStore from './configureStore';
 8  
 9  const store = configureStore();
10  
11  window.addEventListener('load', () => {
12    const getShepherdStatus = () => ({
13      pending: getShepherdPending(),
14      isOnline: !getShepherdOffline()
15    });
16  
17    const { online, offline, lostNetworkNotif, offlineNotif, restoreNotif } = bindActionCreators(
18      {
19        offline: setOffline,
20        online: setOnline,
21        restoreNotif: () =>
22          notificationsActions.showNotification(
23            'success',
24            'Your connection to the network has been restored!',
25            3000
26          ),
27        lostNetworkNotif: () =>
28          notificationsActions.showNotification(
29            'danger',
30            `You’ve lost your connection to the network, check your internet
31      connection or try changing networks from the dropdown at the
32      top right of the page.`,
33            Infinity
34          ),
35  
36        offlineNotif: () =>
37          notificationsActions.showNotification(
38            'info',
39            'You are currently offline. Some features will be unavailable.',
40            5000
41          )
42      },
43      store.dispatch
44    );
45  
46    const getAppOnline = () => !getOffline(store.getState());
47  
48    /**
49     * @description Repeatedly polls itself to check for online state conflict occurs, implemented in recursive style for flexible polling times
50     * as network requests take a variable amount of time.
51     *
52     * Whenever an app online state conflict occurs, it resolves the conflict with the following priority:
53     * * If shepherd is online but app is offline ->  do a ping request via shepherd provider, with the result of the ping being the set app state
54     * * If shepherd is offline but app is online -> set app to offline as it wont be able to make requests anyway
55     */
56    async function detectOnlineStateConflict() {
57      const shepherdStatus = getShepherdStatus();
58      const appOffline = getAppOnline();
59      const onlineStateConflict = shepherdStatus.isOnline !== appOffline;
60  
61      if (shepherdStatus.pending || !onlineStateConflict) {
62        return setTimeout(detectOnlineStateConflict, 1000);
63      }
64  
65      // if app reports online but shepherd offline, then set app offline
66      if (appOffline && !shepherdStatus.isOnline) {
67        lostNetworkNotif();
68        offline();
69      } else if (!appOffline && shepherdStatus.isOnline) {
70        // if app reports offline but shepherd reports online
71        // send a request to shepherd provider to see if we can still send out requests
72        const success = await shepherdProvider.ping().catch(() => false);
73        if (success) {
74          restoreNotif();
75          online();
76        }
77      }
78      detectOnlineStateConflict();
79    }
80    detectOnlineStateConflict();
81  
82    window.addEventListener('offline', () => {
83      const previouslyOnline = getAppOnline();
84  
85      // if browser reports as offline and we were previously online
86      // then set offline without checking balancer state
87      if (!navigator.onLine && previouslyOnline) {
88        offlineNotif();
89        offline();
90      }
91    });
92  });
93  
94  /** @desc When MetaMask is loaded as an extension, watch for network changes. */
95  if ((window as any).web3) {
96    setInterval(handleMetaMaskPolling.bind(null, store), METAMASK_POLLING_INTERVAL);
97  }
98  
99  export default store;