Skip to content

Commit

Permalink
Merge pull request #1135 from vector-im/invite/implement-invite-ui
Browse files Browse the repository at this point in the history
Invite - PR [2/2] - Add UI for inviting users to room
  • Loading branch information
MidhunSureshR authored Sep 4, 2023
2 parents 0cad1e5 + 20cc5b5 commit 20106ca
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 7 deletions.
5 changes: 3 additions & 2 deletions src/domain/navigation/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export type SegmentType = {
"details": true;
"members": true;
"member": string;
"invite": true;
"device-verification": string | boolean;
"verification": string | boolean;
"join-room": true;
Expand Down Expand Up @@ -61,7 +62,7 @@ function allowsChild(parent: Segment<SegmentType> | undefined, child: Segment<Se
case "room":
return type === "lightbox" || type === "right-panel";
case "right-panel":
return type === "details"|| type === "members" || type === "member" || type === "verification";
return type === "details"|| type === "members" || type === "member" || type === "verification" || type === "invite";
case "logout":
return type === "forced";
default:
Expand Down Expand Up @@ -177,7 +178,7 @@ export function parseUrlPath(urlPath: string, currentNavPath: Path<SegmentType>,
if (sessionSegment) {
segments.push(sessionSegment);
}
} else if (type === "details" || type === "members" || type === "verification") {
} else if (type === "details" || type === "members" || type === "verification" || type === "invite") {
pushRightPanelSegment(segments, type);
} else if (type === "member") {
let userId = iterator.next().value;
Expand Down
54 changes: 54 additions & 0 deletions src/domain/session/rightpanel/InvitePanelViewModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
Copyright 2023 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.
*/

import {ErrorReportViewModel} from "../../ErrorReportViewModel";
import type {Options as BaseOptions} from "../../ViewModel";
import type {SegmentType} from "../../navigation";
import type {Room} from "../../../matrix/room/Room.js";
import type {Session} from "../../../matrix/Session.js";

type Options = { room: Room, session: Session } & BaseOptions;

export class InvitePanelViewModel extends ErrorReportViewModel<SegmentType, Options> {
constructor(options: Options) {
super(options);
}

get type() {
return "invite";
}

get shouldShowBackButton() {
return true;
}

get previousSegmentName() {
return "members";
}

get roomName() {
return this.getOption("room").name;
}

async invite(userId: string) {
await this.logAndCatch("InvitePanelViewModel.invite", async () => {
const room = this.getOption("room");
await room.inviteUser(userId);
const path = this.navigation.path.until("room");
this.navigation.applyPath(path);
});
}
}
7 changes: 7 additions & 0 deletions src/domain/session/rightpanel/MemberListViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,11 @@ export class MemberListViewModel extends ViewModel {
return members.mapValues(mapper, updater);
}

openInvitePanel() {
let path = this.navigation.path.until("room");
path = path.with(this.navigation.segment("right-panel", true));
path = path.with(this.navigation.segment("invite", true));
this.navigation.applyPath(path);
}

}
2 changes: 2 additions & 0 deletions src/domain/session/rightpanel/RightPanelViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {ViewModel} from "../../ViewModel";
import {RoomDetailsViewModel} from "./RoomDetailsViewModel.js";
import {MemberListViewModel} from "./MemberListViewModel.js";
import {MemberDetailsViewModel} from "./MemberDetailsViewModel.js";
import {InvitePanelViewModel} from "./InvitePanelViewModel";
import {DeviceVerificationViewModel} from "../verification/DeviceVerificationViewModel";

export class RightPanelViewModel extends ViewModel {
Expand Down Expand Up @@ -61,6 +62,7 @@ export class RightPanelViewModel extends ViewModel {

_setupNavigation() {
this._hookUpdaterToSegment("details", RoomDetailsViewModel, () => { return {room: this._room}; });
this._hookUpdaterToSegment("invite", InvitePanelViewModel, () => { return {room: this._room}; });
this._hookUpdaterToSegment("members", MemberListViewModel, () => this._getMemberListArguments());
this._hookUpdaterToSegment("member", MemberDetailsViewModel, () => this._getMemberDetailsArguments(),
() => {
Expand Down
2 changes: 2 additions & 0 deletions src/platform/web/ui/css/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ the layout viewport up without resizing it when the keyboard shows */

.LazyListParent {
flex: 1;
flex-basis: 0;
margin-top: 15px;
}

.LoadingView {
Expand Down
70 changes: 69 additions & 1 deletion src/platform/web/ui/css/themes/element/theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,54 @@ button.link {

/* Right Panel */

.InvitePanelView {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.InvitePanelView__form {
margin-top: 8px;
}

.InvitePanelView__input {
font-family: "Inter";
font-size: 1.3rem;
font-weight: 500;
line-height: 1.573rem;
outline: none;
border: none;
background-color: var(--icon-background);
color: var(--text-color);
height: 32px;
box-sizing: border-box;
margin: 5px;
border-radius: 16px;
padding: 15px;
width: 90%;
}

.InvitePanelView__form,
.InvitePanelView__btn {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}

.InvitePanelView__btn {
width: 100px;
height: 30px;
margin-top: 8px;
}

.InvitePanelView__heading {
width: 90%;
text-align: center;
margin: 0;
}

.RightPanelView {
background: var(--background-color-secondary);
}
Expand Down Expand Up @@ -1123,12 +1171,32 @@ button.RoomDetailsView_row::after {

/* Memberlist Panel */

.MemberListView {
.MemberListView__list {
padding-left: 16px;
padding-right: 16px;
margin: 0;
}

.MemberListView {
display: flex;
flex-direction: column;
height: 100%;
}

.MemberListView__invite-container {
display: flex;
justify-content: center;
align-items: center;
}

.MemberListView__invite-btn {
width: 80%;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
}

.MemberTileView {
margin-bottom: 8px;
list-style: none;
Expand Down
50 changes: 50 additions & 0 deletions src/platform/web/ui/session/rightpanel/InvitePanelView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
Copyright 2023 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.
*/

import {Builder, TemplateView} from "../../general/TemplateView";
import {ErrorView} from "../../general/ErrorView";
import type {InvitePanelViewModel} from "../../../../../domain/session/rightpanel/InvitePanelViewModel";

export class InvitePanelView extends TemplateView<InvitePanelViewModel> {
render(t: Builder<InvitePanelViewModel>, vm: InvitePanelViewModel) {
const input = t.input({
className: "InvitePanelView__input",
type: "text",
placeholder: "Enter user-id of user",
onkeydown: (e: KeyboardEvent) => {
if (e.key === "Enter") {
vm.invite((input as HTMLInputElement).value);
}
}
});
return t.div({ className: "InvitePanelView" }, [
t.h3({ className: "InvitePanelView__heading" },
(vm: InvitePanelViewModel) => vm.i18n`Invite to ${vm.roomName}`
),
t.div({ className: "InvitePanelView__form" }, [
input,
t.button({
className: "InvitePanelView__btn button-action primary",
onClick: () => vm.invite((input as HTMLInputElement).value),
}, "Invite"),
]),
t.div({ className: "InvitePanelView__error" }, [
t.ifView(vm => !!vm.errorViewModel, vm => new ErrorView(vm.errorViewModel!)),
]),
]);
}

}
21 changes: 17 additions & 4 deletions src/platform/web/ui/session/rightpanel/MemberListView.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,26 @@ limitations under the License.

import {LazyListView} from "../../general/LazyListView";
import {MemberTileView} from "./MemberTileView.js";
import {TemplateView} from "../../general/TemplateView";

export class MemberListView extends LazyListView {
constructor(vm) {
super({
export class MemberListView extends TemplateView {
render(t, vm) {
const list = new LazyListView({
list: vm.memberTileViewModels,
className: "MemberListView",
className: "MemberListView__list",
itemHeight: 40
}, tileViewModel => new MemberTileView(tileViewModel));
return t.div({ className: "MemberListView" }, [
t.div({ className: "MemberListView__invite-container" }, [
t.button(
{
className: "MemberListView__invite-btn button-action primary",
onClick: () => vm.openInvitePanel(),
},
vm.i18n`Invite to this room`
),
]),
t.view(list),
]);
}
}
3 changes: 3 additions & 0 deletions src/platform/web/ui/session/rightpanel/RightPanelView.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {MemberListView} from "./MemberListView.js";
import {LoadingView} from "../../general/LoadingView.js";
import {MemberDetailsView} from "./MemberDetailsView.js";
import {DeviceVerificationView} from "../verification/DeviceVerificationView";
import {InvitePanelView} from "./InvitePanelView";

export class RightPanelView extends TemplateView {
render(t) {
Expand All @@ -40,6 +41,8 @@ export class RightPanelView extends TemplateView {
return new MemberListView(vm);
case "member-details":
return new MemberDetailsView(vm);
case "invite":
return new InvitePanelView(vm);
case "verification":
return new DeviceVerificationView(vm);
default:
Expand Down

0 comments on commit 20106ca

Please sign in to comment.