Add ability to remove members from a group clip clop (#10287)
This commit is contained in:
@@ -21,12 +21,13 @@ import {ConvoProvider, useConvo} from '#/state/messages/convo'
|
|||||||
import {ConvoStatus} from '#/state/messages/convo/types'
|
import {ConvoStatus} from '#/state/messages/convo/types'
|
||||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useAddGroupMembers} from '#/state/queries/messages/add-group-members'
|
import {useAddGroupMembers} from '#/state/queries/messages/add-group-members'
|
||||||
import {useEditGroupName} from '#/state/queries/messages/edit-group-name'
|
import {useEditGroupChatName} from '#/state/queries/messages/edit-group-chat-name'
|
||||||
import {useGetConvoAvailabilityQuery} from '#/state/queries/messages/get-convo-availability'
|
import {useGetConvoAvailabilityQuery} from '#/state/queries/messages/get-convo-availability'
|
||||||
import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members'
|
import {useGetConvoForMembers} from '#/state/queries/messages/get-convo-for-members'
|
||||||
import {useLeaveConvo} from '#/state/queries/messages/leave-conversation'
|
import {useLeaveConvo} from '#/state/queries/messages/leave-conversation'
|
||||||
import {useListJoinRequestsQuery} from '#/state/queries/messages/list-join-requests'
|
import {useListJoinRequestsQuery} from '#/state/queries/messages/list-join-requests'
|
||||||
import {useMuteConvo} from '#/state/queries/messages/mute-conversation'
|
import {useMuteConvo} from '#/state/queries/messages/mute-conversation'
|
||||||
|
import {useRemoveFromGroupChat} from '#/state/queries/messages/remove-from-group'
|
||||||
import {useProfileBlockMutationQueue} from '#/state/queries/profile'
|
import {useProfileBlockMutationQueue} from '#/state/queries/profile'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {List} from '#/view/com/util/List'
|
import {List} from '#/view/com/util/List'
|
||||||
@@ -189,6 +190,7 @@ function SettingsInner({convoId}: {convoId: string}) {
|
|||||||
case 'CHAT_MEMBER':
|
case 'CHAT_MEMBER':
|
||||||
return (
|
return (
|
||||||
<Member
|
<Member
|
||||||
|
convo={convo}
|
||||||
profile={item.profile}
|
profile={item.profile}
|
||||||
status={item.status}
|
status={item.status}
|
||||||
isOwner={isOwner}
|
isOwner={isOwner}
|
||||||
@@ -391,10 +393,12 @@ function AddMembersLink({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Member({
|
function Member({
|
||||||
|
convo,
|
||||||
profile,
|
profile,
|
||||||
status,
|
status,
|
||||||
isOwner,
|
isOwner,
|
||||||
}: {
|
}: {
|
||||||
|
convo: ConvoWithDetails | null
|
||||||
profile: Shadow<bsky.profile.AnyProfileView>
|
profile: Shadow<bsky.profile.AnyProfileView>
|
||||||
status: 'owner' | 'standard' | 'invited'
|
status: 'owner' | 'standard' | 'invited'
|
||||||
isOwner: boolean
|
isOwner: boolean
|
||||||
@@ -429,9 +433,14 @@ function Member({
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
statusBadge = (
|
statusBadge = convo ? (
|
||||||
<MemberMenu profile={profile} type={status} isOwner={isOwner} />
|
<MemberMenu
|
||||||
)
|
convo={convo}
|
||||||
|
profile={profile}
|
||||||
|
type={status}
|
||||||
|
isOwner={isOwner}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -537,10 +546,12 @@ function StatusButton({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function MemberMenu({
|
function MemberMenu({
|
||||||
|
convo,
|
||||||
profile,
|
profile,
|
||||||
type,
|
type,
|
||||||
isOwner,
|
isOwner,
|
||||||
}: {
|
}: {
|
||||||
|
convo: ConvoWithDetails
|
||||||
profile: Shadow<bsky.profile.AnyProfileView>
|
profile: Shadow<bsky.profile.AnyProfileView>
|
||||||
type: 'owner' | 'standard' | 'invited'
|
type: 'owner' | 'standard' | 'invited'
|
||||||
isOwner: boolean
|
isOwner: boolean
|
||||||
@@ -564,6 +575,13 @@ function MemberMenu({
|
|||||||
Toast.show(l`Failed to create conversation`)
|
Toast.show(l`Failed to create conversation`)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
const convoId = convo?.view.id
|
||||||
|
const {mutate: removeMembers} = useRemoveFromGroupChat(convoId, {
|
||||||
|
onError: e => {
|
||||||
|
logger.error('Failed to remove group chat member', {message: e})
|
||||||
|
Toast.show(l`Failed to remove group chat member`)
|
||||||
|
},
|
||||||
|
})
|
||||||
const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
|
const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
|
||||||
|
|
||||||
const messageMember = () => {
|
const messageMember = () => {
|
||||||
@@ -714,7 +732,7 @@ function MemberMenu({
|
|||||||
{isOwner ? (
|
{isOwner ? (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
label={l`Remove ${displayName} from this group chat`}
|
label={l`Remove ${displayName} from this group chat`}
|
||||||
onPress={() => {}}>
|
onPress={() => removeMembers({members: [profile.did]})}>
|
||||||
<Menu.ItemText>
|
<Menu.ItemText>
|
||||||
<Trans>Remove from chat</Trans>
|
<Trans>Remove from chat</Trans>
|
||||||
</Menu.ItemText>
|
</Menu.ItemText>
|
||||||
@@ -759,7 +777,7 @@ function SettingsHeader({
|
|||||||
|
|
||||||
const [isLocked, setIsLocked] = useState(false)
|
const [isLocked, setIsLocked] = useState(false)
|
||||||
|
|
||||||
const {mutate: editGroupName} = useEditGroupName(convo.view.id, {
|
const {mutate: editGroupName} = useEditGroupChatName(convo.view.id, {
|
||||||
onError: e => {
|
onError: e => {
|
||||||
setNewGroupName(groupName)
|
setNewGroupName(groupName)
|
||||||
logger.error('Failed to edit group chat name', {message: e})
|
logger.error('Failed to edit group chat name', {message: e})
|
||||||
|
|||||||
@@ -116,11 +116,11 @@ export function ConvoProvider({
|
|||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case 'invalidate-block-state': {
|
case 'invalidate-block-state': {
|
||||||
for (const did of event.accountDids) {
|
for (const did of event.accountDids) {
|
||||||
queryClient.invalidateQueries({
|
void queryClient.invalidateQueries({
|
||||||
queryKey: createProfileQueryKey(did),
|
queryKey: createProfileQueryKey(did),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
queryClient.invalidateQueries({
|
void queryClient.invalidateQueries({
|
||||||
queryKey: [ListConvosQueryKeyRoot],
|
queryKey: [ListConvosQueryKeyRoot],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ import {useAgent} from '#/state/session'
|
|||||||
import {RQKEY as CONVO_KEY} from './conversation'
|
import {RQKEY as CONVO_KEY} from './conversation'
|
||||||
import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
|
import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
|
||||||
|
|
||||||
export function useEditGroupName(
|
export function useEditGroupChatName(
|
||||||
convoId: string | undefined,
|
convoId: string | undefined,
|
||||||
{
|
{
|
||||||
onSuccess,
|
onSuccess,
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import {
|
||||||
|
type ChatBskyConvoDefs,
|
||||||
|
type ChatBskyConvoListConvos,
|
||||||
|
type ChatBskyGroupRemoveMembers,
|
||||||
|
} from '@atproto/api'
|
||||||
|
import {
|
||||||
|
type InfiniteData,
|
||||||
|
useMutation,
|
||||||
|
useQueryClient,
|
||||||
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
|
import {DM_SERVICE_HEADERS} from '#/lib/constants'
|
||||||
|
import {logger} from '#/logger'
|
||||||
|
import {useAgent} from '#/state/session'
|
||||||
|
import {RQKEY as CONVO_KEY} from './conversation'
|
||||||
|
import {RQKEY_ROOT as CONVO_LIST_KEY} from './list-conversations'
|
||||||
|
|
||||||
|
export function useRemoveFromGroupChat(
|
||||||
|
convoId: string | undefined,
|
||||||
|
{
|
||||||
|
onSuccess,
|
||||||
|
onError,
|
||||||
|
}: {
|
||||||
|
onSuccess?: (data: ChatBskyGroupRemoveMembers.OutputSchema) => void
|
||||||
|
onError?: (error: Error) => void
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
const agent = useAgent()
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({members}: {members: string[]}) => {
|
||||||
|
if (!convoId) throw new Error('No convoId provided')
|
||||||
|
const {data} = await agent.chat.bsky.group.removeMembers(
|
||||||
|
{convoId, members},
|
||||||
|
{headers: DM_SERVICE_HEADERS, encoding: 'application/json'},
|
||||||
|
)
|
||||||
|
return data
|
||||||
|
},
|
||||||
|
onMutate: ({members}) => {
|
||||||
|
if (!convoId) return
|
||||||
|
|
||||||
|
const prevConvo = queryClient.getQueryData<ChatBskyConvoDefs.ConvoView>(
|
||||||
|
CONVO_KEY(convoId),
|
||||||
|
)
|
||||||
|
const prevListEntries = queryClient.getQueriesData<
|
||||||
|
InfiniteData<ChatBskyConvoListConvos.OutputSchema>
|
||||||
|
>({queryKey: [CONVO_LIST_KEY]})
|
||||||
|
|
||||||
|
queryClient.setQueryData<ChatBskyConvoDefs.ConvoView>(
|
||||||
|
CONVO_KEY(convoId),
|
||||||
|
prev => {
|
||||||
|
if (!prev) return
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
members: prev.members.filter(m => !members.includes(m.did)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
queryClient.setQueriesData<
|
||||||
|
InfiniteData<ChatBskyConvoListConvos.OutputSchema>
|
||||||
|
>({queryKey: [CONVO_LIST_KEY]}, prev => {
|
||||||
|
if (!prev?.pages) return
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
pages: prev.pages.map(page => ({
|
||||||
|
...page,
|
||||||
|
convos: page.convos.map(convo => {
|
||||||
|
if (convo.id !== convoId) return convo
|
||||||
|
return {
|
||||||
|
...convo,
|
||||||
|
members: convo.members.filter(m => !members.includes(m.did)),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return {prevConvo, prevListEntries}
|
||||||
|
},
|
||||||
|
onSuccess: data => {
|
||||||
|
onSuccess?.(data)
|
||||||
|
},
|
||||||
|
onError: (e, _variables, context) => {
|
||||||
|
logger.error(e)
|
||||||
|
if (context?.prevConvo && convoId) {
|
||||||
|
queryClient.setQueryData(CONVO_KEY(convoId), context.prevConvo)
|
||||||
|
}
|
||||||
|
if (context?.prevListEntries) {
|
||||||
|
for (const [key, data] of context.prevListEntries) {
|
||||||
|
queryClient.setQueryData(key, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onError?.(e)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user