import React, { MouseEventHandler, useCallback, useEffect, useState } from 'react'; import FocusTrap from 'focus-trap-react'; import { Box, IconButton, Icon, Icons, PopOut, Menu, MenuItem, Text, RectCords, config, Line, Spinner, toRem, } from 'folds'; import { HierarchyItem } from '../../hooks/useSpaceHierarchy'; import { useMatrixClient } from '../../hooks/useMatrixClient'; import { MSpaceChildContent, StateEvent } from '../../../types/matrix/room'; import { openInviteUser } from '../../../client/action/navigation'; import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback'; import { UseStateProvider } from '../../components/UseStateProvider'; import { LeaveSpacePrompt } from '../../components/leave-space-prompt'; import { LeaveRoomPrompt } from '../../components/leave-room-prompt'; import { stopPropagation } from '../../utils/keyboard'; import { useOpenRoomSettings } from '../../state/hooks/roomSettings'; import { useSpaceOptionally } from '../../hooks/useSpace'; import { useOpenSpaceSettings } from '../../state/hooks/spaceSettings'; type HierarchyItemWithParent = HierarchyItem & { parentId: string; }; function SuggestMenuItem({ item, requestClose, }: { item: HierarchyItemWithParent; requestClose: () => void; }) { const mx = useMatrixClient(); const { roomId, parentId, content } = item; const [toggleState, handleToggleSuggested] = useAsyncCallback( useCallback(() => { const newContent: MSpaceChildContent = { ...content, suggested: !content.suggested }; return mx.sendStateEvent(parentId, StateEvent.SpaceChild, newContent, roomId); }, [mx, parentId, roomId, content]) ); useEffect(() => { if (toggleState.status === AsyncStatus.Success) { requestClose(); } }, [requestClose, toggleState]); return ( } disabled={toggleState.status === AsyncStatus.Loading} > {content.suggested ? 'Unset Suggested' : 'Set Suggested'} ); } function RemoveMenuItem({ item, requestClose, }: { item: HierarchyItemWithParent; requestClose: () => void; }) { const mx = useMatrixClient(); const { roomId, parentId } = item; const [removeState, handleRemove] = useAsyncCallback( useCallback( () => mx.sendStateEvent(parentId, StateEvent.SpaceChild, {}, roomId), [mx, parentId, roomId] ) ); useEffect(() => { if (removeState.status === AsyncStatus.Success) { requestClose(); } }, [requestClose, removeState]); return ( ) } disabled={removeState.status === AsyncStatus.Loading} > Remove ); } function InviteMenuItem({ item, requestClose, disabled, }: { item: HierarchyItemWithParent; requestClose: () => void; disabled?: boolean; }) { const handleInvite = () => { openInviteUser(item.roomId); requestClose(); }; return ( Invite ); } function SettingsMenuItem({ item, requestClose, disabled, }: { item: HierarchyItemWithParent; requestClose: () => void; disabled?: boolean; }) { const openRoomSettings = useOpenRoomSettings(); const openSpaceSettings = useOpenSpaceSettings(); const space = useSpaceOptionally(); const handleSettings = () => { if ('space' in item) { openSpaceSettings(item.roomId, item.parentId); } else { openRoomSettings(item.roomId, space?.roomId); } requestClose(); }; return ( Settings ); } type HierarchyItemMenuProps = { item: HierarchyItem & { parentId: string; }; joined: boolean; canInvite: boolean; canEditChild: boolean; pinned?: boolean; onTogglePin?: (roomId: string) => void; }; export function HierarchyItemMenu({ item, joined, canInvite, canEditChild, pinned, onTogglePin, }: HierarchyItemMenuProps) { const [menuAnchor, setMenuAnchor] = useState(); const handleOpenMenu: MouseEventHandler = (evt) => { setMenuAnchor(evt.currentTarget.getBoundingClientRect()); }; const handleRequestClose = useCallback(() => setMenuAnchor(undefined), []); if (!joined && !canEditChild) { return null; } return ( {menuAnchor && ( setMenuAnchor(undefined), clickOutsideDeactivates: true, isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown', isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', escapeDeactivates: stopPropagation, }} > {joined && ( {onTogglePin && ( { onTogglePin(item.roomId); handleRequestClose(); }} > {pinned ? 'Unpin from Sidebar' : 'Pin to Sidebar'} )} {(promptLeave, setPromptLeave) => ( <> setPromptLeave(true)} variant="Critical" fill="None" size="300" after={} radii="300" aria-pressed={promptLeave} > Leave {promptLeave && ('space' in item ? ( setPromptLeave(false)} /> ) : ( setPromptLeave(false)} /> ))} )} )} {(joined || canEditChild) && ( )} {canEditChild && ( )} } /> )} ); }