Migrate ChangeAvatar to TypeScript

This commit is contained in:
Germain Souquet 2021-08-14 11:04:36 +02:00
parent 1f55158727
commit bedfbedff0

View file

@ -1,5 +1,6 @@
/* /*
Copyright 2015, 2016 OpenMarket Ltd Copyright 2015, 2016 OpenMarket Ltd
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -15,54 +16,62 @@ limitations under the License.
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types';
import { MatrixClientPeg } from "../../../MatrixClientPeg"; import { MatrixClientPeg } from "../../../MatrixClientPeg";
import * as sdk from '../../../index'; import * as sdk from '../../../index';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import Spinner from '../elements/Spinner'; import Spinner from '../elements/Spinner';
import { replaceableComponent } from "../../../utils/replaceableComponent"; import { replaceableComponent } from "../../../utils/replaceableComponent";
import { mediaFromMxc } from "../../../customisations/Media"; import { mediaFromMxc } from "../../../customisations/Media";
import { MatrixEvent, Room } from '../../../../../matrix-js-sdk/src';
interface IProps {
initialAvatarUrl?: string;
room?: Room;
// if false, you need to call changeAvatar.onFileSelected yourself.
showUploadSection?: boolean;
width?: number;
height?: number;
className?: string;
}
interface IState {
avatarUrl?: string;
errorText?: string;
phase?: Phases;
}
enum Phases {
Display = "display",
Uploading = "uploading",
Error = "error",
}
@replaceableComponent("views.settings.ChangeAvatar") @replaceableComponent("views.settings.ChangeAvatar")
export default class ChangeAvatar extends React.Component { export default class ChangeAvatar extends React.Component<IProps, IState> {
static propTypes = { public static defaultProps = {
initialAvatarUrl: PropTypes.string,
room: PropTypes.object,
// if false, you need to call changeAvatar.onFileSelected yourself.
showUploadSection: PropTypes.bool,
width: PropTypes.number,
height: PropTypes.number,
className: PropTypes.string,
};
static Phases = {
Display: "display",
Uploading: "uploading",
Error: "error",
};
static defaultProps = {
showUploadSection: true, showUploadSection: true,
className: "", className: "",
width: 80, width: 80,
height: 80, height: 80,
}; };
constructor(props) { private avatarSet = false;
constructor(props: IProps) {
super(props); super(props);
this.state = { this.state = {
avatarUrl: this.props.initialAvatarUrl, avatarUrl: this.props.initialAvatarUrl,
phase: ChangeAvatar.Phases.Display, phase: Phases.Display,
}; };
} }
componentDidMount() { public componentDidMount(): void {
MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents); MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
} }
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
UNSAFE_componentWillReceiveProps(newProps) { // eslint-disable-line camelcase public UNSAFE_componentWillReceiveProps(newProps): void { // eslint-disable-line camelcase
if (this.avatarSet) { if (this.avatarSet) {
// don't clobber what the user has just set // don't clobber what the user has just set
return; return;
@ -72,13 +81,13 @@ export default class ChangeAvatar extends React.Component {
}); });
} }
componentWillUnmount() { public componentWillUnmount(): void {
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents); MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
} }
} }
onRoomStateEvents = (ev) => { public onRoomStateEvents = (ev: MatrixEvent) => {
if (!this.props.room) { if (!this.props.room) {
return; return;
} }
@ -94,18 +103,17 @@ export default class ChangeAvatar extends React.Component {
} }
}; };
setAvatarFromFile(file) { public setAvatarFromFile(file): Promise<{}> {
let newUrl = null; let newUrl = null;
this.setState({ this.setState({
phase: ChangeAvatar.Phases.Uploading, phase: Phases.Uploading,
}); });
const self = this; const httpPromise = MatrixClientPeg.get().uploadContent(file).then((url) => {
const httpPromise = MatrixClientPeg.get().uploadContent(file).then(function(url) {
newUrl = url; newUrl = url;
if (self.props.room) { if (this.props.room) {
return MatrixClientPeg.get().sendStateEvent( return MatrixClientPeg.get().sendStateEvent(
self.props.room.roomId, this.props.room.roomId,
'm.room.avatar', 'm.room.avatar',
{ url: url }, { url: url },
'', '',
@ -115,33 +123,33 @@ export default class ChangeAvatar extends React.Component {
} }
}); });
httpPromise.then(function() { httpPromise.then(() => {
self.setState({ this.setState({
phase: ChangeAvatar.Phases.Display, phase: Phases.Display,
avatarUrl: mediaFromMxc(newUrl).srcHttp, avatarUrl: mediaFromMxc(newUrl).srcHttp,
}); });
}, function(error) { }, () => {
self.setState({ this.setState({
phase: ChangeAvatar.Phases.Error, phase: Phases.Error,
}); });
self.onError(error); this.onError();
}); });
return httpPromise; return httpPromise;
} }
onFileSelected = (ev) => { private onFileSelected = (ev: React.ChangeEvent<HTMLInputElement>) => {
this.avatarSet = true; this.avatarSet = true;
return this.setAvatarFromFile(ev.target.files[0]); return this.setAvatarFromFile(ev.target.files[0]);
}; };
onError = (error) => { private onError = (): void => {
this.setState({ this.setState({
errorText: _t("Failed to upload profile picture!"), errorText: _t("Failed to upload profile picture!"),
}); });
}; };
render() { public render(): JSX.Element {
let avatarImg; let avatarImg;
// Having just set an avatar we just display that since it will take a little // Having just set an avatar we just display that since it will take a little
// time to propagate through to the RoomAvatar. // time to propagate through to the RoomAvatar.
@ -178,8 +186,8 @@ export default class ChangeAvatar extends React.Component {
} }
switch (this.state.phase) { switch (this.state.phase) {
case ChangeAvatar.Phases.Display: case Phases.Display:
case ChangeAvatar.Phases.Error: case Phases.Error:
return ( return (
<div> <div>
<div className={this.props.className}> <div className={this.props.className}>
@ -188,7 +196,7 @@ export default class ChangeAvatar extends React.Component {
{ uploadSection } { uploadSection }
</div> </div>
); );
case ChangeAvatar.Phases.Uploading: case Phases.Uploading:
return ( return (
<Spinner /> <Spinner />
); );