Update chat presentation (#10444)
This commit is contained in:
@@ -24,11 +24,6 @@
|
|||||||
"count": 5
|
"count": 5
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"src/components/Button.tsx": {
|
|
||||||
"@typescript-eslint/no-explicit-any": {
|
|
||||||
"count": 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"src/components/Composer/index.tsx": {
|
"src/components/Composer/index.tsx": {
|
||||||
"@typescript-eslint/no-explicit-any": {
|
"@typescript-eslint/no-explicit-any": {
|
||||||
"count": 2
|
"count": 2
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ export type ButtonState = {
|
|||||||
export type ButtonContext = VariantProps & ButtonState
|
export type ButtonContext = VariantProps & ButtonState
|
||||||
|
|
||||||
type NonTextElements =
|
type NonTextElements =
|
||||||
| React.ReactElement<any>
|
| React.ReactElement
|
||||||
| Iterable<React.ReactElement<any> | null | undefined | boolean>
|
| Iterable<React.ReactElement | null | undefined | boolean>
|
||||||
|
|
||||||
export type ButtonProps = Pick<
|
export type ButtonProps = Pick<
|
||||||
PressableProps,
|
PressableProps,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import {createContext, useCallback, useContext, useId, useMemo} from 'react'
|
import {createContext, useCallback, useContext, useId, useMemo} from 'react'
|
||||||
import {type GestureResponderEvent, View} from 'react-native'
|
import {type GestureResponderEvent, View} from 'react-native'
|
||||||
import {msg} from '@lingui/core/macro'
|
import {useLingui} from '@lingui/react/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
|
||||||
|
|
||||||
import {atoms as a, type TextStyleProp, useTheme, web} from '#/alf'
|
import {atoms as a, type TextStyleProp, useTheme, web} from '#/alf'
|
||||||
import {
|
import {
|
||||||
@@ -139,7 +138,7 @@ export function Cancel({
|
|||||||
*/
|
*/
|
||||||
cta?: string
|
cta?: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const {close} = Dialog.useDialogContext()
|
const {close} = Dialog.useDialogContext()
|
||||||
const onPress = useCallback(() => {
|
const onPress = useCallback(() => {
|
||||||
close()
|
close()
|
||||||
@@ -150,9 +149,9 @@ export function Cancel({
|
|||||||
variant="solid"
|
variant="solid"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
size="large"
|
size="large"
|
||||||
label={cta || _(msg`Cancel`)}
|
label={cta || l`Cancel`}
|
||||||
onPress={onPress}>
|
onPress={onPress}>
|
||||||
<ButtonText>{cta || _(msg`Cancel`)}</ButtonText>
|
<ButtonText>{cta || l`Cancel`}</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -191,7 +190,7 @@ export function Action({
|
|||||||
shouldCloseOnPress?: boolean
|
shouldCloseOnPress?: boolean
|
||||||
testID?: string
|
testID?: string
|
||||||
}) {
|
}) {
|
||||||
const {_} = useLingui()
|
const {t: l} = useLingui()
|
||||||
const {close} = Dialog.useDialogContext()
|
const {close} = Dialog.useDialogContext()
|
||||||
const handleOnPress = useCallback(
|
const handleOnPress = useCallback(
|
||||||
(e: GestureResponderEvent) => {
|
(e: GestureResponderEvent) => {
|
||||||
@@ -209,10 +208,10 @@ export function Action({
|
|||||||
color={color}
|
color={color}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
size="large"
|
size="large"
|
||||||
label={cta || _(msg`Confirm`)}
|
label={cta || l`Confirm`}
|
||||||
onPress={handleOnPress}
|
onPress={handleOnPress}
|
||||||
testID={testID}>
|
testID={testID}>
|
||||||
<ButtonText>{cta || _(msg`Confirm`)}</ButtonText>
|
<ButtonText>{cta || l`Confirm`}</ButtonText>
|
||||||
{icon && <ButtonIcon icon={icon} />}
|
{icon && <ButtonIcon icon={icon} />}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
|
import {plural} from '@lingui/core/macro'
|
||||||
import {Trans, useLingui} from '@lingui/react/macro'
|
import {Trans, useLingui} from '@lingui/react/macro'
|
||||||
|
|
||||||
|
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useAddGroupMembers} from '#/state/queries/messages/add-group-members'
|
import {useAddGroupMembers} from '#/state/queries/messages/add-group-members'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
@@ -30,8 +32,28 @@ export function AddMembersLink({
|
|||||||
const {mutate: addGroupMembers, isPending: isAddPending} = useAddGroupMembers(
|
const {mutate: addGroupMembers, isPending: isAddPending} = useAddGroupMembers(
|
||||||
convoId,
|
convoId,
|
||||||
{
|
{
|
||||||
onSuccess: () => {
|
onSuccess: data => {
|
||||||
addMembersControl.close()
|
addMembersControl.close(() => {
|
||||||
|
const members = data.addedMembers ?? []
|
||||||
|
|
||||||
|
let names = null
|
||||||
|
if (members.length === 1) {
|
||||||
|
names = l`${createSanitizedDisplayName(members[0])} added to chat`
|
||||||
|
} else if (members.length === 2) {
|
||||||
|
names = l`${createSanitizedDisplayName(members[0])} and ${createSanitizedDisplayName(members[1])} added to chat`
|
||||||
|
} else if (members.length > 2) {
|
||||||
|
const memberCount = convo.details.memberCount - 2
|
||||||
|
names = l`${createSanitizedDisplayName(members[0])}, ${createSanitizedDisplayName(members[1])}and ${plural(
|
||||||
|
memberCount,
|
||||||
|
{
|
||||||
|
one: '# other',
|
||||||
|
other: '# others',
|
||||||
|
},
|
||||||
|
)} added to chat`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (names) Toast.show(names)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
onError: e => {
|
onError: e => {
|
||||||
logger.error('Failed to add group chat members', {message: e})
|
logger.error('Failed to add group chat members', {message: e})
|
||||||
|
|||||||
@@ -51,9 +51,7 @@ export function Member({
|
|||||||
requireAuth(async () => {
|
requireAuth(async () => {
|
||||||
try {
|
try {
|
||||||
await queueFollow()
|
await queueFollow()
|
||||||
Toast.show(l`Following ${displayName}`, {
|
Toast.show(l`Following ${displayName}`)
|
||||||
type: 'info',
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const e = err as Error
|
const e = err as Error
|
||||||
if (e?.name !== 'AbortError') {
|
if (e?.name !== 'AbortError') {
|
||||||
|
|||||||
@@ -181,14 +181,6 @@ export function MemberMenu({
|
|||||||
</Menu.Trigger>
|
</Menu.Trigger>
|
||||||
<Menu.Outer>
|
<Menu.Outer>
|
||||||
<Menu.Group>
|
<Menu.Group>
|
||||||
<Menu.Item
|
|
||||||
label={l`Message ${displayName}`}
|
|
||||||
onPress={handleMessageMember}>
|
|
||||||
<Menu.ItemIcon icon={MessageIcon} />
|
|
||||||
<Menu.ItemText>
|
|
||||||
<Trans context="action">Message</Trans>
|
|
||||||
</Menu.ItemText>
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
label={l`View ${displayName}’s profile`}
|
label={l`View ${displayName}’s profile`}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
@@ -199,6 +191,14 @@ export function MemberMenu({
|
|||||||
<Trans>Go to profile</Trans>
|
<Trans>Go to profile</Trans>
|
||||||
</Menu.ItemText>
|
</Menu.ItemText>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
label={l`Message ${displayName}`}
|
||||||
|
onPress={handleMessageMember}>
|
||||||
|
<Menu.ItemIcon icon={MessageIcon} />
|
||||||
|
<Menu.ItemText>
|
||||||
|
<Trans context="action">Message</Trans>
|
||||||
|
</Menu.ItemText>
|
||||||
|
</Menu.Item>
|
||||||
</Menu.Group>
|
</Menu.Group>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Group>
|
<Menu.Group>
|
||||||
|
|||||||
@@ -176,6 +176,8 @@ function GroupSettings({
|
|||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
isReady: boolean
|
isReady: boolean
|
||||||
}) {
|
}) {
|
||||||
|
const [isPTRing, setIsPTRing] = useState(false)
|
||||||
|
|
||||||
const initialNumToRender = useInitialNumToRender({minItemHeight: 68})
|
const initialNumToRender = useInitialNumToRender({minItemHeight: 68})
|
||||||
const bottomBarOffset = useBottomBarOffset()
|
const bottomBarOffset = useBottomBarOffset()
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@ function GroupSettings({
|
|||||||
const primaryMember = convo.primaryMember
|
const primaryMember = convo.primaryMember
|
||||||
const isOwner = !!primaryMember && primaryMember.did === currentAccount?.did
|
const isOwner = !!primaryMember && primaryMember.did === currentAccount?.did
|
||||||
|
|
||||||
const {data: memberListData = []} = useListConvoMembersQuery({
|
const {data: memberListData = [], refetch} = useListConvoMembersQuery({
|
||||||
convoId: convo.view.id,
|
convoId: convo.view.id,
|
||||||
placeholderData: convo.members,
|
placeholderData: convo.members,
|
||||||
})
|
})
|
||||||
@@ -269,6 +271,16 @@ function GroupSettings({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onRefresh = async () => {
|
||||||
|
setIsPTRing(true)
|
||||||
|
try {
|
||||||
|
await refetch()
|
||||||
|
} catch (err) {
|
||||||
|
logger.error('Failed to refresh group chat members', {message: err})
|
||||||
|
}
|
||||||
|
setIsPTRing(false)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List
|
<List
|
||||||
data={items}
|
data={items}
|
||||||
@@ -289,6 +301,8 @@ function GroupSettings({
|
|||||||
renderItem={renderItem}
|
renderItem={renderItem}
|
||||||
sideBorders={false}
|
sideBorders={false}
|
||||||
windowSize={11}
|
windowSize={11}
|
||||||
|
refreshing={isPTRing}
|
||||||
|
onRefresh={() => void onRefresh()}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export function EditNamePrompt({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Prompt.Outer control={control}>
|
<Prompt.Outer control={control}>
|
||||||
|
<>
|
||||||
<Prompt.Content>
|
<Prompt.Content>
|
||||||
<Prompt.TitleText>
|
<Prompt.TitleText>
|
||||||
<Trans>Edit group name</Trans>
|
<Trans>Edit group name</Trans>
|
||||||
@@ -46,6 +47,7 @@ export function EditNamePrompt({
|
|||||||
<Prompt.Action cta={l`Save`} onPress={onConfirm} />
|
<Prompt.Action cta={l`Save`} onPress={onConfirm} />
|
||||||
<Prompt.Cancel />
|
<Prompt.Cancel />
|
||||||
</Prompt.Actions>
|
</Prompt.Actions>
|
||||||
|
</>
|
||||||
</Prompt.Outer>
|
</Prompt.Outer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,9 +74,7 @@ export function ChatLocked({
|
|||||||
a.text_sm,
|
a.text_sm,
|
||||||
a.font_semi_bold,
|
a.font_semi_bold,
|
||||||
a.leading_snug,
|
a.leading_snug,
|
||||||
{
|
t.atoms.text_contrast_high,
|
||||||
color: t.palette.negative_500,
|
|
||||||
},
|
|
||||||
]}>
|
]}>
|
||||||
<Trans>Unlock chat</Trans>
|
<Trans>Unlock chat</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ enum Step {
|
|||||||
INFO,
|
INFO,
|
||||||
GENERATE,
|
GENERATE,
|
||||||
MANAGE,
|
MANAGE,
|
||||||
|
CONFIRM_DISABLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InviteLinkDialog({
|
export function InviteLinkDialog({
|
||||||
@@ -341,13 +342,10 @@ export function InviteLinkDialog({
|
|||||||
{isOwner ? (
|
{isOwner ? (
|
||||||
<StackedButton
|
<StackedButton
|
||||||
label={l`Disable`}
|
label={l`Disable`}
|
||||||
icon={isDisabling ? Loader : ChainLinkBrokenIcon}
|
icon={ChainLinkBrokenIcon}
|
||||||
color="negative_subtle"
|
color="negative_subtle"
|
||||||
style={[a.flex_1, a.rounded_full]}
|
style={[a.flex_1, a.rounded_full]}
|
||||||
disabled={isDisabling}
|
onPress={() => setStep(Step.CONFIRM_DISABLE)}>
|
||||||
onPress={() => {
|
|
||||||
disableJoinLink()
|
|
||||||
}}>
|
|
||||||
<Trans>Disable</Trans>
|
<Trans>Disable</Trans>
|
||||||
</StackedButton>
|
</StackedButton>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -382,10 +380,10 @@ export function InviteLinkDialog({
|
|||||||
) : (
|
) : (
|
||||||
<View style={[a.gap_md, a.mt_lg]}>
|
<View style={[a.gap_md, a.mt_lg]}>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={isEnabling || isDisabling}
|
||||||
label={l`Re-enable invite link`}
|
label={l`Re-enable invite link`}
|
||||||
color="primary"
|
color="primary"
|
||||||
size="large"
|
size="large"
|
||||||
disabled={isEnabling}
|
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
enableJoinLink()
|
enableJoinLink()
|
||||||
}}>
|
}}>
|
||||||
@@ -395,6 +393,7 @@ export function InviteLinkDialog({
|
|||||||
{isEnabling && <ButtonIcon icon={Loader} />}
|
{isEnabling && <ButtonIcon icon={Loader} />}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={isEnabling || isDisabling}
|
||||||
label={l`Generate new invite link`}
|
label={l`Generate new invite link`}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
size="large"
|
size="large"
|
||||||
@@ -409,6 +408,63 @@ export function InviteLinkDialog({
|
|||||||
)
|
)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case Step.CONFIRM_DISABLE:
|
||||||
|
content = (
|
||||||
|
<>
|
||||||
|
<View style={[a.align_center, a.justify_center, a.mb_lg]}>
|
||||||
|
<ChainLinkBrokenIcon fill={t.palette.negative_500} size="3xl" />
|
||||||
|
</View>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.flex_1,
|
||||||
|
a.pb_sm,
|
||||||
|
a.text_center,
|
||||||
|
a.text_lg,
|
||||||
|
a.font_bold,
|
||||||
|
a.leading_snug,
|
||||||
|
]}>
|
||||||
|
<Trans>Disable this invite link?</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
a.pb_2xl,
|
||||||
|
a.text_center,
|
||||||
|
a.text_sm,
|
||||||
|
a.leading_snug,
|
||||||
|
t.atoms.text,
|
||||||
|
]}>
|
||||||
|
<Trans>
|
||||||
|
Anyone who has it will no longer be able to join or request to
|
||||||
|
join. You can always create a new one.
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
<View style={[a.w_full, a.gap_md, a.justify_end]}>
|
||||||
|
<Button
|
||||||
|
color="negative"
|
||||||
|
disabled={isDisabling}
|
||||||
|
size="large"
|
||||||
|
label={l`Disable link`}
|
||||||
|
onPress={() => {
|
||||||
|
disableJoinLink()
|
||||||
|
setStep(Step.MANAGE)
|
||||||
|
}}>
|
||||||
|
<ButtonText>
|
||||||
|
<Trans>Disable link</Trans>
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
color="secondary"
|
||||||
|
size="large"
|
||||||
|
label={l`Cancel`}
|
||||||
|
onPress={() => {
|
||||||
|
setStep(Step.MANAGE)
|
||||||
|
}}>
|
||||||
|
<ButtonText>{l`Cancel`}</ButtonText>
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOwner && (!joinLink || joinLink.enabledStatus === 'disabled')) {
|
if (!isOwner && (!joinLink || joinLink.enabledStatus === 'disabled')) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {Plural, Trans, useLingui} from '@lingui/react/macro'
|
import {Plural, Trans, useLingui} from '@lingui/react/macro'
|
||||||
|
|
||||||
|
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
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'
|
||||||
@@ -56,18 +57,22 @@ export function MessagesListInfoPanel({
|
|||||||
|
|
||||||
let names: React.ReactNode = null
|
let names: React.ReactNode = null
|
||||||
if (members.length === 1) {
|
if (members.length === 1) {
|
||||||
names = <Trans>New chat with {members[0].displayName}</Trans>
|
names = (
|
||||||
|
<Trans>New chat with {createSanitizedDisplayName(members[0])}</Trans>
|
||||||
|
)
|
||||||
} else if (members.length === 2) {
|
} else if (members.length === 2) {
|
||||||
names = (
|
names = (
|
||||||
<Trans>
|
<Trans>
|
||||||
New chat with {members[0].displayName} and {members[1].displayName}
|
New chat with {createSanitizedDisplayName(members[0])} and{' '}
|
||||||
|
{createSanitizedDisplayName(members[1])}
|
||||||
</Trans>
|
</Trans>
|
||||||
)
|
)
|
||||||
} else if (members.length > 2) {
|
} else if (members.length > 2) {
|
||||||
const memberCount = convo.details.memberCount - 2
|
const memberCount = convo.details.memberCount - 2
|
||||||
names = (
|
names = (
|
||||||
<Trans>
|
<Trans>
|
||||||
New chat with {members[0].displayName}, {members[1].displayName}, and{' '}
|
New chat with {createSanitizedDisplayName(members[0])},{' '}
|
||||||
|
{createSanitizedDisplayName(members[1])}, and{' '}
|
||||||
<Plural
|
<Plural
|
||||||
value={memberCount}
|
value={memberCount}
|
||||||
one={`${memberCount} more`}
|
one={`${memberCount} more`}
|
||||||
|
|||||||
@@ -59,7 +59,11 @@ export function useListConvoMembersQuery({
|
|||||||
r => r.did === data.member.did,
|
r => r.did === data.member.did,
|
||||||
)
|
)
|
||||||
if (newMember) {
|
if (newMember) {
|
||||||
mutateList(list => list.concat(newMember))
|
mutateList(list =>
|
||||||
|
list.some(m => m.did === newMember.did)
|
||||||
|
? list
|
||||||
|
: list.concat(newMember),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ChatBskyConvoDefs.isLogRemoveMember(log)) {
|
} else if (ChatBskyConvoDefs.isLogRemoveMember(log)) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
type ChatBskyActorDefs,
|
type ChatBskyActorDefs,
|
||||||
type ChatBskyConvoDefs,
|
ChatBskyConvoDefs,
|
||||||
type ChatBskyConvoListConvos,
|
type ChatBskyConvoListConvos,
|
||||||
type ChatBskyGroupRemoveMembers,
|
type ChatBskyGroupRemoveMembers,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
@@ -56,9 +56,18 @@ export function useRemoveFromGroupChat(
|
|||||||
CONVO_KEY(convoId),
|
CONVO_KEY(convoId),
|
||||||
prev => {
|
prev => {
|
||||||
if (!prev) return
|
if (!prev) return
|
||||||
|
const nextMembers = prev.members.filter(m => !members.includes(m.did))
|
||||||
|
const removed = prev.members.length - nextMembers.length
|
||||||
|
if (!ChatBskyConvoDefs.isGroupConvo(prev.kind)) {
|
||||||
|
return {...prev, members: nextMembers}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
members: prev.members.filter(m => !members.includes(m.did)),
|
members: nextMembers,
|
||||||
|
kind: {
|
||||||
|
...prev.kind,
|
||||||
|
memberCount: Math.max(0, prev.kind.memberCount - removed),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -73,9 +82,20 @@ export function useRemoveFromGroupChat(
|
|||||||
...page,
|
...page,
|
||||||
convos: page.convos.map(convo => {
|
convos: page.convos.map(convo => {
|
||||||
if (convo.id !== convoId) return convo
|
if (convo.id !== convoId) return convo
|
||||||
|
const nextMembers = convo.members.filter(
|
||||||
|
m => !members.includes(m.did),
|
||||||
|
)
|
||||||
|
const removed = convo.members.length - nextMembers.length
|
||||||
|
if (!ChatBskyConvoDefs.isGroupConvo(convo.kind)) {
|
||||||
|
return {...convo, members: nextMembers}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...convo,
|
...convo,
|
||||||
members: convo.members.filter(m => !members.includes(m.did)),
|
members: nextMembers,
|
||||||
|
kind: {
|
||||||
|
...convo.kind,
|
||||||
|
memberCount: Math.max(0, convo.kind.memberCount - removed),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
|
|||||||
Reference in New Issue
Block a user