Use new listConvoRequests endpoint (#10755)
Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import {useCallback, useMemo, useState} from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type ChatBskyConvoDefs,
|
||||
type ChatBskyConvoListConvos,
|
||||
ChatBskyConvoDefs,
|
||||
type ChatBskyConvoListConvoRequests,
|
||||
ChatBskyGroupDefs,
|
||||
} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
import {useFocusEffect, useNavigation} from '@react-navigation/native'
|
||||
@@ -23,7 +24,7 @@ import {logger} from '#/logger'
|
||||
import {MESSAGE_SCREEN_POLL_INTERVAL} from '#/state/messages/convo/const'
|
||||
import {useMessagesEventBus} from '#/state/messages/events'
|
||||
import {useLeftConvos} from '#/state/queries/messages/leave-conversation'
|
||||
import {useListConvosQuery} from '#/state/queries/messages/list-conversations'
|
||||
import {useListConvoRequests} from '#/state/queries/messages/list-conversation-requests'
|
||||
import {useUpdateAllRead} from '#/state/queries/messages/update-all-read'
|
||||
import {EmptyState} from '#/view/com/util/EmptyState'
|
||||
import {List} from '#/view/com/util/List'
|
||||
@@ -43,11 +44,16 @@ import {ListFooter} from '#/components/Lists'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {IS_NATIVE} from '#/env'
|
||||
import {RequestListItem} from './components/RequestListItem'
|
||||
import {IncomingRequestListItem} from './components/IncomingRequestListItem'
|
||||
import {OutgoingRequestListItem} from './components/OutgoingRequestListItem'
|
||||
import {useIsWithinSplitView} from './components/splitView/context'
|
||||
|
||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'MessagesInbox'>
|
||||
|
||||
type RequestItem =
|
||||
| {type: 'incoming'; view: ChatBskyConvoDefs.ConvoView}
|
||||
| {type: 'outgoing'; view: ChatBskyGroupDefs.JoinRequestConvoView}
|
||||
|
||||
export function MessagesInboxScreen(props: Props) {
|
||||
const {t: l} = useLingui()
|
||||
const aaCopy = useAgeAssuranceCopy()
|
||||
@@ -61,29 +67,36 @@ export function MessagesInboxScreen(props: Props) {
|
||||
}
|
||||
|
||||
export function MessagesInboxScreenInner({}: Props) {
|
||||
const listConvosQuery = useListConvosQuery({status: 'request'})
|
||||
const listConvosQuery = useListConvoRequests()
|
||||
const {data} = listConvosQuery
|
||||
|
||||
const leftConvos = useLeftConvos()
|
||||
|
||||
const conversations = useMemo(() => {
|
||||
if (data?.pages) {
|
||||
const convos = data.pages
|
||||
.flatMap(page => page.convos)
|
||||
// filter out convos that are actively being left
|
||||
.filter(convo => !leftConvos.includes(convo.id))
|
||||
|
||||
return convos
|
||||
const conversations = useMemo<RequestItem[]>(() => {
|
||||
if (!data?.pages) return []
|
||||
const items: RequestItem[] = []
|
||||
for (const page of data.pages) {
|
||||
for (const item of page.requests) {
|
||||
if (ChatBskyConvoDefs.isConvoView(item)) {
|
||||
// filter out convos that are actively being left
|
||||
if (leftConvos.includes(item.id)) continue
|
||||
items.push({type: 'incoming', view: item})
|
||||
} else if (ChatBskyGroupDefs.isJoinRequestConvoView(item)) {
|
||||
items.push({type: 'outgoing', view: item})
|
||||
}
|
||||
}
|
||||
}
|
||||
return []
|
||||
return items
|
||||
}, [data, leftConvos])
|
||||
|
||||
const hasUnreadConvos = useMemo(() => {
|
||||
return conversations.some(
|
||||
conversation =>
|
||||
conversation.members.every(
|
||||
item =>
|
||||
item.type === 'incoming' &&
|
||||
item.view.members.every(
|
||||
member => member.handle !== 'missing.invalid',
|
||||
) && conversation.unreadCount > 0,
|
||||
) &&
|
||||
item.view.unreadCount > 0,
|
||||
)
|
||||
}, [conversations])
|
||||
|
||||
@@ -111,10 +124,10 @@ function RequestList({
|
||||
conversations,
|
||||
}: {
|
||||
listConvosQuery: UseInfiniteQueryResult<
|
||||
InfiniteData<ChatBskyConvoListConvos.OutputSchema>,
|
||||
InfiniteData<ChatBskyConvoListConvoRequests.OutputSchema>,
|
||||
Error
|
||||
>
|
||||
conversations: ChatBskyConvoDefs.ConvoView[]
|
||||
conversations: RequestItem[]
|
||||
}) {
|
||||
const {t: l} = useLingui()
|
||||
const t = useTheme()
|
||||
@@ -274,17 +287,21 @@ function RequestList({
|
||||
windowSize={11}
|
||||
desktopFixedHeight
|
||||
sideBorders={false}
|
||||
contentContainerStyle={[web(a.py_sm)]}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function keyExtractor(item: ChatBskyConvoDefs.ConvoView) {
|
||||
return item.id
|
||||
function keyExtractor(item: RequestItem) {
|
||||
return item.type === 'incoming' ? item.view.id : item.view.convoId
|
||||
}
|
||||
|
||||
function renderItem({item}: {item: ChatBskyConvoDefs.ConvoView}) {
|
||||
return <RequestListItem convo={item} />
|
||||
function renderItem({item}: {item: RequestItem}) {
|
||||
if (item.type === 'incoming') {
|
||||
return <IncomingRequestListItem convo={item.view} />
|
||||
}
|
||||
return <OutgoingRequestListItem convo={item.view} />
|
||||
}
|
||||
|
||||
function MarkAsReadHeaderButton() {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import {Text} from '#/components/Typography'
|
||||
import {ChatListItem, ChatListItemPortal} from './ChatListItem'
|
||||
import {AcceptChatButton, DeleteChatButton, RejectMenu} from './RequestButtons'
|
||||
|
||||
export function RequestListItem({
|
||||
export function IncomingRequestListItem({
|
||||
convo: convoView,
|
||||
}: {
|
||||
convo: ChatBskyConvoDefs.ConvoView
|
||||
@@ -0,0 +1,128 @@
|
||||
import {View} from 'react-native'
|
||||
import {
|
||||
type ChatBskyGroupDefs,
|
||||
ChatBskyGroupWithdrawJoinRequest,
|
||||
} from '@atproto/api'
|
||||
import {Trans, useLingui} from '@lingui/react/macro'
|
||||
|
||||
import {isNetworkError} from '#/lib/strings/errors'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useWithdrawJoinGroupChatRequest} from '#/state/queries/messages/withdraw-join-group-chat'
|
||||
import {TimeElapsed} from '#/view/com/util/TimeElapsed'
|
||||
import {atoms as a, useTheme, web} from '#/alf'
|
||||
import {AvatarBubbles} from '#/components/AvatarBubbles'
|
||||
import {createStaticClick, Link} from '#/components/Link'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
import * as Toast from '#/components/Toast'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
export function OutgoingRequestListItem({
|
||||
convo: convoView,
|
||||
}: {
|
||||
convo: ChatBskyGroupDefs.JoinRequestConvoView
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {t: l} = useLingui()
|
||||
|
||||
const prompt = Prompt.usePromptControl()
|
||||
|
||||
const moderationOpts = useModerationOpts()
|
||||
|
||||
const {mutate: withdrawRequest, isPending: isWithdrawPending} =
|
||||
useWithdrawJoinGroupChatRequest({
|
||||
onSuccess: () => {
|
||||
Toast.show(l`Join request rescinded.`)
|
||||
},
|
||||
onError: error => {
|
||||
let errorMessage = l`Failed to rescind your request. Please try again.`
|
||||
if (isNetworkError(error)) {
|
||||
errorMessage = l`There was a problem with your internet connection, please try again`
|
||||
} else if (
|
||||
error instanceof
|
||||
ChatBskyGroupWithdrawJoinRequest.InvalidJoinRequestError
|
||||
) {
|
||||
errorMessage = l`Invalid rescind request.`
|
||||
}
|
||||
Toast.show(errorMessage)
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<Link
|
||||
label={l`Rescind request to join group chat`}
|
||||
{...createStaticClick(() => {
|
||||
prompt.open()
|
||||
})}>
|
||||
{({hovered, pressed, focused}) => (
|
||||
<View
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.align_center,
|
||||
a.flex_1,
|
||||
a.px_lg,
|
||||
a.py_md,
|
||||
a.gap_md,
|
||||
(hovered || pressed || focused) && t.atoms.bg_contrast_25,
|
||||
]}>
|
||||
<AvatarBubbles
|
||||
profiles={[
|
||||
convoView?.owner ?? undefined,
|
||||
...Array(
|
||||
Math.min(3, Math.max(0, convoView.memberCount - 1)),
|
||||
).fill(undefined),
|
||||
]}
|
||||
size={48}
|
||||
moderationOpts={moderationOpts}
|
||||
/>
|
||||
<View style={[a.flex_1]}>
|
||||
<View style={[a.w_full, a.flex_row, a.align_center, a.pb_2xs]}>
|
||||
<View style={[a.flex_shrink]}>
|
||||
<Text
|
||||
emoji
|
||||
numberOfLines={1}
|
||||
style={[a.text_md, a.font_semi_bold]}>
|
||||
{convoView.name}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[a.pl_xs]}>
|
||||
<TimeElapsed timestamp={convoView.requestedAt}>
|
||||
{({timeElapsed}) => (
|
||||
<Text
|
||||
style={[
|
||||
a.text_sm,
|
||||
t.atoms.text_contrast_medium,
|
||||
web({whiteSpace: 'preserve nowrap'}),
|
||||
]}>
|
||||
{timeElapsed}
|
||||
</Text>
|
||||
)}
|
||||
</TimeElapsed>
|
||||
</View>
|
||||
</View>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[a.text_sm, t.atoms.text_contrast_high]}>
|
||||
<Trans comment="Displayed when the user has requested to join a group chat.">
|
||||
You requested to join
|
||||
</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</Link>
|
||||
<Prompt.Basic
|
||||
control={prompt}
|
||||
title={l`Rescind request`}
|
||||
description={l`Are you sure you want to rescind your request to join ${convoView.name}?`}
|
||||
confirmButtonCta={l`Rescind request`}
|
||||
onConfirm={() => {
|
||||
prompt.close(() => {
|
||||
if (isWithdrawPending) return
|
||||
withdrawRequest({convoId: convoView.convoId})
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user