Post-report menu (#7446)
* post-report block/delete dialog * fix * default checked * web styles * add icon to send button * wire everything up * optimisically leave convo * hide pending-leave convos * Capitalize action labels * Code style --------- Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import * as Dialog from '#/components/Dialog'
|
|||||||
import * as Toggle from '#/components/forms/Toggle'
|
import * as Toggle from '#/components/forms/Toggle'
|
||||||
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||||
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
|
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
|
||||||
|
import {PaperPlane_Stroke2_Corner0_Rounded as SendIcon} from '#/components/icons/PaperPlane'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
import {ReportDialogProps} from './types'
|
import {ReportDialogProps} from './types'
|
||||||
@@ -223,7 +224,7 @@ export function SubmitView({
|
|||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans>Send report</Trans>
|
<Trans>Send report</Trans>
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
{submitting && <ButtonIcon icon={Loader} />}
|
<ButtonIcon icon={submitting ? Loader : SendIcon} />
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
{/* Maybe fix this later -h */}
|
{/* Maybe fix this later -h */}
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ let ConvoMenu = ({
|
|||||||
/>
|
/>
|
||||||
{latestReportableMessage ? (
|
{latestReportableMessage ? (
|
||||||
<ReportDialog
|
<ReportDialog
|
||||||
|
currentScreen={currentScreen}
|
||||||
params={{
|
params={{
|
||||||
type: 'convoMessage',
|
type: 'convoMessage',
|
||||||
convoId: convo.id,
|
convoId: convo.id,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useNavigation} from '@react-navigation/native'
|
import {StackActions, useNavigation} from '@react-navigation/native'
|
||||||
|
|
||||||
import {NavigationProp} from '#/lib/routes/types'
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
@@ -22,15 +22,10 @@ export function LeaveConvoPrompt({
|
|||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
|
|
||||||
const {mutate: leaveConvo} = useLeaveConvo(convoId, {
|
const {mutate: leaveConvo} = useLeaveConvo(convoId, {
|
||||||
onSuccess: () => {
|
onMutate: () => {
|
||||||
if (currentScreen === 'conversation') {
|
if (currentScreen === 'conversation') {
|
||||||
navigation.replace(
|
navigation.dispatch(
|
||||||
'Messages',
|
StackActions.replace('Messages', isNative ? {animation: 'pop'} : {}),
|
||||||
isNative
|
|
||||||
? {
|
|
||||||
animation: 'pop',
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ export let MessageMenu = ({
|
|||||||
</Menu.Root>
|
</Menu.Root>
|
||||||
|
|
||||||
<ReportDialog
|
<ReportDialog
|
||||||
|
currentScreen="conversation"
|
||||||
params={{type: 'convoMessage', convoId: convo.convo.id, message}}
|
params={{type: 'convoMessage', convoId: convo.convo.id, message}}
|
||||||
control={reportControl}
|
control={reportControl}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,27 +1,39 @@
|
|||||||
import React, {memo, useMemo, useState} from 'react'
|
import React, {memo, useMemo, useState} from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {
|
import {
|
||||||
|
AppBskyActorDefs,
|
||||||
ChatBskyConvoDefs,
|
ChatBskyConvoDefs,
|
||||||
ComAtprotoModerationCreateReport,
|
ComAtprotoModerationCreateReport,
|
||||||
RichText as RichTextAPI,
|
RichText as RichTextAPI,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
import {StackActions, useNavigation} from '@react-navigation/native'
|
||||||
import {useMutation} from '@tanstack/react-query'
|
import {useMutation} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {ReportOption} from '#/lib/moderation/useReportOptions'
|
import {ReportOption} from '#/lib/moderation/useReportOptions'
|
||||||
|
import {NavigationProp} from '#/lib/routes/types'
|
||||||
|
import {isNative} from '#/platform/detection'
|
||||||
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
|
import {useLeaveConvo} from '#/state/queries/messages/leave-conversation'
|
||||||
|
import {
|
||||||
|
useProfileBlockMutationQueue,
|
||||||
|
useProfileQuery,
|
||||||
|
} from '#/state/queries/profile'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
import {atoms as a, platform, useBreakpoints, useTheme, web} from '#/alf'
|
||||||
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
import * as Dialog from '#/components/Dialog'
|
import * as Dialog from '#/components/Dialog'
|
||||||
import {Button, ButtonIcon, ButtonText} from '../Button'
|
import {Divider} from '#/components/Divider'
|
||||||
import {Divider} from '../Divider'
|
import * as Toggle from '#/components/forms/Toggle'
|
||||||
import {ChevronLeft_Stroke2_Corner0_Rounded as Chevron} from '../icons/Chevron'
|
import {ChevronLeft_Stroke2_Corner0_Rounded as Chevron} from '#/components/icons/Chevron'
|
||||||
import {Loader} from '../Loader'
|
import {PaperPlane_Stroke2_Corner0_Rounded as SendIcon} from '#/components/icons/PaperPlane'
|
||||||
import {SelectReportOptionView} from '../ReportDialog/SelectReportOptionView'
|
import {Loader} from '#/components/Loader'
|
||||||
import {RichText} from '../RichText'
|
import {SelectReportOptionView} from '#/components/ReportDialog/SelectReportOptionView'
|
||||||
import {Text} from '../Typography'
|
import {RichText} from '#/components/RichText'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
import {MessageItemMetadata} from './MessageItem'
|
import {MessageItemMetadata} from './MessageItem'
|
||||||
|
|
||||||
type ReportDialogParams = {
|
type ReportDialogParams = {
|
||||||
@@ -33,16 +45,18 @@ type ReportDialogParams = {
|
|||||||
let ReportDialog = ({
|
let ReportDialog = ({
|
||||||
control,
|
control,
|
||||||
params,
|
params,
|
||||||
|
currentScreen,
|
||||||
}: {
|
}: {
|
||||||
control: Dialog.DialogControlProps
|
control: Dialog.DialogControlProps
|
||||||
params: ReportDialogParams
|
params: ReportDialogParams
|
||||||
|
currentScreen: 'list' | 'conversation'
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
return (
|
return (
|
||||||
<Dialog.Outer control={control}>
|
<Dialog.Outer control={control}>
|
||||||
<Dialog.Handle />
|
<Dialog.Handle />
|
||||||
<Dialog.ScrollableInner label={_(msg`Report this message`)}>
|
<Dialog.ScrollableInner label={_(msg`Report this message`)}>
|
||||||
<DialogInner params={params} />
|
<DialogInner params={params} currentScreen={currentScreen} />
|
||||||
<Dialog.Close />
|
<Dialog.Close />
|
||||||
</Dialog.ScrollableInner>
|
</Dialog.ScrollableInner>
|
||||||
</Dialog.Outer>
|
</Dialog.Outer>
|
||||||
@@ -51,14 +65,44 @@ let ReportDialog = ({
|
|||||||
ReportDialog = memo(ReportDialog)
|
ReportDialog = memo(ReportDialog)
|
||||||
export {ReportDialog}
|
export {ReportDialog}
|
||||||
|
|
||||||
function DialogInner({params}: {params: ReportDialogParams}) {
|
function DialogInner({
|
||||||
|
params,
|
||||||
|
currentScreen,
|
||||||
|
}: {
|
||||||
|
params: ReportDialogParams
|
||||||
|
currentScreen: 'list' | 'conversation'
|
||||||
|
}) {
|
||||||
|
const {data: profile, isError} = useProfileQuery({
|
||||||
|
did: params.message.sender.did,
|
||||||
|
})
|
||||||
const [reportOption, setReportOption] = useState<ReportOption | null>(null)
|
const [reportOption, setReportOption] = useState<ReportOption | null>(null)
|
||||||
|
const [done, setDone] = useState(false)
|
||||||
|
const control = Dialog.useDialogContext()
|
||||||
|
|
||||||
return reportOption ? (
|
return done ? (
|
||||||
|
profile ? (
|
||||||
|
<DoneStep
|
||||||
|
convoId={params.convoId}
|
||||||
|
currentScreen={currentScreen}
|
||||||
|
profile={profile}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<View style={[a.w_full, a.py_5xl, a.align_center]}>
|
||||||
|
<Loader />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
) : reportOption ? (
|
||||||
<SubmitStep
|
<SubmitStep
|
||||||
params={params}
|
params={params}
|
||||||
reportOption={reportOption}
|
reportOption={reportOption}
|
||||||
goBack={() => setReportOption(null)}
|
goBack={() => setReportOption(null)}
|
||||||
|
onComplete={() => {
|
||||||
|
if (isError) {
|
||||||
|
control.close()
|
||||||
|
} else {
|
||||||
|
setDone(true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ReasonStep params={params} setReportOption={setReportOption} />
|
<ReasonStep params={params} setReportOption={setReportOption} />
|
||||||
@@ -89,16 +133,17 @@ function SubmitStep({
|
|||||||
params,
|
params,
|
||||||
reportOption,
|
reportOption,
|
||||||
goBack,
|
goBack,
|
||||||
|
onComplete,
|
||||||
}: {
|
}: {
|
||||||
params: ReportDialogParams
|
params: ReportDialogParams
|
||||||
reportOption: ReportOption
|
reportOption: ReportOption
|
||||||
goBack: () => void
|
goBack: () => void
|
||||||
|
onComplete: () => void
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {gtMobile} = useBreakpoints()
|
const {gtMobile} = useBreakpoints()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const [details, setDetails] = useState('')
|
const [details, setDetails] = useState('')
|
||||||
const control = Dialog.useDialogContext()
|
|
||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -124,11 +169,7 @@ function SubmitStep({
|
|||||||
await agent.createModerationReport(report)
|
await agent.createModerationReport(report)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
onSuccess: onComplete,
|
||||||
control.close(() => {
|
|
||||||
Toast.show(_(msg`Thank you. Your report has been sent.`))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const copy = useMemo(() => {
|
const copy = useMemo(() => {
|
||||||
@@ -181,11 +222,11 @@ function SubmitStep({
|
|||||||
<View style={[a.relative, a.w_full]}>
|
<View style={[a.relative, a.w_full]}>
|
||||||
<Dialog.Input
|
<Dialog.Input
|
||||||
multiline
|
multiline
|
||||||
value={details}
|
defaultValue={details}
|
||||||
onChangeText={setDetails}
|
onChangeText={setDetails}
|
||||||
label="Text field"
|
label="Text field"
|
||||||
style={{paddingRight: 60}}
|
style={{paddingRight: 60}}
|
||||||
numberOfLines={6}
|
numberOfLines={5}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
@@ -231,7 +272,115 @@ function SubmitStep({
|
|||||||
<ButtonText>
|
<ButtonText>
|
||||||
<Trans>Send report</Trans>
|
<Trans>Send report</Trans>
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
{submitting && <ButtonIcon icon={Loader} />}
|
<ButtonIcon icon={submitting ? Loader : SendIcon} />
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function DoneStep({
|
||||||
|
convoId,
|
||||||
|
currentScreen,
|
||||||
|
profile,
|
||||||
|
}: {
|
||||||
|
convoId: string
|
||||||
|
currentScreen: 'list' | 'conversation'
|
||||||
|
profile: AppBskyActorDefs.ProfileViewBasic
|
||||||
|
}) {
|
||||||
|
const {_} = useLingui()
|
||||||
|
const navigation = useNavigation<NavigationProp>()
|
||||||
|
const control = Dialog.useDialogContext()
|
||||||
|
const {gtMobile} = useBreakpoints()
|
||||||
|
const t = useTheme()
|
||||||
|
const [actions, setActions] = useState<string[]>(['block', 'leave'])
|
||||||
|
const shadow = useProfileShadow(profile)
|
||||||
|
const [queueBlock] = useProfileBlockMutationQueue(shadow)
|
||||||
|
|
||||||
|
const {mutate: leaveConvo} = useLeaveConvo(convoId, {
|
||||||
|
onMutate: () => {
|
||||||
|
if (currentScreen === 'conversation') {
|
||||||
|
navigation.dispatch(
|
||||||
|
StackActions.replace('Messages', isNative ? {animation: 'pop'} : {}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: () => {
|
||||||
|
Toast.show(_(msg`Could not leave chat`), 'xmark')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const onPressPrimaryAction = () => {
|
||||||
|
control.close(() => {
|
||||||
|
if (actions.includes('block')) {
|
||||||
|
queueBlock()
|
||||||
|
}
|
||||||
|
if (actions.includes('leave')) {
|
||||||
|
leaveConvo()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let btnText = _(msg`Done`)
|
||||||
|
if (actions.includes('leave') && actions.includes('block')) {
|
||||||
|
btnText = _(msg`Block and Delete`)
|
||||||
|
} else if (actions.includes('leave')) {
|
||||||
|
btnText = _(msg`Delete Conversation`)
|
||||||
|
} else if (actions.includes('block')) {
|
||||||
|
btnText = _(msg`Block User`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={a.gap_2xl}>
|
||||||
|
<View style={[a.justify_center, gtMobile ? a.gap_sm : a.gap_xs]}>
|
||||||
|
<Text style={[a.text_2xl, a.font_bold]}>
|
||||||
|
<Trans>Report submitted</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
|
<Trans>Our moderation team has recieved your report.</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<Toggle.Group
|
||||||
|
label={_(msg`Block and/or delete this conversation`)}
|
||||||
|
values={actions}
|
||||||
|
onChange={setActions}>
|
||||||
|
<View style={[a.gap_md]}>
|
||||||
|
<Toggle.Item name="block" label={_(msg`Block user`)}>
|
||||||
|
<Toggle.Checkbox />
|
||||||
|
<Toggle.LabelText style={[a.text_md]}>
|
||||||
|
<Trans>Block user</Trans>
|
||||||
|
</Toggle.LabelText>
|
||||||
|
</Toggle.Item>
|
||||||
|
<Toggle.Item name="leave" label={_(msg`Delete coversation`)}>
|
||||||
|
<Toggle.Checkbox />
|
||||||
|
<Toggle.LabelText style={[a.text_md]}>
|
||||||
|
<Trans>Delete conversation</Trans>
|
||||||
|
</Toggle.LabelText>
|
||||||
|
</Toggle.Item>
|
||||||
|
</View>
|
||||||
|
</Toggle.Group>
|
||||||
|
|
||||||
|
<View style={[a.gap_md, web([a.flex_row_reverse])]}>
|
||||||
|
<Button
|
||||||
|
label={btnText}
|
||||||
|
onPress={onPressPrimaryAction}
|
||||||
|
size="large"
|
||||||
|
variant="solid"
|
||||||
|
color={actions.length > 0 ? 'negative' : 'primary'}>
|
||||||
|
<ButtonText>{btnText}</ButtonText>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
label={_(msg`Close`)}
|
||||||
|
onPress={() => control.close()}
|
||||||
|
size={platform({native: 'small', web: 'large'})}
|
||||||
|
variant={platform({
|
||||||
|
native: 'ghost',
|
||||||
|
web: 'solid',
|
||||||
|
})}
|
||||||
|
color="secondary">
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Close</Trans>
|
||||||
|
</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {logger} from '#/logger'
|
|||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
import {MESSAGE_SCREEN_POLL_INTERVAL} from '#/state/messages/convo/const'
|
import {MESSAGE_SCREEN_POLL_INTERVAL} from '#/state/messages/convo/const'
|
||||||
import {useMessagesEventBus} from '#/state/messages/events'
|
import {useMessagesEventBus} from '#/state/messages/events'
|
||||||
|
import {useLeftConvos} from '#/state/queries/messages/leave-conversation'
|
||||||
import {useListConvosQuery} from '#/state/queries/messages/list-conversations'
|
import {useListConvosQuery} from '#/state/queries/messages/list-conversations'
|
||||||
import {List} from '#/view/com/util/List'
|
import {List} from '#/view/com/util/List'
|
||||||
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
||||||
@@ -94,12 +95,19 @@ export function MessagesScreen({navigation, route}: Props) {
|
|||||||
|
|
||||||
useRefreshOnFocus(refetch)
|
useRefreshOnFocus(refetch)
|
||||||
|
|
||||||
|
const leftConvos = useLeftConvos()
|
||||||
|
|
||||||
const conversations = useMemo(() => {
|
const conversations = useMemo(() => {
|
||||||
if (data?.pages) {
|
if (data?.pages) {
|
||||||
return data.pages.flatMap(page => page.convos)
|
return (
|
||||||
|
data.pages
|
||||||
|
.flatMap(page => page.convos)
|
||||||
|
// filter out convos that are actively being left
|
||||||
|
.filter(convo => !leftConvos.includes(convo.id))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}, [data])
|
}, [data, leftConvos])
|
||||||
|
|
||||||
const onRefresh = useCallback(async () => {
|
const onRefresh = useCallback(async () => {
|
||||||
setIsPTRing(true)
|
setIsPTRing(true)
|
||||||
|
|||||||
@@ -1,17 +1,28 @@
|
|||||||
import {ChatBskyConvoLeaveConvo, ChatBskyConvoListConvos} from '@atproto/api'
|
import {ChatBskyConvoLeaveConvo, ChatBskyConvoListConvos} from '@atproto/api'
|
||||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
import {
|
||||||
|
useMutation,
|
||||||
|
useMutationState,
|
||||||
|
useQueryClient,
|
||||||
|
} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
|
import {DM_SERVICE_HEADERS} from '#/state/queries/messages/const'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {RQKEY as CONVO_LIST_KEY} from './list-conversations'
|
import {RQKEY as CONVO_LIST_KEY} from './list-conversations'
|
||||||
|
|
||||||
|
const RQKEY_ROOT = 'leave-convo'
|
||||||
|
export function RQKEY(convoId: string | undefined) {
|
||||||
|
return [RQKEY_ROOT, convoId]
|
||||||
|
}
|
||||||
|
|
||||||
export function useLeaveConvo(
|
export function useLeaveConvo(
|
||||||
convoId: string | undefined,
|
convoId: string | undefined,
|
||||||
{
|
{
|
||||||
onSuccess,
|
onSuccess,
|
||||||
|
onMutate,
|
||||||
onError,
|
onError,
|
||||||
}: {
|
}: {
|
||||||
|
onMutate?: () => void
|
||||||
onSuccess?: (data: ChatBskyConvoLeaveConvo.OutputSchema) => void
|
onSuccess?: (data: ChatBskyConvoLeaveConvo.OutputSchema) => void
|
||||||
onError?: (error: Error) => void
|
onError?: (error: Error) => void
|
||||||
},
|
},
|
||||||
@@ -20,6 +31,7 @@ export function useLeaveConvo(
|
|||||||
const agent = useAgent()
|
const agent = useAgent()
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
|
mutationKey: RQKEY(convoId),
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
if (!convoId) throw new Error('No convoId provided')
|
if (!convoId) throw new Error('No convoId provided')
|
||||||
|
|
||||||
@@ -51,6 +63,7 @@ export function useLeaveConvo(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
onMutate?.()
|
||||||
return {prevPages}
|
return {prevPages}
|
||||||
},
|
},
|
||||||
onSuccess: data => {
|
onSuccess: data => {
|
||||||
@@ -77,3 +90,20 @@ export function useLeaveConvo(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets currently pending and successful leave convo mutations
|
||||||
|
*
|
||||||
|
* @returns Array of `convoId`
|
||||||
|
*/
|
||||||
|
export function useLeftConvos() {
|
||||||
|
const pending = useMutationState({
|
||||||
|
filters: {mutationKey: [RQKEY_ROOT], status: 'pending'},
|
||||||
|
select: mutation => mutation.options.mutationKey?.[1] as string | undefined,
|
||||||
|
})
|
||||||
|
const success = useMutationState({
|
||||||
|
filters: {mutationKey: [RQKEY_ROOT], status: 'success'},
|
||||||
|
select: mutation => mutation.options.mutationKey?.[1] as string | undefined,
|
||||||
|
})
|
||||||
|
return [...pending, ...success].filter(id => id !== undefined)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user