mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-03 22:10:29 +03:00 
			
		
		
		
	New add existing room/space modal (#2451)
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Deploy to Netlify (dev) / Deploy to Netlify (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Deploy to Netlify (dev) / Deploy to Netlify (push) Has been cancelled
				
			This commit is contained in:
		
							parent
							
								
									09b88d164f
								
							
						
					
					
						commit
						78a0d11f24
					
				
					 5 changed files with 390 additions and 19 deletions
				
			
		| 
						 | 
				
			
			@ -30,9 +30,7 @@ import { SettingTile } from '../setting-tile';
 | 
			
		|||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
import { stopPropagation } from '../../utils/keyboard';
 | 
			
		||||
import { useAsyncSearch, UseAsyncSearchOptions } from '../../hooks/useAsyncSearch';
 | 
			
		||||
import { findAndReplace } from '../../utils/findAndReplace';
 | 
			
		||||
import { highlightText } from '../../styles/CustomHtml.css';
 | 
			
		||||
import { makeHighlightRegex } from '../../plugins/react-custom-html-parser';
 | 
			
		||||
import { highlightText, makeHighlightRegex } from '../../plugins/react-custom-html-parser';
 | 
			
		||||
 | 
			
		||||
export const useAdditionalCreators = (defaultCreators?: string[]) => {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
| 
						 | 
				
			
			@ -245,19 +243,9 @@ export function AdditionalCreatorInput({
 | 
			
		|||
                                  <Text size="T200" truncate>
 | 
			
		||||
                                    <b>
 | 
			
		||||
                                      {queryHighlighRegex
 | 
			
		||||
                                        ? findAndReplace(
 | 
			
		||||
                                        ? highlightText(queryHighlighRegex, [
 | 
			
		||||
                                            getMxIdLocalPart(userId) ?? userId,
 | 
			
		||||
                                            queryHighlighRegex,
 | 
			
		||||
                                            (match, pushIndex) => (
 | 
			
		||||
                                              <span
 | 
			
		||||
                                                key={`highlight-${pushIndex}`}
 | 
			
		||||
                                                className={highlightText}
 | 
			
		||||
                                              >
 | 
			
		||||
                                                {match[0]}
 | 
			
		||||
                                              </span>
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            (txt) => txt
 | 
			
		||||
                                          )
 | 
			
		||||
                                          ])
 | 
			
		||||
                                        : getMxIdLocalPart(userId)}
 | 
			
		||||
                                    </b>
 | 
			
		||||
                                  </Text>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										375
									
								
								src/app/features/add-existing/AddExisting.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										375
									
								
								src/app/features/add-existing/AddExisting.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,375 @@
 | 
			
		|||
import FocusTrap from 'focus-trap-react';
 | 
			
		||||
import {
 | 
			
		||||
  Avatar,
 | 
			
		||||
  Box,
 | 
			
		||||
  Button,
 | 
			
		||||
  config,
 | 
			
		||||
  Header,
 | 
			
		||||
  Icon,
 | 
			
		||||
  IconButton,
 | 
			
		||||
  Icons,
 | 
			
		||||
  Input,
 | 
			
		||||
  Menu,
 | 
			
		||||
  MenuItem,
 | 
			
		||||
  Modal,
 | 
			
		||||
  Overlay,
 | 
			
		||||
  OverlayBackdrop,
 | 
			
		||||
  OverlayCenter,
 | 
			
		||||
  Scroll,
 | 
			
		||||
  Spinner,
 | 
			
		||||
  Text,
 | 
			
		||||
} from 'folds';
 | 
			
		||||
import React, {
 | 
			
		||||
  ChangeEventHandler,
 | 
			
		||||
  MouseEventHandler,
 | 
			
		||||
  useCallback,
 | 
			
		||||
  useMemo,
 | 
			
		||||
  useRef,
 | 
			
		||||
  useState,
 | 
			
		||||
} from 'react';
 | 
			
		||||
import { useAtomValue } from 'jotai';
 | 
			
		||||
import { useVirtualizer } from '@tanstack/react-virtual';
 | 
			
		||||
import { Room } from 'matrix-js-sdk';
 | 
			
		||||
import { stopPropagation } from '../../utils/keyboard';
 | 
			
		||||
import { useDirects, useRooms, useSpaces } from '../../state/hooks/roomList';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
import { allRoomsAtom } from '../../state/room-list/roomList';
 | 
			
		||||
import { mDirectAtom } from '../../state/mDirectList';
 | 
			
		||||
import { roomToParentsAtom } from '../../state/room/roomToParents';
 | 
			
		||||
import { useAllJoinedRoomsSet, useGetRoom } from '../../hooks/useGetRoom';
 | 
			
		||||
import { VirtualTile } from '../../components/virtualizer';
 | 
			
		||||
import { getDirectRoomAvatarUrl, getRoomAvatarUrl } from '../../utils/room';
 | 
			
		||||
import { RoomAvatar, RoomIcon } from '../../components/room-avatar';
 | 
			
		||||
import { nameInitials } from '../../utils/common';
 | 
			
		||||
import { useMediaAuthentication } from '../../hooks/useMediaAuthentication';
 | 
			
		||||
import { factoryRoomIdByAtoZ } from '../../utils/sort';
 | 
			
		||||
import {
 | 
			
		||||
  SearchItemStrGetter,
 | 
			
		||||
  useAsyncSearch,
 | 
			
		||||
  UseAsyncSearchOptions,
 | 
			
		||||
} from '../../hooks/useAsyncSearch';
 | 
			
		||||
import { highlightText, makeHighlightRegex } from '../../plugins/react-custom-html-parser';
 | 
			
		||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
			
		||||
import { StateEvent } from '../../../types/matrix/room';
 | 
			
		||||
import { getViaServers } from '../../plugins/via-servers';
 | 
			
		||||
import { rateLimitedActions } from '../../utils/matrix';
 | 
			
		||||
import { useAlive } from '../../hooks/useAlive';
 | 
			
		||||
 | 
			
		||||
const SEARCH_OPTS: UseAsyncSearchOptions = {
 | 
			
		||||
  limit: 500,
 | 
			
		||||
  matchOptions: {
 | 
			
		||||
    contain: true,
 | 
			
		||||
  },
 | 
			
		||||
  normalizeOptions: {
 | 
			
		||||
    ignoreWhitespace: false,
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type AddExistingModalProps = {
 | 
			
		||||
  parentId: string;
 | 
			
		||||
  space?: boolean;
 | 
			
		||||
  requestClose: () => void;
 | 
			
		||||
};
 | 
			
		||||
export function AddExistingModal({ parentId, space, requestClose }: AddExistingModalProps) {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const useAuthentication = useMediaAuthentication();
 | 
			
		||||
  const alive = useAlive();
 | 
			
		||||
 | 
			
		||||
  const mDirects = useAtomValue(mDirectAtom);
 | 
			
		||||
  const spaces = useSpaces(mx, allRoomsAtom);
 | 
			
		||||
  const rooms = useRooms(mx, allRoomsAtom, mDirects);
 | 
			
		||||
  const directs = useDirects(mx, allRoomsAtom, mDirects);
 | 
			
		||||
  const roomIdToParents = useAtomValue(roomToParentsAtom);
 | 
			
		||||
  const scrollRef = useRef<HTMLDivElement>(null);
 | 
			
		||||
 | 
			
		||||
  const [selected, setSelected] = useState<string[]>([]);
 | 
			
		||||
 | 
			
		||||
  const allRoomsSet = useAllJoinedRoomsSet();
 | 
			
		||||
  const getRoom = useGetRoom(allRoomsSet);
 | 
			
		||||
 | 
			
		||||
  const allItems: string[] = useMemo(() => {
 | 
			
		||||
    const rIds = space ? [...spaces] : [...rooms, ...directs];
 | 
			
		||||
 | 
			
		||||
    return rIds
 | 
			
		||||
      .filter((rId) => rId !== parentId && !roomIdToParents.get(rId)?.has(parentId))
 | 
			
		||||
      .sort(factoryRoomIdByAtoZ(mx));
 | 
			
		||||
  }, [spaces, rooms, directs, space, parentId, roomIdToParents, mx]);
 | 
			
		||||
 | 
			
		||||
  const getRoomNameStr: SearchItemStrGetter<string> = useCallback(
 | 
			
		||||
    (rId) => getRoom(rId)?.name ?? rId,
 | 
			
		||||
    [getRoom]
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const [searchResult, searchRoom, resetSearch] = useAsyncSearch(
 | 
			
		||||
    allItems,
 | 
			
		||||
    getRoomNameStr,
 | 
			
		||||
    SEARCH_OPTS
 | 
			
		||||
  );
 | 
			
		||||
  const queryHighlighRegex = searchResult?.query
 | 
			
		||||
    ? makeHighlightRegex(searchResult.query.split(' '))
 | 
			
		||||
    : undefined;
 | 
			
		||||
 | 
			
		||||
  const items = searchResult ? searchResult.items : allItems;
 | 
			
		||||
 | 
			
		||||
  const virtualizer = useVirtualizer({
 | 
			
		||||
    count: items.length,
 | 
			
		||||
    getScrollElement: () => scrollRef.current,
 | 
			
		||||
    estimateSize: () => 32,
 | 
			
		||||
    overscan: 5,
 | 
			
		||||
  });
 | 
			
		||||
  const vItems = virtualizer.getVirtualItems();
 | 
			
		||||
 | 
			
		||||
  const handleSearchChange: ChangeEventHandler<HTMLInputElement> = (evt) => {
 | 
			
		||||
    const value = evt.currentTarget.value.trim();
 | 
			
		||||
    if (!value) {
 | 
			
		||||
      resetSearch();
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    searchRoom(value);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const [applyState, applyChanges] = useAsyncCallback<undefined, Error, [Room[]]>(
 | 
			
		||||
    useCallback(
 | 
			
		||||
      async (selectedRooms) => {
 | 
			
		||||
        await rateLimitedActions(selectedRooms, async (room) => {
 | 
			
		||||
          const via = getViaServers(room);
 | 
			
		||||
 | 
			
		||||
          await mx.sendStateEvent(
 | 
			
		||||
            parentId,
 | 
			
		||||
            StateEvent.SpaceChild as any,
 | 
			
		||||
            {
 | 
			
		||||
              auto_join: false,
 | 
			
		||||
              suggested: false,
 | 
			
		||||
              via,
 | 
			
		||||
            },
 | 
			
		||||
            room.roomId
 | 
			
		||||
          );
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      [mx, parentId]
 | 
			
		||||
    )
 | 
			
		||||
  );
 | 
			
		||||
  const applyingChanges = applyState.status === AsyncStatus.Loading;
 | 
			
		||||
 | 
			
		||||
  const handleRoomClick: MouseEventHandler<HTMLButtonElement> = (evt) => {
 | 
			
		||||
    const roomId = evt.currentTarget.getAttribute('data-room-id');
 | 
			
		||||
    if (!roomId) return;
 | 
			
		||||
    if (selected?.includes(roomId)) {
 | 
			
		||||
      setSelected(selected?.filter((rId) => rId !== roomId));
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const addedRooms = [...(selected ?? [])];
 | 
			
		||||
    addedRooms.push(roomId);
 | 
			
		||||
    setSelected(addedRooms);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleApplyChanges = () => {
 | 
			
		||||
    const selectedRooms = selected.map((rId) => getRoom(rId)).filter((room) => room !== undefined);
 | 
			
		||||
    applyChanges(selectedRooms).then(() => {
 | 
			
		||||
      if (alive()) {
 | 
			
		||||
        setSelected([]);
 | 
			
		||||
        requestClose();
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const resetChanges = () => {
 | 
			
		||||
    setSelected([]);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Overlay open backdrop={<OverlayBackdrop />}>
 | 
			
		||||
      <OverlayCenter>
 | 
			
		||||
        <FocusTrap
 | 
			
		||||
          focusTrapOptions={{
 | 
			
		||||
            initialFocus: false,
 | 
			
		||||
            clickOutsideDeactivates: true,
 | 
			
		||||
            onDeactivate: requestClose,
 | 
			
		||||
            escapeDeactivates: stopPropagation,
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <Modal size="300">
 | 
			
		||||
            <Box grow="Yes" direction="Column">
 | 
			
		||||
              <Header
 | 
			
		||||
                size="500"
 | 
			
		||||
                style={{
 | 
			
		||||
                  padding: config.space.S200,
 | 
			
		||||
                  paddingLeft: config.space.S400,
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <Box grow="Yes">
 | 
			
		||||
                  <Text size="H4">Add Existing</Text>
 | 
			
		||||
                </Box>
 | 
			
		||||
                <Box shrink="No">
 | 
			
		||||
                  <IconButton size="300" radii="300" onClick={requestClose}>
 | 
			
		||||
                    <Icon src={Icons.Cross} />
 | 
			
		||||
                  </IconButton>
 | 
			
		||||
                </Box>
 | 
			
		||||
              </Header>
 | 
			
		||||
              <Box grow="Yes">
 | 
			
		||||
                <Scroll ref={scrollRef} size="300" hideTrack>
 | 
			
		||||
                  <Box
 | 
			
		||||
                    style={{ padding: config.space.S300, paddingRight: 0 }}
 | 
			
		||||
                    direction="Column"
 | 
			
		||||
                    gap="500"
 | 
			
		||||
                  >
 | 
			
		||||
                    <Box
 | 
			
		||||
                      direction="Column"
 | 
			
		||||
                      style={{ position: 'sticky', top: config.space.S300, zIndex: 1 }}
 | 
			
		||||
                    >
 | 
			
		||||
                      <Input
 | 
			
		||||
                        onChange={handleSearchChange}
 | 
			
		||||
                        before={<Icon size="200" src={Icons.Search} />}
 | 
			
		||||
                        placeholder="Search"
 | 
			
		||||
                        size="400"
 | 
			
		||||
                        variant="Background"
 | 
			
		||||
                        outlined
 | 
			
		||||
                      />
 | 
			
		||||
                    </Box>
 | 
			
		||||
                    {vItems.length === 0 && (
 | 
			
		||||
                      <Box
 | 
			
		||||
                        style={{ paddingTop: config.space.S700 }}
 | 
			
		||||
                        grow="Yes"
 | 
			
		||||
                        alignItems="Center"
 | 
			
		||||
                        justifyContent="Center"
 | 
			
		||||
                        direction="Column"
 | 
			
		||||
                        gap="100"
 | 
			
		||||
                      >
 | 
			
		||||
                        <Text size="H6" align="Center">
 | 
			
		||||
                          {searchResult ? 'No Match Found' : `No ${space ? 'Spaces' : 'Rooms'}`}
 | 
			
		||||
                        </Text>
 | 
			
		||||
                        <Text size="T200" align="Center">
 | 
			
		||||
                          {searchResult
 | 
			
		||||
                            ? `No match found for "${searchResult.query}".`
 | 
			
		||||
                            : `You do not have any ${space ? 'Spaces' : 'Rooms'} to display yet.`}
 | 
			
		||||
                        </Text>
 | 
			
		||||
                      </Box>
 | 
			
		||||
                    )}
 | 
			
		||||
                    <Box
 | 
			
		||||
                      style={{
 | 
			
		||||
                        position: 'relative',
 | 
			
		||||
                        height: virtualizer.getTotalSize(),
 | 
			
		||||
                      }}
 | 
			
		||||
                    >
 | 
			
		||||
                      {vItems.map((vItem) => {
 | 
			
		||||
                        const roomId = items[vItem.index];
 | 
			
		||||
                        const room = getRoom(roomId);
 | 
			
		||||
                        if (!room) return null;
 | 
			
		||||
                        const selectedItem = selected?.includes(roomId);
 | 
			
		||||
                        const dm = mDirects.has(room.roomId);
 | 
			
		||||
 | 
			
		||||
                        return (
 | 
			
		||||
                          <VirtualTile
 | 
			
		||||
                            virtualItem={vItem}
 | 
			
		||||
                            style={{ paddingBottom: config.space.S100 }}
 | 
			
		||||
                            ref={virtualizer.measureElement}
 | 
			
		||||
                            key={vItem.index}
 | 
			
		||||
                          >
 | 
			
		||||
                            <MenuItem
 | 
			
		||||
                              data-room-id={roomId}
 | 
			
		||||
                              onClick={handleRoomClick}
 | 
			
		||||
                              variant={selectedItem ? 'Success' : 'Surface'}
 | 
			
		||||
                              size="400"
 | 
			
		||||
                              radii="400"
 | 
			
		||||
                              disabled={applyingChanges}
 | 
			
		||||
                              aria-pressed={selectedItem}
 | 
			
		||||
                              before={
 | 
			
		||||
                                <Avatar size="200" radii={dm ? '400' : '300'}>
 | 
			
		||||
                                  {dm || room.isSpaceRoom() ? (
 | 
			
		||||
                                    <RoomAvatar
 | 
			
		||||
                                      roomId={room.roomId}
 | 
			
		||||
                                      src={
 | 
			
		||||
                                        dm
 | 
			
		||||
                                          ? getDirectRoomAvatarUrl(mx, room, 96, useAuthentication)
 | 
			
		||||
                                          : getRoomAvatarUrl(mx, room, 96, useAuthentication)
 | 
			
		||||
                                      }
 | 
			
		||||
                                      alt={room.name}
 | 
			
		||||
                                      renderFallback={() => (
 | 
			
		||||
                                        <Text as="span" size="H6">
 | 
			
		||||
                                          {nameInitials(room.name)}
 | 
			
		||||
                                        </Text>
 | 
			
		||||
                                      )}
 | 
			
		||||
                                    />
 | 
			
		||||
                                  ) : (
 | 
			
		||||
                                    <RoomIcon size="200" joinRule={room.getJoinRule()} />
 | 
			
		||||
                                  )}
 | 
			
		||||
                                </Avatar>
 | 
			
		||||
                              }
 | 
			
		||||
                              after={selectedItem && <Icon size="200" src={Icons.Check} />}
 | 
			
		||||
                            >
 | 
			
		||||
                              <Box grow="Yes">
 | 
			
		||||
                                <Text truncate size="T400">
 | 
			
		||||
                                  {queryHighlighRegex
 | 
			
		||||
                                    ? highlightText(queryHighlighRegex, [room.name])
 | 
			
		||||
                                    : room.name}
 | 
			
		||||
                                </Text>
 | 
			
		||||
                              </Box>
 | 
			
		||||
                            </MenuItem>
 | 
			
		||||
                          </VirtualTile>
 | 
			
		||||
                        );
 | 
			
		||||
                      })}
 | 
			
		||||
                    </Box>
 | 
			
		||||
                    {selected.length > 0 && (
 | 
			
		||||
                      <Menu
 | 
			
		||||
                        style={{
 | 
			
		||||
                          position: 'sticky',
 | 
			
		||||
                          padding: config.space.S200,
 | 
			
		||||
                          paddingLeft: config.space.S400,
 | 
			
		||||
                          bottom: config.space.S400,
 | 
			
		||||
                          left: config.space.S400,
 | 
			
		||||
                          right: 0,
 | 
			
		||||
                          zIndex: 1,
 | 
			
		||||
                        }}
 | 
			
		||||
                        variant="Success"
 | 
			
		||||
                      >
 | 
			
		||||
                        <Box alignItems="Center" gap="400">
 | 
			
		||||
                          <Box grow="Yes" direction="Column">
 | 
			
		||||
                            {applyState.status === AsyncStatus.Error ? (
 | 
			
		||||
                              <Text size="T200">
 | 
			
		||||
                                <b>Failed to apply changes! Please try again.</b>
 | 
			
		||||
                              </Text>
 | 
			
		||||
                            ) : (
 | 
			
		||||
                              <Text size="T200">
 | 
			
		||||
                                <b>Apply when ready. ({selected.length} Selected)</b>
 | 
			
		||||
                              </Text>
 | 
			
		||||
                            )}
 | 
			
		||||
                          </Box>
 | 
			
		||||
                          <Box shrink="No" gap="200">
 | 
			
		||||
                            <Button
 | 
			
		||||
                              size="300"
 | 
			
		||||
                              variant="Success"
 | 
			
		||||
                              fill="None"
 | 
			
		||||
                              radii="300"
 | 
			
		||||
                              disabled={applyingChanges}
 | 
			
		||||
                              onClick={resetChanges}
 | 
			
		||||
                            >
 | 
			
		||||
                              <Text size="B300">Reset</Text>
 | 
			
		||||
                            </Button>
 | 
			
		||||
                            <Button
 | 
			
		||||
                              size="300"
 | 
			
		||||
                              variant="Success"
 | 
			
		||||
                              radii="300"
 | 
			
		||||
                              disabled={applyingChanges}
 | 
			
		||||
                              before={
 | 
			
		||||
                                applyingChanges && (
 | 
			
		||||
                                  <Spinner variant="Success" fill="Solid" size="100" />
 | 
			
		||||
                                )
 | 
			
		||||
                              }
 | 
			
		||||
                              onClick={handleApplyChanges}
 | 
			
		||||
                            >
 | 
			
		||||
                              <Text size="B300">Apply Changes</Text>
 | 
			
		||||
                            </Button>
 | 
			
		||||
                          </Box>
 | 
			
		||||
                        </Box>
 | 
			
		||||
                      </Menu>
 | 
			
		||||
                    )}
 | 
			
		||||
                  </Box>
 | 
			
		||||
                </Scroll>
 | 
			
		||||
              </Box>
 | 
			
		||||
            </Box>
 | 
			
		||||
          </Modal>
 | 
			
		||||
        </FocusTrap>
 | 
			
		||||
      </OverlayCenter>
 | 
			
		||||
    </Overlay>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/app/features/add-existing/index.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/app/features/add-existing/index.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
export * from './AddExisting';
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,6 @@ function CreateRoomModal({ state }: CreateRoomModalProps) {
 | 
			
		|||
                  style={{
 | 
			
		||||
                    padding: config.space.S200,
 | 
			
		||||
                    paddingLeft: config.space.S400,
 | 
			
		||||
                    borderBottomWidth: config.borderWidth.B300,
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  <Box grow="Yes">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,12 +30,12 @@ import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
			
		|||
import * as css from './SpaceItem.css';
 | 
			
		||||
import * as styleCss from './style.css';
 | 
			
		||||
import { useDraggableItem } from './DnD';
 | 
			
		||||
import { openSpaceAddExisting } from '../../../client/action/navigation';
 | 
			
		||||
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 (
 | 
			
		||||
| 
						 | 
				
			
			@ -243,6 +243,7 @@ function RootSpaceProfile({ closed, categoryId, handleClose }: RootSpaceProfileP
 | 
			
		|||
function AddRoomButton({ item }: { item: HierarchyItem }) {
 | 
			
		||||
  const [cords, setCords] = useState<RectCords>();
 | 
			
		||||
  const openCreateRoomModal = useOpenCreateRoomModal();
 | 
			
		||||
  const [addExisting, setAddExisting] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const handleAddRoom: MouseEventHandler<HTMLButtonElement> = (evt) => {
 | 
			
		||||
    setCords(evt.currentTarget.getBoundingClientRect());
 | 
			
		||||
| 
						 | 
				
			
			@ -254,7 +255,7 @@ function AddRoomButton({ item }: { item: HierarchyItem }) {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  const handleAddExisting = () => {
 | 
			
		||||
    openSpaceAddExisting(item.roomId);
 | 
			
		||||
    setAddExisting(true);
 | 
			
		||||
    setCords(undefined);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -300,6 +301,9 @@ function AddRoomButton({ item }: { item: HierarchyItem }) {
 | 
			
		|||
      >
 | 
			
		||||
        <Text size="B300">Add Room</Text>
 | 
			
		||||
      </Chip>
 | 
			
		||||
      {addExisting && (
 | 
			
		||||
        <AddExistingModal parentId={item.roomId} requestClose={() => setAddExisting(false)} />
 | 
			
		||||
      )}
 | 
			
		||||
    </PopOut>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -307,6 +311,7 @@ function AddRoomButton({ item }: { item: HierarchyItem }) {
 | 
			
		|||
function AddSpaceButton({ item }: { item: HierarchyItem }) {
 | 
			
		||||
  const [cords, setCords] = useState<RectCords>();
 | 
			
		||||
  const openCreateSpaceModal = useOpenCreateSpaceModal();
 | 
			
		||||
  const [addExisting, setAddExisting] = useState(false);
 | 
			
		||||
 | 
			
		||||
  const handleAddSpace: MouseEventHandler<HTMLButtonElement> = (evt) => {
 | 
			
		||||
    setCords(evt.currentTarget.getBoundingClientRect());
 | 
			
		||||
| 
						 | 
				
			
			@ -318,7 +323,7 @@ function AddSpaceButton({ item }: { item: HierarchyItem }) {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  const handleAddExisting = () => {
 | 
			
		||||
    openSpaceAddExisting(item.roomId, true);
 | 
			
		||||
    setAddExisting(true);
 | 
			
		||||
    setCords(undefined);
 | 
			
		||||
  };
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -363,6 +368,9 @@ function AddSpaceButton({ item }: { item: HierarchyItem }) {
 | 
			
		|||
      >
 | 
			
		||||
        <Text size="B300">Add Space</Text>
 | 
			
		||||
      </Chip>
 | 
			
		||||
      {addExisting && (
 | 
			
		||||
        <AddExistingModal space parentId={item.roomId} requestClose={() => setAddExisting(false)} />
 | 
			
		||||
      )}
 | 
			
		||||
    </PopOut>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue