Iterate space creation and previews

pull/21833/head
Michael Telatynski 2021-03-16 14:18:45 +00:00
parent 90d87122bc
commit c6f6d24b32
3 changed files with 100 additions and 23 deletions

View File

@ -17,6 +17,7 @@ limitations under the License.
import React, {RefObject, useContext, useRef, useState} from "react"; import React, {RefObject, useContext, useRef, useState} from "react";
import {EventType, RoomType} from "matrix-js-sdk/src/@types/event"; import {EventType, RoomType} from "matrix-js-sdk/src/@types/event";
import {Room} from "matrix-js-sdk/src/models/room"; import {Room} from "matrix-js-sdk/src/models/room";
import {EventSubscription} from "fbemitter";
import MatrixClientContext from "../../contexts/MatrixClientContext"; import MatrixClientContext from "../../contexts/MatrixClientContext";
import RoomAvatar from "../views/avatars/RoomAvatar"; import RoomAvatar from "../views/avatars/RoomAvatar";
@ -42,7 +43,6 @@ import ErrorBoundary from "../views/elements/ErrorBoundary";
import {ActionPayload} from "../../dispatcher/payloads"; import {ActionPayload} from "../../dispatcher/payloads";
import RightPanel from "./RightPanel"; import RightPanel from "./RightPanel";
import RightPanelStore from "../../stores/RightPanelStore"; import RightPanelStore from "../../stores/RightPanelStore";
import {EventSubscription} from "fbemitter";
import {RightPanelPhases} from "../../stores/RightPanelStorePhases"; import {RightPanelPhases} from "../../stores/RightPanelStorePhases";
import {SetRightPanelPhasePayload} from "../../dispatcher/payloads/SetRightPanelPhasePayload"; import {SetRightPanelPhasePayload} from "../../dispatcher/payloads/SetRightPanelPhasePayload";
import {useStateArray} from "../../hooks/useStateArray"; import {useStateArray} from "../../hooks/useStateArray";
@ -54,6 +54,7 @@ import {EnhancedMap} from "../../utils/maps";
import AutoHideScrollbar from "./AutoHideScrollbar"; import AutoHideScrollbar from "./AutoHideScrollbar";
import MemberAvatar from "../views/avatars/MemberAvatar"; import MemberAvatar from "../views/avatars/MemberAvatar";
import {useStateToggle} from "../../hooks/useStateToggle"; import {useStateToggle} from "../../hooks/useStateToggle";
import SpaceStore from "../../stores/SpaceStore";
interface IProps { interface IProps {
space: Room; space: Room;
@ -66,6 +67,7 @@ interface IProps {
interface IState { interface IState {
phase: Phase; phase: Phase;
showRightPanel: boolean; showRightPanel: boolean;
myMembership: string;
} }
enum Phase { enum Phase {
@ -98,6 +100,8 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const myMembership = useMyRoomMembership(space); const myMembership = useMyRoomMembership(space);
const [busy, setBusy] = useState(false);
let inviterSection; let inviterSection;
let joinButtons; let joinButtons;
if (myMembership === "invite") { if (myMembership === "invite") {
@ -121,11 +125,35 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) =>
} }
joinButtons = <> joinButtons = <>
<FormButton label={_t("Reject")} kind="secondary" onClick={onRejectButtonClicked} /> <FormButton
<FormButton label={_t("Accept")} onClick={onJoinButtonClicked} /> label={_t("Reject")}
kind="secondary"
onClick={() => {
setBusy(true);
onRejectButtonClicked();
}} />
<FormButton
label={_t("Accept")}
onClick={() => {
setBusy(true);
onJoinButtonClicked();
}}
/>
</>; </>;
} else { } else {
joinButtons = <FormButton label={_t("Join")} onClick={onJoinButtonClicked} /> joinButtons = (
<FormButton
label={_t("Join")}
onClick={() => {
setBusy(true);
onJoinButtonClicked();
}}
/>
)
}
if (busy) {
joinButtons = <InlineSpinner />;
} }
let visibilitySection; let visibilitySection;
@ -403,7 +431,7 @@ const SpaceSetupPublicShare = ({ space, onFinished }) => {
<SpacePublicShare space={space} onFinished={onFinished} /> <SpacePublicShare space={space} onFinished={onFinished} />
<div className="mx_SpaceRoomView_buttons"> <div className="mx_SpaceRoomView_buttons">
<FormButton label={_t("Finish")} onClick={onFinished} /> <FormButton label={_t("Go to my first room")} onClick={onFinished} />
</div> </div>
</div>; </div>;
}; };
@ -553,17 +581,26 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
this.state = { this.state = {
phase, phase,
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom, showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
myMembership: this.props.space.getMyMembership(),
}; };
this.dispatcherRef = defaultDispatcher.register(this.onAction); this.dispatcherRef = defaultDispatcher.register(this.onAction);
this.rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelStoreUpdate); this.rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelStoreUpdate);
this.context.on("Room.myMembership", this.onMyMembership);
} }
componentWillUnmount() { componentWillUnmount() {
defaultDispatcher.unregister(this.dispatcherRef); defaultDispatcher.unregister(this.dispatcherRef);
this.rightPanelStoreToken.remove(); this.rightPanelStoreToken.remove();
this.context.off("Room.myMembership", this.onMyMembership);
} }
private onMyMembership = (room: Room, myMembership: string) => {
if (room.roomId === this.props.space.roomId) {
this.setState({ myMembership });
}
};
private onRightPanelStoreUpdate = () => { private onRightPanelStoreUpdate = () => {
this.setState({ this.setState({
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom, showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
@ -600,10 +637,43 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
} }
}; };
private goToFirstRoom = async () => {
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 });
};
private renderBody() { private renderBody() {
switch (this.state.phase) { switch (this.state.phase) {
case Phase.Landing: case Phase.Landing:
if (this.props.space.getMyMembership() === "join") { if (this.state.myMembership === "join") {
return <SpaceLanding space={this.props.space} />; return <SpaceLanding space={this.props.space} />;
} else { } else {
return <SpacePreview return <SpacePreview
@ -620,10 +690,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
onFinished={() => this.setState({ phase: Phase.PublicShare })} onFinished={() => this.setState({ phase: Phase.PublicShare })}
/>; />;
case Phase.PublicShare: case Phase.PublicShare:
return <SpaceSetupPublicShare return <SpaceSetupPublicShare space={this.props.space} onFinished={this.goToFirstRoom} />;
space={this.props.space}
onFinished={() => this.setState({ phase: Phase.Landing })}
/>;
case Phase.PrivateScope: case Phase.PrivateScope:
return <SpaceSetupPrivateScope return <SpaceSetupPrivateScope

View File

@ -2631,6 +2631,7 @@
"Creating rooms...": "Creating rooms...", "Creating rooms...": "Creating rooms...",
"It's just you at the moment.": "It's just you at the moment.", "It's just you at the moment.": "It's just you at the moment.",
"%(spaceName)s will be even better with others": "%(spaceName)s will be even better with others", "%(spaceName)s will be even better with others": "%(spaceName)s will be even better with others",
"Go to my first room": "Go to my first room",
"Who are you working with?": "Who are you working with?", "Who are you working with?": "Who are you working with?",
"Ensure the right people have access to the space.": "Ensure the right people have access to the space.", "Ensure the right people have access to the space.": "Ensure the right people have access to the space.",
"Just Me": "Just Me", "Just Me": "Just Me",

View File

@ -118,23 +118,32 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
} }
if (space) { if (space) {
try { const data = await this.fetchSuggestedRooms(space);
const data: { if (this._activeSpace === space) {
rooms: ISpaceSummaryRoom[]; this._suggestedRooms = data.rooms.filter(roomInfo => {
events: ISpaceSummaryEvent[]; return roomInfo.room_type !== RoomType.Space && !this.matrixClient.getRoom(roomInfo.room_id);
} = await this.matrixClient.getSpaceSummary(space.roomId, 0, true, false, MAX_SUGGESTED_ROOMS); });
if (this._activeSpace === space) { this.emit(SUGGESTED_ROOMS, this._suggestedRooms);
this._suggestedRooms = data.rooms.filter(roomInfo => {
return roomInfo.room_type !== RoomType.Space && !this.matrixClient.getRoom(roomInfo.room_id);
});
this.emit(SUGGESTED_ROOMS, this._suggestedRooms);
}
} catch (e) {
console.error(e);
} }
} }
} }
public fetchSuggestedRooms = async (space: Room, limit = MAX_SUGGESTED_ROOMS) => {
try {
const data: {
rooms: ISpaceSummaryRoom[];
events: ISpaceSummaryEvent[];
} = await this.matrixClient.getSpaceSummary(space.roomId, 0, true, false, limit);
return data;
} catch (e) {
console.error(e);
}
return {
rooms: [],
events: [],
};
};
public addRoomToSpace(space: Room, roomId: string, via: string[], suggested = false, autoJoin = false) { public addRoomToSpace(space: Room, roomId: string, via: string[], suggested = false, autoJoin = false) {
return this.matrixClient.sendStateEvent(space.roomId, EventType.SpaceChild, { return this.matrixClient.sendStateEvent(space.roomId, EventType.SpaceChild, {
via, via,