Files
cinny/src/app/features/join-before-navigate/JoinBeforeNavigate.tsx
T
jared 0c6003fb87
CI / Build & Quality Checks (push) Successful in 10m53s
CI / Trigger Desktop Build (push) Successful in 14s
fix(room-preview): make the preview card actually populate + richer
Two review agents found the preview card degrades to 'id + logo + Join' for real
reasons. Fixes:

- **via was dropped at the summary fetch** (root cause). RoomSummaryLoader now
  accepts + forwards `via` to getRoomSummary (and keys the query on it);
  JoinBeforeNavigate passes viaServers; the lobby Preview chip carries data-via and
  Lobby.handleOpenRoom appends it to the navigated URL. Without this, previews of
  rooms the HS isn't already in came back sparse/404.
- **No loading/error state** -> RoomSummaryLoader now surfaces {loading,error};
  JoinBeforeNavigate shows a Spinner while loading instead of the degraded card.
- **Room id leaked as name AND topic AND header** -> stop using the raw `!id` as
  the topic fallback (show 'No description'); name falls back to canonical_alias
  then alias-localpart; the page header shows the summary name.
- **Richer, membership-aware card**: forward canonical_alias (shown under the name),
  world_readable ('Readable' badge), and membership -> the button now shows Accept
  invite / Requested / Banned correctly instead of a Join that lies; a 'hero' layout
  for the single-preview page (primary Join button, unclamped topic). Removed dead
  `|| undefined ||`.

IRoomSummary re-adds canonical_alias (the SDK type Omit<>s it though MSC3266
returns it). 738 tests pass, build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 14:46:21 -04:00

100 lines
3.9 KiB
TypeScript

import React from 'react';
import { Box, Icon, IconButton, Icons, Scroll, Spinner, Text, toRem } from 'folds';
import { useAtomValue } from 'jotai';
import { RoomCard } from '../../components/room-card';
import { RoomTopicViewer } from '../../components/room-topic-viewer';
import { Page, PageHeader } from '../../components/page';
import { RoomSummaryLoader } from '../../components/RoomSummaryLoader';
import { useRoomNavigate } from '../../hooks/useRoomNavigate';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { allRoomsAtom } from '../../state/room-list/roomList';
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
import { BackRouteHandler } from '../../components/BackRouteHandler';
type JoinBeforeNavigateProps = { roomIdOrAlias: string; eventId?: string; viaServers?: string[] };
export function JoinBeforeNavigate({
roomIdOrAlias,
eventId,
viaServers,
}: JoinBeforeNavigateProps) {
const mx = useMatrixClient();
const allRooms = useAtomValue(allRoomsAtom);
const { navigateRoom, navigateSpace } = useRoomNavigate();
const screenSize = useScreenSizeContext();
const handleView = (roomId: string) => {
if (mx.getRoom(roomId)?.isSpaceRoom()) {
navigateSpace(roomId);
return;
}
navigateRoom(roomId, eventId);
};
return (
<Page>
<RoomSummaryLoader roomIdOrAlias={roomIdOrAlias} via={viaServers}>
{(summary, state) => (
<>
<PageHeader balance>
<Box grow="Yes" gap="200">
<Box shrink="No">
{screenSize === ScreenSize.Mobile && (
<BackRouteHandler>
{(onBack) => (
<IconButton onClick={onBack} aria-label="Back">
<Icon src={Icons.ArrowLeft} />
</IconButton>
)}
</BackRouteHandler>
)}
</Box>
<Box grow="Yes" justifyContent="Center" alignItems="Center" gap="200">
<Text size="H3" truncate>
{summary?.name || summary?.canonical_alias || roomIdOrAlias}
</Text>
</Box>
</Box>
</PageHeader>
<Box grow="Yes">
<Scroll hideTrack visibility="Hover" size="0">
<Box
style={{ height: '100%' }}
grow="Yes"
alignItems="Center"
justifyContent="Center"
>
{state.loading && !summary ? (
<Spinner size="600" variant="Secondary" />
) : (
<RoomCard
hero
style={{ maxWidth: toRem(420), width: '100%' }}
roomIdOrAlias={roomIdOrAlias}
allRooms={allRooms}
avatarUrl={summary?.avatar_url}
name={summary?.name}
canonicalAlias={summary?.canonical_alias}
topic={summary?.topic}
memberCount={summary?.num_joined_members}
roomType={summary?.room_type}
joinRule={summary?.join_rule}
encrypted={!!summary?.['im.nheko.summary.encryption']}
worldReadable={summary?.world_readable}
membership={summary?.membership}
viaServers={viaServers}
renderTopicViewer={(name, topic, requestClose) => (
<RoomTopicViewer name={name} topic={topic} requestClose={requestClose} />
)}
onView={handleView}
/>
)}
</Box>
</Scroll>
</Box>
</>
)}
</RoomSummaryLoader>
</Page>
);
}