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,
IconButton,
TooltipProvider,
Tooltip,
} from 'folds';
import FocusTrap from 'focus-trap-react';
import classNames from 'classnames';
import { MatrixError, Room } from 'matrix-js-sdk';
import { IHierarchyRoom } from 'matrix-js-sdk/lib/@types/spaces';
import { HierarchyItem } from '../../hooks/useSpaceHierarchy';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { RoomAvatar } from '../../components/room-avatar';
import { nameInitials } from '../../utils/common';
import { 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 { useDraggableItem } from './DnD';
import { stopPropagation } from '../../utils/keyboard';
import { mxcUrlToHttp } from '../../utils/matrix';
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
import { useOpenCreateRoomModal } from '../../state/hooks/createRoomModal';
import { useOpenCreateSpaceModal } from '../../state/hooks/createSpaceModal';
import { AddExistingModal } from '../add-existing';
function SpaceProfileLoading() {
return (
);
}
type InaccessibleSpaceProfileProps = {
roomId: string;
suggested?: boolean;
};
function InaccessibleSpaceProfile({ roomId, suggested }: InaccessibleSpaceProfileProps) {
return (
(
U
)}
/>
}
>
Unknown
Inaccessible
{suggested && (
Suggested
)}
);
}
type UnjoinedSpaceProfileProps = {
roomId: string;
via?: string[];
name?: string;
avatarUrl?: string;
suggested?: boolean;
};
function UnjoinedSpaceProfile({
roomId,
via,
name,
avatarUrl,
suggested,
}: UnjoinedSpaceProfileProps) {
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 openCreateRoomModal = useOpenCreateRoomModal();
const [addExisting, setAddExisting] = useState(false);
const handleAddRoom: MouseEventHandler = (evt) => {
setCords(evt.currentTarget.getBoundingClientRect());
};
const handleCreateRoom = () => {
openCreateRoomModal(item.roomId);
setCords(undefined);
};
const handleAddExisting = () => {
setAddExisting(true);
setCords(undefined);
};
return (
setCords(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
escapeDeactivates: stopPropagation,
}}
>
}
>
}
onClick={handleAddRoom}
aria-pressed={!!cords}
>
Add Room
{addExisting && (
setAddExisting(false)} />
)}
);
}
function AddSpaceButton({ item }: { item: HierarchyItem }) {
const [cords, setCords] = useState();
const openCreateSpaceModal = useOpenCreateSpaceModal();
const [addExisting, setAddExisting] = useState(false);
const handleAddSpace: MouseEventHandler = (evt) => {
setCords(evt.currentTarget.getBoundingClientRect());
};
const handleCreateSpace = () => {
openCreateSpaceModal(item.roomId as any);
setCords(undefined);
};
const handleAddExisting = () => {
setAddExisting(true);
setCords(undefined);
};
return (
setCords(undefined),
clickOutsideDeactivates: true,
isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
escapeDeactivates: stopPropagation,
}}
>
}
>
{item.parentId === undefined ? (
}
onClick={handleAddSpace}
aria-pressed={!!cords}
>
Add Space
) : (
Add Space
}
>
{(triggerRef) => (
)}
)}
{addExisting && (
setAddExisting(false)} />
)}
);
}
type SpaceItemCardProps = {
summary: IHierarchyRoom | undefined;
loading?: boolean;
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,
summary,
loading,
joined,
closed,
categoryId,
item,
handleClose,
options,
before,
after,
canEditChild,
canReorder,
onDragging,
getRoom,
...props
},
ref
) => {
const mx = useMatrixClient();
const useAuthentication = useMediaAuthentication();
const { roomId, content } = item;
const space = getRoom(roomId);
const targetRef = useRef(null);
useDraggableItem(item, targetRef, onDragging);
return (
{before}
{space ? (
{(localSummary) =>
item.parentId ? (
) : (
)
}
) : (
<>
{!summary &&
(loading ? (
) : (
))}
{summary && (
)}
>
)}
{space && canEditChild && (
)}
{options}
{after}
);
}
);