diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 22bbe784bb..c8b285ca1c 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -24,11 +24,6 @@ "count": 5 } }, - "src/components/Button.tsx": { - "@typescript-eslint/no-explicit-any": { - "count": 2 - } - }, "src/components/Composer/index.tsx": { "@typescript-eslint/no-explicit-any": { "count": 2 diff --git a/src/components/Button.tsx b/src/components/Button.tsx index a7acc8508b..aa705b1897 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -86,8 +86,8 @@ export type ButtonState = { export type ButtonContext = VariantProps & ButtonState type NonTextElements = - | React.ReactElement - | Iterable | null | undefined | boolean> + | React.ReactElement + | Iterable export type ButtonProps = Pick< PressableProps, diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx index 25b7f18840..916a7ec2d9 100644 --- a/src/components/Prompt.tsx +++ b/src/components/Prompt.tsx @@ -1,7 +1,6 @@ import {createContext, useCallback, useContext, useId, useMemo} from 'react' import {type GestureResponderEvent, View} from 'react-native' -import {msg} from '@lingui/core/macro' -import {useLingui} from '@lingui/react' +import {useLingui} from '@lingui/react/macro' import {atoms as a, type TextStyleProp, useTheme, web} from '#/alf' import { @@ -139,7 +138,7 @@ export function Cancel({ */ cta?: string }) { - const {_} = useLingui() + const {t: l} = useLingui() const {close} = Dialog.useDialogContext() const onPress = useCallback(() => { close() @@ -150,9 +149,9 @@ export function Cancel({ variant="solid" color="secondary" size="large" - label={cta || _(msg`Cancel`)} + label={cta || l`Cancel`} onPress={onPress}> - {cta || _(msg`Cancel`)} + {cta || l`Cancel`} ) } @@ -191,7 +190,7 @@ export function Action({ shouldCloseOnPress?: boolean testID?: string }) { - const {_} = useLingui() + const {t: l} = useLingui() const {close} = Dialog.useDialogContext() const handleOnPress = useCallback( (e: GestureResponderEvent) => { @@ -209,10 +208,10 @@ export function Action({ color={color} disabled={disabled} size="large" - label={cta || _(msg`Confirm`)} + label={cta || l`Confirm`} onPress={handleOnPress} testID={testID}> - {cta || _(msg`Confirm`)} + {cta || l`Confirm`} {icon && } ) diff --git a/src/screens/Messages/ConversationSettings/AddMembersLink.tsx b/src/screens/Messages/ConversationSettings/AddMembersLink.tsx index 1253c70881..dfb78c376a 100644 --- a/src/screens/Messages/ConversationSettings/AddMembersLink.tsx +++ b/src/screens/Messages/ConversationSettings/AddMembersLink.tsx @@ -1,6 +1,8 @@ import {View} from 'react-native' +import {plural} from '@lingui/core/macro' import {Trans, useLingui} from '@lingui/react/macro' +import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name' import {logger} from '#/logger' import {useAddGroupMembers} from '#/state/queries/messages/add-group-members' import {atoms as a, useTheme} from '#/alf' @@ -30,8 +32,28 @@ export function AddMembersLink({ const {mutate: addGroupMembers, isPending: isAddPending} = useAddGroupMembers( convoId, { - onSuccess: () => { - addMembersControl.close() + onSuccess: data => { + 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 => { logger.error('Failed to add group chat members', {message: e}) diff --git a/src/screens/Messages/ConversationSettings/Member.tsx b/src/screens/Messages/ConversationSettings/Member.tsx index 5fc520a9c2..9786e69f55 100644 --- a/src/screens/Messages/ConversationSettings/Member.tsx +++ b/src/screens/Messages/ConversationSettings/Member.tsx @@ -51,9 +51,7 @@ export function Member({ requireAuth(async () => { try { await queueFollow() - Toast.show(l`Following ${displayName}`, { - type: 'info', - }) + Toast.show(l`Following ${displayName}`) } catch (err) { const e = err as Error if (e?.name !== 'AbortError') { diff --git a/src/screens/Messages/ConversationSettings/MemberMenu.tsx b/src/screens/Messages/ConversationSettings/MemberMenu.tsx index 4d82d5169d..c13835a85a 100644 --- a/src/screens/Messages/ConversationSettings/MemberMenu.tsx +++ b/src/screens/Messages/ConversationSettings/MemberMenu.tsx @@ -181,14 +181,6 @@ export function MemberMenu({ - - - - Message - - { @@ -199,6 +191,14 @@ export function MemberMenu({ Go to profile + + + + Message + + diff --git a/src/screens/Messages/ConversationSettings/index.tsx b/src/screens/Messages/ConversationSettings/index.tsx index 33d397914b..c65f2caff9 100644 --- a/src/screens/Messages/ConversationSettings/index.tsx +++ b/src/screens/Messages/ConversationSettings/index.tsx @@ -176,6 +176,8 @@ function GroupSettings({ moderationOpts: ModerationOpts isReady: boolean }) { + const [isPTRing, setIsPTRing] = useState(false) + const initialNumToRender = useInitialNumToRender({minItemHeight: 68}) const bottomBarOffset = useBottomBarOffset() @@ -184,7 +186,7 @@ function GroupSettings({ const primaryMember = convo.primaryMember const isOwner = !!primaryMember && primaryMember.did === currentAccount?.did - const {data: memberListData = []} = useListConvoMembersQuery({ + const {data: memberListData = [], refetch} = useListConvoMembersQuery({ convoId: convo.view.id, 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 ( void onRefresh()} /> ) } diff --git a/src/screens/Messages/ConversationSettings/prompts.tsx b/src/screens/Messages/ConversationSettings/prompts.tsx index 4d58249e4b..f5b980b990 100644 --- a/src/screens/Messages/ConversationSettings/prompts.tsx +++ b/src/screens/Messages/ConversationSettings/prompts.tsx @@ -21,31 +21,33 @@ export function EditNamePrompt({ return ( - - - Edit group name - - - - - - - - - - - + <> + + + Edit group name + + + + + + + + + + + + ) } diff --git a/src/screens/Messages/components/ChatLocked.tsx b/src/screens/Messages/components/ChatLocked.tsx index 7e0d9ebafd..5402b6376d 100644 --- a/src/screens/Messages/components/ChatLocked.tsx +++ b/src/screens/Messages/components/ChatLocked.tsx @@ -74,9 +74,7 @@ export function ChatLocked({ a.text_sm, a.font_semi_bold, a.leading_snug, - { - color: t.palette.negative_500, - }, + t.atoms.text_contrast_high, ]}> Unlock chat diff --git a/src/screens/Messages/components/InviteLinkDialog.tsx b/src/screens/Messages/components/InviteLinkDialog.tsx index cca2e530fc..19504441a4 100644 --- a/src/screens/Messages/components/InviteLinkDialog.tsx +++ b/src/screens/Messages/components/InviteLinkDialog.tsx @@ -38,6 +38,7 @@ enum Step { INFO, GENERATE, MANAGE, + CONFIRM_DISABLE, } export function InviteLinkDialog({ @@ -341,13 +342,10 @@ export function InviteLinkDialog({ {isOwner ? ( { - disableJoinLink() - }}> + onPress={() => setStep(Step.CONFIRM_DISABLE)}> Disable ) : null} @@ -382,10 +380,10 @@ export function InviteLinkDialog({ ) : ( + + + + ) + break } if (!isOwner && (!joinLink || joinLink.enabledStatus === 'disabled')) { diff --git a/src/screens/Messages/components/MessagesListInfoPanel.tsx b/src/screens/Messages/components/MessagesListInfoPanel.tsx index 704ea9385b..1c831d3a90 100644 --- a/src/screens/Messages/components/MessagesListInfoPanel.tsx +++ b/src/screens/Messages/components/MessagesListInfoPanel.tsx @@ -1,6 +1,7 @@ import {View} from 'react-native' import {Plural, Trans, useLingui} from '@lingui/react/macro' +import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name' import {logger} from '#/logger' import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useAddGroupMembers} from '#/state/queries/messages/add-group-members' @@ -56,18 +57,22 @@ export function MessagesListInfoPanel({ let names: React.ReactNode = null if (members.length === 1) { - names = New chat with {members[0].displayName} + names = ( + New chat with {createSanitizedDisplayName(members[0])} + ) } else if (members.length === 2) { names = ( - New chat with {members[0].displayName} and {members[1].displayName} + New chat with {createSanitizedDisplayName(members[0])} and{' '} + {createSanitizedDisplayName(members[1])} ) } else if (members.length > 2) { const memberCount = convo.details.memberCount - 2 names = ( - New chat with {members[0].displayName}, {members[1].displayName}, and{' '} + New chat with {createSanitizedDisplayName(members[0])},{' '} + {createSanitizedDisplayName(members[1])}, and{' '} r.did === data.member.did, ) 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)) { diff --git a/src/state/queries/messages/remove-from-group.ts b/src/state/queries/messages/remove-from-group.ts index 566542438c..95f246be5a 100644 --- a/src/state/queries/messages/remove-from-group.ts +++ b/src/state/queries/messages/remove-from-group.ts @@ -1,6 +1,6 @@ import { type ChatBskyActorDefs, - type ChatBskyConvoDefs, + ChatBskyConvoDefs, type ChatBskyConvoListConvos, type ChatBskyGroupRemoveMembers, } from '@atproto/api' @@ -56,9 +56,18 @@ export function useRemoveFromGroupChat( CONVO_KEY(convoId), prev => { 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 { ...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, convos: page.convos.map(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 { ...convo, - members: convo.members.filter(m => !members.includes(m.did)), + members: nextMembers, + kind: { + ...convo.kind, + memberCount: Math.max(0, convo.kind.memberCount - removed), + }, } }), })),