import React, { MouseEventHandler, ReactNode, useCallback, useEffect, useRef } from 'react'; import { Avatar, Badge, Box, Chip, Icon, Icons, Line, Overlay, OverlayBackdrop, OverlayCenter, Spinner, Text, Tooltip, TooltipProvider, as, color, toRem, } from 'folds'; import FocusTrap from 'focus-trap-react'; import { JoinRule, MatrixError, Room } from 'matrix-js-sdk'; import { RoomAvatar, RoomIcon } from '../../components/room-avatar'; import { SequenceCard } from '../../components/sequence-card'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { HierarchyItem } from '../../hooks/useSpaceHierarchy'; import { millify } from '../../plugins/millify'; import { HierarchyRoomSummaryLoader, LocalRoomSummaryLoader, } from '../../components/RoomSummaryLoader'; import { UseStateProvider } from '../../components/UseStateProvider'; import { RoomTopicViewer } from '../../components/room-topic-viewer'; import { onEnterOrSpace, stopPropagation } from '../../utils/keyboard'; import { Membership, RoomType } from '../../../types/matrix/room'; import * as css from './RoomItem.css'; import * as styleCss from './style.css'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import { ErrorCode } from '../../cs-errorcode'; import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room'; import { ItemDraggableTarget, useDraggableItem } from './DnD'; import { mxcUrlToHttp } from '../../utils/matrix'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; type RoomJoinButtonProps = { roomId: string; via?: string[]; }; function RoomJoinButton({ roomId, via }: RoomJoinButtonProps) { const mx = useMatrixClient(); const [joinState, join] = useAsyncCallback( useCallback(() => mx.joinRoom(roomId, { viaServers: via }), [mx, roomId, via]) ); const canJoin = joinState.status === AsyncStatus.Idle || joinState.status === AsyncStatus.Error; return ( {joinState.status === AsyncStatus.Error && ( {joinState.error.data?.error || joinState.error.message} {joinState.error.name} } > {(triggerRef) => ( )} )} : } onClick={join} disabled={!canJoin} > Join ); } function RoomProfileLoading() { return ( ); } type RoomProfileErrorProps = { roomId: string; error: Error; suggested?: boolean; via?: string[]; }; function RoomProfileError({ roomId, suggested, error, via }: RoomProfileErrorProps) { const privateRoom = error.name === ErrorCode.M_FORBIDDEN; return ( ( )} /> Unknown {suggested && ( Suggested )} {privateRoom && ( <> Private Room )} {roomId} {!privateRoom && } ); } type RoomProfileProps = { roomId: string; name: string; topic?: string; avatarUrl?: string; suggested?: boolean; memberCount?: number; joinRule?: JoinRule; options?: ReactNode; }; function RoomProfile({ roomId, name, topic, avatarUrl, suggested, memberCount, joinRule, options, }: RoomProfileProps) { return ( ( )} /> {name} {suggested && ( Suggested )} {memberCount && ( {`${millify(memberCount)} Members`} )} {memberCount && topic && ( )} {topic && ( {(view, setView) => ( <> setView(true)} onKeyDown={onEnterOrSpace(() => setView(true))} tabIndex={0} > {topic} }> setView(false), escapeDeactivates: stopPropagation, }} > setView(false)} /> )} )} {options} ); } function CallbackOnFoundSpace({ roomId, onSpaceFound, }: { roomId: string; onSpaceFound: (roomId: string) => void; }) { useEffect(() => { onSpaceFound(roomId); }, [roomId, onSpaceFound]); return null; } type RoomItemCardProps = { item: HierarchyItem; onSpaceFound: (roomId: string) => void; dm?: boolean; firstChild?: boolean; lastChild?: boolean; onOpen: MouseEventHandler; options?: ReactNode; before?: ReactNode; after?: ReactNode; onDragging: (item?: HierarchyItem) => void; canReorder: boolean; getRoom: (roomId: string) => Room | undefined; }; export const RoomItemCard = as<'div', RoomItemCardProps>( ( { item, onSpaceFound, dm, firstChild, lastChild, onOpen, options, before, after, onDragging, canReorder, getRoom, ...props }, ref ) => { const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const { roomId, content } = item; const room = getRoom(roomId); const targetRef = useRef(null); const targetHandleRef = useRef(null); useDraggableItem(item, targetRef, onDragging, targetHandleRef); const joined = room?.getMyMembership() === Membership.Join; return ( {before} {canReorder && } {room ? ( {(localSummary) => ( ) : ( ) } /> )} ) : ( {(summaryState) => ( <> {summaryState.status === AsyncStatus.Loading && } {summaryState.status === AsyncStatus.Error && ( )} {summaryState.status === AsyncStatus.Success && ( <> {summaryState.data.room_type === RoomType.Space && ( )} } /> )} )} )} {options} {after} ); } );