import React, { ReactNode, useEffect } from 'react'; import { useParams } from 'react-router-dom'; import { useAtom, useAtomValue } from 'jotai'; import { decodeRouteParam } from '../../pathUtils'; import { useSelectedRoom } from '../../../hooks/router/useSelectedRoom'; import { IsDirectRoomProvider, RoomProvider } from '../../../hooks/useRoom'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { JoinBeforeNavigate } from '../../../features/join-before-navigate'; import { useSpace } from '../../../hooks/useSpace'; import { getAllParents, getSpaceChildren, isSpace } from '../../../utils/room'; import { roomToParentsAtom } from '../../../state/room/roomToParents'; import { allRoomsAtom } from '../../../state/room-list/roomList'; import { useSearchParamsViaServers } from '../../../hooks/router/useSearchParamsViaServers'; import { mDirectAtom } from '../../../state/mDirectList'; import { settingsAtom } from '../../../state/settings'; import { useSetting } from '../../../state/hooks/settings'; export function SpaceRouteRoomProvider({ children }: { children: ReactNode }) { const mx = useMatrixClient(); const space = useSpace(); const [developerTools] = useSetting(settingsAtom, 'developerTools'); const [roomToParents, setRoomToParents] = useAtom(roomToParentsAtom); const mDirects = useAtomValue(mDirectAtom); const allRooms = useAtomValue(allRoomsAtom); const { roomIdOrAlias: rawRoomIdOrAlias, eventId: rawEventId } = useParams(); const roomIdOrAlias = decodeRouteParam(rawRoomIdOrAlias); const eventId = decodeRouteParam(rawEventId); const viaServers = useSearchParamsViaServers(); const roomId = useSelectedRoom(); const room = mx.getRoom(roomId); const isJoined = Boolean(room && allRooms.includes(room.roomId)); const isSpaceChild = Boolean(room && getSpaceChildren(space).includes(room.roomId)); const hasParentMapping = Boolean( room && getAllParents(roomToParents, room.roomId).has(space.roomId) ); // roomToParents can lag behind live space state during catch-up sync. // If the room is clearly a child of this space, backfill the map and open it. useEffect(() => { if (!room || !isJoined || hasParentMapping || !isSpaceChild) return; setRoomToParents({ type: 'PUT', parent: space.roomId, children: [room.roomId], }); }, [ room, isJoined, hasParentMapping, isSpaceChild, space.roomId, setRoomToParents, ]); if (!room || !isJoined) { // room is not joined return ( ); } if (developerTools && isSpace(room) && room.roomId === space.roomId) { // allow to view space timeline return ( {children} ); } if (!hasParentMapping && !isSpaceChild) { return ( ); } return ( {children} ); }