render common rooms in user profile

This commit is contained in:
Ajay Bura 2025-07-24 10:09:12 +05:30
parent 275b5bb18f
commit f4761a9418

View file

@ -1,4 +1,5 @@
import { import {
Avatar,
Box, Box,
Button, Button,
Chip, Chip,
@ -10,8 +11,10 @@ import {
MenuItem, MenuItem,
PopOut, PopOut,
RectCords, RectCords,
Scroll,
Spinner, Spinner,
Text, Text,
toRem,
} from 'folds'; } from 'folds';
import React, { MouseEventHandler, useState } from 'react'; import React, { MouseEventHandler, useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -19,7 +22,13 @@ import FocusTrap from 'focus-trap-react';
import { isKeyHotkey } from 'is-hotkey'; import { isKeyHotkey } from 'is-hotkey';
import { UserHero, UserHeroName } from './UserHero'; import { UserHero, UserHeroName } from './UserHero';
import { getMxIdServer, mxcUrlToHttp } from '../../utils/matrix'; import { getMxIdServer, mxcUrlToHttp } from '../../utils/matrix';
import { getMemberAvatarMxc, getMemberDisplayName } from '../../utils/room'; import {
getDirectRoomAvatarUrl,
getMemberAvatarMxc,
getMemberDisplayName,
getRoomAvatarUrl,
joinRuleToIconSrc,
} from '../../utils/room';
import { useMatrixClient } from '../../hooks/useMatrixClient'; import { useMatrixClient } from '../../hooks/useMatrixClient';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { PowerColorBadge, PowerIcon } from '../power'; import { PowerColorBadge, PowerIcon } from '../power';
@ -36,6 +45,12 @@ import { useOpenRoomSettings } from '../../state/hooks/roomSettings';
import { RoomSettingsPage } from '../../state/roomSettings'; import { RoomSettingsPage } from '../../state/roomSettings';
import { useRoom } from '../../hooks/useRoom'; import { useRoom } from '../../hooks/useRoom';
import { useSpaceOptionally } from '../../hooks/useSpace'; import { useSpaceOptionally } from '../../hooks/useSpace';
import { useAllJoinedRoomsSet, useGetRoom } from '../../hooks/useGetRoom';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { factoryRoomIdByAtoZ } from '../../utils/sort';
import { useDirectRooms } from '../../pages/client/direct/useDirectRooms';
import { RoomAvatar, RoomIcon } from '../room-avatar';
import { nameInitials } from '../../utils/common';
function ServerChip({ server }: { server: string }) { function ServerChip({ server }: { server: string }) {
const mx = useMatrixClient(); const mx = useMatrixClient();
@ -249,27 +264,141 @@ function MutualRoomsChip({ userId }: { userId: string }) {
const mx = useMatrixClient(); const mx = useMatrixClient();
const mutualRoomSupported = useMutualRoomsSupport(); const mutualRoomSupported = useMutualRoomsSupport();
const mutualRoomsState = useMutualRooms(userId); const mutualRoomsState = useMutualRooms(userId);
const { navigateRoom, navigateSpace } = useRoomNavigate();
const closeUserRoomProfile = useCloseUserRoomProfile();
const directs = useDirectRooms();
const useAuthentication = useMediaAuthentication();
const allJoinedRooms = useAllJoinedRoomsSet();
const getRoom = useGetRoom(allJoinedRooms);
const [cords, setCords] = useState<RectCords>();
const open: MouseEventHandler<HTMLButtonElement> = (evt) => {
setCords(evt.currentTarget.getBoundingClientRect());
};
const close = () => setCords(undefined);
if ( if (
userId === mx.getSafeUserId() || userId === mx.getSafeUserId() ||
!mutualRoomSupported || !mutualRoomSupported ||
mutualRoomsState.status === AsyncStatus.Error mutualRoomsState.status === AsyncStatus.Error
) ) {
return null; return null;
}
return ( return (
<Chip <PopOut
variant="SurfaceVariant" anchor={cords}
radii="Pill" position="Bottom"
before={mutualRoomsState.status === AsyncStatus.Loading && <Spinner size="50" />} align="Start"
disabled={mutualRoomsState.status !== AsyncStatus.Success} offset={4}
content={
mutualRoomsState.status === AsyncStatus.Success ? (
<FocusTrap
focusTrapOptions={{
initialFocus: false,
onDeactivate: close,
clickOutsideDeactivates: true,
escapeDeactivates: stopPropagation,
isKeyForward: (evt: KeyboardEvent) => isKeyHotkey('arrowdown', evt),
isKeyBackward: (evt: KeyboardEvent) => isKeyHotkey('arrowup', evt),
}}
>
<Menu
style={{
display: 'flex',
maxWidth: toRem(200),
maxHeight: '80vh',
}}
>
<Box grow="Yes">
<Scroll size="300" hideTrack>
<Box
direction="Column"
gap="100"
style={{
padding: config.space.S200,
paddingRight: 0,
}}
>
{mutualRoomsState.data
.sort(factoryRoomIdByAtoZ(mx))
.map((roomId) => getRoom(roomId))
.map((room) => {
if (!room) return null;
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>
);
})}
</Box>
</Scroll>
</Box>
</Menu>
</FocusTrap>
) : null
}
> >
<Text size="B300"> <Chip
{mutualRoomsState.status === AsyncStatus.Success && variant="SurfaceVariant"
`${mutualRoomsState.data.length} Mutual Rooms`} radii="Pill"
{mutualRoomsState.status === AsyncStatus.Loading && 'Mutual Rooms'} before={mutualRoomsState.status === AsyncStatus.Loading && <Spinner size="50" />}
</Text> disabled={mutualRoomsState.status !== AsyncStatus.Success}
</Chip> onClick={open}
aria-pressed={!!cords}
>
<Text size="B300">
{mutualRoomsState.status === AsyncStatus.Success &&
`${mutualRoomsState.data.length} Mutual Rooms`}
{mutualRoomsState.status === AsyncStatus.Loading && 'Mutual Rooms'}
</Text>
</Chip>
</PopOut>
); );
} }