diff --git a/native/components/auto-join-community-handler.react.js b/lib/components/base-auto-join-community-handler.react.js copy from native/components/auto-join-community-handler.react.js copy to lib/components/base-auto-join-community-handler.react.js --- a/native/components/auto-join-community-handler.react.js +++ b/lib/components/base-auto-join-community-handler.react.js @@ -4,35 +4,32 @@ import _pickBy from 'lodash/fp/pickBy.js'; import * as React from 'react'; -import { NeynarClientContext } from 'lib/components/neynar-client-provider.react.js'; -import blobService from 'lib/facts/blob-service.js'; -import { useIsLoggedInToIdentityAndAuthoritativeKeyserver } from 'lib/hooks/account-hooks.js'; -import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js'; +import { NeynarClientContext } from '../components/neynar-client-provider.react.js'; +import blobService from '../facts/blob-service.js'; +import { useIsLoggedInToIdentityAndAuthoritativeKeyserver } from '../hooks/account-hooks.js'; +import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js'; import { farcasterChannelTagBlobHash, useJoinCommunity, -} from 'lib/shared/community-utils.js'; -import type { AuthMetadata } from 'lib/shared/identity-client-context.js'; -import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; -import type { KeyserverOverride } from 'lib/shared/invite-links.js'; +} from '../shared/community-utils.js'; +import type { AuthMetadata } from '../shared/identity-client-context.js'; +import { IdentityClientContext } from '../shared/identity-client-context.js'; +import type { KeyserverOverride } from '../shared/invite-links.js'; import type { OngoingJoinCommunityData, JoinCommunityStep, -} from 'lib/types/community-types.js'; -import type { CalendarQuery } from 'lib/types/entry-types.js'; -import type { SetState } from 'lib/types/hook-types.js'; -import { defaultThreadSubscription } from 'lib/types/subscription-types.js'; -import { getBlobFetchableURL } from 'lib/utils/blob-service.js'; -import { useCurrentUserFID } from 'lib/utils/farcaster-utils.js'; -import { promiseAll } from 'lib/utils/promises.js'; +} from '../types/community-types.js'; +import type { CalendarQuery } from '../types/entry-types.js'; +import type { SetState } from '../types/hook-types.js'; +import { defaultThreadSubscription } from '../types/subscription-types.js'; +import { getBlobFetchableURL } from '../utils/blob-service.js'; +import { useCurrentUserFID } from '../utils/farcaster-utils.js'; +import { promiseAll } from '../utils/promises.js'; +import { useSelector } from '../utils/redux-utils.js'; import { usingCommServicesAccessToken, createDefaultHTTPRequestHeaders, -} from 'lib/utils/services-utils.js'; - -import { nonThreadCalendarQuery } from '../navigation/nav-selectors.js'; -import { NavContext } from '../navigation/navigation-context.js'; -import { useSelector } from '../redux/redux-utils.js'; +} from '../utils/services-utils.js'; type CommunityToAutoJoin = { +communityID: string, @@ -44,7 +41,13 @@ +[communityID: string]: CommunityToAutoJoin, }; -function AutoJoinCommunityHandler(): React.Node { +type Props = { + +calendarQuery: () => CalendarQuery, +}; + +function BaseAutoJoinCommunityHandler(props: Props): React.Node { + const { calendarQuery } = props; + const isActive = useSelector(state => state.lifecycleState !== 'background'); const loggedIn = useIsLoggedInToIdentityAndAuthoritativeKeyserver(); @@ -53,19 +56,10 @@ const neynarClient = React.useContext(NeynarClientContext)?.client; - const navContext = React.useContext(NavContext); - const identityClientContext = React.useContext(IdentityClientContext); invariant(identityClientContext, 'IdentityClientContext should be set'); const { getAuthMetadata } = identityClientContext; - const calendarQuery = useSelector(state => - nonThreadCalendarQuery({ - redux: state, - navContext, - }), - ); - const threadInfos = useSelector(state => state.threadStore.threadInfos); const keyserverInfos = useSelector( @@ -213,6 +207,7 @@ +communitiesToAutoJoin: CommunitiesToAutoJoin, +setCommunitiesToAutoJoin: SetState, }; + function JoinHandler(props: JoinHandlerProps) { const { communityID, @@ -295,4 +290,4 @@ return null; } -export { AutoJoinCommunityHandler }; +export { BaseAutoJoinCommunityHandler }; diff --git a/native/components/auto-join-community-handler.react.js b/native/components/auto-join-community-handler.react.js --- a/native/components/auto-join-community-handler.react.js +++ b/native/components/auto-join-community-handler.react.js @@ -1,64 +1,16 @@ // @flow -import invariant from 'invariant'; -import _pickBy from 'lodash/fp/pickBy.js'; import * as React from 'react'; -import { NeynarClientContext } from 'lib/components/neynar-client-provider.react.js'; -import blobService from 'lib/facts/blob-service.js'; -import { useIsLoggedInToIdentityAndAuthoritativeKeyserver } from 'lib/hooks/account-hooks.js'; -import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js'; -import { - farcasterChannelTagBlobHash, - useJoinCommunity, -} from 'lib/shared/community-utils.js'; -import type { AuthMetadata } from 'lib/shared/identity-client-context.js'; -import { IdentityClientContext } from 'lib/shared/identity-client-context.js'; -import type { KeyserverOverride } from 'lib/shared/invite-links.js'; -import type { - OngoingJoinCommunityData, - JoinCommunityStep, -} from 'lib/types/community-types.js'; -import type { CalendarQuery } from 'lib/types/entry-types.js'; -import type { SetState } from 'lib/types/hook-types.js'; -import { defaultThreadSubscription } from 'lib/types/subscription-types.js'; -import { getBlobFetchableURL } from 'lib/utils/blob-service.js'; -import { useCurrentUserFID } from 'lib/utils/farcaster-utils.js'; -import { promiseAll } from 'lib/utils/promises.js'; -import { - usingCommServicesAccessToken, - createDefaultHTTPRequestHeaders, -} from 'lib/utils/services-utils.js'; +import { BaseAutoJoinCommunityHandler } from 'lib/components/base-auto-join-community-handler.react.js'; import { nonThreadCalendarQuery } from '../navigation/nav-selectors.js'; import { NavContext } from '../navigation/navigation-context.js'; import { useSelector } from '../redux/redux-utils.js'; -type CommunityToAutoJoin = { - +communityID: string, - +keyserverOverride: ?KeyserverOverride, - +joinStatus: 'inactive' | 'joining' | 'joined', -}; - -type CommunitiesToAutoJoin = { - +[communityID: string]: CommunityToAutoJoin, -}; - function AutoJoinCommunityHandler(): React.Node { - const isActive = useSelector(state => state.lifecycleState !== 'background'); - - const loggedIn = useIsLoggedInToIdentityAndAuthoritativeKeyserver(); - - const fid = useCurrentUserFID(); - - const neynarClient = React.useContext(NeynarClientContext)?.client; - const navContext = React.useContext(NavContext); - const identityClientContext = React.useContext(IdentityClientContext); - invariant(identityClientContext, 'IdentityClientContext should be set'); - const { getAuthMetadata } = identityClientContext; - const calendarQuery = useSelector(state => nonThreadCalendarQuery({ redux: state, @@ -66,233 +18,7 @@ }), ); - const threadInfos = useSelector(state => state.threadStore.threadInfos); - - const keyserverInfos = useSelector( - state => state.keyserverStore.keyserverInfos, - ); - - const [communitiesToAutoJoin, setCommunitiesToAutoJoin] = - React.useState(); - - const prevCanQueryRef = React.useRef(); - const canQuery = loggedIn; - - React.useEffect(() => { - if (canQuery === prevCanQueryRef.current) { - return; - } - - prevCanQueryRef.current = canQuery; - if (!loggedIn || !isActive || !fid || !neynarClient || !threadInfos) { - return; - } - - void (async () => { - const authMetadataPromise: Promise = (async () => { - if (!usingCommServicesAccessToken) { - return undefined; - } - return await getAuthMetadata(); - })(); - - const followedFarcasterChannelsPromise = - neynarClient.fetchFollowedFarcasterChannels(fid); - - const [authMetadata, followedFarcasterChannels] = await Promise.all([ - authMetadataPromise, - followedFarcasterChannelsPromise, - ]); - - const headers = authMetadata - ? createDefaultHTTPRequestHeaders(authMetadata) - : {}; - - const followedFarcasterChannelIDs = followedFarcasterChannels.map( - channel => channel.id, - ); - - const promises: { [string]: Promise } = {}; - - for (const channelID of followedFarcasterChannelIDs) { - promises[channelID] = (async () => { - const blobHash = farcasterChannelTagBlobHash(channelID); - const blobURL = getBlobFetchableURL(blobHash); - - const blobResult = await fetch(blobURL, { - method: blobService.httpEndpoints.GET_BLOB.method, - headers, - }); - - if (blobResult.status !== 200) { - return null; - } - - const { commCommunityID, keyserverURL } = await blobResult.json(); - const keyserverID = extractKeyserverIDFromID(commCommunityID); - - // The user is already in the community - if (threadInfos[commCommunityID]) { - return null; - } - - const keyserverOverride = !keyserverInfos[keyserverID] - ? { - keyserverID, - keyserverURL: keyserverURL.replace(/\/$/, ''), - } - : null; - - return { - communityID: commCommunityID, - keyserverOverride, - joinStatus: 'inactive', - }; - })(); - } - - const communitiesObj = await promiseAll(promises); - - const filteredCommunitiesObj = _pickBy(Boolean)(communitiesObj); - - const communitesToJoin: { ...CommunitiesToAutoJoin } = {}; - - for (const key in filteredCommunitiesObj) { - const communityID = filteredCommunitiesObj[key].communityID; - communitesToJoin[communityID] = filteredCommunitiesObj[key]; - } - - setCommunitiesToAutoJoin(communitesToJoin); - })(); - }, [ - threadInfos, - fid, - isActive, - loggedIn, - neynarClient, - getAuthMetadata, - keyserverInfos, - canQuery, - ]); - - const joinHandlers = React.useMemo(() => { - if (!communitiesToAutoJoin) { - return null; - } - - return Object.keys(communitiesToAutoJoin).map(id => { - const communityToAutoJoin = communitiesToAutoJoin[id]; - - const { communityID, keyserverOverride, joinStatus } = - communityToAutoJoin; - - if (joinStatus === 'joined') { - return null; - } - - return ( - - ); - }); - }, [calendarQuery, communitiesToAutoJoin]); - - return joinHandlers; -} - -type JoinHandlerProps = { - +communityID: string, - +keyserverOverride: ?KeyserverOverride, - +calendarQuery: () => CalendarQuery, - +communitiesToAutoJoin: CommunitiesToAutoJoin, - +setCommunitiesToAutoJoin: SetState, -}; -function JoinHandler(props: JoinHandlerProps) { - const { - communityID, - keyserverOverride, - calendarQuery, - communitiesToAutoJoin, - setCommunitiesToAutoJoin, - } = props; - - const [ongoingJoinData, setOngoingJoinData] = - React.useState(null); - - const [step, setStep] = React.useState('inactive'); - - const joinCommunity = useJoinCommunity({ - communityID, - keyserverOverride, - calendarQuery, - ongoingJoinData, - setOngoingJoinData, - step, - setStep, - defaultSubscription: defaultThreadSubscription, - }); - - React.useEffect(() => { - const joinStatus = communitiesToAutoJoin[communityID]?.joinStatus; - if (joinStatus !== 'inactive') { - return; - } - - void joinCommunity(); - }, [ - communitiesToAutoJoin, - communityID, - joinCommunity, - setCommunitiesToAutoJoin, - ]); - - React.useEffect(() => { - if (step !== 'add_keyserver') { - return; - } - - setCommunitiesToAutoJoin(prev => { - if (!prev) { - return null; - } - - return { - ...prev, - [communityID]: { - ...prev[communityID], - joinStatus: 'joining', - }, - }; - }); - }, [communityID, setCommunitiesToAutoJoin, step]); - - React.useEffect(() => { - if (step !== 'finished') { - return; - } - - setCommunitiesToAutoJoin(prev => { - if (!prev) { - return null; - } - - return { - ...prev, - [communityID]: { - ...prev[communityID], - joinStatus: 'joined', - }, - }; - }); - }, [communityID, step, setCommunitiesToAutoJoin]); - - return null; + return ; } export { AutoJoinCommunityHandler };