[SDK] Migrate the notifications cluster to the lex clients (#11362)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-08-13 22:26:17 +03:00
committed by GitHub
parent 6f696e4b73
commit f5c166a055
8 changed files with 94 additions and 74 deletions
@@ -2,10 +2,10 @@ import {useMemo, useState} from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import { import {
type AppBskyNotificationDefs, type AppBskyNotificationDefs,
type AppBskyNotificationListActivitySubscriptions,
type ModerationOpts, type ModerationOpts,
type Un$Typed, type Un$Typed,
} from '@atproto/api' } from '@atproto/api'
import {type DidString} from '@atproto/syntax'
import {msg} from '@lingui/core/macro' import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro' import {Trans} from '@lingui/react/macro'
@@ -20,7 +20,7 @@ import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles' import {sanitizeHandle} from '#/lib/strings/handles'
import {updateProfileShadow} from '#/state/cache/profile-shadow' import {updateProfileShadow} from '#/state/cache/profile-shadow'
import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions' import {RQKEY_getActivitySubscriptions} from '#/state/queries/activity-subscriptions'
import {useAgent} from '#/state/session' import {useAppviewClient} from '#/state/session'
import {atoms as a, platform, useTheme, web} from '#/alf' import {atoms as a, platform, useTheme, web} from '#/alf'
import {Admonition} from '#/components/Admonition' import {Admonition} from '#/components/Admonition'
import { import {
@@ -37,6 +37,7 @@ import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics' import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env' import {IS_WEB} from '#/env'
import {app} from '#/lexicons'
import type * as bsky from '#/types/bsky' import type * as bsky from '#/types/bsky'
export function SubscribeProfileDialog({ export function SubscribeProfileDialog({
@@ -74,7 +75,7 @@ function DialogInner({
const ax = useAnalytics() const ax = useAnalytics()
const {_} = useLingui() const {_} = useLingui()
const t = useTheme() const t = useTheme()
const agent = useAgent() const client = useAppviewClient()
const control = Dialog.useDialogContext() const control = Dialog.useDialogContext()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const initialState = parseActivitySubscription( const initialState = parseActivitySubscription(
@@ -122,8 +123,9 @@ function DialogInner({
mutationFn: async ( mutationFn: async (
activitySubscription: Un$Typed<AppBskyNotificationDefs.ActivitySubscription>, activitySubscription: Un$Typed<AppBskyNotificationDefs.ActivitySubscription>,
) => { ) => {
await agent.app.bsky.notification.putActivitySubscription({ await client.call(app.bsky.notification.putActivitySubscription, {
subject: profile.did, // the profile view carries an already-resolved did
subject: profile.did as DidString,
activitySubscription, activitySubscription,
}) })
}, },
@@ -148,7 +150,7 @@ function DialogInner({
queryClient.setQueryData( queryClient.setQueryData(
RQKEY_getActivitySubscriptions, RQKEY_getActivitySubscriptions,
( (
old?: InfiniteData<AppBskyNotificationListActivitySubscriptions.OutputSchema>, old?: InfiniteData<app.bsky.notification.listActivitySubscriptions.$OutputBody>,
) => { ) => {
if (!old) return old if (!old) return old
return { return {
+10 -5
View File
@@ -5,9 +5,11 @@ import {
useEffect, useEffect,
useState, useState,
} from 'react' } from 'react'
import {type AtUriString} from '@atproto/syntax'
import * as persisted from '#/state/persisted' import * as persisted from '#/state/persisted'
import {useAgent, useSession} from '../session' import {app} from '#/lexicons'
import {useAppviewClient, useSession} from '../session'
type StateContext = Map<string, boolean> type StateContext = Map<string, boolean>
type SetStateContext = (uri: string, value: boolean) => void type SetStateContext = (uri: string, value: boolean) => void
@@ -56,7 +58,7 @@ export function useSetThreadMute() {
} }
function useMigrateMutes(setThreadMute: SetStateContext) { function useMigrateMutes(setThreadMute: SetStateContext) {
const agent = useAgent() const client = useAppviewClient()
const {currentAccount} = useSession() const {currentAccount} = useSession()
useEffect(() => { useEffect(() => {
@@ -87,8 +89,11 @@ function useMigrateMutes(setThreadMute: SetStateContext) {
setThreadMute(root, true) setThreadMute(root, true)
await agent.api.app.bsky.graph await client
.muteThread({root}) .call(app.bsky.graph.muteThread, {
// the persisted list only ever holds post at-uris
root: root as AtUriString,
})
// not a big deal if this fails, since the post might have been deleted // not a big deal if this fails, since the post might have been deleted
.catch(console.error) .catch(console.error)
} }
@@ -100,5 +105,5 @@ function useMigrateMutes(setThreadMute: SetStateContext) {
cancelled = true cancelled = true
} }
} }
}, [agent, currentAccount, setThreadMute]) }, [client, currentAccount, setThreadMute])
} }
+8 -9
View File
@@ -1,7 +1,6 @@
import { import {
type AppBskyActorDefs, type AppBskyActorDefs,
type AppBskyNotificationDeclaration, type AppBskyNotificationDeclaration,
type AppBskyNotificationListActivitySubscriptions,
} from '@atproto/api' } from '@atproto/api'
import {t} from '@lingui/core/macro' import {t} from '@lingui/core/macro'
import { import {
@@ -13,23 +12,23 @@ import {
useQueryClient, useQueryClient,
} from '@tanstack/react-query' } from '@tanstack/react-query'
import {useAgent, useSession} from '#/state/session' import {useAgent, useAppviewClient, useSession} from '#/state/session'
import * as Toast from '#/components/Toast' import * as Toast from '#/components/Toast'
import {app} from '#/lexicons'
export const RQKEY_getActivitySubscriptions = ['activity-subscriptions'] export const RQKEY_getActivitySubscriptions = ['activity-subscriptions']
export const RQKEY_getNotificationDeclaration = ['notification-declaration'] export const RQKEY_getNotificationDeclaration = ['notification-declaration']
export function useActivitySubscriptionsQuery() { export function useActivitySubscriptionsQuery() {
const agent = useAgent() const client = useAppviewClient()
return useInfiniteQuery({ return useInfiniteQuery({
queryKey: RQKEY_getActivitySubscriptions, queryKey: RQKEY_getActivitySubscriptions,
queryFn: async ({pageParam}) => { queryFn: async ({pageParam}) => {
const response = return await client.call(
await agent.app.bsky.notification.listActivitySubscriptions({ app.bsky.notification.listActivitySubscriptions,
cursor: pageParam, {cursor: pageParam},
}) )
return response.data
}, },
initialPageParam: undefined as string | undefined, initialPageParam: undefined as string | undefined,
getNextPageParam: prev => prev.cursor, getNextPageParam: prev => prev.cursor,
@@ -111,7 +110,7 @@ export function* findAllProfilesInQueryData(
did: string, did: string,
): Generator<AppBskyActorDefs.ProfileView, void> { ): Generator<AppBskyActorDefs.ProfileView, void> {
const queryDatas = queryClient.getQueriesData< const queryDatas = queryClient.getQueriesData<
InfiniteData<AppBskyNotificationListActivitySubscriptions.OutputSchema> InfiniteData<app.bsky.notification.listActivitySubscriptions.$OutputBody>
>({ >({
queryKey: RQKEY_getActivitySubscriptions, queryKey: RQKEY_getActivitySubscriptions,
}) })
+3 -3
View File
@@ -33,7 +33,7 @@ import {
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {STALE} from '#/state/queries' import {STALE} from '#/state/queries'
import {useAgent} from '#/state/session' import {useAppviewClient} from '#/state/session'
import {useThreadgateHiddenReplyUris} from '#/state/threadgate-hidden-replies' import {useThreadgateHiddenReplyUris} from '#/state/threadgate-hidden-replies'
import type * as bsky from '#/types/bsky' import type * as bsky from '#/types/bsky'
import { import {
@@ -60,7 +60,7 @@ export function useNotificationFeedQuery(opts: {
enabled?: boolean enabled?: boolean
filter: 'all' | 'mentions' filter: 'all' | 'mentions'
}) { }) {
const agent = useAgent() const client = useAppviewClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
const unreads = useUnreadNotificationsApi() const unreads = useUnreadNotificationsApi()
@@ -106,7 +106,7 @@ export function useNotificationFeedQuery(opts: {
] ]
} }
const {page: fetchedPage} = await fetchPage({ const {page: fetchedPage} = await fetchPage({
agent, client,
limit: PAGE_SIZE, limit: PAGE_SIZE,
cursor: pageParam, cursor: pageParam,
queryClient, queryClient,
+19 -16
View File
@@ -10,10 +10,10 @@ import {
useQueryClient, useQueryClient,
} from '@tanstack/react-query' } from '@tanstack/react-query'
import {DM_SERVICE_HEADERS} from '#/lib/constants'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAgent} from '#/state/session' import {useAppviewClient, useChatClient} from '#/state/session'
import * as Toast from '#/components/Toast' import * as Toast from '#/components/Toast'
import {app, chat} from '#/lexicons'
const RQKEY_ROOT = 'notification-settings' const RQKEY_ROOT = 'notification-settings'
const RQKEY_APP = [RQKEY_ROOT, 'app'] const RQKEY_APP = [RQKEY_ROOT, 'app']
@@ -67,13 +67,13 @@ type ChatNotificationSettingsUpdate =
export function useNotificationSettingsQuery({ export function useNotificationSettingsQuery({
enabled, enabled,
}: {enabled?: boolean} = {}) { }: {enabled?: boolean} = {}) {
const agent = useAgent() const client = useAppviewClient()
return useQuery({ return useQuery({
queryKey: RQKEY_APP, queryKey: RQKEY_APP,
queryFn: async (): Promise<AppNotificationSettingsPreferences> => { queryFn: async (): Promise<AppNotificationSettingsPreferences> => {
const res = await agent.app.bsky.notification.getPreferences() const data = await client.call(app.bsky.notification.getPreferences)
return appPreferencesWithoutChat(res.data.preferences) return appPreferencesWithoutChat(data.preferences)
}, },
enabled, enabled,
}) })
@@ -82,21 +82,24 @@ export function useNotificationSettingsQuery({
export function useChatNotificationSettingsQuery({ export function useChatNotificationSettingsQuery({
enabled, enabled,
}: {enabled?: boolean} = {}) { }: {enabled?: boolean} = {}) {
const agent = useAgent() const client = useChatClient()
return useQuery({ return useQuery({
queryKey: RQKEY_CHAT, queryKey: RQKEY_CHAT,
queryFn: async (): Promise<ChatNotificationSettingsPreferences> => { queryFn: async (): Promise<ChatNotificationSettingsPreferences> => {
const res = await agent.chat.bsky.notification.getPreferences(undefined, { const data = await client.call(chat.bsky.notification.getPreferences)
headers: DM_SERVICE_HEADERS, return chatPreferencesForSettings(data.preferences)
})
return chatPreferencesForSettings(res.data.preferences)
}, },
enabled, enabled,
}) })
} }
export function useNotificationSettingsUpdateMutation() { export function useNotificationSettingsUpdateMutation() {
const agent = useAgent() /*
* App preferences live on the appview and chat preferences on the chat
* service, so a combined update fans out over both clients.
*/
const appviewClient = useAppviewClient()
const chatClient = useChatClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
return useMutation({ return useMutation({
@@ -104,13 +107,13 @@ export function useNotificationSettingsUpdateMutation() {
const {appUpdate, chatUpdate} = splitNotificationSettingsUpdate(update) const {appUpdate, chatUpdate} = splitNotificationSettingsUpdate(update)
await Promise.all([ await Promise.all([
hasUpdates(appUpdate) hasUpdates(appUpdate)
? agent.app.bsky.notification.putPreferencesV2(appUpdate) ? appviewClient.call(
app.bsky.notification.putPreferencesV2,
appUpdate,
)
: undefined, : undefined,
hasUpdates(chatUpdate) hasUpdates(chatUpdate)
? agent.chat.bsky.notification.putPreferences(chatUpdate, { ? chatClient.call(chat.bsky.notification.putPreferences, chatUpdate)
headers: DM_SERVICE_HEADERS,
encoding: 'application/json',
})
: undefined, : undefined,
]) ])
}, },
+11 -8
View File
@@ -11,6 +11,7 @@ import {
useState, useState,
} from 'react' } from 'react'
import {AppState} from 'react-native' import {AppState} from 'react-native'
import {type ISODatetimeString} from '@atproto/syntax'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {EventEmitter} from 'eventemitter3' import {EventEmitter} from 'eventemitter3'
@@ -18,7 +19,8 @@ import BroadcastChannel from '#/lib/broadcast'
import {resetBadgeCount} from '#/lib/notifications/notifications' import {resetBadgeCount} from '#/lib/notifications/notifications'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {truncateAndInvalidate} from '#/state/queries/util' import {truncateAndInvalidate} from '#/state/queries/util'
import {useAgent, useSession} from '#/state/session' import {useAppviewClient, useSession} from '#/state/session'
import {app} from '#/lexicons'
import {RQKEY as RQKEY_NOTIFS} from './feed' import {RQKEY as RQKEY_NOTIFS} from './feed'
import {type CachedFeedPage, type FeedPage} from './types' import {type CachedFeedPage, type FeedPage} from './types'
import {fetchPage} from './util' import {fetchPage} from './util'
@@ -52,7 +54,7 @@ apiContext.displayName = 'NotificationsUnreadApiContext'
export function Provider({children}: React.PropsWithChildren<{}>) { export function Provider({children}: React.PropsWithChildren<{}>) {
const {hasSession} = useSession() const {hasSession} = useSession()
const agent = useAgent() const client = useAppviewClient()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const moderationOpts = useModerationOpts() const moderationOpts = useModerationOpts()
@@ -120,9 +122,10 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
return { return {
async markAllRead() { async markAllRead() {
// update server // update server
await agent.updateSeenNotifications( await client.call(app.bsky.notification.updateSeen, {
cacheRef.current.syncedAt.toISOString(), // toISOString always emits the Z-suffixed form the format requires
) seenAt: cacheRef.current.syncedAt.toISOString() as ISODatetimeString,
})
// update & broadcast // update & broadcast
setNumUnread('') setNumUnread('')
@@ -135,7 +138,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
isPoll, isPoll,
}: {invalidate?: boolean; isPoll?: boolean} = {}) { }: {invalidate?: boolean; isPoll?: boolean} = {}) {
try { try {
if (!agent.session) return if (!hasSession) return
if (AppState.currentState !== 'active') { if (AppState.currentState !== 'active') {
return return
} }
@@ -156,7 +159,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
// count // count
const {page, indexedAt: lastIndexed} = await fetchPage({ const {page, indexedAt: lastIndexed} = await fetchPage({
agent, client,
cursor: undefined, cursor: undefined,
limit: 40, limit: 40,
queryClient, queryClient,
@@ -207,7 +210,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
} }
}, },
} }
}, [setNumUnread, queryClient, moderationOpts, agent]) }, [setNumUnread, queryClient, moderationOpts, client, hasSession])
checkUnreadRef.current = api.checkUnread checkUnreadRef.current = api.checkUnread
return ( return (
+23 -17
View File
@@ -6,15 +6,17 @@ import {
type AppBskyGraphDefs, type AppBskyGraphDefs,
AppBskyGraphStarterpack, AppBskyGraphStarterpack,
type AppBskyNotificationListNotifications, type AppBskyNotificationListNotifications,
type AtpAgent,
hasMutedWord, hasMutedWord,
moderateNotification, moderateNotification,
type ModerationOpts, type ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
import {type Client} from '@atproto/lex'
import {type AtUriString} from '@atproto/syntax'
import {type QueryClient} from '@tanstack/react-query' import {type QueryClient} from '@tanstack/react-query'
import chunk from 'lodash.chunk' import chunk from 'lodash.chunk'
import {labelIsHideableOffense} from '#/lib/moderation' import {labelIsHideableOffense} from '#/lib/moderation'
import {app} from '#/lexicons'
import * as bsky from '#/types/bsky' import * as bsky from '#/types/bsky'
import {precacheProfile} from '../profile' import {precacheProfile} from '../profile'
import { import {
@@ -38,7 +40,7 @@ const MS_2DAY = MS_1HR * 48
// = // =
export async function fetchPage({ export async function fetchPage({
agent, client,
cursor, cursor,
limit, limit,
queryClient, queryClient,
@@ -46,7 +48,7 @@ export async function fetchPage({
fetchAdditionalData, fetchAdditionalData,
reasons, reasons,
}: { }: {
agent: AtpAgent client: Client
cursor: string | undefined cursor: string | undefined
limit: number limit: number
queryClient: QueryClient queryClient: QueryClient
@@ -57,16 +59,16 @@ export async function fetchPage({
page: FeedPage page: FeedPage
indexedAt: string | undefined indexedAt: string | undefined
}> { }> {
const res = await agent.listNotifications({ const data = await client.call(app.bsky.notification.listNotifications, {
limit, limit,
cursor, cursor,
reasons, reasons,
}) })
const indexedAt = res.data.notifications[0]?.indexedAt const indexedAt = data.notifications[0]?.indexedAt
// filter out notifs by mod rules // filter out notifs by mod rules
const notifs = res.data.notifications.filter( const notifs = data.notifications.filter(
notif => !shouldFilterNotif(notif, moderationOpts), notif => !shouldFilterNotif(notif, moderationOpts),
) )
@@ -76,7 +78,7 @@ export async function fetchPage({
// we fetch subjects of notifications (usually posts) now instead of lazily // we fetch subjects of notifications (usually posts) now instead of lazily
// in the UI to avoid relayouts // in the UI to avoid relayouts
if (fetchAdditionalData) { if (fetchAdditionalData) {
const subjects = await fetchSubjects(agent, notifsGrouped) const subjects = await fetchSubjects(client, notifsGrouped)
for (const notif of notifsGrouped) { for (const notif of notifsGrouped) {
if (notif.subjectUri) { if (notif.subjectUri) {
if ( if (
@@ -96,17 +98,17 @@ export async function fetchPage({
} }
} }
let seenAt = res.data.seenAt ? new Date(res.data.seenAt) : new Date() let seenAt = data.seenAt ? new Date(data.seenAt) : new Date()
if (Number.isNaN(seenAt.getTime())) { if (Number.isNaN(seenAt.getTime())) {
seenAt = new Date() seenAt = new Date()
} }
return { return {
page: { page: {
cursor: res.data.cursor, cursor: data.cursor,
seenAt, seenAt,
items: notifsGrouped, items: notifsGrouped,
priority: res.data.priority ?? false, priority: data.priority ?? false,
}, },
indexedAt, indexedAt,
} }
@@ -207,7 +209,7 @@ export function groupNotifications(
} }
async function fetchSubjects( async function fetchSubjects(
agent: AtpAgent, client: Client,
groupedNotifs: FeedNotification[], groupedNotifs: FeedNotification[],
): Promise<{ ): Promise<{
posts: Map<string, AppBskyFeedDefs.PostView> posts: Map<string, AppBskyFeedDefs.PostView>
@@ -224,18 +226,22 @@ async function fetchSubjects(
packUris.add(notif.notification.reasonSubject) packUris.add(notif.notification.reasonSubject)
} }
} }
const postUriChunks = chunk(Array.from(postUris), 25) /*
const packUriChunks = chunk(Array.from(packUris), 25) * Both uri sets are collected from notification fields the server already
* validated as at-uris, so the branded cast reflects what the values are.
*/
const postUriChunks = chunk(Array.from(postUris) as AtUriString[], 25)
const packUriChunks = chunk(Array.from(packUris) as AtUriString[], 25)
const postsChunks = await Promise.all( const postsChunks = await Promise.all(
postUriChunks.map(uris => postUriChunks.map(uris =>
agent.app.bsky.feed.getPosts({uris}).then(res => res.data.posts), client.call(app.bsky.feed.getPosts, {uris}).then(data => data.posts),
), ),
) )
const packsChunks = await Promise.all( const packsChunks = await Promise.all(
packUriChunks.map(uris => packUriChunks.map(uris =>
agent.app.bsky.graph client
.getStarterPacks({uris}) .call(app.bsky.graph.getStarterPacks, {uris})
.then(res => res.data.starterPacks), .then(data => data.starterPacks),
), ),
) )
const postsMap = new Map<string, AppBskyFeedDefs.PostView>() const postsMap = new Map<string, AppBskyFeedDefs.PostView>()
@@ -21,12 +21,13 @@ import {
type ModerationOpts, type ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
import {TID} from '@atproto/common-web' import {TID} from '@atproto/common-web'
import {type DidString} from '@atproto/syntax'
import {plural} from '@lingui/core/macro' import {plural} from '@lingui/core/macro'
import {Plural, Trans, useLingui} from '@lingui/react/macro' import {Plural, Trans, useLingui} from '@lingui/react/macro'
import {useNavigation} from '@react-navigation/native' import {useNavigation} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query' import {useQueryClient} from '@tanstack/react-query'
import {DM_SERVICE_HEADERS, MAX_POST_LINES} from '#/lib/constants' import {MAX_POST_LINES} from '#/lib/constants'
import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue' import {useAnimatedValue} from '#/lib/hooks/useAnimatedValue'
import {makeProfileLink} from '#/lib/routes/links' import {makeProfileLink} from '#/lib/routes/links'
import {type NavigationProp} from '#/lib/routes/types' import {type NavigationProp} from '#/lib/routes/types'
@@ -38,7 +39,7 @@ import {useProfileShadow} from '#/state/cache/profile-shadow'
import {type FeedNotification} from '#/state/queries/notifications/feed' import {type FeedNotification} from '#/state/queries/notifications/feed'
import {useProfileFollowMutationQueue} from '#/state/queries/profile' import {useProfileFollowMutationQueue} from '#/state/queries/profile'
import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache' import {unstableCacheProfileView} from '#/state/queries/unstable-profile-cache'
import {useAgent, useSession} from '#/state/session' import {useChatClient, useSession} from '#/state/session'
import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard' import {FeedSourceCard} from '#/view/com/feeds/FeedSourceCard'
import {Post} from '#/view/com/post/Post' import {Post} from '#/view/com/post/Post'
import {formatCount} from '#/view/com/util/numeric/format' import {formatCount} from '#/view/com/util/numeric/format'
@@ -73,6 +74,7 @@ import * as Toast from '#/components/Toast'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {useAnalytics} from '#/analytics' import {useAnalytics} from '#/analytics'
import {IS_WEB} from '#/env' import {IS_WEB} from '#/env'
import {chat} from '#/lexicons'
import * as bsky from '#/types/bsky' import * as bsky from '#/types/bsky'
const MAX_AUTHORS = 5 const MAX_AUTHORS = 5
@@ -911,21 +913,21 @@ function FollowBackButton({profile}: {profile: AppBskyActorDefs.ProfileView}) {
function SayHelloBtn({profile}: {profile: AppBskyActorDefs.ProfileView}) { function SayHelloBtn({profile}: {profile: AppBskyActorDefs.ProfileView}) {
const {t: l} = useLingui() const {t: l} = useLingui()
const agent = useAgent() const client = useChatClient()
const {currentAccount} = useSession()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const onPress = async () => { const onPress = async () => {
try { try {
setIsLoading(true) setIsLoading(true)
const res = await agent.api.chat.bsky.convo.getConvoForMembers( const data = await client.call(chat.bsky.convo.getConvoForMembers, {
{ // both dids are already resolved - one from the profile view, one from
members: [profile.did, agent.session!.did], // the active session
}, members: [profile.did, currentAccount!.did] as DidString[],
{headers: DM_SERVICE_HEADERS}, })
)
navigation.navigate('MessagesConversation', { navigation.navigate('MessagesConversation', {
conversation: res.data.convo.id, conversation: data.convo.id,
}) })
} catch (e) { } catch (e) {
logger.error('Failed to get conversation', {safeMessage: e}) logger.error('Failed to get conversation', {safeMessage: e})