Add Leave chat button to settings for chat owners (#10764)

Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
DS Boyce
2026-06-08 04:57:08 -07:00
committed by GitHub
parent e60e31733a
commit 6997d220a0
3 changed files with 96 additions and 36 deletions
@@ -58,7 +58,12 @@ import {InviteLinkDialog} from '../components/InviteLinkDialog'
import {AddMembersLink} from './AddMembersLink'
import {Member, MemberPlaceholder} from './Member'
import {MembersAndRequests} from './MembersAndRequests'
import {EditNamePrompt, LeaveChatPrompt, LockChatPrompt} from './prompts'
import {
EditNamePrompt,
LeaveAndLockChatPrompt,
LeaveChatPrompt,
LockChatPrompt,
} from './prompts'
type Item =
| {type: 'MEMBERS_AND_REQUESTS'; key: string}
@@ -374,33 +379,49 @@ function SettingsHeader({
},
)
const {mutate: lockConvo, isPending: isLocking} = useLockConvo(
convo.view.id,
{
onSuccess: data => {
if (!ChatBskyConvoDefs.isGroupConvo(data.convo.kind)) return
if (data.convo.kind.lockStatus === 'locked') {
Toast.show(l({message: 'Group chat locked', context: 'toast'}))
} else {
Toast.show(l({message: 'Group chat unlocked', context: 'toast'}))
}
},
onError: (e, {lock}) => {
if (lock) {
logger.error('Failed to lock group chat', {message: e})
Toast.show(l`Failed to lock group chat`, {type: 'error'})
} else {
logger.error('Failed to unlock group chat', {message: e})
Toast.show(l`Failed to unlock group chat`, {type: 'error'})
}
},
const {
mutate: lockConvo,
mutateAsync: lockConvoAsync,
isPending: isLocking,
} = useLockConvo(convo.view.id, {
onSuccess: (data, {silent}) => {
if (!ChatBskyConvoDefs.isGroupConvo(data.convo.kind)) return
if (silent) return
if (data.convo.kind.lockStatus === 'locked') {
Toast.show(l({message: 'Group chat locked', context: 'toast'}))
} else {
Toast.show(l({message: 'Group chat unlocked', context: 'toast'}))
}
},
)
onError: (e, {lock}) => {
if (lock) {
logger.error('Failed to lock group chat', {message: e})
Toast.show(l`Failed to lock group chat`, {type: 'error'})
} else {
logger.error('Failed to unlock group chat', {message: e})
Toast.show(l`Failed to unlock group chat`, {type: 'error'})
}
},
})
const leaveAndLockConvo = async () => {
try {
if (lockStatus === 'unlocked') {
await lockConvoAsync({lock: true, silent: true})
}
} catch {
// Handled by onError in useLockConvo
return
}
// Owners can only leave a locked chat
leaveConvo()
}
const inviteLinkDialog = Dialog.useDialogControl()
const editNamePrompt = Prompt.usePromptControl()
const lockChatPrompt = Prompt.usePromptControl()
const leaveChatPrompt = Prompt.usePromptControl()
const leaveAndLockChatPrompt = Prompt.usePromptControl()
const reportControl = Prompt.usePromptControl()
const deleteControl = Prompt.usePromptControl()
@@ -452,6 +473,7 @@ function SettingsHeader({
a.justify_center,
a.gap_2xl,
a.pt_2xl,
a.flex_wrap,
]}>
<SettingsButton
color={convo.view.muted ? 'negative_subtle' : 'secondary'}
@@ -517,15 +539,15 @@ function SettingsHeader({
onPress={reportControl.open}
/>
) : null}
{!isOwner ? (
<SettingsButton
disabled={!isReady || isLeaving}
icon={ArrowBoxLeftIcon}
label={l`Leave this group chat`}
text={l`Leave`}
onPress={leaveChatPrompt.open}
/>
) : null}
<SettingsButton
disabled={!isReady || isLeaving || (isOwner && isLocking)}
icon={ArrowBoxLeftIcon}
label={l`Leave this group chat`}
text={l`Leave`}
onPress={
isOwner ? leaveAndLockChatPrompt.open : leaveChatPrompt.open
}
/>
</View>
</View>
<EditNamePrompt
@@ -552,6 +574,13 @@ function SettingsHeader({
groupName={groupName}
onConfirm={leaveConvo}
/>
<LeaveAndLockChatPrompt
control={leaveAndLockChatPrompt}
groupName={groupName}
onConfirm={() => {
void leaveAndLockConvo()
}}
/>
{reportSubjectDid ? (
<>
<ReportConversationDialog
@@ -610,6 +639,7 @@ function SettingsButton({
</Button>
<Text
numberOfLines={1}
maxFontSizeMultiplier={2.5}
style={[
a.text_xs,
a.font_medium,
@@ -127,6 +127,30 @@ export function LeaveChatPrompt({
)
}
export function LeaveAndLockChatPrompt({
control,
groupName,
onConfirm,
}: {
control: Dialog.DialogOuterProps['control']
groupName: string
onConfirm: () => void
}) {
const {t: l} = useLingui()
return (
<Prompt.Basic
control={control}
title={l`Are you sure you want to leave ${groupName}?`}
description={l`Leaving this chat will lock it permanently and you wont be able to rejoin.`}
confirmButtonCta={l`Leave group chat`}
confirmButtonColor="negative"
cancelButtonCta={l`Cancel`}
onConfirm={onConfirm}
/>
)
}
export function BlockMemberPrompt({
control,
onConfirm,
@@ -14,15 +14,21 @@ export function useLockConvo(
onSuccess,
onError,
}: {
onSuccess?: (data: ChatBskyConvoLockConvo.OutputSchema) => void
onError?: (error: Error, variables: {lock: boolean}) => void
onSuccess?: (
data: ChatBskyConvoLockConvo.OutputSchema,
variables: {lock: boolean; silent?: boolean},
) => void
onError?: (
error: Error,
variables: {lock: boolean; silent?: boolean},
) => void
},
) {
const queryClient = useQueryClient()
const agent = useAgent()
return useMutation({
mutationFn: async ({lock}: {lock: boolean}) => {
mutationFn: async ({lock}: {lock: boolean; silent?: boolean}) => {
if (!convoId) throw new Error('No convoId provided')
if (lock) {
const {data} = await agent.chat.bsky.convo.lockConvo(
@@ -51,8 +57,8 @@ export function useLockConvo(
}
})
},
onSuccess: data => {
onSuccess?.(data)
onSuccess: (data, variables) => {
onSuccess?.(data, variables)
},
onError: (e, variables, context) => {
if (convoId && context) {