mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 14:30:29 +03:00 
			
		
		
		
	add options to add creators in create room/space
This commit is contained in:
		
							parent
							
								
									7c8d25872b
								
							
						
					
					
						commit
						1de795ace7
					
				
					 5 changed files with 375 additions and 6 deletions
				
			
		
							
								
								
									
										300
									
								
								src/app/components/create-room/AdditionalCreatorInput.tsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								src/app/components/create-room/AdditionalCreatorInput.tsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,300 @@
 | 
			
		|||
import {
 | 
			
		||||
  Box,
 | 
			
		||||
  Button,
 | 
			
		||||
  Chip,
 | 
			
		||||
  config,
 | 
			
		||||
  Icon,
 | 
			
		||||
  Icons,
 | 
			
		||||
  Input,
 | 
			
		||||
  Line,
 | 
			
		||||
  Menu,
 | 
			
		||||
  MenuItem,
 | 
			
		||||
  PopOut,
 | 
			
		||||
  RectCords,
 | 
			
		||||
  Scroll,
 | 
			
		||||
  Text,
 | 
			
		||||
  toRem,
 | 
			
		||||
} from 'folds';
 | 
			
		||||
import { isKeyHotkey } from 'is-hotkey';
 | 
			
		||||
import FocusTrap from 'focus-trap-react';
 | 
			
		||||
import React, {
 | 
			
		||||
  ChangeEventHandler,
 | 
			
		||||
  KeyboardEventHandler,
 | 
			
		||||
  MouseEventHandler,
 | 
			
		||||
  useMemo,
 | 
			
		||||
  useState,
 | 
			
		||||
} from 'react';
 | 
			
		||||
import { getMxIdLocalPart, getMxIdServer, isUserId } from '../../utils/matrix';
 | 
			
		||||
import { useDirectUsers } from '../../hooks/useDirectUsers';
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
export const useAdditionalCreators = () => {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [additionalCreators, setAdditionalCreators] = useState<string[]>([]);
 | 
			
		||||
 | 
			
		||||
  const addAdditionalCreator = (userId: string) => {
 | 
			
		||||
    if (userId === mx.getSafeUserId()) return;
 | 
			
		||||
 | 
			
		||||
    setAdditionalCreators((creators) => {
 | 
			
		||||
      const creatorsSet = new Set(creators);
 | 
			
		||||
      creatorsSet.add(userId);
 | 
			
		||||
      return Array.from(creatorsSet);
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const removeAdditionalCreator = (userId: string) => {
 | 
			
		||||
    setAdditionalCreators((creators) => {
 | 
			
		||||
      const creatorsSet = new Set(creators);
 | 
			
		||||
      creatorsSet.delete(userId);
 | 
			
		||||
      return Array.from(creatorsSet);
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    additionalCreators,
 | 
			
		||||
    addAdditionalCreator,
 | 
			
		||||
    removeAdditionalCreator,
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const SEARCH_OPTIONS: UseAsyncSearchOptions = {
 | 
			
		||||
  limit: 1000,
 | 
			
		||||
  matchOptions: {
 | 
			
		||||
    contain: true,
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
const getUserIdString = (userId: string) => getMxIdLocalPart(userId) ?? userId;
 | 
			
		||||
 | 
			
		||||
type AdditionalCreatorInputProps = {
 | 
			
		||||
  additionalCreators: string[];
 | 
			
		||||
  onSelect: (userId: string) => void;
 | 
			
		||||
  onRemove: (userId: string) => void;
 | 
			
		||||
};
 | 
			
		||||
export function AdditionalCreatorInput({
 | 
			
		||||
  additionalCreators,
 | 
			
		||||
  onSelect,
 | 
			
		||||
  onRemove,
 | 
			
		||||
}: AdditionalCreatorInputProps) {
 | 
			
		||||
  const mx = useMatrixClient();
 | 
			
		||||
  const [menuCords, setMenuCords] = useState<RectCords>();
 | 
			
		||||
  const directUsers = useDirectUsers();
 | 
			
		||||
 | 
			
		||||
  const [validUserId, setValidUserId] = useState<string>();
 | 
			
		||||
  const filteredUsers = useMemo(
 | 
			
		||||
    () => directUsers.filter((userId) => !additionalCreators.includes(userId)),
 | 
			
		||||
    [directUsers, additionalCreators]
 | 
			
		||||
  );
 | 
			
		||||
  const [result, search, resetSearch] = useAsyncSearch(
 | 
			
		||||
    filteredUsers,
 | 
			
		||||
    getUserIdString,
 | 
			
		||||
    SEARCH_OPTIONS
 | 
			
		||||
  );
 | 
			
		||||
  const queryHighlighRegex = result?.query ? makeHighlightRegex([result.query]) : undefined;
 | 
			
		||||
 | 
			
		||||
  const suggestionUsers = result
 | 
			
		||||
    ? result.items
 | 
			
		||||
    : filteredUsers.sort((a, b) => (a.toLocaleLowerCase() >= b.toLocaleLowerCase() ? 1 : -1));
 | 
			
		||||
 | 
			
		||||
  const handleOpenMenu: MouseEventHandler<HTMLButtonElement> = (evt) => {
 | 
			
		||||
    setMenuCords(evt.currentTarget.getBoundingClientRect());
 | 
			
		||||
  };
 | 
			
		||||
  const handleCloseMenu = () => {
 | 
			
		||||
    setMenuCords(undefined);
 | 
			
		||||
    setValidUserId(undefined);
 | 
			
		||||
    resetSearch();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleCreatorChange: ChangeEventHandler<HTMLInputElement> = (evt) => {
 | 
			
		||||
    const creatorInput = evt.currentTarget;
 | 
			
		||||
    const creator = creatorInput.value.trim();
 | 
			
		||||
    if (isUserId(creator)) {
 | 
			
		||||
      setValidUserId(creator);
 | 
			
		||||
    } else {
 | 
			
		||||
      setValidUserId(undefined);
 | 
			
		||||
      const term =
 | 
			
		||||
        getMxIdLocalPart(creator) ?? (creator.startsWith('@') ? creator.slice(1) : creator);
 | 
			
		||||
      if (term) {
 | 
			
		||||
        search(term);
 | 
			
		||||
      } else {
 | 
			
		||||
        resetSearch();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleSelectUserId = (userId?: string) => {
 | 
			
		||||
    if (userId && isUserId(userId)) {
 | 
			
		||||
      onSelect(userId);
 | 
			
		||||
      handleCloseMenu();
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleCreatorKeyDown: KeyboardEventHandler<HTMLInputElement> = (evt) => {
 | 
			
		||||
    if (isKeyHotkey('enter', evt)) {
 | 
			
		||||
      evt.preventDefault();
 | 
			
		||||
      const creator = evt.currentTarget.value.trim();
 | 
			
		||||
      handleSelectUserId(isUserId(creator) ? creator : suggestionUsers[0]);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const handleEnterClick = () => {
 | 
			
		||||
    handleSelectUserId(validUserId);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SettingTile
 | 
			
		||||
      title="Founders"
 | 
			
		||||
      description="Special privileged users can be assigned during creation. These users have elevated control and can only be modified during a upgrade."
 | 
			
		||||
    >
 | 
			
		||||
      <Box shrink="No" direction="Column" gap="100">
 | 
			
		||||
        <Box gap="200" wrap="Wrap">
 | 
			
		||||
          <Chip type="button" variant="Primary" radii="Pill" outlined>
 | 
			
		||||
            <Text size="B300">{mx.getSafeUserId()}</Text>
 | 
			
		||||
          </Chip>
 | 
			
		||||
          {additionalCreators.map((creator) => (
 | 
			
		||||
            <Chip
 | 
			
		||||
              type="button"
 | 
			
		||||
              key={creator}
 | 
			
		||||
              variant="Secondary"
 | 
			
		||||
              radii="Pill"
 | 
			
		||||
              after={<Icon size="50" src={Icons.Cross} />}
 | 
			
		||||
              onClick={() => onRemove(creator)}
 | 
			
		||||
            >
 | 
			
		||||
              <Text size="B300">{creator}</Text>
 | 
			
		||||
            </Chip>
 | 
			
		||||
          ))}
 | 
			
		||||
          <PopOut
 | 
			
		||||
            anchor={menuCords}
 | 
			
		||||
            position="Bottom"
 | 
			
		||||
            align="Center"
 | 
			
		||||
            content={
 | 
			
		||||
              <FocusTrap
 | 
			
		||||
                focusTrapOptions={{
 | 
			
		||||
                  onDeactivate: handleCloseMenu,
 | 
			
		||||
                  clickOutsideDeactivates: true,
 | 
			
		||||
                  isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
 | 
			
		||||
                  isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
 | 
			
		||||
                  escapeDeactivates: stopPropagation,
 | 
			
		||||
                }}
 | 
			
		||||
              >
 | 
			
		||||
                <Menu
 | 
			
		||||
                  style={{
 | 
			
		||||
                    width: '100vw',
 | 
			
		||||
                    maxWidth: toRem(300),
 | 
			
		||||
                    height: toRem(250),
 | 
			
		||||
                    display: 'flex',
 | 
			
		||||
                  }}
 | 
			
		||||
                >
 | 
			
		||||
                  <Box grow="Yes" direction="Column">
 | 
			
		||||
                    <Box shrink="No" gap="100" style={{ padding: config.space.S100 }}>
 | 
			
		||||
                      <Box grow="Yes" direction="Column" gap="100">
 | 
			
		||||
                        <Input
 | 
			
		||||
                          size="400"
 | 
			
		||||
                          variant="Background"
 | 
			
		||||
                          radii="300"
 | 
			
		||||
                          outlined
 | 
			
		||||
                          placeholder="@john:server"
 | 
			
		||||
                          onChange={handleCreatorChange}
 | 
			
		||||
                          onKeyDown={handleCreatorKeyDown}
 | 
			
		||||
                        />
 | 
			
		||||
                      </Box>
 | 
			
		||||
                      <Button
 | 
			
		||||
                        type="button"
 | 
			
		||||
                        variant="Success"
 | 
			
		||||
                        radii="300"
 | 
			
		||||
                        onClick={handleEnterClick}
 | 
			
		||||
                        disabled={!validUserId}
 | 
			
		||||
                      >
 | 
			
		||||
                        <Text size="B400">Enter</Text>
 | 
			
		||||
                      </Button>
 | 
			
		||||
                    </Box>
 | 
			
		||||
                    <Line size="300" />
 | 
			
		||||
                    <Box grow="Yes" direction="Column">
 | 
			
		||||
                      {!validUserId && suggestionUsers.length > 0 ? (
 | 
			
		||||
                        <Scroll size="300" hideTrack>
 | 
			
		||||
                          <Box
 | 
			
		||||
                            grow="Yes"
 | 
			
		||||
                            direction="Column"
 | 
			
		||||
                            gap="100"
 | 
			
		||||
                            style={{ padding: config.space.S200, paddingRight: 0 }}
 | 
			
		||||
                          >
 | 
			
		||||
                            {suggestionUsers.map((userId) => (
 | 
			
		||||
                              <MenuItem
 | 
			
		||||
                                key={userId}
 | 
			
		||||
                                size="300"
 | 
			
		||||
                                variant="Surface"
 | 
			
		||||
                                radii="300"
 | 
			
		||||
                                onClick={() => handleSelectUserId(userId)}
 | 
			
		||||
                                after={
 | 
			
		||||
                                  <Text size="T200" truncate>
 | 
			
		||||
                                    {getMxIdServer(userId)}
 | 
			
		||||
                                  </Text>
 | 
			
		||||
                                }
 | 
			
		||||
                              >
 | 
			
		||||
                                <Box grow="Yes">
 | 
			
		||||
                                  <Text size="T200" truncate>
 | 
			
		||||
                                    <b>
 | 
			
		||||
                                      {queryHighlighRegex
 | 
			
		||||
                                        ? findAndReplace(
 | 
			
		||||
                                            getMxIdLocalPart(userId) ?? userId,
 | 
			
		||||
                                            queryHighlighRegex,
 | 
			
		||||
                                            (match, pushIndex) => (
 | 
			
		||||
                                              <span
 | 
			
		||||
                                                key={`highlight-${pushIndex}`}
 | 
			
		||||
                                                className={highlightText}
 | 
			
		||||
                                              >
 | 
			
		||||
                                                {match[0]}
 | 
			
		||||
                                              </span>
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            (txt) => txt
 | 
			
		||||
                                          )
 | 
			
		||||
                                        : getMxIdLocalPart(userId)}
 | 
			
		||||
                                    </b>
 | 
			
		||||
                                  </Text>
 | 
			
		||||
                                </Box>
 | 
			
		||||
                              </MenuItem>
 | 
			
		||||
                            ))}
 | 
			
		||||
                          </Box>
 | 
			
		||||
                        </Scroll>
 | 
			
		||||
                      ) : (
 | 
			
		||||
                        <Box
 | 
			
		||||
                          grow="Yes"
 | 
			
		||||
                          alignItems="Center"
 | 
			
		||||
                          justifyContent="Center"
 | 
			
		||||
                          direction="Column"
 | 
			
		||||
                          gap="100"
 | 
			
		||||
                        >
 | 
			
		||||
                          <Text size="H6" align="Center">
 | 
			
		||||
                            No Suggestions
 | 
			
		||||
                          </Text>
 | 
			
		||||
                          <Text size="T200" align="Center">
 | 
			
		||||
                            Please provide the user ID and hit Enter.
 | 
			
		||||
                          </Text>
 | 
			
		||||
                        </Box>
 | 
			
		||||
                      )}
 | 
			
		||||
                    </Box>
 | 
			
		||||
                  </Box>
 | 
			
		||||
                </Menu>
 | 
			
		||||
              </FocusTrap>
 | 
			
		||||
            }
 | 
			
		||||
          >
 | 
			
		||||
            <Chip
 | 
			
		||||
              type="button"
 | 
			
		||||
              variant="Secondary"
 | 
			
		||||
              radii="Pill"
 | 
			
		||||
              onClick={handleOpenMenu}
 | 
			
		||||
              aria-pressed={!!menuCords}
 | 
			
		||||
            >
 | 
			
		||||
              <Icon size="50" src={Icons.Plus} />
 | 
			
		||||
            </Chip>
 | 
			
		||||
          </PopOut>
 | 
			
		||||
        </Box>
 | 
			
		||||
      </Box>
 | 
			
		||||
    </SettingTile>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,3 +2,4 @@ export * from './CreateRoomKindSelector';
 | 
			
		|||
export * from './CreateRoomAliasInput';
 | 
			
		||||
export * from './RoomVersionSelector';
 | 
			
		||||
export * from './utils';
 | 
			
		||||
export * from './AdditionalCreatorInput';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,8 @@ import { getMxIdServer } from '../../utils/matrix';
 | 
			
		|||
 | 
			
		||||
export const createRoomCreationContent = (
 | 
			
		||||
  type: RoomType | undefined,
 | 
			
		||||
  allowFederation: boolean
 | 
			
		||||
  allowFederation: boolean,
 | 
			
		||||
  additionalCreators: string[] | undefined
 | 
			
		||||
): object => {
 | 
			
		||||
  const content: Record<string, any> = {};
 | 
			
		||||
  if (typeof type === 'string') {
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +24,9 @@ export const createRoomCreationContent = (
 | 
			
		|||
  if (allowFederation === false) {
 | 
			
		||||
    content['m.federate'] = false;
 | 
			
		||||
  }
 | 
			
		||||
  if (Array.isArray(additionalCreators)) {
 | 
			
		||||
    content.additional_creators = additionalCreators;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return content;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -89,6 +93,7 @@ export type CreateRoomData = {
 | 
			
		|||
  encryption?: boolean;
 | 
			
		||||
  knock: boolean;
 | 
			
		||||
  allowFederation: boolean;
 | 
			
		||||
  additionalCreators?: string[];
 | 
			
		||||
};
 | 
			
		||||
export const createRoom = async (mx: MatrixClient, data: CreateRoomData): Promise<string> => {
 | 
			
		||||
  const initialState: ICreateRoomStateEvent[] = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +113,11 @@ export const createRoom = async (mx: MatrixClient, data: CreateRoomData): Promis
 | 
			
		|||
    name: data.name,
 | 
			
		||||
    topic: data.topic,
 | 
			
		||||
    room_alias_name: data.aliasLocalPart,
 | 
			
		||||
    creation_content: createRoomCreationContent(data.type, data.allowFederation),
 | 
			
		||||
    creation_content: createRoomCreationContent(
 | 
			
		||||
      data.type,
 | 
			
		||||
      data.allowFederation,
 | 
			
		||||
      data.additionalCreators
 | 
			
		||||
    ),
 | 
			
		||||
    initial_state: initialState,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import React, { FormEventHandler, useCallback, useState } from 'react';
 | 
			
		||||
import React, { FormEventHandler, useCallback, useEffect, useState } from 'react';
 | 
			
		||||
import { MatrixError, Room } from 'matrix-js-sdk';
 | 
			
		||||
import {
 | 
			
		||||
  Box,
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,12 @@ import {
 | 
			
		|||
} from 'folds';
 | 
			
		||||
import { SettingTile } from '../../components/setting-tile';
 | 
			
		||||
import { SequenceCard } from '../../components/sequence-card';
 | 
			
		||||
import { knockRestrictedSupported, knockSupported, restrictedSupported } from '../../utils/matrix';
 | 
			
		||||
import {
 | 
			
		||||
  creatorsSupported,
 | 
			
		||||
  knockRestrictedSupported,
 | 
			
		||||
  knockSupported,
 | 
			
		||||
  restrictedSupported,
 | 
			
		||||
} from '../../utils/matrix';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
import { millisecondsToMinutes, replaceSpaceWithDash } from '../../utils/common';
 | 
			
		||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
			
		||||
| 
						 | 
				
			
			@ -24,12 +29,14 @@ import { useCapabilities } from '../../hooks/useCapabilities';
 | 
			
		|||
import { useAlive } from '../../hooks/useAlive';
 | 
			
		||||
import { ErrorCode } from '../../cs-errorcode';
 | 
			
		||||
import {
 | 
			
		||||
  AdditionalCreatorInput,
 | 
			
		||||
  createRoom,
 | 
			
		||||
  CreateRoomAliasInput,
 | 
			
		||||
  CreateRoomData,
 | 
			
		||||
  CreateRoomKind,
 | 
			
		||||
  CreateRoomKindSelector,
 | 
			
		||||
  RoomVersionSelector,
 | 
			
		||||
  useAdditionalCreators,
 | 
			
		||||
} from '../../components/create-room';
 | 
			
		||||
 | 
			
		||||
const getCreateRoomKindToIcon = (kind: CreateRoomKind) => {
 | 
			
		||||
| 
						 | 
				
			
			@ -50,12 +57,19 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP
 | 
			
		|||
  const capabilities = useCapabilities();
 | 
			
		||||
  const roomVersions = capabilities['m.room_versions'];
 | 
			
		||||
  const [selectedRoomVersion, selectRoomVersion] = useState(roomVersions?.default ?? '1');
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    // capabilities load async
 | 
			
		||||
    selectRoomVersion(roomVersions?.default ?? '1');
 | 
			
		||||
  }, [roomVersions?.default]);
 | 
			
		||||
 | 
			
		||||
  const allowRestricted = space && restrictedSupported(selectedRoomVersion);
 | 
			
		||||
 | 
			
		||||
  const [kind, setKind] = useState(
 | 
			
		||||
    defaultKind ?? allowRestricted ? CreateRoomKind.Restricted : CreateRoomKind.Private
 | 
			
		||||
  );
 | 
			
		||||
  const allowAdditionalCreators = creatorsSupported(selectedRoomVersion);
 | 
			
		||||
  const { additionalCreators, addAdditionalCreator, removeAdditionalCreator } =
 | 
			
		||||
    useAdditionalCreators();
 | 
			
		||||
  const [federation, setFederation] = useState(true);
 | 
			
		||||
  const [encryption, setEncryption] = useState(false);
 | 
			
		||||
  const [knock, setKnock] = useState(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +126,7 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP
 | 
			
		|||
      encryption: publicRoom ? false : encryption,
 | 
			
		||||
      knock: roomKnock,
 | 
			
		||||
      allowFederation: federation,
 | 
			
		||||
      additionalCreators: allowAdditionalCreators ? additionalCreators : undefined,
 | 
			
		||||
    }).then((roomId) => {
 | 
			
		||||
      if (alive()) {
 | 
			
		||||
        onCreate?.(roomId);
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +187,20 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP
 | 
			
		|||
            </Chip>
 | 
			
		||||
          </Box>
 | 
			
		||||
        </Box>
 | 
			
		||||
        {allowAdditionalCreators && (
 | 
			
		||||
          <SequenceCard
 | 
			
		||||
            style={{ padding: config.space.S300 }}
 | 
			
		||||
            variant="SurfaceVariant"
 | 
			
		||||
            direction="Column"
 | 
			
		||||
            gap="500"
 | 
			
		||||
          >
 | 
			
		||||
            <AdditionalCreatorInput
 | 
			
		||||
              additionalCreators={additionalCreators}
 | 
			
		||||
              onSelect={addAdditionalCreator}
 | 
			
		||||
              onRemove={removeAdditionalCreator}
 | 
			
		||||
            />
 | 
			
		||||
          </SequenceCard>
 | 
			
		||||
        )}
 | 
			
		||||
        {kind !== CreateRoomKind.Public && (
 | 
			
		||||
          <>
 | 
			
		||||
            <SequenceCard
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import React, { FormEventHandler, useCallback, useState } from 'react';
 | 
			
		||||
import React, { FormEventHandler, useCallback, useEffect, useState } from 'react';
 | 
			
		||||
import { MatrixError, Room } from 'matrix-js-sdk';
 | 
			
		||||
import {
 | 
			
		||||
  Box,
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,12 @@ import {
 | 
			
		|||
} from 'folds';
 | 
			
		||||
import { SettingTile } from '../../components/setting-tile';
 | 
			
		||||
import { SequenceCard } from '../../components/sequence-card';
 | 
			
		||||
import { knockRestrictedSupported, knockSupported, restrictedSupported } from '../../utils/matrix';
 | 
			
		||||
import {
 | 
			
		||||
  creatorsSupported,
 | 
			
		||||
  knockRestrictedSupported,
 | 
			
		||||
  knockSupported,
 | 
			
		||||
  restrictedSupported,
 | 
			
		||||
} from '../../utils/matrix';
 | 
			
		||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
 | 
			
		||||
import { millisecondsToMinutes, replaceSpaceWithDash } from '../../utils/common';
 | 
			
		||||
import { AsyncStatus, useAsyncCallback } from '../../hooks/useAsyncCallback';
 | 
			
		||||
| 
						 | 
				
			
			@ -24,12 +29,14 @@ import { useCapabilities } from '../../hooks/useCapabilities';
 | 
			
		|||
import { useAlive } from '../../hooks/useAlive';
 | 
			
		||||
import { ErrorCode } from '../../cs-errorcode';
 | 
			
		||||
import {
 | 
			
		||||
  AdditionalCreatorInput,
 | 
			
		||||
  createRoom,
 | 
			
		||||
  CreateRoomAliasInput,
 | 
			
		||||
  CreateRoomData,
 | 
			
		||||
  CreateRoomKind,
 | 
			
		||||
  CreateRoomKindSelector,
 | 
			
		||||
  RoomVersionSelector,
 | 
			
		||||
  useAdditionalCreators,
 | 
			
		||||
} from '../../components/create-room';
 | 
			
		||||
import { RoomType } from '../../../types/matrix/room';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,12 +58,20 @@ export function CreateSpaceForm({ defaultKind, space, onCreate }: CreateSpaceFor
 | 
			
		|||
  const capabilities = useCapabilities();
 | 
			
		||||
  const roomVersions = capabilities['m.room_versions'];
 | 
			
		||||
  const [selectedRoomVersion, selectRoomVersion] = useState(roomVersions?.default ?? '1');
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    // capabilities load async
 | 
			
		||||
    selectRoomVersion(roomVersions?.default ?? '1');
 | 
			
		||||
  }, [roomVersions?.default]);
 | 
			
		||||
 | 
			
		||||
  const allowRestricted = space && restrictedSupported(selectedRoomVersion);
 | 
			
		||||
 | 
			
		||||
  const [kind, setKind] = useState(
 | 
			
		||||
    defaultKind ?? allowRestricted ? CreateRoomKind.Restricted : CreateRoomKind.Private
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const allowAdditionalCreators = creatorsSupported(selectedRoomVersion);
 | 
			
		||||
  const { additionalCreators, addAdditionalCreator, removeAdditionalCreator } =
 | 
			
		||||
    useAdditionalCreators();
 | 
			
		||||
  const [federation, setFederation] = useState(true);
 | 
			
		||||
  const [knock, setKnock] = useState(false);
 | 
			
		||||
  const [advance, setAdvance] = useState(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -112,6 +127,7 @@ export function CreateSpaceForm({ defaultKind, space, onCreate }: CreateSpaceFor
 | 
			
		|||
      aliasLocalPart: publicRoom ? aliasLocalPart : undefined,
 | 
			
		||||
      knock: roomKnock,
 | 
			
		||||
      allowFederation: federation,
 | 
			
		||||
      additionalCreators: allowAdditionalCreators ? additionalCreators : undefined,
 | 
			
		||||
    }).then((roomId) => {
 | 
			
		||||
      if (alive()) {
 | 
			
		||||
        onCreate?.(roomId);
 | 
			
		||||
| 
						 | 
				
			
			@ -172,6 +188,20 @@ export function CreateSpaceForm({ defaultKind, space, onCreate }: CreateSpaceFor
 | 
			
		|||
            </Chip>
 | 
			
		||||
          </Box>
 | 
			
		||||
        </Box>
 | 
			
		||||
        {allowAdditionalCreators && (
 | 
			
		||||
          <SequenceCard
 | 
			
		||||
            style={{ padding: config.space.S300 }}
 | 
			
		||||
            variant="SurfaceVariant"
 | 
			
		||||
            direction="Column"
 | 
			
		||||
            gap="500"
 | 
			
		||||
          >
 | 
			
		||||
            <AdditionalCreatorInput
 | 
			
		||||
              additionalCreators={additionalCreators}
 | 
			
		||||
              onSelect={addAdditionalCreator}
 | 
			
		||||
              onRemove={removeAdditionalCreator}
 | 
			
		||||
            />
 | 
			
		||||
          </SequenceCard>
 | 
			
		||||
        )}
 | 
			
		||||
        {kind !== CreateRoomKind.Public && advance && (allowKnock || allowKnockRestricted) && (
 | 
			
		||||
          <SequenceCard
 | 
			
		||||
            style={{ padding: config.space.S300 }}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue