diff --git a/lib/components/farcaster-data-handler.react.js b/lib/components/farcaster-data-handler.react.js --- a/lib/components/farcaster-data-handler.react.js +++ b/lib/components/farcaster-data-handler.react.js @@ -9,17 +9,13 @@ import { useIsLoggedInToIdentityAndAuthoritativeKeyserver } from '../hooks/account-hooks.js'; import { useDeviceKind } from '../hooks/primary-device-hooks.js'; import { useUpdateRelationships } from '../hooks/relationship-hooks.js'; -import { useFarcasterConversationsSync } from '../shared/farcaster/farcaster-hooks.js'; import { IdentityClientContext } from '../shared/identity-client-context.js'; -import { useTunnelbroker } from '../tunnelbroker/tunnelbroker-context.js'; import { relationshipActions } from '../types/relationship-types.js'; import { useCurrentUserFID, useUnlinkFID, useSetLocalFID, useSetLocalCurrentUserSupportsDCs, - useCurrentUserSupportsDCs, - useFarcasterDCsLoaded, } from '../utils/farcaster-utils.js'; import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; import { useSelector, useDispatch } from '../utils/redux-utils.js'; @@ -241,46 +237,6 @@ return children; }, [children, fidLoaded]); - const syncFarcasterConversations = useFarcasterConversationsSync(); - const currentUserSupportsDCs = useCurrentUserSupportsDCs(); - const farcasterDCsLoaded = useFarcasterDCsLoaded(); - const [syncType, setSyncType] = React.useState<'none' | 'partial' | 'full'>( - farcasterDCsLoaded ? 'partial' : 'full', - ); - const tunnelbroker = useTunnelbroker(); - - const prevSupport = React.useRef(currentUserSupportsDCs); - React.useEffect(() => { - if (currentUserSupportsDCs && !prevSupport.current) { - setSyncType('full'); - } - prevSupport.current = currentUserSupportsDCs; - }, [currentUserSupportsDCs]); - - React.useEffect(() => { - if ( - !currentUserSupportsDCs || - syncType === 'none' || - !tunnelbroker.socketState.connected - ) { - return; - } - setSyncType('none'); - const limit = syncType === 'partial' ? 20 : Number.POSITIVE_INFINITY; - void syncFarcasterConversations(limit); - }, [ - currentUserSupportsDCs, - syncType, - syncFarcasterConversations, - tunnelbroker.socketState.connected, - ]); - - React.useEffect(() => { - if (!currentUserSupportsDCs && syncType === 'none') { - setSyncType('full'); - } - }, [currentUserSupportsDCs, syncType]); - return farcasterDataHandler; } diff --git a/lib/shared/farcaster/farcaster-hooks.js b/lib/shared/farcaster/farcaster-hooks.js --- a/lib/shared/farcaster/farcaster-hooks.js +++ b/lib/shared/farcaster/farcaster-hooks.js @@ -8,14 +8,15 @@ useFetchFarcasterConversation, useFetchFarcasterInbox, useFetchFarcasterMessages, - useSendFarcasterTextMessage, } from './farcaster-api.js'; import type { FarcasterConversation } from './farcaster-conversation-types.js'; import { type FarcasterMessage, farcasterMessageValidator, } from './farcaster-messages-types.js'; +import { useIsUserDataReady } from '../../hooks/backup-hooks.js'; import { useGetCommFCUsersForFIDs } from '../../hooks/user-identities-hooks.js'; +import { isLoggedIn } from '../../selectors/user-selectors.js'; import type { RawMessageInfo } from '../../types/message-types.js'; import { messageTruncationStatus } from '../../types/message-types.js'; import type { Dispatch } from '../../types/redux-types.js'; @@ -24,10 +25,13 @@ import { extractFarcasterIDsFromPayload } from '../../utils/conversion-utils.js'; import { convertFarcasterMessageToCommMessages } from '../../utils/convert-farcaster-message-to-comm-messages.js'; import { createFarcasterRawThreadInfo } from '../../utils/create-farcaster-raw-thread-info.js'; -import { useSetFarcasterDCsLoaded } from '../../utils/farcaster-utils.js'; -import { useDispatch } from '../../utils/redux-utils.js'; +import { + useCurrentUserSupportsDCs, + useFarcasterDCsLoaded, + useSetFarcasterDCsLoaded, +} from '../../utils/farcaster-utils.js'; +import { useDispatch, useSelector } from '../../utils/redux-utils.js'; import sleep from '../../utils/sleep.js'; -import { useSendDMOperationUtils } from '../dm-ops/dm-op-utils.js'; import { userIDFromFID } from '../id-utils.js'; const FARCASTER_DATA_BATCH_SIZE = 20; @@ -340,111 +344,101 @@ } function useFarcasterConversationsSync(): (limit: number) => Promise { - const [fullInbox, setFullInbox] = React.useState(false); - const [conversations, setConversations] = React.useState< - $ReadOnlyArray, - >([]); - const [messagesNumberLimit, setMessagesNumberLimit] = React.useState(20); - const fetchFarcasterInbox = useFetchFarcasterInbox(); - const sendFarcasterTextMessage = useSendFarcasterTextMessage(); const dispatch = useDispatch(); - const utils = useSendDMOperationUtils(); const fetchConversation = useFetchConversationWithBatching(); const fetchMessagesForConversation = useFetchMessagesForConversation(); + const setFarcasterDCsLoaded = useSetFarcasterDCsLoaded(); + + const fetchInboxes = React.useCallback( + async (cursor: ?string): Promise<$ReadOnlyArray> => { + const allConversations: Array = []; + let currentCursor = cursor; + + while (true) { + try { + let input = { limit: 20 }; + if (currentCursor) { + input = { + ...input, + cursor: currentCursor, + }; + } + const { result, next } = await withRetry( + () => fetchFarcasterInbox(input), + MAX_RETRIES, + RETRY_DELAY_MS, + ); - const fetchInboxes: (cursor: ?string) => Promise = React.useCallback( - async (cursor: ?string) => { - try { - let input = { limit: 20 }; - if (cursor) { - input = { - ...input, - cursor, - }; - } - const { result, next } = await withRetry( - () => fetchFarcasterInbox(input), - MAX_RETRIES, - RETRY_DELAY_MS, - ); - setConversations(prev => { const ids = result.conversations.map( conversation => conversation.conversationId, ); - return [...prev, ...ids]; - }); - if (next?.cursor) { - void fetchInboxes(next.cursor); - } else { - setFullInbox(true); + allConversations.push(...ids); + + if (next?.cursor) { + currentCursor = next.cursor; + } else { + break; + } + } catch (e) { + console.error('Error fetching inbox', e); + break; } - } catch (e) { - console.error('Error fetching inbox', e); - setFullInbox(true); } + + return allConversations; }, [fetchFarcasterInbox], ); - const [inProgress, setInProgress] = React.useState(false); - const setFarcasterDCsLoaded = useSetFarcasterDCsLoaded(); - React.useEffect(() => { - if (!fullInbox || conversations.length === 0 || inProgress) { - return; - } - setInProgress(true); - - void (async () => { - const farcasterConversations: Array = []; - - const conversationResults = await processInBatchesWithReduxBatching( - conversations, - FARCASTER_DATA_BATCH_SIZE, - (conversationID, batchedUpdates) => - fetchConversation(conversationID, batchedUpdates), - dispatch, - ); - - const successfulConversations = conversationResults.filter(Boolean); - farcasterConversations.push(...successfulConversations); - - await processInBatchesWithReduxBatching( - farcasterConversations, - FARCASTER_DATA_BATCH_SIZE, - (conversation, batchedUpdates) => - fetchMessagesForConversation( - conversation.conversationId, - messagesNumberLimit, - batchedUpdates, - ), - dispatch, - ); - - setConversations([]); - setInProgress(false); - setFarcasterDCsLoaded(true); - })(); - }, [ - conversations, - dispatch, - fetchConversation, - fetchMessagesForConversation, - fullInbox, - inProgress, - messagesNumberLimit, - sendFarcasterTextMessage, - utils, - setFarcasterDCsLoaded, - ]); - return React.useCallback( async (limit: number) => { - setMessagesNumberLimit(limit); - setFullInbox(false); - void fetchInboxes(null); + try { + const conversations = await fetchInboxes(null); + + if (conversations.length === 0) { + setFarcasterDCsLoaded(true); + return; + } + + const farcasterConversations: Array = []; + + const conversationResults = await processInBatchesWithReduxBatching( + conversations, + FARCASTER_DATA_BATCH_SIZE, + (conversationID, batchedUpdates) => + fetchConversation(conversationID, batchedUpdates), + dispatch, + ); + + const successfulConversations = conversationResults.filter(Boolean); + farcasterConversations.push(...successfulConversations); + + await processInBatchesWithReduxBatching( + farcasterConversations, + FARCASTER_DATA_BATCH_SIZE, + (conversation, batchedUpdates) => + fetchMessagesForConversation( + conversation.conversationId, + limit, + batchedUpdates, + ), + dispatch, + ); + + setFarcasterDCsLoaded(true); + } catch (e) { + console.error('Error syncing Farcaster conversations', e); + throw e; + } }, - [fetchInboxes], + [ + fetchInboxes, + fetchConversation, + fetchMessagesForConversation, + dispatch, + setFarcasterDCsLoaded, + ], ); } @@ -506,6 +500,45 @@ ); } +function useFarcasterSync(onComplete?: () => void): { +inProgress: boolean } { + const syncFarcasterConversations = useFarcasterConversationsSync(); + const currentUserSupportsDCs = useCurrentUserSupportsDCs(); + const farcasterDCsLoaded = useFarcasterDCsLoaded(); + const isUserLoggedIn = useSelector(isLoggedIn); + const userDataReady = useIsUserDataReady(); + const fullyLoggedIn = isUserLoggedIn && userDataReady; + const [inProgress, setInProgress] = React.useState(false); + + React.useEffect(() => { + if ( + inProgress || + farcasterDCsLoaded !== false || + !fullyLoggedIn || + !currentUserSupportsDCs + ) { + return; + } + setInProgress(true); + void (async () => { + try { + await syncFarcasterConversations(Number.POSITIVE_INFINITY); + } finally { + setInProgress(false); + onComplete?.(); + } + })(); + }, [ + currentUserSupportsDCs, + farcasterDCsLoaded, + fullyLoggedIn, + inProgress, + onComplete, + syncFarcasterConversations, + ]); + + return { inProgress }; +} + export { useFarcasterConversationsSync, useFetchConversationWithBatching, @@ -513,4 +546,5 @@ useFetchMessagesForConversation, useRefreshFarcasterConversation, useAddNewFarcasterMessage, + useFarcasterSync, }; diff --git a/lib/tunnelbroker/use-peer-to-peer-message-handler.js b/lib/tunnelbroker/use-peer-to-peer-message-handler.js --- a/lib/tunnelbroker/use-peer-to-peer-message-handler.js +++ b/lib/tunnelbroker/use-peer-to-peer-message-handler.js @@ -34,10 +34,7 @@ } from '../shared/device-list-utils.js'; import { dmOperationSpecificationTypes } from '../shared/dm-ops/dm-op-types.js'; import { useProcessDMOperation } from '../shared/dm-ops/process-dm-ops.js'; -import { - useAddNewFarcasterMessage, - useFarcasterConversationsSync, -} from '../shared/farcaster/farcaster-hooks.js'; +import { useAddNewFarcasterMessage } from '../shared/farcaster/farcaster-hooks.js'; import { IdentityClientContext } from '../shared/identity-client-context.js'; import type { IdentityServiceClient, @@ -61,6 +58,7 @@ import { getMessageForException } from '../utils/errors.js'; import { useClearFarcasterThreads, + useSetFarcasterDCsLoaded, useSetLocalCurrentUserSupportsDCs, useSetLocalFID, } from '../utils/farcaster-utils.js'; @@ -115,7 +113,6 @@ const setLocalFID = useSetLocalFID(); const setLocalDCsSupport = useSetLocalCurrentUserSupportsDCs(); const clearFarcasterThreads = useClearFarcasterThreads(); - const syncFarcasterConversations = useFarcasterConversationsSync(); const confirmPeerToPeerMessage = useConfirmPeerToPeerMessage(); const removeAndConfirmMessage = React.useCallback( @@ -134,6 +131,7 @@ ); const fullBackupSupport = useFullBackupSupportEnabled(); + const setFarcasterDCsLoaded = useSetFarcasterDCsLoaded(); return React.useCallback( async ( @@ -265,9 +263,8 @@ try { if (!userActionMessage.hasDCsToken) { clearFarcasterThreads(); - } else { - await syncFarcasterConversations(Number.POSITIVE_INFINITY); } + setFarcasterDCsLoaded(false); } finally { await removeAndConfirmMessage(messageID, senderInfo.deviceID); } @@ -286,15 +283,15 @@ getAuthMetadata, reBroadcastAccountDeletion, dispatch, + removeAndConfirmMessage, fullBackupSupport, restoreBackupState.status, restoreBackupState.payload.forced, userDataRestore, setLocalFID, setLocalDCsSupport, + setFarcasterDCsLoaded, clearFarcasterThreads, - syncFarcasterConversations, - removeAndConfirmMessage, ], ); } diff --git a/lib/utils/farcaster-utils.js b/lib/utils/farcaster-utils.js --- a/lib/utils/farcaster-utils.js +++ b/lib/utils/farcaster-utils.js @@ -52,15 +52,20 @@ return currentUserFIDDCs === 'true'; } -function useFarcasterDCsLoaded(): boolean { +function useFarcasterDCsLoaded(): ?boolean { const farcasterDCsLoaded = useSelector( state => state.syncedMetadataStore.syncedMetadata[ syncedMetadataNames.FARCASTER_DCS_LOADED - ] ?? 'false', + ], ); - return farcasterDCsLoaded === 'true'; + if (farcasterDCsLoaded === 'true') { + return true; + } else if (farcasterDCsLoaded === 'false') { + return false; + } + return undefined; } function useSetLocalFID(): (fid: ?string) => void { diff --git a/native/components/farcaster-sync-handler.react.js b/native/components/farcaster-sync-handler.react.js new file mode 100644 --- /dev/null +++ b/native/components/farcaster-sync-handler.react.js @@ -0,0 +1,60 @@ +// @flow + +import { CommonActions } from '@react-navigation/core'; +import * as React from 'react'; + +import { useIsUserDataReady } from 'lib/hooks/backup-hooks.js'; +import { isLoggedIn } from 'lib/selectors/user-selectors.js'; +import { + useCurrentUserSupportsDCs, + useFarcasterDCsLoaded, +} from 'lib/utils/farcaster-utils.js'; +import { useSelector } from 'lib/utils/redux-utils.js'; + +import { useCurrentLeafRouteName } from '../navigation/nav-selectors.js'; +import { NavContext } from '../navigation/navigation-context.js'; +import { FarcasterSyncScreenRouteName } from '../navigation/route-names.js'; + +function FarcasterSyncHandler(): React.Node { + const navContext = React.useContext(NavContext); + + const isUserLoggedIn = useSelector(isLoggedIn); + const userDataReady = useIsUserDataReady(); + const fullyLoggedIn = isUserLoggedIn && userDataReady; + + const currentUserSupportsDCs = useCurrentUserSupportsDCs(); + const farcasterDCsLoaded = useFarcasterDCsLoaded(); + const currentRouteName = useCurrentLeafRouteName(); + + React.useEffect(() => { + if (!navContext) { + return; + } + + const { dispatch } = navContext; + + if ( + fullyLoggedIn && + currentUserSupportsDCs && + farcasterDCsLoaded === false && + currentRouteName !== FarcasterSyncScreenRouteName + ) { + dispatch( + CommonActions.navigate({ + name: FarcasterSyncScreenRouteName, + }), + ); + } + }, [ + navContext, + userDataReady, + currentUserSupportsDCs, + farcasterDCsLoaded, + currentRouteName, + fullyLoggedIn, + ]); + + return null; +} + +export default FarcasterSyncHandler; diff --git a/native/farcaster/farcaster-sync-loading-screen.react.js b/native/farcaster/farcaster-sync-loading-screen.react.js new file mode 100644 --- /dev/null +++ b/native/farcaster/farcaster-sync-loading-screen.react.js @@ -0,0 +1,78 @@ +// @flow + +import * as React from 'react'; +import { Text, View } from 'react-native'; +import * as Progress from 'react-native-progress'; +import { SafeAreaView } from 'react-native-safe-area-context'; + +import { useFarcasterSync } from 'lib/shared/farcaster/farcaster-hooks.js'; + +import type { RootNavigationProp } from '../navigation/root-navigator.react.js'; +import type { NavigationRoute } from '../navigation/route-names.js'; +import { useColors, useStyles } from '../themes/colors.js'; + +type Props = { + +navigation: RootNavigationProp<'FarcasterSyncScreen'>, + +route: NavigationRoute<'FarcasterSyncScreen'>, +}; + +function FarcasterSyncLoadingScreen(props: Props): React.Node { + const styles = useStyles(unboundStyles); + const colors = useColors(); + + const handleComplete = React.useCallback(() => { + props.navigation.goBack(); + }, [props.navigation]); + + useFarcasterSync(handleComplete); + + return ( + + Fetching Farcaster threads + + We’re fetching all your Farcaster threads and messages. + + + This could take a while depending on how many conversations you have. + + + + + + ); +} + +const safeAreaEdges = ['bottom', 'top']; + +const unboundStyles = { + container: { + flex: 1, + backgroundColor: 'panelBackground', + justifyContent: 'space-between', + padding: 16, + }, + header: { + fontSize: 24, + color: 'panelForegroundLabel', + paddingBottom: 16, + }, + section: { + fontFamily: 'Arial', + fontSize: 15, + lineHeight: 20, + color: 'panelForegroundSecondaryLabel', + paddingBottom: 16, + }, + progressContainer: { + flexGrow: 1, + alignItems: 'center', + justifyContent: 'center', + }, +}; + +export default FarcasterSyncLoadingScreen; diff --git a/native/navigation/root-navigator.react.js b/native/navigation/root-navigator.react.js --- a/native/navigation/root-navigator.react.js +++ b/native/navigation/root-navigator.react.js @@ -58,6 +58,7 @@ LinkedDevicesBottomSheetRouteName, QRAuthNavigatorRouteName, CommunityJoinerModalRouteName, + FarcasterSyncScreenRouteName, } from './route-names.js'; import LoggedOutModal from '../account/logged-out-modal.react.js'; import QRAuthNavigator from '../account/qr-auth/qr-auth-navigator.react.js'; @@ -77,6 +78,7 @@ import CommunityJoinerModal from '../components/community-joiner-modal.react.js'; import ConnectFarcasterBottomSheet from '../components/connect-farcaster-bottom-sheet.react.js'; import DirectoryPromptBottomSheet from '../components/directory-prompt-bottom-sheet.react.js'; +import FarcasterSyncLoadingScreen from '../farcaster/farcaster-sync-loading-screen.react.js'; import InviteLinksNavigator from '../invite-links/invite-links-navigator.react.js'; import CustomServerModal from '../profile/custom-server-modal.react.js'; import KeyserverSelectionBottomSheet from '../profile/keyserver-selection-bottom-sheet.react.js'; @@ -215,6 +217,11 @@ component={RegistrationNavigator} options={disableGesturesScreenOptions} /> + ); }, diff --git a/native/root.react.js b/native/root.react.js --- a/native/root.react.js +++ b/native/root.react.js @@ -68,6 +68,7 @@ import ColdStartTracker from './components/cold-start-tracker.react.js'; import ConnectFarcasterAlertHandler from './components/connect-farcaster-alert-handler.react.js'; import DisplayCommunityDirectoryPromptHandler from './components/display-community-directory-prompt.react.js'; +import FarcasterSyncHandler from './components/farcaster-sync-handler.react.js'; import { FeatureFlagsProvider } from './components/feature-flags-provider.react.js'; import NonKeyserverActivityHandler from './components/non-keyserver-activity-handler.react.js'; import { NUXTipsContextProvider } from './components/nux-tips-context.react.js'; @@ -322,6 +323,7 @@ ); + let navigation; if (initialState) { navigation = ( @@ -423,6 +425,7 @@ + diff --git a/web/app.react.js b/web/app.react.js --- a/web/app.react.js +++ b/web/app.react.js @@ -66,6 +66,7 @@ import { MemberListSidebarProvider } from './chat/member-list-sidebar/member-list-sidebar-provider.react.js'; import { AutoJoinCommunityHandler } from './components/auto-join-community-handler.react.js'; import CommunitiesRefresher from './components/communities-refresher.react.js'; +import FarcasterSyncOverlay from './components/farcaster-sync-overlay.react.js'; import LogOutIfMissingCSATHandler from './components/log-out-if-missing-csat-handler.react.js'; import NavigationArrows from './components/navigation-arrows.react.js'; import NonKeyserverActivityHandler from './components/non-keyserver-activity-handler.react.js'; @@ -228,16 +229,18 @@ if (this.props.loggedIn) { content = ( <> - - - - - {this.renderMainContent()} - {this.props.modals} - - - - + + + + + + {this.renderMainContent()} + {this.props.modals} + + + + + ); } else { diff --git a/web/components/farcaster-sync-overlay.react.js b/web/components/farcaster-sync-overlay.react.js new file mode 100644 --- /dev/null +++ b/web/components/farcaster-sync-overlay.react.js @@ -0,0 +1,46 @@ +// @flow + +import * as React from 'react'; + +import { + useCurrentUserSupportsDCs, + useFarcasterDCsLoaded, +} from 'lib/utils/farcaster-utils.js'; + +import FarcasterSyncLoadingScreen from '../farcaster/farcaster-sync-loading-screen.react.js'; + +type Props = { + +children: React.Node, +}; + +function FarcasterSyncOverlay(props: Props): React.Node { + const { children } = props; + const farcasterDCsLoaded = useFarcasterDCsLoaded(); + const currentUserSupportsDCs = useCurrentUserSupportsDCs(); + + const isFullSyncInProgress = + currentUserSupportsDCs && farcasterDCsLoaded === false; + + const style = React.useMemo(() => { + if (!isFullSyncInProgress) { + return {}; + } + return { opacity: 0 }; + }, [isFullSyncInProgress]); + + const loadingScreen = React.useMemo(() => { + if (!isFullSyncInProgress) { + return null; + } + return ; + }, [isFullSyncInProgress]); + + return ( + <> +
{children}
+ {loadingScreen} + + ); +} + +export default FarcasterSyncOverlay; diff --git a/web/farcaster/farcaster-sync-loading-screen.css b/web/farcaster/farcaster-sync-loading-screen.css new file mode 100644 --- /dev/null +++ b/web/farcaster/farcaster-sync-loading-screen.css @@ -0,0 +1,66 @@ +div.loadingContainer { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(0, 0, 0, 0.5); + z-index: 10000; +} + +div.loading { + width: 380px; + min-height: 438px; + background: var(--auth-modal-bg); + border: var(--auth-modal-border-color) solid 1px; + border-radius: 12px; + display: flex; + justify-content: center; + padding: 19px 17px; + box-sizing: border-box; +} + +div.innerLoading { + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + gap: 32px; +} + +div.content { + text-align: left; + width: 100%; +} + +h2.header { + font-size: var(--xl-font-20); + font-weight: 700; + color: var(--fg); + margin: 0; + line-height: var(--line-height-display); +} + +p.description { + font-size: var(--s-font-14); + line-height: var(--line-height-text); + color: var(--fg); + margin: 5px 0; + font-weight: var(--normal); +} + +div.separator { + width: 100%; + height: 1px; + background: var(--border); + margin: 8px 0; +} + +div.spinner { + display: flex; + justify-content: center; + margin: auto; +} diff --git a/web/farcaster/farcaster-sync-loading-screen.react.js b/web/farcaster/farcaster-sync-loading-screen.react.js new file mode 100644 --- /dev/null +++ b/web/farcaster/farcaster-sync-loading-screen.react.js @@ -0,0 +1,37 @@ +// @flow + +import * as React from 'react'; + +import { useFarcasterSync } from 'lib/shared/farcaster/farcaster-hooks.js'; + +import css from './farcaster-sync-loading-screen.css'; +import LoadingIndicator from '../loading-indicator.react.js'; + +function FarcasterSyncLoadingScreen(): React.Node { + useFarcasterSync(); + + return ( +
+
+
+
+

Fetching Farcaster threads

+
+

+ We’re fetching all your Farcaster threads and messages. +

+

+ This could take a while depending on how many conversations you + have. +

+
+
+ +
+
+
+
+ ); +} + +export default FarcasterSyncLoadingScreen; diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js --- a/web/settings/account-settings.react.js +++ b/web/settings/account-settings.react.js @@ -182,10 +182,10 @@ [pushModal], ); - const farcasterConversationsSync = useFarcasterConversationsSync(); + const syncFarcasterConversations = useFarcasterConversationsSync(); const syncConversations = React.useCallback(() => { - return farcasterConversationsSync(Number.POSITIVE_INFINITY); - }, [farcasterConversationsSync]); + return syncFarcasterConversations(Number.POSITIVE_INFINITY); + }, [syncFarcasterConversations]); if (!currentUserInfo || currentUserInfo.anonymous) { return null;