2021-03-01 21:10:17 +03:00
|
|
|
/*
|
|
|
|
Copyright 2021 The Matrix.org Foundation C.I.C.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2021-03-26 12:44:52 +03:00
|
|
|
import React, {RefObject, useContext, useRef, useState} from "react";
|
|
|
|
import {EventType} from "matrix-js-sdk/src/@types/event";
|
2021-03-01 21:10:17 +03:00
|
|
|
import {Room} from "matrix-js-sdk/src/models/room";
|
2021-03-16 17:18:45 +03:00
|
|
|
import {EventSubscription} from "fbemitter";
|
2021-03-01 21:10:17 +03:00
|
|
|
|
|
|
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
|
|
|
import RoomAvatar from "../views/avatars/RoomAvatar";
|
|
|
|
import {_t} from "../../languageHandler";
|
|
|
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
|
|
|
import RoomName from "../views/elements/RoomName";
|
|
|
|
import RoomTopic from "../views/elements/RoomTopic";
|
2021-03-02 17:37:28 +03:00
|
|
|
import InlineSpinner from "../views/elements/InlineSpinner";
|
2021-03-02 13:07:43 +03:00
|
|
|
import {inviteMultipleToRoom, showRoomInviteDialog} from "../../RoomInvite";
|
2021-03-01 21:10:17 +03:00
|
|
|
import {useRoomMembers} from "../../hooks/useRoomMembers";
|
|
|
|
import createRoom, {IOpts, Preset} from "../../createRoom";
|
|
|
|
import Field from "../views/elements/Field";
|
|
|
|
import {useEventEmitter} from "../../hooks/useEventEmitter";
|
|
|
|
import withValidation from "../views/elements/Validation";
|
|
|
|
import * as Email from "../../email";
|
|
|
|
import defaultDispatcher from "../../dispatcher/dispatcher";
|
|
|
|
import {Action} from "../../dispatcher/actions";
|
|
|
|
import ResizeNotifier from "../../utils/ResizeNotifier"
|
|
|
|
import MainSplit from './MainSplit';
|
|
|
|
import ErrorBoundary from "../views/elements/ErrorBoundary";
|
|
|
|
import {ActionPayload} from "../../dispatcher/payloads";
|
|
|
|
import RightPanel from "./RightPanel";
|
|
|
|
import RightPanelStore from "../../stores/RightPanelStore";
|
|
|
|
import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
|
|
|
|
import {SetRightPanelPhasePayload} from "../../dispatcher/payloads/SetRightPanelPhasePayload";
|
|
|
|
import {useStateArray} from "../../hooks/useStateArray";
|
|
|
|
import SpacePublicShare from "../views/spaces/SpacePublicShare";
|
2021-03-02 16:32:24 +03:00
|
|
|
import {showAddExistingRooms, showCreateNewRoom, shouldShowSpaceSettings, showSpaceSettings} from "../../utils/space";
|
2021-03-26 12:44:52 +03:00
|
|
|
import {showRoom, SpaceHierarchy} from "./SpaceRoomDirectory";
|
2021-03-01 21:10:17 +03:00
|
|
|
import MemberAvatar from "../views/avatars/MemberAvatar";
|
2021-03-02 17:37:28 +03:00
|
|
|
import {useStateToggle} from "../../hooks/useStateToggle";
|
2021-03-16 17:18:45 +03:00
|
|
|
import SpaceStore from "../../stores/SpaceStore";
|
2021-03-25 19:15:34 +03:00
|
|
|
import FacePile from "../views/elements/FacePile";
|
2021-04-26 14:41:04 +03:00
|
|
|
import {AddExistingToSpace} from "../views/dialogs/AddExistingToSpaceDialog";
|
2021-05-05 13:54:14 +03:00
|
|
|
import {sleep} from "../../utils/promise";
|
2021-04-26 14:41:04 +03:00
|
|
|
import {calculateRoomVia} from "../../utils/permalinks/Permalinks";
|
2021-05-05 19:25:29 +03:00
|
|
|
import {ChevronFace, ContextMenuButton, useContextMenu} from "./ContextMenu";
|
|
|
|
import IconizedContextMenu, {
|
|
|
|
IconizedContextMenuOption,
|
|
|
|
IconizedContextMenuOptionList,
|
|
|
|
} from "../views/context_menus/IconizedContextMenu";
|
|
|
|
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
2021-04-28 10:41:31 +03:00
|
|
|
import {BetaPill} from "../views/beta/BetaCard";
|
|
|
|
import {USER_LABS_TAB} from "../views/dialogs/UserSettingsDialog";
|
|
|
|
import SettingsStore from "../../settings/SettingsStore";
|
|
|
|
import dis from "../../dispatcher/dispatcher";
|
2021-03-01 21:10:17 +03:00
|
|
|
|
|
|
|
interface IProps {
|
|
|
|
space: Room;
|
|
|
|
justCreatedOpts?: IOpts;
|
|
|
|
resizeNotifier: ResizeNotifier;
|
|
|
|
onJoinButtonClicked(): void;
|
|
|
|
onRejectButtonClicked(): void;
|
|
|
|
}
|
|
|
|
|
|
|
|
interface IState {
|
|
|
|
phase: Phase;
|
|
|
|
showRightPanel: boolean;
|
2021-03-16 17:18:45 +03:00
|
|
|
myMembership: string;
|
2021-03-01 21:10:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
enum Phase {
|
|
|
|
Landing,
|
|
|
|
PublicCreateRooms,
|
|
|
|
PublicShare,
|
|
|
|
PrivateScope,
|
|
|
|
PrivateInvite,
|
|
|
|
PrivateCreateRooms,
|
|
|
|
PrivateExistingRooms,
|
|
|
|
}
|
|
|
|
|
|
|
|
const RoomMemberCount = ({ room, children }) => {
|
|
|
|
const members = useRoomMembers(room);
|
|
|
|
const count = members.length;
|
|
|
|
|
|
|
|
if (children) return children(count);
|
|
|
|
return count;
|
|
|
|
};
|
|
|
|
|
|
|
|
const useMyRoomMembership = (room: Room) => {
|
|
|
|
const [membership, setMembership] = useState(room.getMyMembership());
|
|
|
|
useEventEmitter(room, "Room.myMembership", () => {
|
|
|
|
setMembership(room.getMyMembership());
|
|
|
|
});
|
|
|
|
return membership;
|
|
|
|
};
|
|
|
|
|
2021-03-26 16:11:57 +03:00
|
|
|
const SpaceInfo = ({ space }) => {
|
|
|
|
const joinRule = space.getJoinRule();
|
|
|
|
|
|
|
|
let visibilitySection;
|
|
|
|
if (joinRule === "public") {
|
|
|
|
visibilitySection = <span className="mx_SpaceRoomView_info_public">
|
|
|
|
{ _t("Public space") }
|
|
|
|
</span>;
|
|
|
|
} else {
|
|
|
|
visibilitySection = <span className="mx_SpaceRoomView_info_private">
|
|
|
|
{ _t("Private space") }
|
|
|
|
</span>;
|
|
|
|
}
|
|
|
|
|
|
|
|
return <div className="mx_SpaceRoomView_info">
|
|
|
|
{ visibilitySection }
|
|
|
|
{ joinRule === "public" && <RoomMemberCount room={space}>
|
|
|
|
{(count) => count > 0 ? (
|
|
|
|
<AccessibleButton
|
|
|
|
kind="link"
|
|
|
|
onClick={() => {
|
|
|
|
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
|
|
|
action: Action.SetRightPanelPhase,
|
|
|
|
phase: RightPanelPhases.RoomMemberList,
|
|
|
|
refireParams: { space },
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{ _t("%(count)s members", { count }) }
|
|
|
|
</AccessibleButton>
|
|
|
|
) : null}
|
|
|
|
</RoomMemberCount> }
|
|
|
|
</div>
|
|
|
|
};
|
|
|
|
|
2021-04-28 10:41:31 +03:00
|
|
|
const onBetaClick = () => {
|
|
|
|
defaultDispatcher.dispatch({
|
|
|
|
action: Action.ViewUserSettings,
|
|
|
|
initialTabId: USER_LABS_TAB,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2021-03-11 14:49:43 +03:00
|
|
|
const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) => {
|
2021-03-01 21:10:17 +03:00
|
|
|
const cli = useContext(MatrixClientContext);
|
|
|
|
const myMembership = useMyRoomMembership(space);
|
|
|
|
|
2021-03-16 17:18:45 +03:00
|
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
|
2021-04-28 10:41:31 +03:00
|
|
|
const spacesEnabled = SettingsStore.getValue("feature_spaces");
|
|
|
|
|
2021-03-11 14:49:43 +03:00
|
|
|
let inviterSection;
|
2021-03-01 21:10:17 +03:00
|
|
|
let joinButtons;
|
2021-04-28 10:41:31 +03:00
|
|
|
if (myMembership === "join") {
|
|
|
|
// XXX remove this when spaces leaves Beta
|
|
|
|
joinButtons = (
|
|
|
|
<AccessibleButton
|
2021-04-28 14:10:03 +03:00
|
|
|
kind="danger_outline"
|
2021-04-28 10:41:31 +03:00
|
|
|
onClick={() => {
|
|
|
|
dis.dispatch({
|
|
|
|
action: "leave_room",
|
|
|
|
room_id: space.roomId,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{ _t("Leave") }
|
|
|
|
</AccessibleButton>
|
|
|
|
);
|
|
|
|
} else if (myMembership === "invite") {
|
2021-03-11 14:49:43 +03:00
|
|
|
const inviteSender = space.getMember(cli.getUserId())?.events.member?.getSender();
|
|
|
|
const inviter = inviteSender && space.getMember(inviteSender);
|
|
|
|
|
|
|
|
if (inviteSender) {
|
|
|
|
inviterSection = <div className="mx_SpaceRoomView_preview_inviter">
|
|
|
|
<MemberAvatar member={inviter} width={32} height={32} />
|
|
|
|
<div>
|
|
|
|
<div className="mx_SpaceRoomView_preview_inviter_name">
|
|
|
|
{ _t("<inviter/> invites you", {}, {
|
|
|
|
inviter: () => <b>{ inviter.name || inviteSender }</b>,
|
|
|
|
}) }
|
|
|
|
</div>
|
|
|
|
{ inviter ? <div className="mx_SpaceRoomView_preview_inviter_mxid">
|
|
|
|
{ inviteSender }
|
|
|
|
</div> : null }
|
|
|
|
</div>
|
|
|
|
</div>;
|
|
|
|
}
|
|
|
|
|
|
|
|
joinButtons = <>
|
2021-03-24 16:15:31 +03:00
|
|
|
<AccessibleButton
|
2021-03-16 17:18:45 +03:00
|
|
|
kind="secondary"
|
|
|
|
onClick={() => {
|
|
|
|
setBusy(true);
|
|
|
|
onRejectButtonClicked();
|
2021-03-24 16:15:31 +03:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
{ _t("Reject") }
|
|
|
|
</AccessibleButton>
|
|
|
|
<AccessibleButton
|
|
|
|
kind="primary"
|
2021-03-16 17:18:45 +03:00
|
|
|
onClick={() => {
|
|
|
|
setBusy(true);
|
|
|
|
onJoinButtonClicked();
|
|
|
|
}}
|
2021-04-28 10:41:31 +03:00
|
|
|
disabled={!spacesEnabled}
|
2021-03-24 16:15:31 +03:00
|
|
|
>
|
|
|
|
{ _t("Accept") }
|
|
|
|
</AccessibleButton>
|
2021-03-11 14:49:43 +03:00
|
|
|
</>;
|
|
|
|
} else {
|
2021-03-16 17:18:45 +03:00
|
|
|
joinButtons = (
|
2021-03-24 16:15:31 +03:00
|
|
|
<AccessibleButton
|
|
|
|
kind="primary"
|
2021-03-16 17:18:45 +03:00
|
|
|
onClick={() => {
|
|
|
|
setBusy(true);
|
|
|
|
onJoinButtonClicked();
|
|
|
|
}}
|
2021-04-28 10:41:31 +03:00
|
|
|
disabled={!spacesEnabled}
|
2021-03-24 16:15:31 +03:00
|
|
|
>
|
|
|
|
{ _t("Join") }
|
|
|
|
</AccessibleButton>
|
2021-04-28 10:41:31 +03:00
|
|
|
);
|
2021-03-16 17:18:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (busy) {
|
|
|
|
joinButtons = <InlineSpinner />;
|
2021-03-11 14:49:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return <div className="mx_SpaceRoomView_preview">
|
2021-04-28 10:41:31 +03:00
|
|
|
<BetaPill onClick={onBetaClick} />
|
2021-03-11 14:49:43 +03:00
|
|
|
{ inviterSection }
|
|
|
|
<RoomAvatar room={space} height={80} width={80} viewAvatarOnClick={true} />
|
|
|
|
<h1 className="mx_SpaceRoomView_preview_name">
|
|
|
|
<RoomName room={space} />
|
|
|
|
</h1>
|
2021-03-26 16:11:57 +03:00
|
|
|
<SpaceInfo space={space} />
|
2021-03-11 14:49:43 +03:00
|
|
|
<RoomTopic room={space}>
|
|
|
|
{(topic, ref) =>
|
|
|
|
<div className="mx_SpaceRoomView_preview_topic" ref={ref}>
|
|
|
|
{ topic }
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
</RoomTopic>
|
2021-03-26 16:11:57 +03:00
|
|
|
{ space.getJoinRule() === "public" && <FacePile room={space} /> }
|
2021-03-11 14:49:43 +03:00
|
|
|
<div className="mx_SpaceRoomView_preview_joinButtons">
|
|
|
|
{ joinButtons }
|
|
|
|
</div>
|
2021-04-28 10:41:31 +03:00
|
|
|
{ !spacesEnabled && <div className="mx_SpaceRoomView_preview_spaceBetaPrompt">
|
|
|
|
{ myMembership === "join"
|
|
|
|
? _t("To view %(spaceName)s, turn on the <a>Spaces beta</a>", {
|
|
|
|
spaceName: space.name,
|
|
|
|
}, {
|
|
|
|
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
|
|
|
|
})
|
|
|
|
: _t("To join %(spaceName)s, turn on the <a>Spaces beta</a>", {
|
|
|
|
spaceName: space.name,
|
|
|
|
}, {
|
|
|
|
a: sub => <AccessibleButton onClick={onBetaClick} kind="link">{ sub }</AccessibleButton>,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
</div> }
|
2021-03-11 14:49:43 +03:00
|
|
|
</div>;
|
|
|
|
};
|
|
|
|
|
2021-05-05 19:25:29 +03:00
|
|
|
const SpaceLandingAddButton = ({ space, onNewRoomAdded }) => {
|
|
|
|
const cli = useContext(MatrixClientContext);
|
|
|
|
const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu();
|
|
|
|
|
|
|
|
let contextMenu;
|
|
|
|
if (menuDisplayed) {
|
|
|
|
const rect = handle.current.getBoundingClientRect();
|
|
|
|
contextMenu = <IconizedContextMenu
|
|
|
|
left={rect.left + window.pageXOffset + 0}
|
|
|
|
top={rect.bottom + window.pageYOffset + 8}
|
|
|
|
chevronFace={ChevronFace.None}
|
|
|
|
onFinished={closeMenu}
|
|
|
|
className="mx_RoomTile_contextMenu"
|
|
|
|
compact
|
|
|
|
>
|
|
|
|
<IconizedContextMenuOptionList first>
|
|
|
|
<IconizedContextMenuOption
|
|
|
|
label={_t("Create new room")}
|
|
|
|
iconClassName="mx_RoomList_iconPlus"
|
|
|
|
onClick={async (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
closeMenu();
|
|
|
|
|
|
|
|
if (await showCreateNewRoom(cli, space)) {
|
|
|
|
onNewRoomAdded();
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
<IconizedContextMenuOption
|
|
|
|
label={_t("Add existing room")}
|
|
|
|
iconClassName="mx_RoomList_iconHash"
|
|
|
|
onClick={async (e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
closeMenu();
|
|
|
|
|
|
|
|
const [added] = await showAddExistingRooms(cli, space);
|
|
|
|
if (added) {
|
|
|
|
onNewRoomAdded();
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</IconizedContextMenuOptionList>
|
|
|
|
</IconizedContextMenu>;
|
|
|
|
}
|
|
|
|
|
|
|
|
return <>
|
|
|
|
<ContextMenuButton
|
|
|
|
kind="primary"
|
|
|
|
inputRef={handle}
|
|
|
|
onClick={openMenu}
|
|
|
|
isExpanded={menuDisplayed}
|
|
|
|
label={_t("Add")}
|
|
|
|
>
|
|
|
|
{ _t("Add") }
|
|
|
|
</ContextMenuButton>
|
|
|
|
{ contextMenu }
|
|
|
|
</>;
|
|
|
|
};
|
|
|
|
|
2021-03-11 14:49:43 +03:00
|
|
|
const SpaceLanding = ({ space }) => {
|
|
|
|
const cli = useContext(MatrixClientContext);
|
|
|
|
const myMembership = useMyRoomMembership(space);
|
|
|
|
const userId = cli.getUserId();
|
|
|
|
|
2021-03-02 13:07:43 +03:00
|
|
|
let inviteButton;
|
|
|
|
if (myMembership === "join" && space.canInvite(userId)) {
|
|
|
|
inviteButton = (
|
2021-03-26 16:11:57 +03:00
|
|
|
<AccessibleButton
|
|
|
|
kind="primary"
|
|
|
|
className="mx_SpaceRoomView_landing_inviteButton"
|
|
|
|
onClick={() => {
|
|
|
|
showRoomInviteDialog(space.roomId);
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{ _t("Invite") }
|
2021-03-02 13:07:43 +03:00
|
|
|
</AccessibleButton>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-03-02 16:28:05 +03:00
|
|
|
const canAddRooms = myMembership === "join" && space.currentState.maySendStateEvent(EventType.SpaceChild, userId);
|
|
|
|
|
2021-03-24 20:02:12 +03:00
|
|
|
const [refreshToken, forceUpdate] = useStateToggle(false);
|
2021-03-02 17:37:28 +03:00
|
|
|
|
2021-05-05 19:25:29 +03:00
|
|
|
let addRoomButton;
|
2021-03-02 16:28:05 +03:00
|
|
|
if (canAddRooms) {
|
2021-05-05 19:25:29 +03:00
|
|
|
addRoomButton = <SpaceLandingAddButton space={space} onNewRoomAdded={forceUpdate} />;
|
2021-03-02 16:28:05 +03:00
|
|
|
}
|
|
|
|
|
2021-03-02 13:34:28 +03:00
|
|
|
let settingsButton;
|
|
|
|
if (shouldShowSpaceSettings(cli, space)) {
|
2021-05-05 19:25:29 +03:00
|
|
|
settingsButton = <AccessibleTooltipButton
|
|
|
|
className="mx_SpaceRoomView_landing_settingsButton"
|
|
|
|
onClick={() => {
|
|
|
|
showSpaceSettings(cli, space);
|
|
|
|
}}
|
|
|
|
title={_t("Settings")}
|
|
|
|
/>;
|
2021-03-02 13:34:28 +03:00
|
|
|
}
|
|
|
|
|
2021-03-26 16:11:57 +03:00
|
|
|
const onMembersClick = () => {
|
|
|
|
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
|
|
|
action: Action.SetRightPanelPhase,
|
|
|
|
phase: RightPanelPhases.RoomMemberList,
|
|
|
|
refireParams: { space },
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2021-03-01 21:10:17 +03:00
|
|
|
return <div className="mx_SpaceRoomView_landing">
|
|
|
|
<RoomAvatar room={space} height={80} width={80} viewAvatarOnClick={true} />
|
|
|
|
<div className="mx_SpaceRoomView_landing_name">
|
|
|
|
<RoomName room={space}>
|
|
|
|
{(name) => {
|
|
|
|
const tags = { name: () => <div className="mx_SpaceRoomView_landing_nameRow">
|
|
|
|
<h1>{ name }</h1>
|
|
|
|
</div> };
|
|
|
|
return _t("Welcome to <name/>", {}, tags) as JSX.Element;
|
|
|
|
}}
|
|
|
|
</RoomName>
|
|
|
|
</div>
|
2021-03-26 16:11:57 +03:00
|
|
|
<div className="mx_SpaceRoomView_landing_info">
|
|
|
|
<SpaceInfo space={space} />
|
|
|
|
<FacePile room={space} onlyKnownUsers={false} numShown={7} onClick={onMembersClick} />
|
|
|
|
{ inviteButton }
|
2021-05-05 19:25:29 +03:00
|
|
|
{ settingsButton }
|
2021-03-26 16:11:57 +03:00
|
|
|
</div>
|
2021-03-01 21:10:17 +03:00
|
|
|
<div className="mx_SpaceRoomView_landing_topic">
|
|
|
|
<RoomTopic room={space} />
|
|
|
|
</div>
|
2021-03-26 16:46:01 +03:00
|
|
|
<hr />
|
2021-03-02 17:37:28 +03:00
|
|
|
|
2021-05-05 19:25:29 +03:00
|
|
|
<SpaceHierarchy
|
|
|
|
space={space}
|
|
|
|
showRoom={showRoom}
|
|
|
|
refreshToken={refreshToken}
|
|
|
|
additionalButtons={addRoomButton}
|
|
|
|
/>
|
2021-03-01 21:10:17 +03:00
|
|
|
</div>;
|
|
|
|
};
|
|
|
|
|
|
|
|
const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
|
|
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
const [error, setError] = useState("");
|
|
|
|
const numFields = 3;
|
|
|
|
const placeholders = [_t("General"), _t("Random"), _t("Support")];
|
|
|
|
// TODO vary default prefills for "Just Me" spaces
|
|
|
|
const [roomNames, setRoomName] = useStateArray(numFields, [_t("General"), _t("Random"), ""]);
|
|
|
|
const fields = new Array(numFields).fill(0).map((_, i) => {
|
|
|
|
const name = "roomName" + i;
|
|
|
|
return <Field
|
|
|
|
key={name}
|
|
|
|
name={name}
|
|
|
|
type="text"
|
|
|
|
label={_t("Room name")}
|
|
|
|
placeholder={placeholders[i]}
|
|
|
|
value={roomNames[i]}
|
|
|
|
onChange={ev => setRoomName(i, ev.target.value)}
|
2021-03-19 16:20:04 +03:00
|
|
|
autoFocus={i === 2}
|
2021-03-01 21:10:17 +03:00
|
|
|
/>;
|
|
|
|
});
|
|
|
|
|
2021-05-11 12:01:40 +03:00
|
|
|
const onNextClick = async (ev) => {
|
|
|
|
ev.preventDefault();
|
2021-05-10 18:06:23 +03:00
|
|
|
if (busy) return;
|
2021-03-01 21:10:17 +03:00
|
|
|
setError("");
|
|
|
|
setBusy(true);
|
|
|
|
try {
|
|
|
|
await Promise.all(roomNames.map(name => name.trim()).filter(Boolean).map(name => {
|
|
|
|
return createRoom({
|
|
|
|
createOpts: {
|
|
|
|
preset: space.getJoinRule() === "public" ? Preset.PublicChat : Preset.PrivateChat,
|
|
|
|
name,
|
|
|
|
},
|
|
|
|
spinner: false,
|
|
|
|
encryption: false,
|
|
|
|
andView: false,
|
|
|
|
inlineErrors: true,
|
|
|
|
parentSpace: space,
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
onFinished();
|
|
|
|
} catch (e) {
|
|
|
|
console.error("Failed to create initial space rooms", e);
|
|
|
|
setError(_t("Failed to create initial space rooms"));
|
|
|
|
}
|
|
|
|
setBusy(false);
|
|
|
|
};
|
|
|
|
|
2021-05-11 12:01:40 +03:00
|
|
|
let onClick = (ev) => {
|
|
|
|
ev.preventDefault();
|
|
|
|
onFinished();
|
|
|
|
};
|
2021-03-01 21:10:17 +03:00
|
|
|
let buttonLabel = _t("Skip for now");
|
|
|
|
if (roomNames.some(name => name.trim())) {
|
|
|
|
onClick = onNextClick;
|
2021-04-26 14:41:04 +03:00
|
|
|
buttonLabel = busy ? _t("Creating rooms...") : _t("Continue");
|
2021-03-01 21:10:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return <div>
|
|
|
|
<h1>{ title }</h1>
|
|
|
|
<div className="mx_SpaceRoomView_description">{ description }</div>
|
|
|
|
|
|
|
|
{ error && <div className="mx_SpaceRoomView_errorText">{ error }</div> }
|
2021-05-11 12:01:40 +03:00
|
|
|
<form onSubmit={onClick} id="mx_SpaceSetupFirstRooms">
|
|
|
|
{ fields }
|
|
|
|
</form>
|
2021-03-01 21:10:17 +03:00
|
|
|
|
|
|
|
<div className="mx_SpaceRoomView_buttons">
|
2021-03-24 16:15:31 +03:00
|
|
|
<AccessibleButton
|
|
|
|
kind="primary"
|
2021-03-01 21:10:17 +03:00
|
|
|
disabled={busy}
|
|
|
|
onClick={onClick}
|
2021-05-11 12:01:40 +03:00
|
|
|
element="input"
|
|
|
|
type="submit"
|
|
|
|
form="mx_SpaceSetupFirstRooms"
|
|
|
|
value={buttonLabel}
|
|
|
|
/>
|
2021-03-01 21:10:17 +03:00
|
|
|
</div>
|
|
|
|
</div>;
|
|
|
|
};
|
|
|
|
|
2021-04-26 14:41:04 +03:00
|
|
|
const SpaceAddExistingRooms = ({ space, onFinished }) => {
|
|
|
|
const [selectedToAdd, setSelectedToAdd] = useState(new Set<Room>());
|
|
|
|
|
|
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
const [error, setError] = useState("");
|
|
|
|
|
|
|
|
let onClick = onFinished;
|
|
|
|
let buttonLabel = _t("Skip for now");
|
|
|
|
if (selectedToAdd.size > 0) {
|
|
|
|
onClick = async () => {
|
|
|
|
setBusy(true);
|
2021-05-05 13:54:14 +03:00
|
|
|
|
|
|
|
for (const room of selectedToAdd) {
|
|
|
|
const via = calculateRoomVia(room);
|
|
|
|
try {
|
|
|
|
await SpaceStore.instance.addRoomToSpace(space, room.roomId, via).catch(async e => {
|
|
|
|
if (e.errcode === "M_LIMIT_EXCEEDED") {
|
|
|
|
await sleep(e.data.retry_after_ms);
|
|
|
|
return SpaceStore.instance.addRoomToSpace(space, room.roomId, via); // retry
|
|
|
|
}
|
|
|
|
|
|
|
|
throw e;
|
|
|
|
});
|
|
|
|
} catch (e) {
|
|
|
|
console.error("Failed to add rooms to space", e);
|
|
|
|
setError(_t("Failed to add rooms to space"));
|
|
|
|
break;
|
|
|
|
}
|
2021-04-26 14:41:04 +03:00
|
|
|
}
|
|
|
|
setBusy(false);
|
|
|
|
};
|
|
|
|
buttonLabel = busy ? _t("Adding...") : _t("Add");
|
|
|
|
}
|
|
|
|
|
|
|
|
return <div>
|
|
|
|
<h1>{ _t("What do you want to organise?") }</h1>
|
|
|
|
<div className="mx_SpaceRoomView_description">
|
|
|
|
{ _t("Pick rooms or conversations to add. This is just a space for you, " +
|
|
|
|
"no one will be informed. You can add more later.") }
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{ error && <div className="mx_SpaceRoomView_errorText">{ error }</div> }
|
|
|
|
|
|
|
|
<AddExistingToSpace
|
|
|
|
space={space}
|
|
|
|
selected={selectedToAdd}
|
|
|
|
onChange={(checked, room) => {
|
|
|
|
if (checked) {
|
|
|
|
selectedToAdd.add(room);
|
|
|
|
} else {
|
|
|
|
selectedToAdd.delete(room);
|
|
|
|
}
|
|
|
|
setSelectedToAdd(new Set(selectedToAdd));
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
|
|
|
|
<div className="mx_SpaceRoomView_buttons">
|
|
|
|
<AccessibleButton
|
|
|
|
kind="primary"
|
|
|
|
disabled={busy}
|
|
|
|
onClick={onClick}
|
|
|
|
>
|
|
|
|
{ buttonLabel }
|
|
|
|
</AccessibleButton>
|
|
|
|
</div>
|
|
|
|
</div>;
|
|
|
|
};
|
|
|
|
|
2021-05-04 12:48:34 +03:00
|
|
|
const SpaceSetupPublicShare = ({ justCreatedOpts, space, onFinished }) => {
|
2021-03-01 21:10:17 +03:00
|
|
|
return <div className="mx_SpaceRoomView_publicShare">
|
2021-05-04 12:48:34 +03:00
|
|
|
<h1>{ _t("Share %(name)s", {
|
|
|
|
name: justCreatedOpts?.createOpts?.name || space.name,
|
|
|
|
}) }</h1>
|
2021-03-24 17:02:25 +03:00
|
|
|
<div className="mx_SpaceRoomView_description">
|
2021-03-19 16:20:04 +03:00
|
|
|
{ _t("It's just you at the moment, it will be even better with others.") }
|
2021-03-16 14:39:06 +03:00
|
|
|
</div>
|
2021-03-01 21:10:17 +03:00
|
|
|
|
2021-03-24 17:19:10 +03:00
|
|
|
<SpacePublicShare space={space} />
|
2021-03-01 21:10:17 +03:00
|
|
|
|
|
|
|
<div className="mx_SpaceRoomView_buttons">
|
2021-03-24 16:15:31 +03:00
|
|
|
<AccessibleButton kind="primary" onClick={onFinished}>
|
|
|
|
{ _t("Go to my first room") }
|
|
|
|
</AccessibleButton>
|
2021-03-01 21:10:17 +03:00
|
|
|
</div>
|
|
|
|
</div>;
|
|
|
|
};
|
|
|
|
|
2021-04-29 00:47:08 +03:00
|
|
|
const SpaceSetupPrivateScope = ({ space, justCreatedOpts, onFinished }) => {
|
2021-03-01 21:10:17 +03:00
|
|
|
return <div className="mx_SpaceRoomView_privateScope">
|
|
|
|
<h1>{ _t("Who are you working with?") }</h1>
|
2021-03-19 16:20:04 +03:00
|
|
|
<div className="mx_SpaceRoomView_description">
|
2021-04-29 00:47:08 +03:00
|
|
|
{ _t("Make sure the right people have access to %(name)s", {
|
|
|
|
name: justCreatedOpts?.createOpts?.name || space.name,
|
|
|
|
}) }
|
2021-03-19 16:20:04 +03:00
|
|
|
</div>
|
2021-03-01 21:10:17 +03:00
|
|
|
|
2021-03-19 16:16:36 +03:00
|
|
|
<AccessibleButton
|
|
|
|
className="mx_SpaceRoomView_privateScope_justMeButton"
|
|
|
|
onClick={() => { onFinished(false) }}
|
|
|
|
>
|
|
|
|
<h3>{ _t("Just me") }</h3>
|
|
|
|
<div>{ _t("A private space to organise your rooms") }</div>
|
|
|
|
</AccessibleButton>
|
|
|
|
<AccessibleButton
|
|
|
|
className="mx_SpaceRoomView_privateScope_meAndMyTeammatesButton"
|
|
|
|
onClick={() => { onFinished(true) }}
|
|
|
|
>
|
|
|
|
<h3>{ _t("Me and my teammates") }</h3>
|
|
|
|
<div>{ _t("A private space for you and your teammates") }</div>
|
|
|
|
</AccessibleButton>
|
2021-03-01 21:10:17 +03:00
|
|
|
</div>;
|
|
|
|
};
|
|
|
|
|
|
|
|
const validateEmailRules = withValidation({
|
|
|
|
rules: [{
|
|
|
|
key: "email",
|
|
|
|
test: ({ value }) => !value || Email.looksValid(value),
|
|
|
|
invalid: () => _t("Doesn't look like a valid email address"),
|
|
|
|
}],
|
|
|
|
});
|
|
|
|
|
|
|
|
const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
|
|
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
const [error, setError] = useState("");
|
|
|
|
const numFields = 3;
|
|
|
|
const fieldRefs: RefObject<Field>[] = [useRef(), useRef(), useRef()];
|
|
|
|
const [emailAddresses, setEmailAddress] = useStateArray(numFields, "");
|
|
|
|
const fields = new Array(numFields).fill(0).map((_, i) => {
|
|
|
|
const name = "emailAddress" + i;
|
|
|
|
return <Field
|
|
|
|
key={name}
|
|
|
|
name={name}
|
|
|
|
type="text"
|
|
|
|
label={_t("Email address")}
|
|
|
|
placeholder={_t("Email")}
|
|
|
|
value={emailAddresses[i]}
|
|
|
|
onChange={ev => setEmailAddress(i, ev.target.value)}
|
|
|
|
ref={fieldRefs[i]}
|
|
|
|
onValidate={validateEmailRules}
|
2021-03-19 16:20:04 +03:00
|
|
|
autoFocus={i === 0}
|
2021-03-01 21:10:17 +03:00
|
|
|
/>;
|
|
|
|
});
|
|
|
|
|
2021-05-11 12:01:40 +03:00
|
|
|
const onNextClick = async (ev) => {
|
|
|
|
ev.preventDefault();
|
2021-05-10 18:06:23 +03:00
|
|
|
if (busy) return;
|
2021-03-01 21:10:17 +03:00
|
|
|
setError("");
|
|
|
|
for (let i = 0; i < fieldRefs.length; i++) {
|
|
|
|
const fieldRef = fieldRefs[i];
|
|
|
|
const valid = await fieldRef.current.validate({ allowEmpty: true });
|
|
|
|
|
|
|
|
if (valid === false) { // true/null are allowed
|
|
|
|
fieldRef.current.focus();
|
|
|
|
fieldRef.current.validate({ allowEmpty: true, focused: true });
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setBusy(true);
|
|
|
|
const targetIds = emailAddresses.map(name => name.trim()).filter(Boolean);
|
|
|
|
try {
|
|
|
|
const result = await inviteMultipleToRoom(space.roomId, targetIds);
|
|
|
|
|
|
|
|
const failedUsers = Object.keys(result.states).filter(a => result.states[a] === "error");
|
|
|
|
if (failedUsers.length > 0) {
|
|
|
|
console.log("Failed to invite users to space: ", result);
|
|
|
|
setError(_t("Failed to invite the following users to your space: %(csvUsers)s", {
|
|
|
|
csvUsers: failedUsers.join(", "),
|
|
|
|
}));
|
|
|
|
} else {
|
|
|
|
onFinished();
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.error("Failed to invite users to space: ", err);
|
|
|
|
setError(_t("We couldn't invite those users. Please check the users you want to invite and try again."));
|
|
|
|
}
|
|
|
|
setBusy(false);
|
|
|
|
};
|
|
|
|
|
2021-05-11 12:01:40 +03:00
|
|
|
let onClick = (ev) => {
|
|
|
|
ev.preventDefault();
|
|
|
|
onFinished();
|
|
|
|
};
|
2021-03-19 16:20:04 +03:00
|
|
|
let buttonLabel = _t("Skip for now");
|
|
|
|
if (emailAddresses.some(name => name.trim())) {
|
|
|
|
onClick = onNextClick;
|
|
|
|
buttonLabel = busy ? _t("Inviting...") : _t("Continue")
|
|
|
|
}
|
|
|
|
|
2021-03-01 21:10:17 +03:00
|
|
|
return <div className="mx_SpaceRoomView_inviteTeammates">
|
|
|
|
<h1>{ _t("Invite your teammates") }</h1>
|
2021-03-19 16:20:04 +03:00
|
|
|
<div className="mx_SpaceRoomView_description">
|
|
|
|
{ _t("Make sure the right people have access. You can invite more later.") }
|
|
|
|
</div>
|
2021-03-01 21:10:17 +03:00
|
|
|
|
2021-04-29 00:47:08 +03:00
|
|
|
<div className="mx_SpaceRoomView_inviteTeammates_betaDisclaimer">
|
2021-04-29 18:08:59 +03:00
|
|
|
<BetaPill onClick={onBetaClick} />
|
2021-04-29 00:47:08 +03:00
|
|
|
{ _t("<b>This is an experimental feature.</b> For now, " +
|
|
|
|
"new users receiving an invite will have to open the invite on <link/> to actually join.", {}, {
|
|
|
|
b: sub => <b>{ sub }</b>,
|
|
|
|
link: () => <a href="https://app.element.io/" rel="noreferrer noopener" target="_blank">
|
|
|
|
app.element.io
|
|
|
|
</a>,
|
|
|
|
}) }
|
|
|
|
</div>
|
|
|
|
|
2021-03-01 21:10:17 +03:00
|
|
|
{ error && <div className="mx_SpaceRoomView_errorText">{ error }</div> }
|
2021-05-11 12:01:40 +03:00
|
|
|
<form onSubmit={onClick} id="mx_SpaceSetupPrivateInvite">
|
|
|
|
{ fields }
|
|
|
|
</form>
|
2021-03-01 21:10:17 +03:00
|
|
|
|
|
|
|
<div className="mx_SpaceRoomView_inviteTeammates_buttons">
|
|
|
|
<AccessibleButton
|
|
|
|
className="mx_SpaceRoomView_inviteTeammates_inviteDialogButton"
|
2021-03-02 13:07:43 +03:00
|
|
|
onClick={() => showRoomInviteDialog(space.roomId)}
|
2021-03-01 21:10:17 +03:00
|
|
|
>
|
|
|
|
{ _t("Invite by username") }
|
|
|
|
</AccessibleButton>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div className="mx_SpaceRoomView_buttons">
|
2021-05-11 12:01:40 +03:00
|
|
|
<AccessibleButton
|
|
|
|
kind="primary"
|
|
|
|
disabled={busy}
|
|
|
|
onClick={onClick}
|
|
|
|
element="input"
|
|
|
|
type="submit"
|
|
|
|
form="mx_SpaceSetupPrivateInvite"
|
|
|
|
value={buttonLabel}
|
|
|
|
/>
|
2021-03-01 21:10:17 +03:00
|
|
|
</div>
|
|
|
|
</div>;
|
|
|
|
};
|
|
|
|
|
|
|
|
export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
|
|
|
static contextType = MatrixClientContext;
|
|
|
|
|
|
|
|
private readonly creator: string;
|
|
|
|
private readonly dispatcherRef: string;
|
|
|
|
private readonly rightPanelStoreToken: EventSubscription;
|
|
|
|
|
|
|
|
constructor(props, context) {
|
|
|
|
super(props, context);
|
|
|
|
|
|
|
|
let phase = Phase.Landing;
|
|
|
|
|
|
|
|
this.creator = this.props.space.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
|
|
|
|
const showSetup = this.props.justCreatedOpts && this.context.getUserId() === this.creator;
|
|
|
|
|
|
|
|
if (showSetup) {
|
|
|
|
phase = this.props.justCreatedOpts.createOpts.preset === Preset.PublicChat
|
|
|
|
? Phase.PublicCreateRooms : Phase.PrivateScope;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.state = {
|
|
|
|
phase,
|
|
|
|
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
|
2021-03-16 17:18:45 +03:00
|
|
|
myMembership: this.props.space.getMyMembership(),
|
2021-03-01 21:10:17 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
|
|
|
this.rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelStoreUpdate);
|
2021-03-16 17:18:45 +03:00
|
|
|
this.context.on("Room.myMembership", this.onMyMembership);
|
2021-03-01 21:10:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
defaultDispatcher.unregister(this.dispatcherRef);
|
|
|
|
this.rightPanelStoreToken.remove();
|
2021-03-16 17:18:45 +03:00
|
|
|
this.context.off("Room.myMembership", this.onMyMembership);
|
2021-03-01 21:10:17 +03:00
|
|
|
}
|
|
|
|
|
2021-03-16 17:18:45 +03:00
|
|
|
private onMyMembership = (room: Room, myMembership: string) => {
|
|
|
|
if (room.roomId === this.props.space.roomId) {
|
|
|
|
this.setState({ myMembership });
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-03-01 21:10:17 +03:00
|
|
|
private onRightPanelStoreUpdate = () => {
|
|
|
|
this.setState({
|
|
|
|
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
private onAction = (payload: ActionPayload) => {
|
|
|
|
if (payload.action !== Action.ViewUser && payload.action !== "view_3pid_invite") return;
|
|
|
|
|
|
|
|
if (payload.action === Action.ViewUser && payload.member) {
|
|
|
|
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
|
|
|
action: Action.SetRightPanelPhase,
|
|
|
|
phase: RightPanelPhases.SpaceMemberInfo,
|
|
|
|
refireParams: {
|
|
|
|
space: this.props.space,
|
|
|
|
member: payload.member,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else if (payload.action === "view_3pid_invite" && payload.event) {
|
|
|
|
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
|
|
|
action: Action.SetRightPanelPhase,
|
|
|
|
phase: RightPanelPhases.Space3pidMemberInfo,
|
|
|
|
refireParams: {
|
|
|
|
space: this.props.space,
|
|
|
|
event: payload.event,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
|
|
|
action: Action.SetRightPanelPhase,
|
|
|
|
phase: RightPanelPhases.SpaceMemberList,
|
|
|
|
refireParams: { space: this.props.space },
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-03-16 17:18:45 +03:00
|
|
|
private goToFirstRoom = async () => {
|
2021-03-24 20:02:12 +03:00
|
|
|
// TODO actually go to the first room
|
|
|
|
|
2021-03-16 17:18:45 +03:00
|
|
|
const childRooms = SpaceStore.instance.getChildRooms(this.props.space.roomId);
|
|
|
|
if (childRooms.length) {
|
|
|
|
const room = childRooms[0];
|
|
|
|
defaultDispatcher.dispatch({
|
|
|
|
action: "view_room",
|
|
|
|
room_id: room.roomId,
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let suggestedRooms = SpaceStore.instance.suggestedRooms;
|
|
|
|
if (SpaceStore.instance.activeSpace !== this.props.space) {
|
|
|
|
// the space store has the suggested rooms loaded for a different space, fetch the right ones
|
|
|
|
suggestedRooms = (await SpaceStore.instance.fetchSuggestedRooms(this.props.space, 1)).rooms;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (suggestedRooms.length) {
|
|
|
|
const room = suggestedRooms[0];
|
|
|
|
defaultDispatcher.dispatch({
|
|
|
|
action: "view_room",
|
|
|
|
room_id: room.room_id,
|
|
|
|
oobData: {
|
|
|
|
avatarUrl: room.avatar_url,
|
|
|
|
name: room.name || room.canonical_alias || room.aliases.pop() || _t("Empty room"),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setState({ phase: Phase.Landing });
|
|
|
|
};
|
|
|
|
|
2021-03-01 21:10:17 +03:00
|
|
|
private renderBody() {
|
|
|
|
switch (this.state.phase) {
|
|
|
|
case Phase.Landing:
|
2021-04-28 10:41:31 +03:00
|
|
|
if (this.state.myMembership === "join" && SettingsStore.getValue("feature_spaces")) {
|
2021-03-11 14:49:43 +03:00
|
|
|
return <SpaceLanding space={this.props.space} />;
|
|
|
|
} else {
|
|
|
|
return <SpacePreview
|
|
|
|
space={this.props.space}
|
|
|
|
onJoinButtonClicked={this.props.onJoinButtonClicked}
|
|
|
|
onRejectButtonClicked={this.props.onRejectButtonClicked}
|
|
|
|
/>;
|
|
|
|
}
|
2021-03-01 21:10:17 +03:00
|
|
|
case Phase.PublicCreateRooms:
|
|
|
|
return <SpaceSetupFirstRooms
|
|
|
|
space={this.props.space}
|
2021-03-25 16:24:16 +03:00
|
|
|
title={_t("What are some things you want to discuss in %(spaceName)s?", {
|
2021-05-04 12:48:34 +03:00
|
|
|
spaceName: this.props.justCreatedOpts?.createOpts?.name || this.props.space.name,
|
2021-03-25 16:24:16 +03:00
|
|
|
})}
|
|
|
|
description={
|
|
|
|
_t("Let's create a room for each of them.") + "\n" +
|
|
|
|
_t("You can add more later too, including already existing ones.")
|
|
|
|
}
|
2021-03-01 21:10:17 +03:00
|
|
|
onFinished={() => this.setState({ phase: Phase.PublicShare })}
|
|
|
|
/>;
|
|
|
|
case Phase.PublicShare:
|
2021-05-04 12:48:34 +03:00
|
|
|
return <SpaceSetupPublicShare
|
|
|
|
justCreatedOpts={this.props.justCreatedOpts}
|
|
|
|
space={this.props.space}
|
|
|
|
onFinished={this.goToFirstRoom}
|
|
|
|
/>;
|
2021-03-01 21:10:17 +03:00
|
|
|
|
|
|
|
case Phase.PrivateScope:
|
|
|
|
return <SpaceSetupPrivateScope
|
2021-03-19 16:20:04 +03:00
|
|
|
space={this.props.space}
|
2021-04-29 00:47:08 +03:00
|
|
|
justCreatedOpts={this.props.justCreatedOpts}
|
2021-03-01 21:10:17 +03:00
|
|
|
onFinished={(invite: boolean) => {
|
2021-04-26 14:41:04 +03:00
|
|
|
this.setState({ phase: invite ? Phase.PrivateInvite : Phase.PrivateExistingRooms });
|
2021-03-01 21:10:17 +03:00
|
|
|
}}
|
|
|
|
/>;
|
|
|
|
case Phase.PrivateInvite:
|
|
|
|
return <SpaceSetupPrivateInvite
|
|
|
|
space={this.props.space}
|
|
|
|
onFinished={() => this.setState({ phase: Phase.PrivateCreateRooms })}
|
|
|
|
/>;
|
|
|
|
case Phase.PrivateCreateRooms:
|
|
|
|
return <SpaceSetupFirstRooms
|
|
|
|
space={this.props.space}
|
|
|
|
title={_t("What projects are you working on?")}
|
2021-03-19 16:20:04 +03:00
|
|
|
description={_t("We'll create rooms for each of them. " +
|
|
|
|
"You can add more later too, including already existing ones.")}
|
2021-03-01 21:10:17 +03:00
|
|
|
onFinished={() => this.setState({ phase: Phase.Landing })}
|
|
|
|
/>;
|
2021-04-26 14:41:04 +03:00
|
|
|
case Phase.PrivateExistingRooms:
|
|
|
|
return <SpaceAddExistingRooms
|
|
|
|
space={this.props.space}
|
|
|
|
onFinished={() => this.setState({ phase: Phase.Landing })}
|
|
|
|
/>;
|
2021-03-01 21:10:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const rightPanel = this.state.showRightPanel && this.state.phase === Phase.Landing
|
|
|
|
? <RightPanel room={this.props.space} resizeNotifier={this.props.resizeNotifier} />
|
|
|
|
: null;
|
|
|
|
|
|
|
|
return <main className="mx_SpaceRoomView">
|
|
|
|
<ErrorBoundary>
|
|
|
|
<MainSplit panel={rightPanel} resizeNotifier={this.props.resizeNotifier}>
|
|
|
|
{ this.renderBody() }
|
|
|
|
</MainSplit>
|
|
|
|
</ErrorBoundary>
|
|
|
|
</main>;
|
|
|
|
}
|
|
|
|
}
|