Files
cinny/src/app/pages/client/space/RoomProvider.tsx
litruv 99a294791e Open DMs during sync catch-up instead of blocking on parent maps.
Prefer the direct route for m.direct rooms and allow joined space children before roomToParents finishes backfilling.
2026-07-24 16:52:34 +10:00

93 lines
3.3 KiB
TypeScript

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 (
<JoinBeforeNavigate
roomIdOrAlias={roomIdOrAlias ?? rawRoomIdOrAlias!}
eventId={eventId}
viaServers={viaServers}
/>
);
}
if (developerTools && isSpace(room) && room.roomId === space.roomId) {
// allow to view space timeline
return (
<RoomProvider key={room.roomId} value={room}>
<IsDirectRoomProvider value={mDirects.has(room.roomId)}>{children}</IsDirectRoomProvider>
</RoomProvider>
);
}
if (!hasParentMapping && !isSpaceChild) {
return (
<JoinBeforeNavigate
roomIdOrAlias={roomIdOrAlias ?? rawRoomIdOrAlias!}
eventId={eventId}
viaServers={viaServers}
/>
);
}
return (
<RoomProvider key={room.roomId} value={room}>
<IsDirectRoomProvider value={mDirects.has(room.roomId)}>{children}</IsDirectRoomProvider>
</RoomProvider>
);
}