127 lines
2.9 KiB
TypeScript
127 lines
2.9 KiB
TypeScript
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<State | undefined>(undefined)
|
|
|
|
export type State = {
|
|
loading: boolean
|
|
failed: boolean
|
|
client: Client | undefined
|
|
community: Community['description'] | undefined
|
|
account: Account | undefined
|
|
dispatch?: React.Dispatch<Action>
|
|
}
|
|
|
|
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 <Failed />
|
|
}
|
|
|
|
if (loading) {
|
|
return <Loading />
|
|
}
|
|
|
|
return (
|
|
<Context.Provider value={{ ...state, dispatch }}>
|
|
{children}
|
|
</Context.Provider>
|
|
)
|
|
}
|