import React, { forwardRef, MouseEventHandler, useEffect, useMemo } from 'react'; import { MatrixError, Room } from 'matrix-js-sdk'; import { IHierarchyRoom } from 'matrix-js-sdk/lib/@types/spaces'; import { Box, config, Text } from 'folds'; import { HierarchyItem, HierarchyItemRoom, HierarchyItemSpace, useFetchSpaceHierarchyLevel, } from '../../hooks/useSpaceHierarchy'; import { IPowerLevels } from '../../hooks/usePowerLevels'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { SpaceItemCard } from './SpaceItem'; import { AfterItemDropTarget, CanDropCallback } from './DnD'; import { HierarchyItemMenu } from './HierarchyItemMenu'; import { RoomItemCard } from './RoomItem'; import { RoomType, StateEvent } from '../../../types/matrix/room'; import { SequenceCard } from '../../components/sequence-card'; import { getRoomCreatorsForRoomId } from '../../hooks/useRoomCreators'; import { getRoomPermissionsAPI } from '../../hooks/useRoomPermissions'; type SpaceHierarchyProps = { summary: IHierarchyRoom | undefined; spaceItem: HierarchyItemSpace; roomItems?: HierarchyItemRoom[]; allJoinedRooms: Set; mDirects: Set; roomsPowerLevels: Map; categoryId: string; closed: boolean; handleClose: MouseEventHandler; draggingItem?: HierarchyItem; onDragging: (item?: HierarchyItem) => void; canDrop: CanDropCallback; disabledReorder?: boolean; nextSpaceId?: string; getRoom: (roomId: string) => Room | undefined; pinned: boolean; togglePinToSidebar: (roomId: string) => void; onSpacesFound: (spaceItems: IHierarchyRoom[]) => void; onOpenRoom: MouseEventHandler; }; export const SpaceHierarchy = forwardRef( ( { summary, spaceItem, roomItems, allJoinedRooms, mDirects, roomsPowerLevels, categoryId, closed, handleClose, draggingItem, onDragging, canDrop, disabledReorder, nextSpaceId, getRoom, pinned, togglePinToSidebar, onOpenRoom, onSpacesFound, }, ref ) => { const mx = useMatrixClient(); const { fetching, error, rooms } = useFetchSpaceHierarchyLevel(spaceItem.roomId, true); const subspaces = useMemo(() => { const s: Map = new Map(); rooms.forEach((r) => { if (r.room_type === RoomType.Space) { s.set(r.room_id, r); } }); return s; }, [rooms]); const spacePowerLevels = roomsPowerLevels.get(spaceItem.roomId); const spaceCreators = getRoomCreatorsForRoomId(mx, spaceItem.roomId); const spacePermissions = spacePowerLevels && getRoomPermissionsAPI(spaceCreators, spacePowerLevels); const draggingSpace = draggingItem?.roomId === spaceItem.roomId && draggingItem.parentId === spaceItem.parentId; const { parentId } = spaceItem; const parentPowerLevels = parentId ? roomsPowerLevels.get(parentId) : undefined; const parentCreators = parentId ? getRoomCreatorsForRoomId(mx, parentId) : undefined; const parentPermissions = parentCreators && parentPowerLevels && getRoomPermissionsAPI(parentCreators, parentPowerLevels); useEffect(() => { onSpacesFound(Array.from(subspaces.values())); }, [subspaces, onSpacesFound]); let childItems = roomItems?.filter((i) => !subspaces.has(i.roomId)); if (!spacePermissions?.stateEvent(StateEvent.SpaceChild, mx.getSafeUserId())) { // hide unknown rooms for normal user childItems = childItems?.filter((i) => { const forbidden = error instanceof MatrixError ? error.errcode === 'M_FORBIDDEN' : false; const inaccessibleRoom = !rooms.get(i.roomId) && !fetching && (error ? forbidden : true); return !inaccessibleRoom; }); } return ( ) } after={ } onDragging={onDragging} data-dragging={draggingSpace} /> {childItems && childItems.length > 0 ? ( {childItems.map((roomItem, index) => { const roomSummary = rooms.get(roomItem.roomId); const roomPowerLevels = roomsPowerLevels.get(roomItem.roomId) ?? {}; const lastItem = index === childItems.length; const nextRoomId = lastItem ? nextSpaceId : childItems[index + 1]?.roomId; const roomDragging = draggingItem?.roomId === roomItem.roomId && draggingItem.parentId === roomItem.parentId; return ( } after={ } data-dragging={roomDragging} onDragging={onDragging} /> ); })} ) : ( childItems && ( No Rooms This space does not contains rooms yet. ) )} ); } );