From 2d335191f4c22def05a8e7b792168fe8e46ff9e6 Mon Sep 17 00:00:00 2001 From: Ajay Bura <32841439+ajbura@users.noreply.github.com> Date: Sat, 9 Aug 2025 12:35:31 +0530 Subject: [PATCH] add option to block user in user profile --- src/app/components/user-profile/UserChips.tsx | 105 +++++++++++++++++- .../user-profile/UserRoomProfile.tsx | 9 +- 2 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/app/components/user-profile/UserChips.tsx b/src/app/components/user-profile/UserChips.tsx index f4b8a56a..da606e36 100644 --- a/src/app/components/user-profile/UserChips.tsx +++ b/src/app/components/user-profile/UserChips.tsx @@ -1,4 +1,4 @@ -import React, { MouseEventHandler, useMemo, useState } from 'react'; +import React, { MouseEventHandler, useCallback, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import FocusTrap from 'focus-trap-react'; import { isKeyHotkey } from 'is-hotkey'; @@ -26,7 +26,7 @@ import { useCloseUserRoomProfile } from '../../state/hooks/userRoomProfile'; import { stopPropagation } from '../../utils/keyboard'; import { copyToClipboard } from '../../utils/dom'; import { getExploreServerPath } from '../../pages/pathUtils'; -import { AsyncStatus } from '../../hooks/useAsyncCallback'; +import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import { factoryRoomIdByAtoZ } from '../../utils/sort'; import { useMutualRooms, useMutualRoomsSupport } from '../../hooks/useMutualRooms'; import { useRoomNavigate } from '../../hooks/useRoomNavigate'; @@ -38,12 +38,16 @@ import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room'; import { nameInitials } from '../../utils/common'; import { getMatrixToUser } from '../../plugins/matrix-to'; import { useTimeoutToggle } from '../../hooks/useTimeoutToggle'; +import { useIgnoredUsers } from '../../hooks/useIgnoredUsers'; +import { CutoutCard } from '../cutout-card'; +import { SettingTile } from '../setting-tile'; export function ServerChip({ server }: { server: string }) { const mx = useMatrixClient(); const myServer = getMxIdServer(mx.getSafeUserId()); const navigate = useNavigate(); const closeProfile = useCloseUserRoomProfile(); + const [copied, setCopied] = useTimeoutToggle(); const [cords, setCords] = useState(); @@ -79,6 +83,7 @@ export function ServerChip({ server }: { server: string }) { radii="300" onClick={() => { copyToClipboard(server); + setCopied(); close(); }} > @@ -123,7 +128,7 @@ export function ServerChip({ server }: { server: string }) { cords ? ( ) : ( - + ) } onClick={open} @@ -413,3 +418,97 @@ export function MutualRoomsChip({ userId }: { userId: string }) { ); } + +export function IgnoredUserAlert() { + return ( + + + + + Blocked User + + + You do not receive any messages or invites sent by this user. + + + + + ); +} + +export function OptionsChip({ userId }: { userId: string }) { + const mx = useMatrixClient(); + const [cords, setCords] = useState(); + + const open: MouseEventHandler = (evt) => { + setCords(evt.currentTarget.getBoundingClientRect()); + }; + + const close = () => setCords(undefined); + + const ignoredUsers = useIgnoredUsers(); + const ignored = ignoredUsers.includes(userId); + + const [ignoreState, toggleIgnore] = useAsyncCallback( + useCallback(async () => { + const users = ignoredUsers.filter((u) => u !== userId); + if (!ignored) users.push(userId); + await mx.setIgnoredUsers(users); + }, [mx, ignoredUsers, userId, ignored]) + ); + const ignoring = ignoreState.status === AsyncStatus.Loading; + + return ( + isKeyHotkey('arrowdown', evt), + isKeyBackward: (evt: KeyboardEvent) => isKeyHotkey('arrowup', evt), + }} + > + +
+ { + toggleIgnore(); + close(); + }} + before={ + ignoring ? ( + + ) : ( + + ) + } + disabled={ignoring} + > + {ignored ? 'Unblock User' : 'Block User'} + +
+
+ + } + > + + {ignoring ? ( + + ) : ( + + )} + +
+ ); +} diff --git a/src/app/components/user-profile/UserRoomProfile.tsx b/src/app/components/user-profile/UserRoomProfile.tsx index 119f76f4..ab31fc2e 100644 --- a/src/app/components/user-profile/UserRoomProfile.tsx +++ b/src/app/components/user-profile/UserRoomProfile.tsx @@ -8,15 +8,16 @@ import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; import { usePowerLevels, usePowerLevelsAPI } from '../../hooks/usePowerLevels'; import { useRoom } from '../../hooks/useRoom'; import { useUserPresence } from '../../hooks/useUserPresence'; -import { MutualRoomsChip, ServerChip, ShareChip } from './UserChips'; +import { IgnoredUserAlert, MutualRoomsChip, OptionsChip, ServerChip, ShareChip } from './UserChips'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; -import { createDM } from '../../../client/action/room'; +import { createDM, ignore } from '../../../client/action/room'; import { hasDevices } from '../../../util/matrixUtil'; import { useRoomNavigate } from '../../hooks/useRoomNavigate'; import { useAlive } from '../../hooks/useAlive'; import { useCloseUserRoomProfile } from '../../state/hooks/userRoomProfile'; import { PowerChip } from './PowerChip'; import { UserBanAlert, UserModeration } from './UserModeration'; +import { useIgnoredUsers } from '../../hooks/useIgnoredUsers'; type UserRoomProfileProps = { userId: string; @@ -27,6 +28,8 @@ export function UserRoomProfile({ userId }: UserRoomProfileProps) { const { navigateRoom } = useRoomNavigate(); const alive = useAlive(); const closeUserRoomProfile = useCloseUserRoomProfile(); + const ignoredUsers = useIgnoredUsers(); + const ignored = ignoredUsers.includes(userId); const room = useRoom(); const powerlevels = usePowerLevels(room); @@ -108,8 +111,10 @@ export function UserRoomProfile({ userId }: UserRoomProfileProps) { + + {ignored && } {member?.membership === 'ban' && (