2020-07-22 08:53:29 +03:00
import * as React from "react" ;
import * as System from "~/components/system" ;
import * as Actions from "~/common/actions" ;
2020-07-23 11:57:44 +03:00
import * as Validations from "~/common/validations" ;
2020-04-09 00:29:13 +03:00
2020-07-22 08:53:29 +03:00
import { css } from "@emotion/react" ;
2020-04-09 00:29:13 +03:00
2020-07-22 08:53:29 +03:00
import ScenePage from "~/components/core/ScenePage" ;
import Avatar from "~/components/core/Avatar" ;
2020-06-08 09:45:53 +03:00
const STYLES _FILE _HIDDEN = css `
height : 1 px ;
width : 1 px ;
opacity : 0 ;
visibility : hidden ;
position : fixed ;
top : - 1 px ;
left : - 1 px ;
` ;
2020-04-09 00:29:13 +03:00
2020-07-22 08:53:29 +03:00
const delay = ( time ) =>
new Promise ( ( resolve ) =>
setTimeout ( ( ) => {
resolve ( ) ;
} , time )
) ;
2020-04-09 00:29:13 +03:00
export default class SceneEditAccount extends React . Component {
2020-07-23 11:57:44 +03:00
state = {
username : this . props . viewer . username ,
password : "" ,
confirm : "" ,
deleting : false ,
changingPassword : false ,
changingUsername : false ,
changingAvatar : false ,
} ;
2020-07-01 09:41:54 +03:00
2020-06-08 09:45:53 +03:00
_handleUpload = async ( e ) => {
2020-07-23 11:57:44 +03:00
this . setState ( { changingAvatar : true } ) ;
2020-06-08 09:45:53 +03:00
e . persist ( ) ;
let file = e . target . files [ 0 ] ;
if ( ! file ) {
2020-08-02 09:00:04 +03:00
alert ( "TODO: Something went wrong" ) ;
return ;
}
if ( ! file . type . startsWith ( "image/" ) ) {
alert ( "TODO: Error message for not an image." ) ;
return ;
2020-06-08 09:45:53 +03:00
}
let data = new FormData ( ) ;
2020-08-03 19:41:26 +03:00
data . append ( "data" , file ) ;
2020-06-08 09:45:53 +03:00
const options = {
2020-07-22 08:53:29 +03:00
method : "POST" ,
2020-06-08 09:45:53 +03:00
headers : {
2020-07-22 08:53:29 +03:00
Accept : "application/json" ,
2020-06-08 09:45:53 +03:00
} ,
body : data ,
} ;
2020-07-22 13:51:40 +03:00
const response = await fetch ( ` /api/data/ ${ file . name } ` , options ) ;
const json = await response . json ( ) ;
2020-07-24 10:45:21 +03:00
if ( json . error ) {
alert ( "TODO: Image already exists in bucket error message" ) ;
this . setState ( { changingAvatar : false } ) ;
return ;
}
2020-07-22 13:51:40 +03:00
await Actions . updateViewer ( {
data : { photo : ` https://hub.textile.io ${ json . data . ipfs } ` } ,
} ) ;
2020-07-23 11:57:44 +03:00
await this . props . onRehydrate ( ) ;
this . setState ( { changingAvatar : false } ) ;
2020-06-08 09:45:53 +03:00
} ;
2020-07-01 09:41:54 +03:00
_handleSave = async ( e ) => {
2020-07-23 11:57:44 +03:00
this . setState ( { changingUsername : true } ) ;
if ( ! Validations . username ( this . state . username ) ) {
alert ( "TODO: Not a valid username" ) ;
this . setState ( { changingUsername : false } ) ;
return ;
}
2020-07-22 13:51:40 +03:00
await Actions . updateViewer ( {
username : this . state . username ,
} ) ;
2020-07-01 09:41:54 +03:00
2020-07-23 11:57:44 +03:00
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 : "" } ) ;
2020-07-01 09:41:54 +03:00
} ;
2020-07-22 08:53:29 +03:00
_handleDelete = async ( e ) => {
this . setState ( { deleting : true } ) ;
await delay ( 100 ) ;
const response = await this . props . onDeleteYourself ( ) ;
if ( ! response ) {
this . setState ( { deleting : false } ) ;
}
} ;
2020-04-09 00:29:13 +03:00
_handleChange = ( e ) => {
2020-07-01 09:41:54 +03:00
e . persist ( ) ;
this . setState ( { [ e . target . name ] : e . target . value } ) ;
2020-04-09 00:29:13 +03:00
} ;
render ( ) {
2020-08-07 02:06:54 +03:00
const profileURL = ` https://slate.host/ ${ this . state . username } ` ;
2020-07-23 04:25:19 +03:00
2020-04-09 00:29:13 +03:00
return (
< ScenePage >
2020-07-31 13:12:10 +03:00
< System . H1 > Profile & account settings < / S y s t e m . H 1 >
2020-04-09 00:29:13 +03:00
< System . DescriptionGroup
style = { { marginTop : 48 } }
label = "Avatar image"
description = "This image will appear in various lists."
/ >
2020-08-07 02:06:54 +03:00
< Avatar
style = { { marginTop : 24 } }
size = { 256 }
url = { this . props . viewer . data . photo }
/ >
2020-04-09 00:29:13 +03:00
< div style = { { marginTop : 24 } } >
2020-08-07 02:06:54 +03:00
< input
css = { STYLES _FILE _HIDDEN }
type = "file"
id = "file"
onChange = { this . _handleUpload }
/ >
2020-07-22 08:53:29 +03:00
< System . ButtonPrimary
style = { { margin : "0 16px 16px 0" } }
type = "label"
htmlFor = "file"
2020-08-07 02:06:54 +03:00
loading = { this . state . changingAvatar }
>
2020-07-23 11:57:44 +03:00
Pick avatar
2020-04-09 00:29:13 +03:00
< / S y s t e m . B u t t o n P r i m a r y >
< / d i v >
< System . Input
containerStyle = { { marginTop : 48 } }
2020-07-22 10:41:29 +03:00
label = "Username"
2020-07-23 04:25:19 +03:00
description = {
< React . Fragment >
2020-08-07 02:06:54 +03:00
This is your username on Slate . Your username is used for your
profile URL { " " }
2020-07-23 04:25:19 +03:00
< a href = { profileURL } target = "_blank" >
{ profileURL }
< / a >
< / R e a c t . F r a g m e n t >
}
2020-07-22 10:41:29 +03:00
name = "username"
value = { this . state . username }
2020-04-09 00:29:13 +03:00
placeholder = "Name"
onChange = { this . _handleChange }
/ >
2020-07-01 09:41:54 +03:00
< div style = { { marginTop : 24 } } >
2020-08-07 02:06:54 +03:00
< System . ButtonPrimary
onClick = { this . _handleSave }
loading = { this . state . changingUsername }
>
2020-07-23 11:57:44 +03:00
Change username
< / S y s t e m . B u t t o n P r i m a r y >
< / d i v >
< System . DescriptionGroup
style = { { marginTop : 48 } }
label = "Reset password"
2020-07-24 06:09:58 +03:00
description = "Your new password must be a minimum of eight characters."
2020-07-23 11:57:44 +03:00
/ >
< 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 } } >
2020-08-07 02:06:54 +03:00
< System . ButtonPrimary
onClick = { this . _handleChangePassword }
loading = { this . state . changingPassword }
>
2020-07-23 11:57:44 +03:00
Change password
2020-07-22 08:53:29 +03:00
< / S y s t e m . B u t t o n P r i m a r y >
< / d i v >
< 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 } } >
2020-08-07 02:06:54 +03:00
< System . ButtonPrimary
onClick = { this . _handleDelete }
loading = { this . state . deleting }
>
2020-07-22 08:53:29 +03:00
Delete my account
< / S y s t e m . B u t t o n P r i m a r y >
2020-07-01 09:41:54 +03:00
< / d i v >
2020-04-09 00:29:13 +03:00
< / S c e n e P a g e >
) ;
}
}