Page MenuHomePhorge

D15204.1765070705.diff
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

D15204.1765070705.diff

diff --git a/lib/shared/farcaster/farcaster-hooks.js b/lib/shared/farcaster/farcaster-hooks.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/farcaster/farcaster-hooks.js
@@ -0,0 +1,128 @@
+// @flow
+
+import * as React from 'react';
+
+import {
+ type FetchFarcasterConversationResult,
+ useFetchFarcasterConversation,
+ useFetchFarcasterInbox,
+ type FetchFarcasterMessageResult,
+ useFetchFarcasterMessage,
+ useSendFarcasterTextMessage,
+} from './farcaster-api.js';
+import type { FarcasterConversation } from './farcaster-conversation-types.js';
+import type { FarcasterMessage } from './farcaster-messages-types.js';
+import { useDispatch } from '../../utils/redux-utils.js';
+import { useSendDMOperationUtils } from '../dm-ops/dm-op-utils.js';
+
+function useFarcasterConversationsSync(): () => Promise<void> {
+ const [fullInbox, setFullInbox] = React.useState(false);
+ const [conversations, setConversations] = React.useState<
+ $ReadOnlyArray<string>,
+ >([]);
+
+ const fetchFarcasterInbox = useFetchFarcasterInbox();
+ const fetchFarcasterConversation = useFetchFarcasterConversation();
+ const fetchFarcasterMessage = useFetchFarcasterMessage();
+ const sendFarcasterTextMessage = useSendFarcasterTextMessage();
+ const dispatch = useDispatch();
+ const utils = useSendDMOperationUtils();
+
+ const fetchInboxes: (cursor: ?string) => Promise<void> = React.useCallback(
+ async (cursor: ?string) => {
+ try {
+ let input = { limit: 20 };
+ if (cursor) {
+ input = {
+ ...input,
+ cursor,
+ };
+ }
+ const { result, next } = await fetchFarcasterInbox(input);
+ setConversations(prev => {
+ const ids = result.conversations.map(
+ conversation => conversation.conversationId,
+ );
+ return [...prev, ...ids];
+ });
+ if (next?.cursor) {
+ void fetchInboxes(next.cursor);
+ } else {
+ setFullInbox(true);
+ }
+ } catch (e) {
+ console.error('Error fetching inbox', e);
+ setFullInbox(true);
+ }
+ },
+ [fetchFarcasterInbox],
+ );
+
+ React.useEffect(() => {
+ if (!fullInbox || conversations.length === 0) {
+ return;
+ }
+
+ void (async () => {
+ const conversationPromises: $ReadOnlyArray<
+ Promise<?FetchFarcasterConversationResult>,
+ > = conversations.map(async conversationId => {
+ try {
+ return await fetchFarcasterConversation({ conversationId });
+ } catch (e) {
+ console.error(`Failed fetching conversation ${conversationId}:`, e);
+ return null;
+ }
+ });
+
+ const farcasterConversationsResults: $ReadOnlyArray<?FetchFarcasterConversationResult> =
+ await Promise.all(conversationPromises);
+
+ const farcasterConversations: $ReadOnlyArray<FarcasterConversation> =
+ farcasterConversationsResults
+ .filter(Boolean)
+ .map(conversationResult => conversationResult.result.conversation);
+
+ console.log('Farcaster conversations:', farcasterConversations);
+
+ const messagePromises: $ReadOnlyArray<
+ Promise<?FetchFarcasterMessageResult>,
+ > = farcasterConversations.map(async ({ conversationId }) => {
+ try {
+ return await fetchFarcasterMessage({ conversationId, limit: 30 });
+ } catch (e) {
+ console.error(`Failed fetching messages for ${conversationId}:`, e);
+ return null;
+ }
+ });
+
+ const farcasterMessagesResult: $ReadOnlyArray<?FetchFarcasterMessageResult> =
+ await Promise.all(messagePromises);
+
+ const farcasterMessages: $ReadOnlyArray<FarcasterMessage> =
+ farcasterMessagesResult
+ .filter(Boolean)
+ .flatMap(messagesResult => messagesResult.result.messages);
+
+ console.log('Farcaster messages:', farcasterMessages);
+
+ //TODO: dispatch threads and messages
+ setConversations([]);
+ })();
+ }, [
+ conversations,
+ dispatch,
+ fetchFarcasterConversation,
+ fetchFarcasterMessage,
+ fullInbox,
+ sendFarcasterTextMessage,
+ utils,
+ ]);
+
+ return React.useCallback(async () => {
+ setFullInbox(false);
+ void fetchInboxes(null);
+ }, [fetchInboxes]);
+}
+
+export { useFarcasterConversationsSync };
diff --git a/native/profile/profile-screen.react.js b/native/profile/profile-screen.react.js
--- a/native/profile/profile-screen.react.js
+++ b/native/profile/profile-screen.react.js
@@ -20,6 +20,7 @@
dmOperationSpecificationTypes,
} from 'lib/shared/dm-ops/dm-op-types.js';
import { useProcessAndSendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js';
+import { useFarcasterConversationsSync } from 'lib/shared/farcaster/farcaster-hooks.js';
import type { LogOutResult } from 'lib/types/account-types.js';
import type { DMCreateThreadOperation } from 'lib/types/dm-ops';
import { thickThreadTypes } from 'lib/types/thread-types-enum.js';
@@ -29,7 +30,10 @@
useDispatchActionPromise,
type DispatchActionPromise,
} from 'lib/utils/redux-promise-utils.js';
-import { useIsRestoreFlowEnabled } from 'lib/utils/services-utils.js';
+import {
+ supportsFarcasterDCs,
+ useIsRestoreFlowEnabled,
+} from 'lib/utils/services-utils.js';
import type { ProfileNavigationProp } from './profile.react.js';
import { deleteNativeCredentialsFor } from '../account/native-credentials.js';
@@ -182,6 +186,7 @@
+onCreateDMThread: () => Promise<void>,
+currentUserFID: ?string,
+usingRestoreFlow: boolean,
+ +farcasterConversationsSync: () => Promise<void>,
};
class ProfileScreen extends React.PureComponent<Props> {
@@ -279,6 +284,17 @@
</>
);
}
+ let farcaster;
+ if (staffCanSee && supportsFarcasterDCs) {
+ farcaster = (
+ <>
+ <ProfileRow
+ content="Farcaster DCs integration sync"
+ onPress={this.onPressFarcasterConversationsSync}
+ />
+ </>
+ );
+ }
return (
<View style={this.props.styles.container}>
@@ -338,6 +354,7 @@
<ProfileRow content="Build info" onPress={this.onPressBuildInfo} />
{developerTools}
{dmActions}
+ {farcaster}
{debugLogs}
</View>
<View style={this.props.styles.unpaddedSection}>
@@ -544,6 +561,10 @@
void this.props.onCreateDMThread();
};
+ onPressFarcasterConversationsSync = () => {
+ void this.props.farcasterConversationsSync();
+ };
+
onPressDebugLogs = () => {
this.props.navigation.navigate({ name: DebugLogsScreenRouteName });
};
@@ -616,6 +637,7 @@
}, [checkIfPrimaryDevice]);
const usingRestoreFlow = useIsRestoreFlowEnabled();
+ const farcasterConversationsSync = useFarcasterConversationsSync();
return (
<ProfileScreen
@@ -635,6 +657,7 @@
onCreateDMThread={onCreateDMThread}
currentUserFID={currentUserID}
usingRestoreFlow={usingRestoreFlow}
+ farcasterConversationsSync={farcasterConversationsSync}
/>
);
});
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
@@ -18,6 +18,7 @@
type OutboundDMOperationSpecification,
} from 'lib/shared/dm-ops/dm-op-types.js';
import { useProcessAndSendDMOperation } from 'lib/shared/dm-ops/process-dm-ops.js';
+import { useFarcasterConversationsSync } from 'lib/shared/farcaster/farcaster-hooks.js';
import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
import { useTunnelbroker } from 'lib/tunnelbroker/tunnelbroker-context.js';
import type { DMCreateThreadOperation } from 'lib/types/dm-ops.js';
@@ -27,7 +28,10 @@
getContentSigningKey,
} from 'lib/utils/crypto-utils.js';
import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
-import { useIsRestoreFlowEnabled } from 'lib/utils/services-utils.js';
+import {
+ supportsFarcasterDCs,
+ useIsRestoreFlowEnabled,
+} from 'lib/utils/services-utils.js';
import css from './account-settings.css';
import AppearanceChangeModal from './appearance-change-modal.react.js';
@@ -178,6 +182,8 @@
[pushModal],
);
+ const farcasterConversationsSync = useFarcasterConversationsSync();
+
if (!currentUserInfo || currentUserInfo.anonymous) {
return null;
}
@@ -276,6 +282,25 @@
);
}
+ let farcaster;
+ if (staffCanSee && supportsFarcasterDCs) {
+ farcaster = (
+ <div className={css.preferencesContainer}>
+ <h4 className={css.preferencesHeader}>Farcaster menu</h4>
+ <div className={css.content}>
+ <ul>
+ <li>
+ <span>Farcaster DCs integration</span>
+ <Button variant="text" onClick={farcasterConversationsSync}>
+ <p className={css.buttonText}>Sync</p>
+ </Button>
+ </li>
+ </ul>
+ </div>
+ </div>
+ );
+ }
+
let debugLogs;
if (staffCanSee) {
debugLogs = (
@@ -329,6 +354,7 @@
{tunnelbroker}
{deviceData}
{dms}
+ {farcaster}
{debugLogs}
</div>
</div>

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 7, 1:25 AM (6 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5841946
Default Alt Text
D15204.1765070705.diff (9 KB)

Event Timeline