mirror of https://github.com/vector-im/riot-web
Merge pull request #6838 from SimonBrandner/task/room_settings-ts
commit
e4e696f409
|
@ -15,27 +15,43 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { createRef } from 'react';
|
import React, { createRef } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import Field from "../elements/Field";
|
import Field from "../elements/Field";
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { mediaFromMxc } from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
import AvatarSetting from "../settings/AvatarSetting";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
roomId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
originalDisplayName: string;
|
||||||
|
displayName: string;
|
||||||
|
originalAvatarUrl: string;
|
||||||
|
avatarUrl: string;
|
||||||
|
avatarFile: File;
|
||||||
|
originalTopic: string;
|
||||||
|
topic: string;
|
||||||
|
enableProfileSave: boolean;
|
||||||
|
canSetName: boolean;
|
||||||
|
canSetTopic: boolean;
|
||||||
|
canSetAvatar: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Merge with ProfileSettings?
|
// TODO: Merge with ProfileSettings?
|
||||||
@replaceableComponent("views.room_settings.RoomProfileSettings")
|
@replaceableComponent("views.room_settings.RoomProfileSettings")
|
||||||
export default class RoomProfileSettings extends React.Component {
|
export default class RoomProfileSettings extends React.Component<IProps, IState> {
|
||||||
static propTypes = {
|
private avatarUpload = createRef<HTMLInputElement>();
|
||||||
roomId: PropTypes.string.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props: IProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const room = client.getRoom(props.roomId);
|
const room = client.getRoom(props.roomId);
|
||||||
if (!room) throw new Error("Expected a room for ID: ", props.roomId);
|
if (!room) throw new Error(`Expected a room for ID: ${props.roomId}`);
|
||||||
|
|
||||||
const avatarEvent = room.currentState.getStateEvents("m.room.avatar", "");
|
const avatarEvent = room.currentState.getStateEvents("m.room.avatar", "");
|
||||||
let avatarUrl = avatarEvent && avatarEvent.getContent() ? avatarEvent.getContent()["url"] : null;
|
let avatarUrl = avatarEvent && avatarEvent.getContent() ? avatarEvent.getContent()["url"] : null;
|
||||||
|
@ -60,17 +76,15 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
canSetTopic: room.currentState.maySendStateEvent('m.room.topic', client.getUserId()),
|
canSetTopic: room.currentState.maySendStateEvent('m.room.topic', client.getUserId()),
|
||||||
canSetAvatar: room.currentState.maySendStateEvent('m.room.avatar', client.getUserId()),
|
canSetAvatar: room.currentState.maySendStateEvent('m.room.avatar', client.getUserId()),
|
||||||
};
|
};
|
||||||
|
|
||||||
this._avatarUpload = createRef();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_uploadAvatar = () => {
|
private uploadAvatar = (): void => {
|
||||||
this._avatarUpload.current.click();
|
this.avatarUpload.current.click();
|
||||||
};
|
};
|
||||||
|
|
||||||
_removeAvatar = () => {
|
private removeAvatar = (): void => {
|
||||||
// clear file upload field so same file can be selected
|
// clear file upload field so same file can be selected
|
||||||
this._avatarUpload.current.value = "";
|
this.avatarUpload.current.value = "";
|
||||||
this.setState({
|
this.setState({
|
||||||
avatarUrl: null,
|
avatarUrl: null,
|
||||||
avatarFile: null,
|
avatarFile: null,
|
||||||
|
@ -78,7 +92,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_cancelProfileChanges = async (e) => {
|
private cancelProfileChanges = async (e: React.MouseEvent): Promise<void> => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -92,7 +106,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_saveProfile = async (e) => {
|
private saveProfile = async (e: React.FormEvent): Promise<void> => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -100,35 +114,46 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
this.setState({ enableProfileSave: false });
|
this.setState({ enableProfileSave: false });
|
||||||
|
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const newState = {};
|
|
||||||
|
let originalDisplayName: string;
|
||||||
|
let avatarUrl: string;
|
||||||
|
let originalAvatarUrl: string;
|
||||||
|
let originalTopic: string;
|
||||||
|
let avatarFile: File;
|
||||||
|
|
||||||
// TODO: What do we do about errors?
|
// TODO: What do we do about errors?
|
||||||
const displayName = this.state.displayName.trim();
|
const displayName = this.state.displayName.trim();
|
||||||
if (this.state.originalDisplayName !== this.state.displayName) {
|
if (this.state.originalDisplayName !== this.state.displayName) {
|
||||||
await client.setRoomName(this.props.roomId, displayName);
|
await client.setRoomName(this.props.roomId, displayName);
|
||||||
newState.originalDisplayName = displayName;
|
originalDisplayName = displayName;
|
||||||
newState.displayName = displayName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.avatarFile) {
|
if (this.state.avatarFile) {
|
||||||
const uri = await client.uploadContent(this.state.avatarFile);
|
const uri = await client.uploadContent(this.state.avatarFile);
|
||||||
await client.sendStateEvent(this.props.roomId, 'm.room.avatar', { url: uri }, '');
|
await client.sendStateEvent(this.props.roomId, 'm.room.avatar', { url: uri }, '');
|
||||||
newState.avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96);
|
avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96);
|
||||||
newState.originalAvatarUrl = newState.avatarUrl;
|
originalAvatarUrl = avatarUrl;
|
||||||
newState.avatarFile = null;
|
avatarFile = null;
|
||||||
} else if (this.state.originalAvatarUrl !== this.state.avatarUrl) {
|
} else if (this.state.originalAvatarUrl !== this.state.avatarUrl) {
|
||||||
await client.sendStateEvent(this.props.roomId, 'm.room.avatar', {}, '');
|
await client.sendStateEvent(this.props.roomId, 'm.room.avatar', {}, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state.originalTopic !== this.state.topic) {
|
if (this.state.originalTopic !== this.state.topic) {
|
||||||
await client.setRoomTopic(this.props.roomId, this.state.topic);
|
await client.setRoomTopic(this.props.roomId, this.state.topic);
|
||||||
newState.originalTopic = this.state.topic;
|
originalTopic = this.state.topic;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(newState);
|
this.setState({
|
||||||
|
originalAvatarUrl,
|
||||||
|
avatarUrl,
|
||||||
|
originalDisplayName,
|
||||||
|
originalTopic,
|
||||||
|
displayName,
|
||||||
|
avatarFile,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_onDisplayNameChanged = (e) => {
|
private onDisplayNameChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
this.setState({ displayName: e.target.value });
|
this.setState({ displayName: e.target.value });
|
||||||
if (this.state.originalDisplayName === e.target.value) {
|
if (this.state.originalDisplayName === e.target.value) {
|
||||||
this.setState({ enableProfileSave: false });
|
this.setState({ enableProfileSave: false });
|
||||||
|
@ -137,7 +162,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_onTopicChanged = (e) => {
|
private onTopicChanged = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {
|
||||||
this.setState({ topic: e.target.value });
|
this.setState({ topic: e.target.value });
|
||||||
if (this.state.originalTopic === e.target.value) {
|
if (this.state.originalTopic === e.target.value) {
|
||||||
this.setState({ enableProfileSave: false });
|
this.setState({ enableProfileSave: false });
|
||||||
|
@ -146,7 +171,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_onAvatarChanged = (e) => {
|
private onAvatarChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
if (!e.target.files || !e.target.files.length) {
|
if (!e.target.files || !e.target.files.length) {
|
||||||
this.setState({
|
this.setState({
|
||||||
avatarUrl: this.state.originalAvatarUrl,
|
avatarUrl: this.state.originalAvatarUrl,
|
||||||
|
@ -160,7 +185,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (ev) => {
|
reader.onload = (ev) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
avatarUrl: ev.target.result,
|
avatarUrl: String(ev.target.result),
|
||||||
avatarFile: file,
|
avatarFile: file,
|
||||||
enableProfileSave: true,
|
enableProfileSave: true,
|
||||||
});
|
});
|
||||||
|
@ -168,10 +193,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
public render(): JSX.Element {
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
|
||||||
const AvatarSetting = sdk.getComponent('settings.AvatarSetting');
|
|
||||||
|
|
||||||
let profileSettingsButtons;
|
let profileSettingsButtons;
|
||||||
if (
|
if (
|
||||||
this.state.canSetName ||
|
this.state.canSetName ||
|
||||||
|
@ -181,14 +203,14 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
profileSettingsButtons = (
|
profileSettingsButtons = (
|
||||||
<div className="mx_ProfileSettings_buttons">
|
<div className="mx_ProfileSettings_buttons">
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this._cancelProfileChanges}
|
onClick={this.cancelProfileChanges}
|
||||||
kind="link"
|
kind="link"
|
||||||
disabled={!this.state.enableProfileSave}
|
disabled={!this.state.enableProfileSave}
|
||||||
>
|
>
|
||||||
{ _t("Cancel") }
|
{ _t("Cancel") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
onClick={this._saveProfile}
|
onClick={this.saveProfile}
|
||||||
kind="primary"
|
kind="primary"
|
||||||
disabled={!this.state.enableProfileSave}
|
disabled={!this.state.enableProfileSave}
|
||||||
>
|
>
|
||||||
|
@ -200,16 +222,16 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={this._saveProfile}
|
onSubmit={this.saveProfile}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
noValidate={true}
|
noValidate={true}
|
||||||
className="mx_ProfileSettings_profileForm"
|
className="mx_ProfileSettings_profileForm"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
ref={this._avatarUpload}
|
ref={this.avatarUpload}
|
||||||
className="mx_ProfileSettings_avatarUpload"
|
className="mx_ProfileSettings_avatarUpload"
|
||||||
onChange={this._onAvatarChanged}
|
onChange={this.onAvatarChanged}
|
||||||
accept="image/*"
|
accept="image/*"
|
||||||
/>
|
/>
|
||||||
<div className="mx_ProfileSettings_profile">
|
<div className="mx_ProfileSettings_profile">
|
||||||
|
@ -219,7 +241,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
type="text"
|
type="text"
|
||||||
value={this.state.displayName}
|
value={this.state.displayName}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onChange={this._onDisplayNameChanged}
|
onChange={this.onDisplayNameChanged}
|
||||||
disabled={!this.state.canSetName}
|
disabled={!this.state.canSetName}
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
|
@ -230,7 +252,7 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
type="text"
|
type="text"
|
||||||
value={this.state.topic}
|
value={this.state.topic}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onChange={this._onTopicChanged}
|
onChange={this.onTopicChanged}
|
||||||
element="textarea"
|
element="textarea"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -238,8 +260,8 @@ export default class RoomProfileSettings extends React.Component {
|
||||||
avatarUrl={this.state.avatarUrl}
|
avatarUrl={this.state.avatarUrl}
|
||||||
avatarName={this.state.displayName || this.props.roomId}
|
avatarName={this.state.displayName || this.props.roomId}
|
||||||
avatarAltText={_t("Room avatar")}
|
avatarAltText={_t("Room avatar")}
|
||||||
uploadAvatar={this.state.canSetAvatar ? this._uploadAvatar : undefined}
|
uploadAvatar={this.state.canSetAvatar ? this.uploadAvatar : undefined}
|
||||||
removeAvatar={this.state.canSetAvatar ? this._removeAvatar : undefined} />
|
removeAvatar={this.state.canSetAvatar ? this.removeAvatar : undefined} />
|
||||||
</div>
|
</div>
|
||||||
{ profileSettingsButtons }
|
{ profileSettingsButtons }
|
||||||
</form>
|
</form>
|
|
@ -18,8 +18,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import { _t, _td } from '../../../languageHandler';
|
import { _t, _td } from '../../../languageHandler';
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
|
@ -27,21 +25,22 @@ import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import SettingsFlag from "../elements/SettingsFlag";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
room: Room;
|
||||||
|
}
|
||||||
|
|
||||||
@replaceableComponent("views.room_settings.UrlPreviewSettings")
|
@replaceableComponent("views.room_settings.UrlPreviewSettings")
|
||||||
export default class UrlPreviewSettings extends React.Component {
|
export default class UrlPreviewSettings extends React.Component<IProps> {
|
||||||
static propTypes = {
|
private onClickUserSettings = (e: React.MouseEvent): void => {
|
||||||
room: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
_onClickUserSettings = (e) => {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
dis.fire(Action.ViewUserSettings);
|
dis.fire(Action.ViewUserSettings);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
public render(): JSX.Element {
|
||||||
const SettingsFlag = sdk.getComponent("elements.SettingsFlag");
|
|
||||||
const roomId = this.props.room.roomId;
|
const roomId = this.props.room.roomId;
|
||||||
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
|
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
|
||||||
|
|
||||||
|
@ -54,18 +53,18 @@ export default class UrlPreviewSettings extends React.Component {
|
||||||
if (accountEnabled) {
|
if (accountEnabled) {
|
||||||
previewsForAccount = (
|
previewsForAccount = (
|
||||||
_t("You have <a>enabled</a> URL previews by default.", {}, {
|
_t("You have <a>enabled</a> URL previews by default.", {}, {
|
||||||
'a': (sub)=><a onClick={this._onClickUserSettings} href=''>{ sub }</a>,
|
'a': (sub)=><a onClick={this.onClickUserSettings} href=''>{ sub }</a>,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
previewsForAccount = (
|
previewsForAccount = (
|
||||||
_t("You have <a>disabled</a> URL previews by default.", {}, {
|
_t("You have <a>disabled</a> URL previews by default.", {}, {
|
||||||
'a': (sub)=><a onClick={this._onClickUserSettings} href=''>{ sub }</a>,
|
'a': (sub)=><a onClick={this.onClickUserSettings} href=''>{ sub }</a>,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, "room")) {
|
if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, SettingLevel.ROOM)) {
|
||||||
previewsForRoom = (
|
previewsForRoom = (
|
||||||
<label>
|
<label>
|
||||||
<SettingsFlag
|
<SettingsFlag
|
Loading…
Reference in New Issue