mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 14:30:29 +03:00 
			
		
		
		
	Revert most changes to Space.tsx
This commit is contained in:
		
							parent
							
								
									eaf70fb79a
								
							
						
					
					
						commit
						efc77ceb44
					
				
					 1 changed files with 47 additions and 216 deletions
				
			
		| 
						 | 
				
			
			@ -26,7 +26,6 @@ import { useVirtualizer } from '@tanstack/react-virtual';
 | 
			
		|||
import { JoinRule, Room } from 'matrix-js-sdk';
 | 
			
		||||
import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types';
 | 
			
		||||
import FocusTrap from 'focus-trap-react';
 | 
			
		||||
import { logger } from 'matrix-js-sdk/lib/logger';
 | 
			
		||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
 | 
			
		||||
import { mDirectAtom } from '../../../state/mDirectList';
 | 
			
		||||
import {
 | 
			
		||||
| 
						 | 
				
			
			@ -46,8 +45,7 @@ import {
 | 
			
		|||
import { useSpace } from '../../../hooks/useSpace';
 | 
			
		||||
import { VirtualTile } from '../../../components/virtualizer';
 | 
			
		||||
import { RoomNavCategoryButton, RoomNavItem } from '../../../features/room-nav';
 | 
			
		||||
// Using the original name for clarity when generating space category IDs
 | 
			
		||||
import { makeNavCategoryId as makeSpaceNavCategoryId } from '../../../state/closedNavCategories';
 | 
			
		||||
import { makeNavCategoryId } from '../../../state/closedNavCategories';
 | 
			
		||||
import { roomToUnreadAtom } from '../../../state/room/roomToUnread';
 | 
			
		||||
import { useCategoryHandler } from '../../../hooks/useCategoryHandler';
 | 
			
		||||
import { useNavToActivePathMapper } from '../../../hooks/useNavToActivePathMapper';
 | 
			
		||||
| 
						 | 
				
			
			@ -79,118 +77,6 @@ import {
 | 
			
		|||
import { useOpenSpaceSettings } from '../../../state/hooks/spaceSettings';
 | 
			
		||||
import { useRoomNavigate } from '../../../hooks/useRoomNavigate';
 | 
			
		||||
import { CallNavStatus } from '../../../features/room-nav/RoomCallNavStatus';
 | 
			
		||||
import { getStateEvents } from '../../../utils/room';
 | 
			
		||||
import { RoomNavUser } from '../../../features/room-nav/RoomNavUser';
 | 
			
		||||
import { useStateEvents } from '../../../hooks/useStateEvents';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Processes the raw hierarchy from useSpaceJoinedHierarchy into a flat list
 | 
			
		||||
 * suitable for the virtualizer, including collapsible headers for text/voice rooms.
 | 
			
		||||
 * Removes the top-level "Rooms" category header.
 | 
			
		||||
 *
 | 
			
		||||
 * @param hierarchy - The raw hierarchy data (array of { roomId: string }).
 | 
			
		||||
 * @param mx - The Matrix client instance.
 | 
			
		||||
 * @param spaceRoomId - The ID of the root space being viewed.
 | 
			
		||||
 * @param closedCategories - The Set of currently closed category IDs.
 | 
			
		||||
 * @returns An array of processed items for rendering.
 | 
			
		||||
 */
 | 
			
		||||
const processHierarchyForVirtualizer = (
 | 
			
		||||
  hierarchy: { roomId: string }[],
 | 
			
		||||
  mx: ReturnType<typeof useMatrixClient>,
 | 
			
		||||
  spaceRoomId: string,
 | 
			
		||||
  closedCategories: Set<string>
 | 
			
		||||
): Array<{ type: string; key: string; [key: string]: any }> => {
 | 
			
		||||
  const processed: Array<{ type: string; key: string; [key: string]: any }> = [];
 | 
			
		||||
  let currentCategoryRooms = { text: [], voice: [], users: [] };
 | 
			
		||||
  let currentParentId: string = spaceRoomId;
 | 
			
		||||
 | 
			
		||||
  const addCollectedRoomsToProcessed = (parentId: string) => {
 | 
			
		||||
    const textCategoryId = `${parentId}_text_rooms`;
 | 
			
		||||
    const voiceCategoryId = `${parentId}_call_rooms`;
 | 
			
		||||
    const isTextClosed = closedCategories.has(textCategoryId);
 | 
			
		||||
    const isCallClosed = closedCategories.has(voiceCategoryId);
 | 
			
		||||
 | 
			
		||||
    if (currentCategoryRooms.text.length > 0) {
 | 
			
		||||
      processed.push({
 | 
			
		||||
        type: 'room_header',
 | 
			
		||||
        title: 'Text Rooms',
 | 
			
		||||
        categoryId: textCategoryId,
 | 
			
		||||
        key: `${parentId}-text-header`,
 | 
			
		||||
      });
 | 
			
		||||
      if (!isTextClosed) {
 | 
			
		||||
        currentCategoryRooms.text.forEach((room) =>
 | 
			
		||||
          processed.push({ type: 'room', room, key: room.roomId })
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (currentCategoryRooms.voice.length > 0) {
 | 
			
		||||
      processed.push({
 | 
			
		||||
        type: 'room_header',
 | 
			
		||||
        title: 'Call Rooms',
 | 
			
		||||
        categoryId: voiceCategoryId,
 | 
			
		||||
        key: `${parentId}-voice-header`,
 | 
			
		||||
      });
 | 
			
		||||
      if (!isCallClosed) {
 | 
			
		||||
        currentCategoryRooms.voice.forEach((room) => {
 | 
			
		||||
          processed.push({ type: 'room', room, key: room.roomId });
 | 
			
		||||
 | 
			
		||||
          currentCategoryRooms.users.forEach((entry) => {
 | 
			
		||||
            if (entry.room.roomId === room.roomId) {
 | 
			
		||||
              processed.push(entry);
 | 
			
		||||
            }
 | 
			
		||||
          });
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    currentCategoryRooms = { text: [], voice: [], users: [] };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  hierarchy.forEach((item) => {
 | 
			
		||||
    const room = mx.getRoom(item.roomId);
 | 
			
		||||
    if (!room) {
 | 
			
		||||
      logger.warn(`processHierarchyForVirtualizer: Room not found for ID ${item.roomId}`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (room.isSpaceRoom()) {
 | 
			
		||||
      addCollectedRoomsToProcessed(currentParentId);
 | 
			
		||||
      currentParentId = room.roomId;
 | 
			
		||||
      if (room.roomId !== spaceRoomId) {
 | 
			
		||||
        const spaceCategoryId = makeSpaceNavCategoryId(spaceRoomId, room.roomId);
 | 
			
		||||
        processed.push({
 | 
			
		||||
          type: 'category',
 | 
			
		||||
          room,
 | 
			
		||||
          categoryId: spaceCategoryId,
 | 
			
		||||
          key: room.roomId,
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    } else if (room.isCallRoom()) {
 | 
			
		||||
      currentCategoryRooms.voice.push(room);
 | 
			
		||||
      getStateEvents(room, 'org.matrix.msc3401.call.member').forEach(({ event }) => {
 | 
			
		||||
        if (Object.entries(event?.content).length !== 0) {
 | 
			
		||||
          if (event.origin_server_ts + event.content.expires > Date.now()) {
 | 
			
		||||
            currentCategoryRooms.users.push({
 | 
			
		||||
              type: 'user',
 | 
			
		||||
              sender: event.sender,
 | 
			
		||||
              key: event.event_id,
 | 
			
		||||
              room,
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    } else if (!room.isCallRoom()) {
 | 
			
		||||
      currentCategoryRooms.text.push(room);
 | 
			
		||||
    } else {
 | 
			
		||||
      logger.warn(`processHierarchyForVirtualizer: Room ${room.roomId} is neither text nor voice.`);
 | 
			
		||||
      currentCategoryRooms.text.push(room);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  addCollectedRoomsToProcessed(currentParentId);
 | 
			
		||||
 | 
			
		||||
  return processed;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type SpaceMenuProps = {
 | 
			
		||||
  room: Room;
 | 
			
		||||
| 
						 | 
				
			
			@ -203,7 +89,7 @@ const SpaceMenu = forwardRef<HTMLDivElement, SpaceMenuProps>(({ room, requestClo
 | 
			
		|||
  const roomToParents = useAtomValue(roomToParentsAtom);
 | 
			
		||||
  const powerLevels = usePowerLevels(room);
 | 
			
		||||
  const { getPowerLevel, canDoAction } = usePowerLevelsAPI(powerLevels);
 | 
			
		||||
  const canInvite = canDoAction('invite', mx.getUserId() ?? '');
 | 
			
		||||
  const canInvite = canDoAction('invite', getPowerLevel(mx.getUserId() ?? ''));
 | 
			
		||||
  const openSpaceSettings = useOpenSpaceSettings();
 | 
			
		||||
  const { navigateRoom } = useRoomNavigate();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -354,6 +240,7 @@ function SpaceHeader() {
 | 
			
		|||
      return cords;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <PageNavHeader>
 | 
			
		||||
| 
						 | 
				
			
			@ -430,8 +317,7 @@ export function Space() {
 | 
			
		|||
    getRoom,
 | 
			
		||||
    useCallback(
 | 
			
		||||
      (parentId, roomId) => {
 | 
			
		||||
        const parentSpaceCategoryId = makeSpaceNavCategoryId(space.roomId, parentId);
 | 
			
		||||
        if (!closedCategories.has(parentSpaceCategoryId)) {
 | 
			
		||||
        if (!closedCategories.has(makeNavCategoryId(space.roomId, parentId))) {
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        const showRoomAnyway = roomToUnread.has(roomId) || roomId === selectedRoomId;
 | 
			
		||||
| 
						 | 
				
			
			@ -439,31 +325,14 @@ export function Space() {
 | 
			
		|||
      },
 | 
			
		||||
      [space.roomId, closedCategories, roomToUnread, selectedRoomId]
 | 
			
		||||
    ),
 | 
			
		||||
 | 
			
		||||
    useCallback(
 | 
			
		||||
      (subCategoryId) => closedCategories.has(makeSpaceNavCategoryId(space.roomId, subCategoryId)),
 | 
			
		||||
      (sId) => closedCategories.has(makeNavCategoryId(space.roomId, sId)),
 | 
			
		||||
      [closedCategories, space.roomId]
 | 
			
		||||
    )
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const callRooms = useMemo(
 | 
			
		||||
    () =>
 | 
			
		||||
      hierarchy
 | 
			
		||||
        .map((item) => mx.getRoom(item.roomId))
 | 
			
		||||
        .filter((room): room is Room => !!room && room.isCallRoom()),
 | 
			
		||||
    [hierarchy, mx]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const updateTrigger = useStateEvents(callRooms, StateEvent.GroupCallMemberPrefix);
 | 
			
		||||
 | 
			
		||||
  const processedHierarchy = useMemo(
 | 
			
		||||
    () => processHierarchyForVirtualizer(hierarchy, mx, space.roomId, closedCategories),
 | 
			
		||||
    // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
			
		||||
    [hierarchy, mx, space.roomId, closedCategories, updateTrigger]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const virtualizer = useVirtualizer({
 | 
			
		||||
    count: processedHierarchy.length,
 | 
			
		||||
    count: hierarchy.length,
 | 
			
		||||
    getScrollElement: () => scrollRef.current,
 | 
			
		||||
    estimateSize: () => 32,
 | 
			
		||||
    overscan: 10,
 | 
			
		||||
| 
						 | 
				
			
			@ -477,12 +346,9 @@ export function Space() {
 | 
			
		|||
    getSpaceRoomPath(spaceIdOrAlias, getCanonicalAliasOrRoomId(mx, roomId));
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <PageNav style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
 | 
			
		||||
    <PageNav>
 | 
			
		||||
      <SpaceHeader />
 | 
			
		||||
      <PageNavContent
 | 
			
		||||
        scrollRef={scrollRef}
 | 
			
		||||
        style={{ flexGrow: 1, overflowY: 'auto', overflowX: 'hidden' }}
 | 
			
		||||
      >
 | 
			
		||||
      <PageNavContent scrollRef={scrollRef}>
 | 
			
		||||
        <Box direction="Column" gap="300">
 | 
			
		||||
          <NavCategory>
 | 
			
		||||
            <NavItem variant="Background" radii="400" aria-selected={lobbySelected}>
 | 
			
		||||
| 
						 | 
				
			
			@ -518,91 +384,56 @@ export function Space() {
 | 
			
		|||
              </NavLink>
 | 
			
		||||
            </NavItem>
 | 
			
		||||
          </NavCategory>
 | 
			
		||||
        </Box>
 | 
			
		||||
        <NavCategory
 | 
			
		||||
          style={{
 | 
			
		||||
            height: `${virtualizer.getTotalSize()}px`,
 | 
			
		||||
            width: '100%',
 | 
			
		||||
            position: 'relative',
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          {virtualizer.getVirtualItems().map((vItem) => {
 | 
			
		||||
            const item = processedHierarchy[vItem.index];
 | 
			
		||||
            if (!item) return null;
 | 
			
		||||
            const renderContent = () => {
 | 
			
		||||
              switch (item.type) {
 | 
			
		||||
                case 'category': {
 | 
			
		||||
                  const { room, categoryId } = item;
 | 
			
		||||
                  const { name } = room;
 | 
			
		||||
                  const paddingTop = config?.space?.S400 ?? '1rem';
 | 
			
		||||
                  return (
 | 
			
		||||
                    <div style={{ paddingTop }}>
 | 
			
		||||
          <NavCategory
 | 
			
		||||
            style={{
 | 
			
		||||
              height: virtualizer.getTotalSize(),
 | 
			
		||||
              position: 'relative',
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            {virtualizer.getVirtualItems().map((vItem) => {
 | 
			
		||||
              const { roomId } = hierarchy[vItem.index] ?? {};
 | 
			
		||||
              const room = mx.getRoom(roomId);
 | 
			
		||||
              if (!room) return null;
 | 
			
		||||
 | 
			
		||||
              if (room.isSpaceRoom()) {
 | 
			
		||||
                const categoryId = makeNavCategoryId(space.roomId, roomId);
 | 
			
		||||
 | 
			
		||||
                return (
 | 
			
		||||
                  <VirtualTile
 | 
			
		||||
                    virtualItem={vItem}
 | 
			
		||||
                    key={vItem.index}
 | 
			
		||||
                    ref={virtualizer.measureElement}
 | 
			
		||||
                  >
 | 
			
		||||
                    <div style={{ paddingTop: vItem.index === 0 ? undefined : config.space.S400 }}>
 | 
			
		||||
                      <NavCategoryHeader>
 | 
			
		||||
                        <RoomNavCategoryButton
 | 
			
		||||
                          data-category-id={categoryId}
 | 
			
		||||
                          onClick={handleCategoryClick}
 | 
			
		||||
                          closed={closedCategories.has(categoryId)}
 | 
			
		||||
                        >
 | 
			
		||||
                          {name}
 | 
			
		||||
                          {roomId === space.roomId ? 'Rooms' : room?.name}
 | 
			
		||||
                        </RoomNavCategoryButton>
 | 
			
		||||
                      </NavCategoryHeader>
 | 
			
		||||
                    </div>
 | 
			
		||||
                  );
 | 
			
		||||
                }
 | 
			
		||||
                case 'room_header': {
 | 
			
		||||
                  const { title, categoryId } = item;
 | 
			
		||||
                  return (
 | 
			
		||||
                    <Box>
 | 
			
		||||
                      <NavCategoryHeader variant="Subtle">
 | 
			
		||||
                        <RoomNavCategoryButton
 | 
			
		||||
                          data-category-id={categoryId}
 | 
			
		||||
                          onClick={handleCategoryClick}
 | 
			
		||||
                          closed={closedCategories.has(categoryId)}
 | 
			
		||||
                        >
 | 
			
		||||
                          {title}
 | 
			
		||||
                        </RoomNavCategoryButton>
 | 
			
		||||
                      </NavCategoryHeader>
 | 
			
		||||
                    </Box>
 | 
			
		||||
                  );
 | 
			
		||||
                }
 | 
			
		||||
                case 'room': {
 | 
			
		||||
                  const { room } = item;
 | 
			
		||||
                  return (
 | 
			
		||||
                    <Box>
 | 
			
		||||
                      <RoomNavItem
 | 
			
		||||
                        room={room}
 | 
			
		||||
                        selected={selectedRoomId === room.roomId}
 | 
			
		||||
                        showAvatar={mDirects.has(room.roomId)}
 | 
			
		||||
                        direct={mDirects.has(room.roomId)}
 | 
			
		||||
                        linkPath={getToLink(room.roomId)}
 | 
			
		||||
                        notificationMode={getRoomNotificationMode(
 | 
			
		||||
                          notificationPreferences,
 | 
			
		||||
                          room.roomId
 | 
			
		||||
                        )}
 | 
			
		||||
                      />
 | 
			
		||||
                    </Box>
 | 
			
		||||
                  );
 | 
			
		||||
                }
 | 
			
		||||
                case 'user': {
 | 
			
		||||
                  const { sender, room } = item;
 | 
			
		||||
                  return (
 | 
			
		||||
                    <Box style={{ paddingLeft: config.space.S200 }}>
 | 
			
		||||
                      <RoomNavUser room={room} space={space} sender={sender} />
 | 
			
		||||
                    </Box>
 | 
			
		||||
                  );
 | 
			
		||||
                }
 | 
			
		||||
                default:
 | 
			
		||||
                  return null;
 | 
			
		||||
                  </VirtualTile>
 | 
			
		||||
                );
 | 
			
		||||
              }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return (
 | 
			
		||||
              <VirtualTile virtualItem={vItem} key={item.key} ref={virtualizer.measureElement}>
 | 
			
		||||
                {renderContent()}
 | 
			
		||||
              </VirtualTile>
 | 
			
		||||
            );
 | 
			
		||||
          })}
 | 
			
		||||
        </NavCategory>
 | 
			
		||||
              return (
 | 
			
		||||
                <VirtualTile virtualItem={vItem} key={vItem.index} ref={virtualizer.measureElement}>
 | 
			
		||||
                  <RoomNavItem
 | 
			
		||||
                    room={room}
 | 
			
		||||
                    selected={selectedRoomId === roomId}
 | 
			
		||||
                    showAvatar={mDirects.has(roomId)}
 | 
			
		||||
                    direct={mDirects.has(roomId)}
 | 
			
		||||
                    linkPath={getToLink(roomId)}
 | 
			
		||||
                    notificationMode={getRoomNotificationMode(notificationPreferences, room.roomId)}
 | 
			
		||||
                  />
 | 
			
		||||
                </VirtualTile>
 | 
			
		||||
              );
 | 
			
		||||
            })}
 | 
			
		||||
          </NavCategory>
 | 
			
		||||
        </Box>
 | 
			
		||||
      </PageNavContent>
 | 
			
		||||
      <CallNavStatus />
 | 
			
		||||
    </PageNav>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue