import React, { MouseEventHandler, ReactNode, useCallback, useRef, useState } from 'react'; import { Box, Avatar, Text, Chip, Icon, Icons, as, Badge, toRem, Spinner, PopOut, Menu, MenuItem, RectCords, config, } from 'folds'; import FocusTrap from 'focus-trap-react'; import classNames from 'classnames'; import { MatrixError, Room } from 'matrix-js-sdk'; import { HierarchyItem } from '../../hooks/useSpaceHierarchy'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { RoomAvatar } from '../../components/room-avatar'; import { nameInitials } from '../../utils/common'; import { HierarchyRoomSummaryLoader, LocalRoomSummaryLoader, } from '../../components/RoomSummaryLoader'; import { getRoomAvatarUrl } from '../../utils/room'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import * as css from './SpaceItem.css'; import * as styleCss from './style.css'; import { ErrorCode } from '../../cs-errorcode'; import { useDraggableItem } from './DnD'; import { openCreateRoom, openSpaceAddExisting } from '../../../client/action/navigation'; function SpaceProfileLoading() { return ( ); } type UnknownPrivateSpaceProfileProps = { roomId: string; name?: string; avatarUrl?: string; suggested?: boolean; }; function UnknownPrivateSpaceProfile({ roomId, name, avatarUrl, suggested, }: UnknownPrivateSpaceProfileProps) { return ( ( {nameInitials(name)} )} /> } > {name || 'Unknown'} Private Space {suggested && ( Suggested )} ); } type UnknownSpaceProfileProps = { roomId: string; via?: string[]; name?: string; avatarUrl?: string; suggested?: boolean; }; function UnknownSpaceProfile({ roomId, via, name, avatarUrl, suggested, }: UnknownSpaceProfileProps) { 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 ( ( {nameInitials(name)} )} /> } after={ canJoin ? : } > {name || 'Unknown'} {suggested && ( Suggested )} {joinState.status === AsyncStatus.Error && ( {joinState.error.name} )} ); } type SpaceProfileProps = { roomId: string; name: string; avatarUrl?: string; suggested?: boolean; closed: boolean; categoryId: string; handleClose?: MouseEventHandler; }; function SpaceProfile({ roomId, name, avatarUrl, suggested, closed, categoryId, handleClose, }: SpaceProfileProps) { return ( ( {nameInitials(name)} )} /> } after={} > {name} {suggested && ( Suggested )} ); } type RootSpaceProfileProps = { closed: boolean; categoryId: string; handleClose?: MouseEventHandler; }; function RootSpaceProfile({ closed, categoryId, handleClose }: RootSpaceProfileProps) { return ( } > Rooms ); } function AddRoomButton({ item }: { item: HierarchyItem }) { const [cords, setCords] = useState(); const handleAddRoom: MouseEventHandler = (evt) => { setCords(evt.currentTarget.getBoundingClientRect()); }; const handleCreateRoom = () => { openCreateRoom(false, item.roomId as any); setCords(undefined); }; const handleAddExisting = () => { openSpaceAddExisting(item.roomId); setCords(undefined); }; return ( setCords(undefined), clickOutsideDeactivates: true, isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown', isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', }} > New Room Existing Room } > } onClick={handleAddRoom} aria-pressed={!!cords} > Add Room ); } function AddSpaceButton({ item }: { item: HierarchyItem }) { const [cords, setCords] = useState(); const handleAddSpace: MouseEventHandler = (evt) => { setCords(evt.currentTarget.getBoundingClientRect()); }; const handleCreateSpace = () => { openCreateRoom(true, item.roomId as any); setCords(undefined); }; const handleAddExisting = () => { openSpaceAddExisting(item.roomId, true); setCords(undefined); }; return ( setCords(undefined), clickOutsideDeactivates: true, isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown', isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', }} > New Space Existing Space } > } onClick={handleAddSpace} aria-pressed={!!cords} > Add Space ); } type SpaceItemCardProps = { item: HierarchyItem; joined?: boolean; categoryId: string; closed: boolean; handleClose?: MouseEventHandler; options?: ReactNode; before?: ReactNode; after?: ReactNode; canEditChild: boolean; canReorder: boolean; onDragging: (item?: HierarchyItem) => void; getRoom: (roomId: string) => Room | undefined; }; export const SpaceItemCard = as<'div', SpaceItemCardProps>( ( { className, joined, closed, categoryId, item, handleClose, options, before, after, canEditChild, canReorder, onDragging, getRoom, ...props }, ref ) => { const mx = useMatrixClient(); const { roomId, content } = item; const space = getRoom(roomId); const targetRef = useRef(null); useDraggableItem(item, targetRef, onDragging); return ( {before} {space ? ( {(localSummary) => item.parentId ? ( ) : ( ) } ) : ( {(summaryState) => ( <> {summaryState.status === AsyncStatus.Loading && } {summaryState.status === AsyncStatus.Error && (summaryState.error.name === ErrorCode.M_FORBIDDEN ? ( ) : ( ))} {summaryState.status === AsyncStatus.Success && ( )} )} )} {canEditChild && ( {item.parentId === undefined && } )} {options} {after} ); } );