diff --git a/src/app/organisms/create-room/CreateRoom.jsx b/src/app/organisms/create-room/CreateRoom.jsx
index 6c4968a..20e7609 100644
--- a/src/app/organisms/create-room/CreateRoom.jsx
+++ b/src/app/organisms/create-room/CreateRoom.jsx
@@ -2,79 +2,87 @@ import React, { useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import './CreateRoom.scss';
+import { twemojify } from '../../../util/twemojify';
import initMatrix from '../../../client/initMatrix';
import cons from '../../../client/state/cons';
-import { isRoomAliasAvailable } from '../../../util/matrixUtil';
+import navigation from '../../../client/state/navigation';
+import { selectRoom, openReusableContextMenu } from '../../../client/action/navigation';
import * as roomActions from '../../../client/action/room';
-import { selectRoom } from '../../../client/action/navigation';
+import { isRoomAliasAvailable, getIdServer } from '../../../util/matrixUtil';
+import { getEventCords } from '../../../util/common';
import Text from '../../atoms/text/Text';
import Button from '../../atoms/button/Button';
import Toggle from '../../atoms/button/Toggle';
import IconButton from '../../atoms/button/IconButton';
+import { MenuHeader, MenuItem } from '../../atoms/context-menu/ContextMenu';
import Input from '../../atoms/input/Input';
import Spinner from '../../atoms/spinner/Spinner';
import SegmentControl from '../../atoms/segmented-controls/SegmentedControls';
-import PopupWindow from '../../molecules/popup-window/PopupWindow';
+import Dialog from '../../molecules/dialog/Dialog';
import SettingTile from '../../molecules/setting-tile/SettingTile';
import HashPlusIC from '../../../../public/res/ic/outlined/hash-plus.svg';
+import SpacePlusIC from '../../../../public/res/ic/outlined/space-plus.svg';
+import HashIC from '../../../../public/res/ic/outlined/hash.svg';
+import HashLockIC from '../../../../public/res/ic/outlined/hash-lock.svg';
+import HashGlobeIC from '../../../../public/res/ic/outlined/hash-globe.svg';
+import SpaceIC from '../../../../public/res/ic/outlined/space.svg';
+import SpaceLockIC from '../../../../public/res/ic/outlined/space-lock.svg';
+import SpaceGlobeIC from '../../../../public/res/ic/outlined/space-globe.svg';
+import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg';
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
-function CreateRoom({ isOpen, onRequestClose }) {
- const [isPublic, togglePublic] = useState(false);
- const [isEncrypted, toggleEncrypted] = useState(true);
- const [isValidAddress, updateIsValidAddress] = useState(null);
- const [isCreatingRoom, updateIsCreatingRoom] = useState(false);
- const [creatingError, updateCreatingError] = useState(null);
+function CreateRoomContent({ isSpace, parentId, onRequestClose }) {
+ const [joinRule, setJoinRule] = useState(parentId ? 'restricted' : 'invite');
+ const [isEncrypted, setIsEncrypted] = useState(true);
+ const [isCreatingRoom, setIsCreatingRoom] = useState(false);
+ const [creatingError, setCreatingError] = useState(null);
- const [titleValue, updateTitleValue] = useState(undefined);
- const [topicValue, updateTopicValue] = useState(undefined);
- const [addressValue, updateAddressValue] = useState(undefined);
+ const [isValidAddress, setIsValidAddress] = useState(null);
+ const [addressValue, setAddressValue] = useState(undefined);
const [roleIndex, setRoleIndex] = useState(0);
const addressRef = useRef(null);
- const topicRef = useRef(null);
- const nameRef = useRef(null);
- const userId = initMatrix.matrixClient.getUserId();
- const hsString = userId.slice(userId.indexOf(':'));
-
- function resetForm() {
- togglePublic(false);
- toggleEncrypted(true);
- updateIsValidAddress(null);
- updateIsCreatingRoom(false);
- updateCreatingError(null);
- updateTitleValue(undefined);
- updateTopicValue(undefined);
- updateAddressValue(undefined);
- setRoleIndex(0);
- }
-
- const onCreated = (roomId) => {
- resetForm();
- selectRoom(roomId);
- onRequestClose();
- };
+ const mx = initMatrix.matrixClient;
+ const userHs = getIdServer(mx.getUserId());
useEffect(() => {
const { roomList } = initMatrix;
+ const onCreated = (roomId) => {
+ setJoinRule(false);
+ setIsEncrypted(true);
+ setIsValidAddress(null);
+ setIsCreatingRoom(false);
+ setCreatingError(null);
+ setAddressValue(undefined);
+ setRoleIndex(0);
+
+ if (!mx.getRoom(roomId)?.isSpaceRoom()) {
+ selectRoom(roomId);
+ }
+ onRequestClose();
+ };
roomList.on(cons.events.roomList.ROOM_CREATED, onCreated);
return () => {
roomList.removeListener(cons.events.roomList.ROOM_CREATED, onCreated);
};
}, []);
- async function createRoom() {
+ const handleSubmit = async (evt) => {
+ evt.preventDefault();
+ const { target } = evt;
+
if (isCreatingRoom) return;
- updateIsCreatingRoom(true);
- updateCreatingError(null);
- const name = nameRef.current.value;
- let topic = topicRef.current.value;
+ setIsCreatingRoom(true);
+ setCreatingError(null);
+
+ const name = target.name.value;
+ let topic = target.topic.value;
if (topic.trim() === '') topic = undefined;
let roomAlias;
- if (isPublic) {
+ if (joinRule === 'public') {
roomAlias = addressRef?.current?.value;
if (roomAlias.trim() === '') roomAlias = undefined;
}
@@ -82,115 +90,217 @@ function CreateRoom({ isOpen, onRequestClose }) {
const powerLevel = roleIndex === 1 ? 101 : undefined;
try {
- await roomActions.create({
- name, topic, isPublic, roomAlias, isEncrypted, powerLevel,
+ await roomActions.createRoom({
+ name,
+ topic,
+ joinRule,
+ alias: roomAlias,
+ isEncrypted: (isSpace || joinRule === 'public') ? false : isEncrypted,
+ powerLevel,
+ isSpace,
+ parentId,
});
} catch (e) {
if (e.message === 'M_UNKNOWN: Invalid characters in room alias') {
- updateCreatingError('ERROR: Invalid characters in room address');
- updateIsValidAddress(false);
+ setCreatingError('ERROR: Invalid characters in address');
+ setIsValidAddress(false);
} else if (e.message === 'M_ROOM_IN_USE: Room alias already taken') {
- updateCreatingError('ERROR: Room address is already in use');
- updateIsValidAddress(false);
- } else updateCreatingError(e.message);
- updateIsCreatingRoom(false);
+ setCreatingError('ERROR: This address is already in use');
+ setIsValidAddress(false);
+ } else setCreatingError(e.message);
+ setIsCreatingRoom(false);
}
- }
+ };
- function validateAddress(e) {
+ const validateAddress = (e) => {
const myAddress = e.target.value;
- updateIsValidAddress(null);
- updateAddressValue(e.target.value);
- updateCreatingError(null);
+ setIsValidAddress(null);
+ setAddressValue(e.target.value);
+ setCreatingError(null);
setTimeout(async () => {
if (myAddress !== addressRef.current.value) return;
const roomAlias = addressRef.current.value;
if (roomAlias === '') return;
- const roomAddress = `#${roomAlias}${hsString}`;
+ const roomAddress = `#${roomAlias}:${userHs}`;
if (await isRoomAliasAvailable(roomAddress)) {
- updateIsValidAddress(true);
+ setIsValidAddress(true);
} else {
- updateIsValidAddress(false);
+ setIsValidAddress(false);
}
}, 1000);
- }
- function handleTitleChange(e) {
- if (e.target.value.trim() === '') updateTitleValue(undefined);
- updateTitleValue(e.target.value);
- }
- function handleTopicChange(e) {
- if (e.target.value.trim() === '') updateTopicValue(undefined);
- updateTopicValue(e.target.value);
- }
+ };
+
+ const joinRules = ['invite', 'restricted', 'public'];
+ const joinRuleShortText = ['Private', 'Restricted', 'Public'];
+ const joinRuleText = ['Private (invite only)', 'Restricted (space member can join)', 'Public (anyone can join)'];
+ const jrRoomIC = [HashLockIC, HashIC, HashGlobeIC];
+ const jrSpaceIC = [SpaceLockIC, SpaceIC, SpaceGlobeIC];
+ const handleJoinRule = (evt) => {
+ openReusableContextMenu(
+ 'bottom',
+ getEventCords(evt, '.btn-surface'),
+ (closeMenu) => (
+ <>
+