mirror of
https://github.com/filecoin-project/slate.git
synced 2024-12-25 18:13:10 +03:00
236 lines
6.2 KiB
JavaScript
236 lines
6.2 KiB
JavaScript
import * as React from "react";
|
|
import * as System from "~/components/system";
|
|
import * as Actions from "~/common/actions";
|
|
import * as Validations from "~/common/validations";
|
|
|
|
import { css } from "@emotion/react";
|
|
|
|
import ScenePage from "~/components/core/ScenePage";
|
|
import Avatar from "~/components/core/Avatar";
|
|
|
|
const STYLES_FILE_HIDDEN = css`
|
|
height: 1px;
|
|
width: 1px;
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
position: fixed;
|
|
top: -1px;
|
|
left: -1px;
|
|
`;
|
|
|
|
const delay = (time) =>
|
|
new Promise((resolve) =>
|
|
setTimeout(() => {
|
|
resolve();
|
|
}, time)
|
|
);
|
|
|
|
export default class SceneEditAccount extends React.Component {
|
|
state = {
|
|
username: this.props.viewer.username,
|
|
password: "",
|
|
confirm: "",
|
|
deleting: false,
|
|
changingPassword: false,
|
|
changingUsername: false,
|
|
changingAvatar: false,
|
|
};
|
|
|
|
_handleUpload = async (e) => {
|
|
this.setState({ changingAvatar: true });
|
|
e.persist();
|
|
let file = e.target.files[0];
|
|
|
|
if (!file) {
|
|
alert("TODO: Something went wrong");
|
|
return;
|
|
}
|
|
|
|
if (!file.type.startsWith("image/")) {
|
|
alert("TODO: Error message for not an image.");
|
|
return;
|
|
}
|
|
|
|
let data = new FormData();
|
|
data.append("image", file);
|
|
|
|
const options = {
|
|
method: "POST",
|
|
headers: {
|
|
Accept: "application/json",
|
|
},
|
|
body: data,
|
|
};
|
|
|
|
const response = await fetch(`/api/data/${file.name}`, options);
|
|
const json = await response.json();
|
|
|
|
if (json.error) {
|
|
alert("TODO: Image already exists in bucket error message");
|
|
this.setState({ changingAvatar: false });
|
|
return;
|
|
}
|
|
|
|
console.log(json);
|
|
|
|
await Actions.updateViewer({
|
|
data: { photo: `https://hub.textile.io${json.data.ipfs}` },
|
|
});
|
|
|
|
await this.props.onRehydrate();
|
|
|
|
this.setState({ changingAvatar: false });
|
|
};
|
|
|
|
_handleSave = async (e) => {
|
|
this.setState({ changingUsername: true });
|
|
|
|
if (!Validations.username(this.state.username)) {
|
|
alert("TODO: Not a valid username");
|
|
this.setState({ changingUsername: false });
|
|
return;
|
|
}
|
|
|
|
await Actions.updateViewer({
|
|
username: this.state.username,
|
|
});
|
|
|
|
await this.props.onRehydrate();
|
|
this.setState({ changingUsername: false });
|
|
};
|
|
|
|
_handleChangePassword = async (e) => {
|
|
this.setState({ changingPassword: true });
|
|
if (this.state.password !== this.state.confirm) {
|
|
alert("TODO: Error message for non-matching passwords");
|
|
this.setState({ changingPassword: false });
|
|
return;
|
|
}
|
|
|
|
if (!Validations.password(this.state.password)) {
|
|
alert("TODO: Not a valid password");
|
|
this.setState({ changingPassword: false });
|
|
return;
|
|
}
|
|
|
|
await Actions.updateViewer({
|
|
type: "CHANGE_PASSWORD",
|
|
password: this.state.password,
|
|
});
|
|
|
|
this.setState({ changingPassword: false, password: "", confirm: "" });
|
|
};
|
|
|
|
_handleDelete = async (e) => {
|
|
this.setState({ deleting: true });
|
|
|
|
await delay(100);
|
|
|
|
const response = await this.props.onDeleteYourself();
|
|
if (!response) {
|
|
this.setState({ deleting: false });
|
|
}
|
|
};
|
|
|
|
_handleChange = (e) => {
|
|
e.persist();
|
|
this.setState({ [e.target.name]: e.target.value });
|
|
};
|
|
|
|
render() {
|
|
const profileURL = `https://slate.host/@${this.state.username}`;
|
|
|
|
return (
|
|
<ScenePage>
|
|
<System.H1>Profile & account settings</System.H1>
|
|
|
|
<System.DescriptionGroup
|
|
style={{ marginTop: 48 }}
|
|
label="Avatar image"
|
|
description="This image will appear in various lists."
|
|
/>
|
|
|
|
<Avatar style={{ marginTop: 24 }} size={256} url={this.props.viewer.data.photo} />
|
|
|
|
<div style={{ marginTop: 24 }}>
|
|
<input css={STYLES_FILE_HIDDEN} type="file" id="file" onChange={this._handleUpload} />
|
|
<System.ButtonPrimary
|
|
style={{ margin: "0 16px 16px 0" }}
|
|
type="label"
|
|
htmlFor="file"
|
|
loading={this.state.changingAvatar}>
|
|
Pick avatar
|
|
</System.ButtonPrimary>
|
|
</div>
|
|
|
|
<System.Input
|
|
containerStyle={{ marginTop: 48 }}
|
|
label="Username"
|
|
description={
|
|
<React.Fragment>
|
|
This is your username on Slate. Your username is used for your profile URL{" "}
|
|
<a href={profileURL} target="_blank">
|
|
{profileURL}
|
|
</a>
|
|
</React.Fragment>
|
|
}
|
|
name="username"
|
|
value={this.state.username}
|
|
placeholder="Name"
|
|
onChange={this._handleChange}
|
|
/>
|
|
|
|
<div style={{ marginTop: 24 }}>
|
|
<System.ButtonPrimary onClick={this._handleSave} loading={this.state.changingUsername}>
|
|
Change username
|
|
</System.ButtonPrimary>
|
|
</div>
|
|
|
|
<System.DescriptionGroup
|
|
style={{ marginTop: 48 }}
|
|
label="Reset password"
|
|
description="Your new password must be a minimum of eight characters."
|
|
/>
|
|
|
|
<System.Input
|
|
containerStyle={{ marginTop: 24 }}
|
|
label="New password"
|
|
name="password"
|
|
type="password"
|
|
value={this.state.password}
|
|
placeholder="Your new password"
|
|
onChange={this._handleChange}
|
|
/>
|
|
|
|
<System.Input
|
|
containerStyle={{ marginTop: 24 }}
|
|
label="Confirm password"
|
|
name="confirm"
|
|
type="password"
|
|
value={this.state.confirm}
|
|
placeholder="Confirm it!"
|
|
onChange={this._handleChange}
|
|
/>
|
|
|
|
<div style={{ marginTop: 24 }}>
|
|
<System.ButtonPrimary onClick={this._handleChangePassword} loading={this.state.changingPassword}>
|
|
Change password
|
|
</System.ButtonPrimary>
|
|
</div>
|
|
|
|
<System.DescriptionGroup
|
|
style={{ marginTop: 48 }}
|
|
label="Delete your account"
|
|
description="If you choose to delete your account you will lose your Textile Hub and Powergate key. Make sure you back those up before deleting your account."
|
|
/>
|
|
|
|
<div style={{ marginTop: 24 }}>
|
|
<System.ButtonPrimary onClick={this._handleDelete} loading={this.state.deleting}>
|
|
Delete my account
|
|
</System.ButtonPrimary>
|
|
</div>
|
|
</ScenePage>
|
|
);
|
|
}
|
|
}
|