show mutual rooms in spaces, rooms and direct messages categories

This commit is contained in:
Ajay Bura 2025-08-05 09:15:07 +05:30
parent 1b63b59fdc
commit 65600b2a1c

View file

@ -1,7 +1,8 @@
import React, { MouseEventHandler, useState } from 'react'; import React, { MouseEventHandler, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import FocusTrap from 'focus-trap-react'; import FocusTrap from 'focus-trap-react';
import { isKeyHotkey } from 'is-hotkey'; import { isKeyHotkey } from 'is-hotkey';
import { Room } from 'matrix-js-sdk';
import { import {
PopOut, PopOut,
Menu, Menu,
@ -134,6 +135,12 @@ export function ServerChip({ server }: { server: string }) {
); );
} }
type MutualRoomsData = {
rooms: Room[];
spaces: Room[];
directs: Room[];
};
export function MutualRoomsChip({ userId }: { userId: string }) { export function MutualRoomsChip({ userId }: { userId: string }) {
const mx = useMatrixClient(); const mx = useMatrixClient();
const mutualRoomSupported = useMutualRoomsSupport(); const mutualRoomSupported = useMutualRoomsSupport();
@ -154,6 +161,33 @@ export function MutualRoomsChip({ userId }: { userId: string }) {
const close = () => setCords(undefined); const close = () => setCords(undefined);
const mutual: MutualRoomsData = useMemo(() => {
const data: MutualRoomsData = {
rooms: [],
spaces: [],
directs: [],
};
if (mutualRoomsState.status === AsyncStatus.Success) {
const mutualRooms = mutualRoomsState.data
.sort(factoryRoomIdByAtoZ(mx))
.map(getRoom)
.filter((room) => !!room);
mutualRooms.forEach((room) => {
if (room.isSpaceRoom()) {
data.spaces.push(room);
return;
}
if (directs.includes(room.roomId)) {
data.directs.push(room);
return;
}
data.rooms.push(room);
});
}
return data;
}, [mutualRoomsState, getRoom, directs, mx]);
if ( if (
userId === mx.getSafeUserId() || userId === mx.getSafeUserId() ||
!mutualRoomSupported || !mutualRoomSupported ||
@ -162,6 +196,56 @@ export function MutualRoomsChip({ userId }: { userId: string }) {
return null; return null;
} }
const renderItem = (room: Room) => {
const { roomId } = room;
const dm = directs.includes(roomId);
return (
<MenuItem
key={roomId}
variant="Surface"
fill="None"
size="300"
radii="300"
style={{ paddingLeft: config.space.S100 }}
onClick={() => {
if (room.isSpaceRoom()) {
navigateSpace(roomId);
} else {
navigateRoom(roomId);
}
closeUserRoomProfile();
}}
before={
<Avatar size="200" radii={dm ? '400' : '300'}>
{dm || room.isSpaceRoom() ? (
<RoomAvatar
roomId={room.roomId}
src={
dm
? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication)
: getRoomAvatarUrl(mx, room, 96, useAuthentication)
}
alt={room.name}
renderFallback={() => (
<Text as="span" size="H6">
{nameInitials(room.name)}
</Text>
)}
/>
) : (
<RoomIcon size="100" joinRule={room.getJoinRule()} />
)}
</Avatar>
}
>
<Text size="B300" truncate>
{room.name}
</Text>
</MenuItem>
);
};
return ( return (
<PopOut <PopOut
anchor={cords} anchor={cords}
@ -191,65 +275,33 @@ export function MutualRoomsChip({ userId }: { userId: string }) {
<Scroll size="300" hideTrack> <Scroll size="300" hideTrack>
<Box <Box
direction="Column" direction="Column"
gap="100" gap="400"
style={{ style={{ padding: config.space.S200, paddingRight: 0 }}
padding: config.space.S200,
paddingRight: 0,
}}
> >
{mutualRoomsState.data {mutual.spaces.length > 0 && (
.sort(factoryRoomIdByAtoZ(mx)) <Box direction="Column" gap="100">
.map((roomId) => getRoom(roomId)) <Text style={{ paddingLeft: config.space.S100 }} size="L400">
.map((room) => { Spaces
if (!room) return null; </Text>
const { roomId } = room; {mutual.spaces.map(renderItem)}
const dm = directs.includes(roomId); </Box>
)}
return ( {mutual.rooms.length > 0 && (
<MenuItem <Box direction="Column" gap="100">
key={roomId} <Text style={{ paddingLeft: config.space.S100 }} size="L400">
variant="Surface" Rooms
fill="None" </Text>
size="300" {mutual.rooms.map(renderItem)}
radii="300" </Box>
style={{ paddingLeft: config.space.S100 }} )}
onClick={() => { {mutual.directs.length > 0 && (
if (room.isSpaceRoom()) { <Box direction="Column" gap="100">
navigateSpace(roomId); <Text style={{ paddingLeft: config.space.S100 }} size="L400">
} else { Direct Messages
navigateRoom(roomId); </Text>
} {mutual.directs.map(renderItem)}
closeUserRoomProfile(); </Box>
}} )}
before={
<Avatar size="200" radii={dm ? '400' : '300'}>
{dm || room.isSpaceRoom() ? (
<RoomAvatar
roomId={room.roomId}
src={
dm
? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication)
: getRoomAvatarUrl(mx, room, 96, useAuthentication)
}
alt={room.name}
renderFallback={() => (
<Text as="span" size="H6">
{nameInitials(room.name)}
</Text>
)}
/>
) : (
<RoomIcon size="100" joinRule={room.getJoinRule()} />
)}
</Avatar>
}
>
<Text size="B300" truncate>
{room.name}
</Text>
</MenuItem>
);
})}
</Box> </Box>
</Scroll> </Scroll>
</Box> </Box>
@ -262,7 +314,9 @@ export function MutualRoomsChip({ userId }: { userId: string }) {
variant="SurfaceVariant" variant="SurfaceVariant"
radii="Pill" radii="Pill"
before={mutualRoomsState.status === AsyncStatus.Loading && <Spinner size="50" />} before={mutualRoomsState.status === AsyncStatus.Loading && <Spinner size="50" />}
disabled={mutualRoomsState.status !== AsyncStatus.Success} disabled={
mutualRoomsState.status !== AsyncStatus.Success || mutualRoomsState.data.length === 0
}
onClick={open} onClick={open}
aria-pressed={!!cords} aria-pressed={!!cords}
> >