import { createContext, useEffect, useReducer } from 'react' import { createClient } from '@status-im/js' import { Failed } from '../components/failed' import { Loading } from '../components/loading' import type { Account, Client, ClientOptions, Community } from '@status-im/js' import type React from 'react' export const Context = createContext(undefined) export type State = { loading: boolean failed: boolean client: Client | undefined community: Community['description'] | undefined account: Account | undefined dispatch?: React.Dispatch } export type Action = | { type: 'INIT'; client: Client } | { type: 'UPDATE_COMMUNITY'; community: Community['description'] } | { type: 'SET_ACCOUNT'; account: Account | undefined } | { type: 'FAIL' } | { type: 'CONNECT'; connected: boolean } interface Props { options: ClientOptions children: React.ReactNode } const reducer = (state: State, action: Action): State => { switch (action.type) { case 'INIT': { const { client } = action return { ...state, loading: false, client, account: client.account, community: client.community.description, } } case 'UPDATE_COMMUNITY': { return { ...state, community: action.community } } case 'SET_ACCOUNT': { return { ...state, account: action.account } } case 'FAIL': { return { ...state, failed: true, loading: false } } case 'CONNECT': { return { ...state, loading: !action.connected } } } } export const ProtocolProvider = (props: Props) => { const { options, children } = props const [state, dispatch] = useReducer(reducer, { loading: true, client: undefined, community: undefined, account: undefined, dispatch: undefined, failed: false, }) const { client, loading, failed } = state useEffect(() => { const loadClient = async () => { try { const client = await createClient(options) dispatch({ type: 'INIT', client }) } catch (error) { console.error(error) dispatch({ type: 'FAIL' }) } } loadClient() // Community public key should not change during the lifetime }, []) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { if (client) { const unsubscribe = [ client.onConnection(connected => { dispatch({ type: 'CONNECT', connected }) }), client.onAccountChange(account => { dispatch({ type: 'SET_ACCOUNT', account }) }), client.community.onChange(community => { dispatch({ type: 'UPDATE_COMMUNITY', community }) }), ] return () => { unsubscribe.forEach(fn => fn()) } } }, [client]) if (failed) { return } if (loading) { return } return ( {children} ) }