mirror of https://github.com/vector-im/riot-web
				
				
				
			Add an invite users to community step to dialog flow
							parent
							
								
									7c1a9993e3
								
							
						
					
					
						commit
						56c7f86983
					
				| 
						 | 
				
			
			@ -72,6 +72,7 @@
 | 
			
		|||
@import "./views/dialogs/_KeyboardShortcutsDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_MessageEditHistoryDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_NewSessionReviewDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_PrototypeCommunityInviteDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_PrototypeCreateGroupDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_RoomSettingsDialog.scss";
 | 
			
		||||
@import "./views/dialogs/_RoomSettingsDialogBridges.scss";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2020 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.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
.mx_PrototypeCommunityInviteDialog {
 | 
			
		||||
    &.mx_Dialog_fixedWidth {
 | 
			
		||||
        width: 360px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .mx_Dialog_content {
 | 
			
		||||
        margin-bottom: 0;
 | 
			
		||||
 | 
			
		||||
        .mx_PrototypeCommunityInviteDialog_people {
 | 
			
		||||
            position: relative;
 | 
			
		||||
            margin-bottom: 4px;
 | 
			
		||||
 | 
			
		||||
            .mx_AccessibleButton {
 | 
			
		||||
                display: inline-block;
 | 
			
		||||
                background-color: $focus-bg-color; // XXX: Abuse of variables
 | 
			
		||||
                border-radius: 4px;
 | 
			
		||||
                padding: 3px 5px;
 | 
			
		||||
                font-size: $font-12px;
 | 
			
		||||
                float: right;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .mx_PrototypeCommunityInviteDialog_morePeople {
 | 
			
		||||
            margin-top: 8px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .mx_PrototypeCommunityInviteDialog_person {
 | 
			
		||||
            position: relative;
 | 
			
		||||
            margin-top: 4px;
 | 
			
		||||
 | 
			
		||||
            & > * {
 | 
			
		||||
                vertical-align: middle;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .mx_Checkbox {
 | 
			
		||||
                position: absolute;
 | 
			
		||||
                right: 0;
 | 
			
		||||
                top: calc(50% - 8px); // checkbox is 16px high
 | 
			
		||||
                width: 16px; // to force a square
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            .mx_PrototypeCommunityInviteDialog_personIdentifiers {
 | 
			
		||||
                display: inline-block;
 | 
			
		||||
 | 
			
		||||
                & > * {
 | 
			
		||||
                    display: block;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                .mx_PrototypeCommunityInviteDialog_personName {
 | 
			
		||||
                    font-weight: 600;
 | 
			
		||||
                    font-size: $font-14px;
 | 
			
		||||
                    color: $primary-fg-color;
 | 
			
		||||
                    margin-left: 7px;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                .mx_PrototypeCommunityInviteDialog_personId {
 | 
			
		||||
                    font-size: $font-12px;
 | 
			
		||||
                    color: $muted-fg-color;
 | 
			
		||||
                    margin-left: 7px;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .mx_PrototypeCommunityInviteDialog_primaryButton {
 | 
			
		||||
            display: block;
 | 
			
		||||
            font-size: $font-13px;
 | 
			
		||||
            line-height: 20px;
 | 
			
		||||
            height: 20px;
 | 
			
		||||
            margin-top: 24px;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ import Modal from './Modal';
 | 
			
		|||
import * as sdk from './';
 | 
			
		||||
import { _t } from './languageHandler';
 | 
			
		||||
import {KIND_DM, KIND_INVITE} from "./components/views/dialogs/InviteDialog";
 | 
			
		||||
import PrototypeCommunityInviteDialog from "./components/views/dialogs/PrototypeCommunityInviteDialog";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Invites multiple addresses to a room
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +57,13 @@ export function showRoomInviteDialog(roomId) {
 | 
			
		|||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function showCommunityRoomInviteDialog(roomId, communityName) {
 | 
			
		||||
    Modal.createTrackedDialog(
 | 
			
		||||
        'Invite Users to Community', '', PrototypeCommunityInviteDialog, {communityName, roomId},
 | 
			
		||||
        /*className=*/null, /*isPriority=*/false, /*isStatic=*/true,
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks if the given MatrixEvent is a valid 3rd party user invite.
 | 
			
		||||
 * @param {MatrixEvent} event The event to check
 | 
			
		||||
| 
						 | 
				
			
			@ -77,7 +85,7 @@ export function isValid3pidInvite(event) {
 | 
			
		|||
export function inviteUsersToRoom(roomId, userIds) {
 | 
			
		||||
    return inviteMultipleToRoom(roomId, userIds).then((result) => {
 | 
			
		||||
        const room = MatrixClientPeg.get().getRoom(roomId);
 | 
			
		||||
        return _showAnyInviteErrors(result.states, room, result.inviter);
 | 
			
		||||
        showAnyInviteErrors(result.states, room, result.inviter);
 | 
			
		||||
    }).catch((err) => {
 | 
			
		||||
        console.error(err.stack);
 | 
			
		||||
        const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +96,7 @@ export function inviteUsersToRoom(roomId, userIds) {
 | 
			
		|||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function _showAnyInviteErrors(addrs, room, inviter) {
 | 
			
		||||
export function showAnyInviteErrors(addrs, room, inviter) {
 | 
			
		||||
    // Show user any errors
 | 
			
		||||
    const failedUsers = Object.keys(addrs).filter(a => addrs[a] === 'error');
 | 
			
		||||
    if (failedUsers.length === 1 && inviter.fatal) {
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +108,7 @@ function _showAnyInviteErrors(addrs, room, inviter) {
 | 
			
		|||
            title: _t("Failed to invite users to the room:", {roomName: room.name}),
 | 
			
		||||
            description: inviter.getErrorText(failedUsers[0]),
 | 
			
		||||
        });
 | 
			
		||||
        return false;
 | 
			
		||||
    } else {
 | 
			
		||||
        const errorList = [];
 | 
			
		||||
        for (const addr of failedUsers) {
 | 
			
		||||
| 
						 | 
				
			
			@ -118,8 +127,9 @@ function _showAnyInviteErrors(addrs, room, inviter) {
 | 
			
		|||
                title: _t("Failed to invite the following users to the %(roomName)s room:", {roomName: room.name}),
 | 
			
		||||
                description,
 | 
			
		||||
            });
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return addrs;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -327,7 +327,7 @@ export default class InviteDialog extends React.PureComponent {
 | 
			
		|||
        this.state = {
 | 
			
		||||
            targets: [], // array of Member objects (see interface above)
 | 
			
		||||
            filterText: "",
 | 
			
		||||
            recents: this._buildRecents(alreadyInvited),
 | 
			
		||||
            recents: InviteDialog.buildRecents(alreadyInvited),
 | 
			
		||||
            numRecentsShown: INITIAL_ROOMS_SHOWN,
 | 
			
		||||
            suggestions: this._buildSuggestions(alreadyInvited),
 | 
			
		||||
            numSuggestionsShown: INITIAL_ROOMS_SHOWN,
 | 
			
		||||
| 
						 | 
				
			
			@ -344,7 +344,7 @@ export default class InviteDialog extends React.PureComponent {
 | 
			
		|||
        this._editorRef = createRef();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _buildRecents(excludedTargetIds: Set<string>): {userId: string, user: RoomMember, lastActive: number} {
 | 
			
		||||
    static buildRecents(excludedTargetIds: Set<string>): {userId: string, user: RoomMember, lastActive: number} {
 | 
			
		||||
        const rooms = DMRoomMap.shared().getUniqueRoomsWithIndividuals(); // map of userId => js-sdk Room
 | 
			
		||||
 | 
			
		||||
        // Also pull in all the rooms tagged as DefaultTagID.DM so we don't miss anything. Sometimes the
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,252 @@
 | 
			
		|||
/*
 | 
			
		||||
Copyright 2020 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 React, { ChangeEvent, FormEvent } from 'react';
 | 
			
		||||
import BaseDialog from "./BaseDialog";
 | 
			
		||||
import { _t } from "../../../languageHandler";
 | 
			
		||||
import { IDialogProps } from "./IDialogProps";
 | 
			
		||||
import Field from "../elements/Field";
 | 
			
		||||
import AccessibleButton from "../elements/AccessibleButton";
 | 
			
		||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import InfoTooltip from "../elements/InfoTooltip";
 | 
			
		||||
import dis from "../../../dispatcher/dispatcher";
 | 
			
		||||
import {showCommunityRoomInviteDialog} from "../../../RoomInvite";
 | 
			
		||||
import { arrayFastClone } from "../../../utils/arrays";
 | 
			
		||||
import SdkConfig from "../../../SdkConfig";
 | 
			
		||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
 | 
			
		||||
import InviteDialog from "./InviteDialog";
 | 
			
		||||
import BaseAvatar from "../avatars/BaseAvatar";
 | 
			
		||||
import {getHttpUriForMxc} from "matrix-js-sdk/src/content-repo";
 | 
			
		||||
import {inviteMultipleToRoom, showAnyInviteErrors} from "../../../RoomInvite";
 | 
			
		||||
import {humanizeTime} from "../../../utils/humanize";
 | 
			
		||||
import StyledCheckbox from "../elements/StyledCheckbox";
 | 
			
		||||
import Modal from "../../../Modal";
 | 
			
		||||
import ErrorDialog from "./ErrorDialog";
 | 
			
		||||
 | 
			
		||||
interface IProps extends IDialogProps {
 | 
			
		||||
    roomId: string;
 | 
			
		||||
    communityName: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IPerson {
 | 
			
		||||
    userId: string;
 | 
			
		||||
    user: RoomMember;
 | 
			
		||||
    lastActive: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IState {
 | 
			
		||||
    emailTargets: string[];
 | 
			
		||||
    userTargets: string[];
 | 
			
		||||
    showPeople: boolean;
 | 
			
		||||
    people: IPerson[];
 | 
			
		||||
    numPeople: number;
 | 
			
		||||
    busy: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class PrototypeCommunityInviteDialog extends React.PureComponent<IProps, IState> {
 | 
			
		||||
    constructor(props: IProps) {
 | 
			
		||||
        super(props);
 | 
			
		||||
 | 
			
		||||
        this.state = {
 | 
			
		||||
            emailTargets: [],
 | 
			
		||||
            userTargets: [],
 | 
			
		||||
            showPeople: false,
 | 
			
		||||
            people: this.buildSuggestions(),
 | 
			
		||||
            numPeople: 5, // arbitrary default
 | 
			
		||||
            busy: false,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private buildSuggestions(): IPerson[] {
 | 
			
		||||
        const alreadyInvited = new Set([MatrixClientPeg.get().getUserId(), SdkConfig.get()['welcomeUserId']]);
 | 
			
		||||
        if (this.props.roomId) {
 | 
			
		||||
            const room = MatrixClientPeg.get().getRoom(this.props.roomId);
 | 
			
		||||
            if (!room) throw new Error("Room ID given to InviteDialog does not look like a room");
 | 
			
		||||
            room.getMembersWithMembership('invite').forEach(m => alreadyInvited.add(m.userId));
 | 
			
		||||
            room.getMembersWithMembership('join').forEach(m => alreadyInvited.add(m.userId));
 | 
			
		||||
            // add banned users, so we don't try to invite them
 | 
			
		||||
            room.getMembersWithMembership('ban').forEach(m => alreadyInvited.add(m.userId));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return InviteDialog.buildRecents(alreadyInvited);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onSubmit = async (ev: FormEvent) => {
 | 
			
		||||
        ev.preventDefault();
 | 
			
		||||
        ev.stopPropagation();
 | 
			
		||||
 | 
			
		||||
        this.setState({busy: true});
 | 
			
		||||
        try {
 | 
			
		||||
            const targets = [...this.state.emailTargets, ...this.state.userTargets];
 | 
			
		||||
            const result = await inviteMultipleToRoom(this.props.roomId, targets);
 | 
			
		||||
            const room = MatrixClientPeg.get().getRoom(this.props.roomId);
 | 
			
		||||
            const success = showAnyInviteErrors(result.states, room, result.inviter);
 | 
			
		||||
            if (success) {
 | 
			
		||||
                this.props.onFinished(true);
 | 
			
		||||
            } else {
 | 
			
		||||
                this.setState({busy: false});
 | 
			
		||||
            }
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            this.setState({busy: false});
 | 
			
		||||
            console.error(e);
 | 
			
		||||
            Modal.createTrackedDialog('Failed to invite', '', ErrorDialog, {
 | 
			
		||||
                title: _t("Failed to invite"),
 | 
			
		||||
                description: ((e && e.message) ? e.message : _t("Operation failed")),
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onAddressChange = (ev: ChangeEvent<HTMLInputElement>, index: number) => {
 | 
			
		||||
        const targets = arrayFastClone(this.state.emailTargets);
 | 
			
		||||
        if (index >= targets.length) {
 | 
			
		||||
            targets.push(ev.target.value);
 | 
			
		||||
        } else {
 | 
			
		||||
            targets[index] = ev.target.value;
 | 
			
		||||
        }
 | 
			
		||||
        this.setState({emailTargets: targets});
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onAddressBlur = (index: number) => {
 | 
			
		||||
        const targets = arrayFastClone(this.state.emailTargets);
 | 
			
		||||
        if (index >= targets.length) return; // not important
 | 
			
		||||
        if (targets[index].trim() === "") {
 | 
			
		||||
            targets.splice(index, 1);
 | 
			
		||||
            this.setState({emailTargets: targets});
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private onShowPeopleClick = () => {
 | 
			
		||||
        this.setState({showPeople: !this.state.showPeople});
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private setPersonToggle = (person: IPerson, selected: boolean) => {
 | 
			
		||||
        const targets = arrayFastClone(this.state.userTargets);
 | 
			
		||||
        if (selected && !targets.includes(person.userId)) {
 | 
			
		||||
            targets.push(person.userId);
 | 
			
		||||
        } else if (!selected && targets.includes(person.userId)) {
 | 
			
		||||
            targets.splice(targets.indexOf(person.userId), 1);
 | 
			
		||||
        }
 | 
			
		||||
        this.setState({userTargets: targets});
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    private renderPerson(person: IPerson, key: any) {
 | 
			
		||||
        const avatarSize = 36;
 | 
			
		||||
        return (
 | 
			
		||||
            <div className="mx_PrototypeCommunityInviteDialog_person" key={key}>
 | 
			
		||||
                <BaseAvatar
 | 
			
		||||
                    url={getHttpUriForMxc(
 | 
			
		||||
                        MatrixClientPeg.get().getHomeserverUrl(), person.user.getMxcAvatarUrl(),
 | 
			
		||||
                        avatarSize, avatarSize, "crop")}
 | 
			
		||||
                    name={person.user.name}
 | 
			
		||||
                    idName={person.user.userId}
 | 
			
		||||
                    width={avatarSize}
 | 
			
		||||
                    height={avatarSize}
 | 
			
		||||
                />
 | 
			
		||||
                <div className="mx_PrototypeCommunityInviteDialog_personIdentifiers">
 | 
			
		||||
                    <span className="mx_PrototypeCommunityInviteDialog_personName">{person.user.name}</span>
 | 
			
		||||
                    <span className="mx_PrototypeCommunityInviteDialog_personId">{person.userId}</span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <StyledCheckbox onChange={(e) => this.setPersonToggle(person, e.target.checked)} />
 | 
			
		||||
            </div>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private onShowMorePeople = () => {
 | 
			
		||||
        this.setState({numPeople: this.state.numPeople + 5}); // arbitrary increase
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    public render() {
 | 
			
		||||
        const emailAddresses = [];
 | 
			
		||||
        this.state.emailTargets.forEach((address, i) => {
 | 
			
		||||
            emailAddresses.push(
 | 
			
		||||
                <Field
 | 
			
		||||
                    key={i}
 | 
			
		||||
                    value={address}
 | 
			
		||||
                    onChange={(e) => this.onAddressChange(e, i)}
 | 
			
		||||
                    label={_t("Email address")}
 | 
			
		||||
                    placeholder={_t("Email address")}
 | 
			
		||||
                    onBlur={() => this.onAddressBlur(i)}
 | 
			
		||||
                />
 | 
			
		||||
            );
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Push a clean input
 | 
			
		||||
        emailAddresses.push(
 | 
			
		||||
            <Field
 | 
			
		||||
                key={emailAddresses.length}
 | 
			
		||||
                value={""}
 | 
			
		||||
                onChange={(e) => this.onAddressChange(e, emailAddresses.length)}
 | 
			
		||||
                label={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
 | 
			
		||||
                placeholder={emailAddresses.length > 0 ? _t("Add another email") : _t("Email address")}
 | 
			
		||||
            />
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let peopleIntro = null;
 | 
			
		||||
        let people = [];
 | 
			
		||||
        if (this.state.showPeople) {
 | 
			
		||||
            const humansToPresent = this.state.people.slice(0, this.state.numPeople);
 | 
			
		||||
            humansToPresent.forEach((person, i) => {
 | 
			
		||||
                people.push(this.renderPerson(person, i));
 | 
			
		||||
            });
 | 
			
		||||
            if (humansToPresent.length < this.state.people.length) {
 | 
			
		||||
                people.push(
 | 
			
		||||
                    <AccessibleButton
 | 
			
		||||
                        onClick={this.onShowMorePeople}
 | 
			
		||||
                        kind="link" key="more"
 | 
			
		||||
                        className="mx_PrototypeCommunityInviteDialog_morePeople"
 | 
			
		||||
                    >{_t("Show more")}</AccessibleButton>
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (this.state.people.length > 0) {
 | 
			
		||||
            peopleIntro = (
 | 
			
		||||
                <div className="mx_PrototypeCommunityInviteDialog_people">
 | 
			
		||||
                    <span>{_t("People you know on %(brand)s", {brand: SdkConfig.get().brand})}</span>
 | 
			
		||||
                    <AccessibleButton onClick={this.onShowPeopleClick}>
 | 
			
		||||
                        {this.state.showPeople ? _t("Hide") : _t("Show")}
 | 
			
		||||
                    </AccessibleButton>
 | 
			
		||||
                </div>
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let buttonText = _t("Skip");
 | 
			
		||||
        const targetCount = this.state.userTargets.length + this.state.emailTargets.length;
 | 
			
		||||
        if (targetCount > 0) {
 | 
			
		||||
            buttonText = _t("Send %(count)s invites", {count: targetCount});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <BaseDialog
 | 
			
		||||
                className="mx_PrototypeCommunityInviteDialog"
 | 
			
		||||
                onFinished={this.props.onFinished}
 | 
			
		||||
                title={_t("Invite people to join %(communityName)s", {communityName: this.props.communityName})}
 | 
			
		||||
            >
 | 
			
		||||
                <form onSubmit={this.onSubmit}>
 | 
			
		||||
                    <div className="mx_Dialog_content">
 | 
			
		||||
                        {emailAddresses}
 | 
			
		||||
                        {peopleIntro}
 | 
			
		||||
                        {people}
 | 
			
		||||
                        <AccessibleButton
 | 
			
		||||
                            kind="primary" onClick={this.onSubmit}
 | 
			
		||||
                            disabled={this.state.busy}
 | 
			
		||||
                            className="mx_PrototypeCommunityInviteDialog_primaryButton"
 | 
			
		||||
                        >{buttonText}</AccessibleButton>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
            </BaseDialog>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +23,7 @@ import AccessibleButton from "../elements/AccessibleButton";
 | 
			
		|||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
 | 
			
		||||
import InfoTooltip from "../elements/InfoTooltip";
 | 
			
		||||
import dis from "../../../dispatcher/dispatcher";
 | 
			
		||||
import {showCommunityRoomInviteDialog} from "../../../RoomInvite";
 | 
			
		||||
 | 
			
		||||
interface IProps extends IDialogProps {
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +68,7 @@ export default class PrototypeCreateGroupDialog extends React.PureComponent<IPro
 | 
			
		|||
        // the background for the user to look at while they invite people.
 | 
			
		||||
        this.setState({busy: true});
 | 
			
		||||
        try {
 | 
			
		||||
            let avatarUrl = null;
 | 
			
		||||
            let avatarUrl = ''; // must be a string for synapse to accept it
 | 
			
		||||
            if (this.state.avatarFile) {
 | 
			
		||||
                avatarUrl = await MatrixClientPeg.get().uploadContent(this.state.avatarFile);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -87,11 +88,15 @@ export default class PrototypeCreateGroupDialog extends React.PureComponent<IPro
 | 
			
		|||
                tag: result.group_id,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            // Close our own dialog before moving much further
 | 
			
		||||
            this.props.onFinished(true);
 | 
			
		||||
 | 
			
		||||
            if (result.room_id) {
 | 
			
		||||
                dis.dispatch({
 | 
			
		||||
                    action: 'view_room',
 | 
			
		||||
                    room_id: result.room_id,
 | 
			
		||||
                });
 | 
			
		||||
                showCommunityRoomInviteDialog(result.room_id, this.state.name);
 | 
			
		||||
            } else {
 | 
			
		||||
                dis.dispatch({
 | 
			
		||||
                    action: 'view_group',
 | 
			
		||||
| 
						 | 
				
			
			@ -99,8 +104,6 @@ export default class PrototypeCreateGroupDialog extends React.PureComponent<IPro
 | 
			
		|||
                    group_is_new: true,
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // TODO: Show invite dialog
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            console.error(e);
 | 
			
		||||
            this.setState({
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1729,6 +1729,15 @@
 | 
			
		|||
    "Use this session to verify your new one, granting it access to encrypted messages:": "Use this session to verify your new one, granting it access to encrypted messages:",
 | 
			
		||||
    "If you didn’t sign in to this session, your account may be compromised.": "If you didn’t sign in to this session, your account may be compromised.",
 | 
			
		||||
    "This wasn't me": "This wasn't me",
 | 
			
		||||
    "Email address": "Email address",
 | 
			
		||||
    "Add another email": "Add another email",
 | 
			
		||||
    "People you know on %(brand)s": "People you know on %(brand)s",
 | 
			
		||||
    "Hide": "Hide",
 | 
			
		||||
    "Show": "Show",
 | 
			
		||||
    "Skip": "Skip",
 | 
			
		||||
    "Send %(count)s invites|other": "Send %(count)s invites",
 | 
			
		||||
    "Send %(count)s invites|one": "Send %(count)s invite",
 | 
			
		||||
    "Invite people to join %(communityName)s": "Invite people to join %(communityName)s",
 | 
			
		||||
    "There was an error creating your community. The name may be taken or the server is unable to process your request.": "There was an error creating your community. The name may be taken or the server is unable to process your request.",
 | 
			
		||||
    "Community ID: +<localpart />:%(domain)s": "Community ID: +<localpart />:%(domain)s",
 | 
			
		||||
    "Use this when referencing your community to others. The community ID cannot be changed.": "Use this when referencing your community to others. The community ID cannot be changed.",
 | 
			
		||||
| 
						 | 
				
			
			@ -1783,9 +1792,7 @@
 | 
			
		|||
    "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.": "Clearing your browser's storage may fix the problem, but will sign you out and cause any encrypted chat history to become unreadable.",
 | 
			
		||||
    "Verification Pending": "Verification Pending",
 | 
			
		||||
    "Please check your email and click on the link it contains. Once this is done, click continue.": "Please check your email and click on the link it contains. Once this is done, click continue.",
 | 
			
		||||
    "Email address": "Email address",
 | 
			
		||||
    "This will allow you to reset your password and receive notifications.": "This will allow you to reset your password and receive notifications.",
 | 
			
		||||
    "Skip": "Skip",
 | 
			
		||||
    "A username can only contain lower case letters, numbers and '=_-./'": "A username can only contain lower case letters, numbers and '=_-./'",
 | 
			
		||||
    "Username not available": "Username not available",
 | 
			
		||||
    "Username invalid: %(errMessage)s": "Username invalid: %(errMessage)s",
 | 
			
		||||
| 
						 | 
				
			
			@ -1898,7 +1905,6 @@
 | 
			
		|||
    "Set status": "Set status",
 | 
			
		||||
    "Set a new status...": "Set a new status...",
 | 
			
		||||
    "View Community": "View Community",
 | 
			
		||||
    "Hide": "Hide",
 | 
			
		||||
    "Reload": "Reload",
 | 
			
		||||
    "Take picture": "Take picture",
 | 
			
		||||
    "Remove for everyone": "Remove for everyone",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue