Skip to content

Commit

Permalink
improve member search
Browse files Browse the repository at this point in the history
  • Loading branch information
ajbura committed Oct 19, 2023
1 parent 49219d8 commit b517b94
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 23 deletions.
32 changes: 17 additions & 15 deletions src/app/components/editor/autocomplete/UserMentionAutocomplete.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, KeyboardEvent as ReactKeyboardEvent } from 'react';
import { Editor } from 'slate';
import { Avatar, AvatarFallback, AvatarImage, MenuItem, Text, color } from 'folds';
import { MatrixClient, RoomMember } from 'matrix-js-sdk';
import { MatrixClient, Room, RoomMember } from 'matrix-js-sdk';

import { AutocompleteQuery } from './autocompleteQuery';
import { AutocompleteMenu } from './AutocompleteMenu';
Expand All @@ -16,6 +16,7 @@ import { onTabPress } from '../../../utils/keyboard';
import { createMentionElement, moveCursor, replaceWithElement } from '../utils';
import { useKeyDown } from '../../../hooks/useKeyDown';
import { getMxIdLocalPart, getMxIdServer, validMxId } from '../../../utils/matrix';
import { getMemberDisplayName, getMemberSearchStr } from '../../../utils/room';

type MentionAutoCompleteHandler = (userId: string, name: string) => void;

Expand Down Expand Up @@ -64,7 +65,7 @@ function UnknownMentionItem({
}

type UserMentionAutocompleteProps = {
roomId: string;
room: Room;
editor: Editor;
query: AutocompleteQuery<string>;
requestClose: () => void;
Expand All @@ -77,21 +78,19 @@ const SEARCH_OPTIONS: UseAsyncSearchOptions = {
},
};

const getRoomMemberStr: SearchItemStrGetter<RoomMember> = (roomMember) => [
roomMember.name,
getMxIdLocalPart(roomMember.userId) ?? roomMember.userId,
roomMember.userId,
];
const mxIdToName = (mxId: string) => getMxIdLocalPart(mxId) ?? mxId;
const getRoomMemberStr: SearchItemStrGetter<RoomMember> = (m, query) =>
getMemberSearchStr(m, query, mxIdToName);

export function UserMentionAutocomplete({
roomId,
room,
editor,
query,
requestClose,
}: UserMentionAutocompleteProps) {
const mx = useMatrixClient();
const room = mx.getRoom(roomId);
const roomAliasOrId = room?.getCanonicalAlias() || roomId;
const roomId: string = room.roomId!;
const roomAliasOrId = room.getCanonicalAlias() || roomId;
const members = useRoomMembers(mx, roomId);

const [result, search, resetSearch] = useAsyncSearch(members, getRoomMemberStr, SEARCH_OPTIONS);
Expand Down Expand Up @@ -129,6 +128,9 @@ export function UserMentionAutocomplete({
});
});

const getName = (member: RoomMember) =>
getMemberDisplayName(room, member.userId) ?? getMxIdLocalPart(member.userId) ?? member.userId;

return (
<AutocompleteMenu headerContent={<Text size="L400">Mentions</Text>} requestClose={requestClose}>
{query.text === 'room' && (
Expand All @@ -155,9 +157,9 @@ export function UserMentionAutocomplete({
as="button"
radii="300"
onKeyDown={(evt: ReactKeyboardEvent<HTMLButtonElement>) =>
onTabPress(evt, () => handleAutocomplete(roomMember.userId, roomMember.name))
onTabPress(evt, () => handleAutocomplete(roomMember.userId, getName(roomMember)))
}
onClick={() => handleAutocomplete(roomMember.userId, roomMember.name)}
onClick={() => handleAutocomplete(roomMember.userId, getName(roomMember))}
after={
<Text size="T200" priority="300" truncate>
{roomMember.userId}
Expand All @@ -166,22 +168,22 @@ export function UserMentionAutocomplete({
before={
<Avatar size="200">
{avatarUrl ? (
<AvatarImage src={avatarUrl} alt={roomMember.userId} />
<AvatarImage src={avatarUrl} alt={getName(roomMember)} />
) : (
<AvatarFallback
style={{
backgroundColor: color.Secondary.Container,
color: color.Secondary.OnContainer,
}}
>
<Text size="H6">{roomMember.name[0] || roomMember.userId[1]}</Text>
<Text size="H6">{getName(roomMember)[0]}</Text>
</AvatarFallback>
)}
</Avatar>
}
>
<Text style={{ flexGrow: 1 }} size="B400" truncate>
{roomMember.name}
{getName(roomMember)}
</Text>
</MenuItem>
);
Expand Down
5 changes: 3 additions & 2 deletions src/app/hooks/useAsyncSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export type UseAsyncSearchOptions = AsyncSearchOption & {
};

export type SearchItemStrGetter<TSearchItem extends object | string | number> = (
searchItem: TSearchItem
searchItem: TSearchItem,
query: string
) => string | string[];

export type UseAsyncSearchResult<TSearchItem extends object | string | number> = {
Expand All @@ -38,7 +39,7 @@ export const useAsyncSearch = <TSearchItem extends object | string | number>(
setResult(undefined);

const handleMatch: MatchHandler<TSearchItem> = (item, query) => {
const itemStr = getItemStr(item);
const itemStr = getItemStr(item, query);
if (Array.isArray(itemStr))
return !!itemStr.find((i) =>
matchQuery(normalize(i, options?.normalizeOptions), query, options?.matchOptions)
Expand Down
15 changes: 11 additions & 4 deletions src/app/organisms/room/MembersDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@ import {
} from '../../hooks/useIntersectionObserver';
import { Membership } from '../../../types/matrix/room';
import { UseStateProvider } from '../../components/UseStateProvider';
import { UseAsyncSearchOptions, useAsyncSearch } from '../../hooks/useAsyncSearch';
import {
SearchItemStrGetter,
UseAsyncSearchOptions,
useAsyncSearch,
} from '../../hooks/useAsyncSearch';
import { useDebounce } from '../../hooks/useDebounce';
import colorMXID from '../../../util/colorMXID';
import { usePowerLevelTags, PowerLevelTag } from '../../hooks/usePowerLevelTags';
import { roomIdToTypingMembersAtom, selectRoomTypingMembersAtom } from '../../state/typingMembers';
import { TypingIndicator } from '../../components/typing-indicator';
import { getMemberDisplayName } from '../../utils/room';
import { getMemberDisplayName, getMemberSearchStr } from '../../utils/room';
import { getMxIdLocalPart } from '../../utils/matrix';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
Expand Down Expand Up @@ -161,7 +165,10 @@ const SEARCH_OPTIONS: UseAsyncSearchOptions = {
contain: true,
},
};
const getMemberItemStr = (m: RoomMember) => [m.name, m.userId];

const mxIdToName = (mxId: string) => getMxIdLocalPart(mxId) ?? mxId;
const getRoomMemberStr: SearchItemStrGetter<RoomMember> = (m, query) =>
getMemberSearchStr(m, query, mxIdToName);

type MembersDrawerProps = {
room: Room;
Expand Down Expand Up @@ -200,7 +207,7 @@ export function MembersDrawer({ room }: MembersDrawerProps) {

const [result, search, resetSearch] = useAsyncSearch(
filteredMembers,
getMemberItemStr,
getRoomMemberStr,
SEARCH_OPTIONS
);
if (!result && searchInputRef.current?.value) search(searchInputRef.current.value);
Expand Down
2 changes: 1 addition & 1 deletion src/app/organisms/room/RoomInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
)}
{autocompleteQuery?.prefix === AutocompletePrefix.UserMention && (
<UserMentionAutocomplete
roomId={roomId}
room={room}
editor={editor}
query={autocompleteQuery}
requestClose={handleCloseAutocomplete}
Expand Down
2 changes: 1 addition & 1 deletion src/app/organisms/room/message/MessageEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export const MessageEditor = as<'div', MessageEditorProps>(
)}
{autocompleteQuery?.prefix === AutocompletePrefix.UserMention && (
<UserMentionAutocomplete
roomId={roomId}
room={room}
editor={editor}
query={autocompleteQuery}
requestClose={handleCloseAutocomplete}
Expand Down
10 changes: 10 additions & 0 deletions src/app/utils/room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
NotificationCountType,
RelationType,
Room,
RoomMember,
} from 'matrix-js-sdk';
import { CryptoBackend } from 'matrix-js-sdk/lib/common-crypto/CryptoBackend';
import { AccountDataEvent } from '../../types/matrix/accountData';
Expand Down Expand Up @@ -293,6 +294,15 @@ export const getMemberDisplayName = (room: Room, userId: string): string | undef
return name;
};

export const getMemberSearchStr = (
member: RoomMember,
query: string,
mxIdToName: (mxId: string) => string
): string[] => [
member.rawDisplayName === member.userId ? mxIdToName(member.userId) : member.rawDisplayName,
query.startsWith('@') || query.indexOf(':') > -1 ? member.userId : mxIdToName(member.userId),
];

export const getMemberAvatarMxc = (room: Room, userId: string): string | undefined => {
const member = room.getMember(userId);
return member?.getMxcAvatarUrl();
Expand Down

0 comments on commit b517b94

Please sign in to comment.