diff --git a/packages/status-react/src/protocol/index.tsx b/packages/status-react/src/protocol/index.tsx index ccf1abc8..d7e25304 100644 --- a/packages/status-react/src/protocol/index.tsx +++ b/packages/status-react/src/protocol/index.tsx @@ -1,6 +1,6 @@ -export { ClientProvider } from './provider' -export { useCommunity } from './use-community' -export { useChats } from './use-chats' -export { useChannel, Channel } from './use-channel' +export { ProtocolProvider, useProtocol } from './provider' export { useAccount } from './use-account' +export type { Chat } from './use-chat' +export { useChat } from './use-chat' +export { useChats } from './use-chats' export { useMembers } from './use-members' diff --git a/packages/status-react/src/protocol/provider.tsx b/packages/status-react/src/protocol/provider.tsx index ea297abd..ea44ec51 100644 --- a/packages/status-react/src/protocol/provider.tsx +++ b/packages/status-react/src/protocol/provider.tsx @@ -1,101 +1,109 @@ -import React, { - createContext, - useContext, - useEffect, - useMemo, - useState, -} from 'react' +import React, { createContext, useContext, useEffect, useReducer } from 'react' import { createClient } from '@status-im/js' import { Loading } from '~/src/components/loading' import type { Account, Client, ClientOptions, Community } from '@status-im/js' -import type { Config } from '~/src/types/config' -const Context = createContext(undefined) -const CommunityContext = createContext< - Community['communityMetadata'] | undefined ->(undefined) +const Context = createContext(undefined) -export function useClient() { - const context = useContext(Context) - - if (!context) { - throw new Error(`useClient must be used within a ClientProvider`) - } - - return context +type State = { + loading: boolean + client: Client | undefined + community: Community['communityMetadata'] | undefined + account: Account | undefined + dispatch?: React.Dispatch } -export function useCommunity() { - const context = useContext(CommunityContext) +type Action = + | { type: 'INIT'; client: Client } + | { type: 'UPDATE_COMMUNITY'; community: Community['communityMetadata'] } + | { type: 'SET_ACCOUNT'; account: Account } + | { type: 'REMOVE_ACCOUNT' } - if (!context) { - // return {} - throw new Error(`useCommunity must be used within a ClientProvider`) - } - - return context -} - -interface ClientProviderProps { +interface Props { options: ClientOptions children: React.ReactNode } -export const ClientProvider = (props: ClientProviderProps) => { - const [client, setClient] = useState() - const [community, setCommunity] = useState() - const [account, setAccount] = useState() - const [loading, setLoading] = useState(true) +const reducer = (state: State, action: Action): State => { + switch (action.type) { + case 'INIT': { + const { client } = action + return { + ...state, + loading: false, + client, + community: client.community.communityMetadata, + } + } + case 'UPDATE_COMMUNITY': { + return { ...state, community: action.community } + } + case 'SET_ACCOUNT': { + return { ...state, account: action.account } + } + case 'REMOVE_ACCOUNT': { + return { ...state, account: undefined } + } + } +} +export const ProtocolProvider = (props: Props) => { const { options, children } = props - // const client = useMemo(() => { - // return createClient(options) - // }, [options]) + const [state, dispatch] = useReducer(reducer, { + loading: true, + client: undefined, + community: undefined, + account: undefined, + dispatch: undefined, + }) + + const { client, loading } = state useEffect(() => { const loadClient = async () => { - // setLoading(true) - const client = await createClient({ publicKey: props.options.publicKey }) - console.log('init', client) - setCommunity(client.community.communityMetadata) - console.log( - 'file: provider.tsx > line 64 > loadClient > client.community.communityMetadata', - client.community.communityMetadata - ) - - setClient(client) - setLoading(false) + const client = await createClient({ publicKey: options.publicKey }) + dispatch({ type: 'INIT', client }) } loadClient() - }, []) + + // Community public key should not change during the lifetime + }, []) // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { if (client) { - console.log('useEffect subscribe') return client.community.onCommunityUpdate(community => { - setCommunity(community) - console.log( - 'file: provider.tsx > line 75 > useEffect > community', - community - ) + dispatch({ type: 'UPDATE_COMMUNITY', community }) }) } }, [client]) - // if (!client) { - // return - // } + if (loading) { + return + } return ( - - - {loading ? : children} - + + {children} ) } + +export function useProtocol() { + const context = useContext(Context) + + if (!context) { + throw new Error(`useProtocol must be used within a ProtocolProvider`) + } + + // we enforce initialization of client before rendering children + return context as State & { + client: Client + community: Community['communityMetadata'] + dispatch: React.Dispatch + } +}