fix space room list

This commit is contained in:
Ajay Bura 2024-04-04 20:54:38 +05:30
parent 50696be46e
commit bd68d0b0fa
8 changed files with 176 additions and 144 deletions

View file

@ -0,0 +1,24 @@
import { ReactNode } from 'react';
import { RoomToParents } from '../../types/matrix/room';
import { useMatrixClient } from '../hooks/useMatrixClient';
import { allRoomsAtom } from '../state/room-list/roomList';
import { useSpaceChildDirects } from '../state/hooks/roomList';
type SpaceChildDirectsProviderProps = {
spaceId: string;
mDirects: Set<string>;
roomToParents: RoomToParents;
children: (rooms: string[]) => ReactNode;
};
export function SpaceChildDirectsProvider({
spaceId,
roomToParents,
mDirects,
children,
}: SpaceChildDirectsProviderProps) {
const mx = useMatrixClient();
const childDirects = useSpaceChildDirects(mx, spaceId, allRoomsAtom, mDirects, roomToParents);
return children(childDirects);
}

View file

@ -6,17 +6,19 @@ import { useSpaceChildRooms } from '../state/hooks/roomList';
type SpaceChildRoomsProviderProps = {
spaceId: string;
mDirects: Set<string>;
roomToParents: RoomToParents;
children: (rooms: string[]) => ReactNode;
};
export function SpaceChildRoomsProvider({
spaceId,
roomToParents,
mDirects,
children,
}: SpaceChildRoomsProviderProps) {
const mx = useMatrixClient();
const childRooms = useSpaceChildRooms(mx, spaceId, allRoomsAtom, roomToParents);
const childRooms = useSpaceChildRooms(mx, spaceId, allRoomsAtom, mDirects, roomToParents);
return children(childRooms);
}

View file

@ -42,7 +42,7 @@ import { ClientLayout, ClientRoot } from './client';
import { Home, HomeSearch } from './client/home';
import { RoomViewer } from '../organisms/room/Room';
import { Direct } from './client/direct';
import { SpaceViewer } from './client/space';
import { RouteSpaceProvider, Space, SpaceSearch } from './client/space';
import { Explore, ExploreRedirect, FeaturedRooms, PublicRooms } from './client/explore';
import { Notifications, Inbox, InboxRedirect, Invites } from './client/inbox';
import { setAfterLoginRedirectPath } from './afterLoginRedirectPath';
@ -94,11 +94,13 @@ const createRouter = (clientConfig: ClientConfig) => {
<Route path={_CREATE_PATH} element={<p>create</p>} />
<Route path={_ROOM_PATH} element={<RoomViewer />} />
</Route>
<Route path={SPACE_PATH} element={<SpaceViewer />}>
<Route index element={<p>welcome</p>} />
<Route path={_LOBBY_PATH} element={<p>lobby</p>} />
<Route path={_SEARCH_PATH} element={<p>search</p>} />
<Route path={_ROOM_PATH} element={<RoomViewer />} />
<Route path={SPACE_PATH} element={<RouteSpaceProvider />}>
<Route element={<Space />}>
<Route index element={<p>welcome</p>} />
<Route path={_LOBBY_PATH} element={<p>lobby</p>} />
<Route path={_SEARCH_PATH} element={<SpaceSearch />} />
<Route path={_ROOM_PATH} element={<RoomViewer />} />
</Route>
</Route>
<Route path={EXPLORE_PATH} element={<Explore />}>
<Route index element={<ExploreRedirect />} />

View file

@ -0,0 +1,36 @@
import React, { useRef } from 'react';
import { Box, Icon, Icons, Text, Scroll } from 'folds';
import { Page, PageContent, PageContentCenter, PageHeader } from '../../../components/page';
import { MessageSearch } from '../../../features/message-search';
export function SpaceSearch() {
const scrollRef = useRef<HTMLDivElement>(null);
const rooms = [''];
return (
<Page>
<PageHeader>
<Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
<Icon size="400" src={Icons.Search} />
<Text size="H3" truncate>
Message Search
</Text>
</Box>
</PageHeader>
<Box style={{ position: 'relative' }} grow="Yes">
<Scroll ref={scrollRef} hideTrack visibility="Hover">
<PageContent>
<PageContentCenter>
<MessageSearch
defaultRoomsFilterName="Space"
allowGlobal
rooms={rooms}
scrollRef={scrollRef}
/>
</PageContentCenter>
</PageContent>
</Scroll>
</Box>
</Page>
);
}

View file

@ -1,20 +1,16 @@
import React, { useRef } from 'react';
import { Outlet, useParams } from 'react-router-dom';
import { Outlet } from 'react-router-dom';
import { useAtomValue } from 'jotai';
import { Avatar, Box, Icon, Icons, Text } from 'folds';
import { Room } from 'matrix-js-sdk';
import { ClientContentLayout } from '../ClientContentLayout';
import { ClientDrawerLayout } from '../ClientDrawerLayout';
import { ClientDrawerHeaderLayout } from '../ClientDrawerHeaderLayout';
import {
useSpaceRecursiveChildDirects,
useSpaceRecursiveChildSpaces,
} from '../../../state/hooks/roomList';
import { useSpaceChildSpacesRecursive } from '../../../state/hooks/roomList';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { allRoomsAtom } from '../../../state/room-list/roomList';
import { mDirectAtom } from '../../../state/mDirectList';
import { roomToParentsAtom } from '../../../state/room/roomToParents';
import { factoryRoomIdByAtoZ } from '../../../utils/sort';
import { factoryRoomIdByActivity, factoryRoomIdByAtoZ } from '../../../utils/sort';
import { ClientDrawerContentLayout } from '../ClientDrawerContentLayout';
import {
NavCategory,
@ -24,43 +20,38 @@ import {
NavLink,
} from '../../../components/nav';
import { UnreadBadge, UnreadBadgeCenter } from '../../../components/unread-badge';
import { RoomIcon } from '../../../components/room-avatar';
import { RoomAvatar, RoomIcon } from '../../../components/room-avatar';
import { getSpaceLobbyPath, getSpaceRoomPath, getSpaceSearchPath } from '../../pathUtils';
import { getCanonicalAliasOrRoomId } from '../../../utils/matrix';
import { RoomUnreadProvider } from '../../../components/RoomUnreadProvider';
import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom';
import {
useSelectedSpace,
useSpaceLobbySelected,
useSpaceSearchSelected,
} from '../../../hooks/router/useSelectedSpace';
import { SpaceChildRoomsProvider } from '../../../components/SpaceChildRoomsProvider';
import { getRoomAvatarUrl } from '../../../utils/room';
import { nameInitials } from '../../../utils/common';
import { SpaceChildDirectsProvider } from '../../../components/SpaceChildDirectsProvider';
import { useSpace } from '../../../hooks/useSpace';
export function Space({ spaceIdOrAlias, space }: { spaceIdOrAlias: string; space: Room }) {
export function Space() {
const mx = useMatrixClient();
const space = useSpace();
const spaceIdOrAlias = getCanonicalAliasOrRoomId(mx, space.roomId);
const scrollRef = useRef<HTMLDivElement>(null);
const mDirects = useAtomValue(mDirectAtom);
const roomToParents = useAtomValue(roomToParentsAtom);
const childSpaces = useSpaceRecursiveChildSpaces(mx, space.roomId, allRoomsAtom, roomToParents);
const childDirects = useSpaceRecursiveChildDirects(
mx,
space.roomId,
allRoomsAtom,
mDirects,
roomToParents
);
const childSpaces = useSpaceChildSpacesRecursive(mx, space.roomId, allRoomsAtom, roomToParents);
const selectedRoomId = useSelectedRoom();
const lobbySelected = useSpaceLobbySelected(spaceIdOrAlias);
const searchSelected = useSpaceSearchSelected(spaceIdOrAlias);
const getToLink = (roomId: string) =>
getSpaceRoomPath(
getCanonicalAliasOrRoomId(mx, space.roomId),
getCanonicalAliasOrRoomId(mx, roomId)
);
getSpaceRoomPath(spaceIdOrAlias, getCanonicalAliasOrRoomId(mx, roomId));
const renderRoomSelector = (roomId: string) => {
const room = mx.getRoom(roomId);
@ -81,7 +72,16 @@ export function Space({ spaceIdOrAlias, space }: { spaceIdOrAlias: string; space
<NavItemContent size="T300">
<Box as="span" grow="Yes" alignItems="Center" gap="200">
<Avatar size="200" radii="400">
<RoomIcon filled={selected} size="100" joinRule={room.getJoinRule()} />
{mDirects.has(roomId) ? (
<RoomAvatar
variant="Background"
src={getRoomAvatarUrl(mx, room, 96)}
alt={room.name}
renderInitials={() => <Text size="H6">{nameInitials(room.name)}</Text>}
/>
) : (
<RoomIcon filled={selected} size="100" joinRule={room.getJoinRule()} />
)}
</Avatar>
<Box as="span" grow="Yes">
<Text as="span" size="Inherit" truncate>
@ -151,7 +151,11 @@ export function Space({ spaceIdOrAlias, space }: { spaceIdOrAlias: string; space
</NavLink>
</NavItem>
</NavCategory>
<SpaceChildRoomsProvider spaceId={space.roomId} roomToParents={roomToParents}>
<SpaceChildRoomsProvider
spaceId={space.roomId}
mDirects={mDirects}
roomToParents={roomToParents}
>
{(childRooms) =>
childRooms.length > 0 && (
<NavCategory>
@ -167,30 +171,52 @@ export function Space({ spaceIdOrAlias, space }: { spaceIdOrAlias: string; space
<SpaceChildRoomsProvider
key={childSpaceId}
spaceId={childSpaceId}
mDirects={mDirects}
roomToParents={roomToParents}
>
{(childRooms) =>
childRooms.length > 0 && (
<NavCategory>
<NavCategoryHeader>
<Text size="O400">{mx.getRoom(childSpaceId)?.name}</Text>
</NavCategoryHeader>
{Array.from(childRooms)
.sort(factoryRoomIdByAtoZ(mx))
.map(renderRoomSelector)}
</NavCategory>
)
}
{(childRooms) => (
<SpaceChildDirectsProvider
spaceId={childSpaceId}
mDirects={mDirects}
roomToParents={roomToParents}
>
{(childDirects) =>
(childRooms.length > 0 || childDirects.length > 0) && (
<NavCategory>
<NavCategoryHeader>
<Text size="O400">{mx.getRoom(childSpaceId)?.name}</Text>
</NavCategoryHeader>
{Array.from(childRooms)
.sort(factoryRoomIdByAtoZ(mx))
.map(renderRoomSelector)}
{Array.from(childDirects)
.sort(factoryRoomIdByActivity(mx))
.map(renderRoomSelector)}
</NavCategory>
)
}
</SpaceChildDirectsProvider>
)}
</SpaceChildRoomsProvider>
))}
{childDirects.length > 0 && (
<NavCategory>
<NavCategoryHeader>
<Text size="O400">People</Text>
</NavCategoryHeader>
{Array.from(childDirects).sort(factoryRoomIdByAtoZ(mx)).map(renderRoomSelector)}
</NavCategory>
)}
<SpaceChildDirectsProvider
spaceId={space.roomId}
mDirects={mDirects}
roomToParents={roomToParents}
>
{(childDirects) =>
childDirects.length > 0 && (
<NavCategory>
<NavCategoryHeader>
<Text size="O400">People</Text>
</NavCategoryHeader>
{Array.from(childDirects)
.sort(factoryRoomIdByActivity(mx))
.map(renderRoomSelector)}
</NavCategory>
)
}
</SpaceChildDirectsProvider>
</Box>
</ClientDrawerContentLayout>
</ClientDrawerLayout>
@ -200,17 +226,3 @@ export function Space({ spaceIdOrAlias, space }: { spaceIdOrAlias: string; space
</ClientContentLayout>
);
}
export function SpaceViewer() {
const mx = useMatrixClient();
const { spaceIdOrAlias } = useParams();
const selectedSpaceId = useSelectedSpace();
const space = mx.getRoom(selectedSpaceId);
if (!space || !spaceIdOrAlias) {
return <p>TODO: join space screen</p>;
}
return <Space spaceIdOrAlias={spaceIdOrAlias} space={space} />;
}

View file

@ -0,0 +1,25 @@
import React from 'react';
import { Outlet } from 'react-router-dom';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { useSpaces } from '../../../state/hooks/roomList';
import { allRoomsAtom } from '../../../state/room-list/roomList';
import { useSelectedSpace } from '../../../hooks/router/useSelectedSpace';
import { SpaceProvider } from '../../../hooks/useSpace';
export function RouteSpaceProvider() {
const mx = useMatrixClient();
const joinedSpaces = useSpaces(mx, allRoomsAtom);
const selectedSpaceId = useSelectedSpace();
const space = mx.getRoom(selectedSpaceId);
if (!space || !joinedSpaces.includes(space.roomId)) {
return <p>TODO: join space screen</p>;
}
return (
<SpaceProvider value={space}>
<Outlet />
</SpaceProvider>
);
}

View file

@ -1 +1,3 @@
export * from './SpaceProvider';
export * from './Space';
export * from './Search';

View file

@ -7,12 +7,6 @@ import { compareRoomsEqual } from '../room-list/utils';
import { allRoomsAtom } from '../room-list/roomList';
import { RoomToParents } from '../../../types/matrix/room';
/**
* select list of space room id's from all rooms
* @param mx to check room type
* @param roomsAtom to pick rooms
* @returns list of space id's
*/
export const useSpaces = (mx: MatrixClient, roomsAtom: typeof allRoomsAtom) => {
const selector = useCallback(
(rooms: string[]) => rooms.filter((roomId) => isSpace(mx.getRoom(roomId))),
@ -21,13 +15,6 @@ export const useSpaces = (mx: MatrixClient, roomsAtom: typeof allRoomsAtom) => {
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of space room ids from all rooms which doesn't have any parent
* @param mx to check room type
* @param roomsAtom to pick rooms
* @param roomToParents: to exclude space's with parent
* @returns list of space ids
*/
export const useOrphanSpaces = (
mx: MatrixClient,
roomsAtom: typeof allRoomsAtom,
@ -41,15 +28,7 @@ export const useOrphanSpaces = (
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of all room ids from all rooms for which spaceId is in all parents
* @param mx to check room type
* @param spaceId as root parent
* @param roomsAtom to pick rooms
* @param roomToParents: to include child room
* @returns list of space ids
*/
export const useSpaceRecursiveChildSpaces = (
export const useSpaceChildSpacesRecursive = (
mx: MatrixClient,
spaceId: string,
roomsAtom: typeof allRoomsAtom,
@ -68,40 +47,27 @@ export const useSpaceRecursiveChildSpaces = (
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of all room ids from all rooms for which spaceId is in parents
* @param mx to check room type
* @param spaceId as root parent
* @param roomsAtom to pick rooms
* @param roomToParents: to include child room
* @returns list of space ids
*/
export const useSpaceChildRooms = (
mx: MatrixClient,
spaceId: string,
roomsAtom: typeof allRoomsAtom,
mDirects: Set<string>,
roomToParents: RoomToParents
) => {
const selector = useCallback(
(rooms: string[]) =>
rooms.filter(
(roomId) => isRoom(mx.getRoom(roomId)) && roomToParents.get(roomId)?.has(spaceId)
(roomId) =>
isRoom(mx.getRoom(roomId)) &&
!mDirects.has(roomId) &&
roomToParents.get(roomId)?.has(spaceId)
),
[mx, spaceId, roomToParents]
[mx, spaceId, mDirects, roomToParents]
);
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of all room ids from all rooms for which spaceId is in all parents
* @param mx to check room type
* @param spaceId as root parent
* @param roomsAtom to pick rooms
* @param mDirects to include only direct rooms
* @param roomToParents: to include child room
* @returns list of direct room ids
*/
export const useSpaceRecursiveChildDirects = (
export const useSpaceChildDirectsRecursive = (
mx: MatrixClient,
spaceId: string,
roomsAtom: typeof allRoomsAtom,
@ -122,15 +88,6 @@ export const useSpaceRecursiveChildDirects = (
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of all room ids from all rooms for which spaceId is in parents and is in mDirects
* @param mx to check room type
* @param spaceId as root parent
* @param roomsAtom to pick rooms
* @param mDirects to include only direct rooms
* @param roomToParents: to include child rooms
* @returns list of space ids
*/
export const useSpaceChildDirects = (
mx: MatrixClient,
spaceId: string,
@ -151,13 +108,6 @@ export const useSpaceChildDirects = (
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of room ids from all rooms which are not direct(dm)
* @param mx to check room type
* @param roomsAtom to pick rooms
* @param mDirects to exclude direct rooms
* @returns list of room ids
*/
export const useRooms = (
mx: MatrixClient,
roomsAtom: typeof allRoomsAtom,
@ -171,14 +121,6 @@ export const useRooms = (
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of room ids from all rooms which are not direct(dm) and doesn't have any parent
* @param mx to check room type
* @param roomsAtom to pick rooms
* @param mDirects to exclude direct rooms
* @param roomToParents to exclude rooms with parent
* @returns list of room ids
*/
export const useOrphanRooms = (
mx: MatrixClient,
roomsAtom: typeof allRoomsAtom,
@ -196,13 +138,6 @@ export const useOrphanRooms = (
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of room ids from all rooms which are direct(dm)
* @param mx to check room type
* @param roomsAtom to pick rooms
* @param mDirects to only include direct rooms
* @returns list of room ids
*/
export const useDirects = (
mx: MatrixClient,
roomsAtom: typeof allRoomsAtom,
@ -216,12 +151,6 @@ export const useDirects = (
return useAtomValue(selectAtom(roomsAtom, selector, compareRoomsEqual));
};
/**
* select list of room ids for which room type is unsupported
* @param mx to check room type
* @param roomsAtom to pick rooms
* @returns list of unsupported room ids
*/
export const useUnsupportedRooms = (mx: MatrixClient, roomsAtom: typeof allRoomsAtom) => {
const selector = useCallback(
(rooms: string[]) => rooms.filter((roomId) => isUnsupportedRoom(mx.getRoom(roomId))),