diff --git a/src/components/dms/MessagesListPendingAcceptFooter.tsx b/src/components/dms/MessagesListPendingAcceptFooter.tsx
new file mode 100644
index 0000000000..7b1a133a6e
--- /dev/null
+++ b/src/components/dms/MessagesListPendingAcceptFooter.tsx
@@ -0,0 +1,75 @@
+import {View} from 'react-native'
+import {AppBskyActorDefs} from '@atproto/api'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {atoms as a, useTheme} from '#/alf'
+import {Button, ButtonText} from '#/components/Button'
+import {useDialogControl} from '#/components/Dialog'
+import {Divider} from '#/components/Divider'
+import {LeaveConvoPrompt} from '#/components/dms/LeaveConvoPrompt'
+import {ReportConversationPrompt} from '#/components/dms/ReportConversationPrompt'
+import {Text} from '#/components/Typography'
+
+export function MessagesListPendingAcceptFooter({
+ // recipient: initialRecipient,
+ convoId,
+ hasMessages,
+}: {
+ recipient: AppBskyActorDefs.ProfileViewBasic
+ convoId: string
+ hasMessages: boolean
+}) {
+ const t = useTheme()
+ const {_} = useLingui()
+ // const recipient = useProfileShadow(initialRecipient)
+
+ const leaveConvoControl = useDialogControl()
+ const reportControl = useDialogControl()
+
+ return (
+
+
+
+ {/* {isBlocking ? (
+ You have blocked this user
+ ) : (
+ This user has blocked you
+ )} */}
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/screens/Messages/Conversation.tsx b/src/screens/Messages/Conversation.tsx
index b8b0bfe0d3..0abbc8c2b9 100644
--- a/src/screens/Messages/Conversation.tsx
+++ b/src/screens/Messages/Conversation.tsx
@@ -23,9 +23,11 @@ import {useDialogControl} from '#/components/Dialog'
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter'
import {MessagesListHeader} from '#/components/dms/MessagesListHeader'
+import {MessagesListPendingAcceptFooter} from '#/components/dms/MessagesListPendingAcceptFooter'
import {Error} from '#/components/Error'
import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader'
+import {ChatDisabled} from './components/ChatDisabled'
type Props = NativeStackScreenProps<
CommonNavigatorParams,
@@ -193,14 +195,23 @@ function InnerReady({
0}
- blockInfo={blockInfo}
- />
+ convoState.status === ConvoStatus.Disabled ? (
+
+ ) : moderation?.blocked ? (
+ 0}
+ blockInfo={blockInfo}
+ />
+ ) : convoState.pendingAcceptance ? (
+ 0}
+ />
+ ) : null
}
/>
)}
diff --git a/src/screens/Messages/components/MessagesList.tsx b/src/screens/Messages/components/MessagesList.tsx
index 071ce1cd71..27013d0d9c 100644
--- a/src/screens/Messages/components/MessagesList.tsx
+++ b/src/screens/Messages/components/MessagesList.tsx
@@ -31,7 +31,6 @@ import {
EmojiPickerState,
} from '#/view/com/composer/text-input/web/EmojiPicker.web'
import {List, ListMethods} from '#/view/com/util/List'
-import {ChatDisabled} from '#/screens/Messages/components/ChatDisabled'
import {MessageInput} from '#/screens/Messages/components/MessageInput'
import {MessageListError} from '#/screens/Messages/components/MessageListError'
import {ChatEmptyPill} from '#/components/dms/ChatEmptyPill'
@@ -78,13 +77,11 @@ function onScrollToIndexFailed() {
export function MessagesList({
hasScrolled,
setHasScrolled,
- blocked,
footer,
}: {
hasScrolled: boolean
setHasScrolled: React.Dispatch>
- blocked?: boolean
- footer?: React.ReactNode
+ footer: React.ReactNode | null
}) {
const convoState = useConvoActive()
const agent = useAgent()
@@ -427,11 +424,7 @@ export function MessagesList({
/>
- {convoState.status === ConvoStatus.Disabled ? (
-
- ) : blocked ? (
- footer
- ) : (
+ {footer || (
<>
{isConvoActive(convoState) &&
!convoState.isFetchingHistory &&
diff --git a/src/state/messages/convo/agent.ts b/src/state/messages/convo/agent.ts
index 53d77046a2..32a9c41751 100644
--- a/src/state/messages/convo/agent.ts
+++ b/src/state/messages/convo/agent.ts
@@ -78,10 +78,13 @@ export class Convo {
private emitter = new EventEmitter<{event: [ConvoEvent]}>()
+ private onMarkAsRead: () => void
+
convoId: string
convo: ChatBskyConvoDefs.ConvoView | undefined
sender: AppBskyActorDefs.ProfileViewBasic | undefined
recipients: AppBskyActorDefs.ProfileViewBasic[] | undefined = undefined
+ pendingAcceptance: boolean | undefined
snapshot: ConvoState | undefined
constructor(params: ConvoParams) {
@@ -89,7 +92,8 @@ export class Convo {
this.convoId = params.convoId
this.agent = params.agent
this.events = params.events
- this.senderUserDid = params.agent.session?.did!
+ this.senderUserDid = params.agent.session!.did
+ this.onMarkAsRead = params.onMarkAsRead
this.subscribe = this.subscribe.bind(this)
this.getSnapshot = this.getSnapshot.bind(this)
@@ -139,6 +143,7 @@ export class Convo {
deleteMessage: undefined,
sendMessage: undefined,
fetchMessageHistory: undefined,
+ pendingAcceptance: undefined,
}
}
case ConvoStatus.Disabled:
@@ -156,6 +161,7 @@ export class Convo {
deleteMessage: this.deleteMessage,
sendMessage: this.sendMessage,
fetchMessageHistory: this.fetchMessageHistory,
+ pendingAcceptance: this.pendingAcceptance,
}
}
case ConvoStatus.Error: {
@@ -170,6 +176,7 @@ export class Convo {
deleteMessage: undefined,
sendMessage: undefined,
fetchMessageHistory: undefined,
+ pendingAcceptance: undefined,
}
}
default: {
@@ -184,6 +191,7 @@ export class Convo {
deleteMessage: undefined,
sendMessage: undefined,
fetchMessageHistory: undefined,
+ pendingAcceptance: undefined,
}
}
}
@@ -246,11 +254,13 @@ export class Convo {
case ConvoDispatchEvent.Resume: {
this.refreshConvo()
this.requestPollInterval(ACTIVE_POLL_INTERVAL)
+ this.markAsRead()
break
}
case ConvoDispatchEvent.Background: {
this.status = ConvoStatus.Backgrounded
this.requestPollInterval(BACKGROUND_POLL_INTERVAL)
+ this.markAsRead()
break
}
case ConvoDispatchEvent.Suspend: {
@@ -513,6 +523,7 @@ export class Convo {
convo: ChatBskyConvoDefs.ConvoView
sender: AppBskyActorDefs.ProfileViewBasic | undefined
recipients: AppBskyActorDefs.ProfileViewBasic[]
+ pendingAcceptance: boolean
}>
| undefined
async fetchConvo() {
@@ -522,10 +533,11 @@ export class Convo {
convo: ChatBskyConvoDefs.ConvoView
sender: AppBskyActorDefs.ProfileViewBasic | undefined
recipients: AppBskyActorDefs.ProfileViewBasic[]
+ pendingAcceptance: boolean
}>(async (resolve, reject) => {
try {
const response = await networkRetry(2, () => {
- return this.agent.api.chat.bsky.convo.getConvo(
+ return this.agent.chat.bsky.convo.getConvo(
{
convoId: this.convoId,
},
@@ -539,6 +551,7 @@ export class Convo {
convo,
sender: convo.members.find(m => m.did === this.senderUserDid),
recipients: convo.members.filter(m => m.did !== this.senderUserDid),
+ pendingAcceptance: !convo.opened,
})
} catch (e) {
reject(e)
@@ -552,11 +565,13 @@ export class Convo {
async refreshConvo() {
try {
- const {convo, sender, recipients} = await this.fetchConvo()
+ const {convo, sender, recipients, pendingAcceptance} =
+ await this.fetchConvo()
// throw new Error('UNCOMMENT TO TEST REFRESH FAILURE')
this.convo = convo || this.convo
this.sender = sender || this.sender
this.recipients = recipients || this.recipients
+ this.pendingAcceptance = pendingAcceptance ?? this.pendingAcceptance
} catch (e: any) {
logger.error(e, {context: `Convo: failed to refresh convo`})
}
@@ -592,7 +607,7 @@ export class Convo {
const nextCursor = this.oldestRev // for TS
const response = await networkRetry(2, () => {
- return this.agent.api.chat.bsky.convo.getMessages(
+ return this.agent.chat.bsky.convo.getMessages(
{
cursor: nextCursor,
convoId: this.convoId,
@@ -793,7 +808,7 @@ export class Convo {
const {id, message} = pendingMessage
- const response = await this.agent.api.chat.bsky.convo.sendMessage(
+ const response = await this.agent.chat.bsky.convo.sendMessage(
{
convoId: this.convoId,
message,
@@ -888,7 +903,7 @@ export class Convo {
)
try {
- const {data} = await this.agent.api.chat.bsky.convo.sendMessageBatch(
+ const {data} = await this.agent.chat.bsky.convo.sendMessageBatch(
{
items: messageArray.map(({message}) => ({
convoId: this.convoId,
@@ -935,7 +950,7 @@ export class Convo {
try {
await networkRetry(2, () => {
- return this.agent.api.chat.bsky.convo.deleteMessageForSelf(
+ return this.agent.chat.bsky.convo.deleteMessageForSelf(
{
convoId: this.convoId,
messageId,
@@ -1104,4 +1119,21 @@ export class Convo {
return item
})
}
+
+ async acceptChat() {
+ await this.agent.chat.bsky.convo.updateRead({
+ convoId: this.convoId,
+ })
+ this.pendingAcceptance = false
+ this.onMarkAsRead()
+ }
+
+ markAsRead() {
+ if (!this.pendingAcceptance) {
+ this.agent.chat.bsky.convo.updateRead({
+ convoId: this.convoId,
+ })
+ this.onMarkAsRead()
+ }
+ }
}
diff --git a/src/state/messages/convo/index.tsx b/src/state/messages/convo/index.tsx
index 10ec2a348a..52eea47d74 100644
--- a/src/state/messages/convo/index.tsx
+++ b/src/state/messages/convo/index.tsx
@@ -3,6 +3,7 @@ import {useFocusEffect} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
import {useAppState} from '#/lib/hooks/useAppState'
+import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {Convo} from '#/state/messages/convo/agent'
import {
ConvoParams,
@@ -14,8 +15,10 @@ import {
} from '#/state/messages/convo/types'
import {isConvoActive} from '#/state/messages/convo/util'
import {useMessagesEventBus} from '#/state/messages/events'
-import {useMarkAsReadMutation} from '#/state/queries/messages/conversation'
-import {RQKEY as ListConvosQueryKey} from '#/state/queries/messages/list-conversations'
+import {
+ RQKEY as ListConvosQueryKey,
+ useOnMarkAsRead,
+} from '#/state/queries/messages/list-conversations'
import {RQKEY as createProfileQueryKey} from '#/state/queries/profile'
import {useAgent} from '#/state/session'
@@ -60,16 +63,20 @@ export function ConvoProvider({
const queryClient = useQueryClient()
const agent = useAgent()
const events = useMessagesEventBus()
+ const onMarkAsRead = useOnMarkAsRead()
+ const stableMAR = useNonReactiveCallback(() => {
+ onMarkAsRead(convoId)
+ })
const [convo] = useState(
() =>
new Convo({
convoId,
agent,
events,
+ onMarkAsRead: stableMAR,
}),
)
const service = useSyncExternalStore(convo.subscribe, convo.getSnapshot)
- const {mutate: markAsRead} = useMarkAsReadMutation()
const appState = useAppState()
const isActive = appState === 'active'
@@ -77,14 +84,12 @@ export function ConvoProvider({
React.useCallback(() => {
if (isActive) {
convo.resume()
- markAsRead({convoId})
return () => {
convo.background()
- markAsRead({convoId})
}
}
- }, [isActive, convo, convoId, markAsRead]),
+ }, [isActive, convo]),
)
React.useEffect(() => {
diff --git a/src/state/messages/convo/types.ts b/src/state/messages/convo/types.ts
index 21772262ea..0ab095c618 100644
--- a/src/state/messages/convo/types.ts
+++ b/src/state/messages/convo/types.ts
@@ -11,6 +11,7 @@ export type ConvoParams = {
convoId: string
agent: BskyAgent
events: MessagesEventBus
+ onMarkAsRead: () => void
}
export enum ConvoStatus {
@@ -150,6 +151,7 @@ export type ConvoStateUninitialized = {
deleteMessage: undefined
sendMessage: undefined
fetchMessageHistory: undefined
+ pendingAcceptance: undefined
}
export type ConvoStateInitializing = {
status: ConvoStatus.Initializing
@@ -162,6 +164,7 @@ export type ConvoStateInitializing = {
deleteMessage: undefined
sendMessage: undefined
fetchMessageHistory: undefined
+ pendingAcceptance: undefined
}
export type ConvoStateReady = {
status: ConvoStatus.Ready
@@ -174,6 +177,7 @@ export type ConvoStateReady = {
deleteMessage: DeleteMessage
sendMessage: SendMessage
fetchMessageHistory: FetchMessageHistory
+ pendingAcceptance: boolean | undefined
}
export type ConvoStateBackgrounded = {
status: ConvoStatus.Backgrounded
@@ -186,6 +190,7 @@ export type ConvoStateBackgrounded = {
deleteMessage: DeleteMessage
sendMessage: SendMessage
fetchMessageHistory: FetchMessageHistory
+ pendingAcceptance: boolean | undefined
}
export type ConvoStateSuspended = {
status: ConvoStatus.Suspended
@@ -198,6 +203,7 @@ export type ConvoStateSuspended = {
deleteMessage: DeleteMessage
sendMessage: SendMessage
fetchMessageHistory: FetchMessageHistory
+ pendingAcceptance: boolean | undefined
}
export type ConvoStateError = {
status: ConvoStatus.Error
@@ -210,6 +216,7 @@ export type ConvoStateError = {
deleteMessage: undefined
sendMessage: undefined
fetchMessageHistory: undefined
+ pendingAcceptance: undefined
}
export type ConvoStateDisabled = {
status: ConvoStatus.Disabled
@@ -222,6 +229,7 @@ export type ConvoStateDisabled = {
deleteMessage: DeleteMessage
sendMessage: SendMessage
fetchMessageHistory: FetchMessageHistory
+ pendingAcceptance: boolean | undefined
}
export type ConvoState =
| ConvoStateUninitialized