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-08-25 21:08:42 +03:00
import * as Constants from "~/common/constants" ;
import * as Strings from "~/common/strings" ;
2020-07-23 11:57:44 +03:00
import * as Validations from "~/common/validations" ;
2020-08-20 08:29:33 +03:00
import * as FileUtilities from "~/common/file-utilities" ;
2020-04-09 00:29:13 +03:00
2020-07-22 08:53:29 +03:00
import { css } from "@emotion/react" ;
2020-09-12 01:25:33 +03:00
import { dispatchCustomEvent } from "~/common/custom-events" ;
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 : "" ,
2020-08-22 08:45:50 +03:00
body : this . props . viewer . data . body ,
photo : this . props . viewer . data . photo ,
2020-08-25 08:00:32 +03:00
name : this . props . viewer . data . name ,
2020-07-23 11:57:44 +03:00
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-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
message : "Something went wrong with the upload. Please try again" ,
} ,
} ,
} ) ;
2020-08-02 09:00:04 +03:00
return ;
}
2020-09-08 08:08:10 +03:00
// NOTE(jim): Only allow images for account avatar.
2020-08-02 09:00:04 +03:00
if ( ! file . type . startsWith ( "image/" ) ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : { message : "Upload failed. Only images and gifs are allowed" } ,
} ,
} ) ;
2020-08-02 09:00:04 +03:00
return ;
2020-06-08 09:45:53 +03:00
}
2020-09-23 23:54:43 +03:00
const response = await FileUtilities . upload ( { file } ) ;
2020-07-22 13:51:40 +03:00
2020-09-23 23:54:43 +03:00
if ( ! response ) {
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : { message : "We're having trouble connecting right now" } ,
} ,
} ) ;
this . setState ( { changingAvatar : false } ) ;
return ;
}
if ( response . error ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : { alert : { decorator : json . decorator } } ,
} ) ;
2020-07-24 10:45:21 +03:00
this . setState ( { changingAvatar : false } ) ;
return ;
}
2020-09-23 23:54:43 +03:00
const { json } = response ;
2020-08-25 21:08:42 +03:00
const cid = json . data . ipfs . replace ( "/ipfs/" , "" ) ;
2020-09-03 03:58:56 +03:00
const url = Strings . getCIDGatewayURL ( cid ) ;
2020-07-22 13:51:40 +03:00
await Actions . updateViewer ( {
2020-08-22 08:45:50 +03:00
data : {
2020-08-25 21:08:42 +03:00
photo : Strings . getCIDGatewayURL ( cid ) ,
2020-08-22 08:45:50 +03:00
body : this . state . body ,
2020-08-25 08:00:32 +03:00
name : this . state . name ,
2020-08-22 08:45:50 +03:00
} ,
2020-07-22 13:51:40 +03:00
} ) ;
2020-07-23 11:57:44 +03:00
await this . props . onRehydrate ( ) ;
2020-09-03 03:58:56 +03:00
this . setState ( { changingAvatar : false , photo : url } ) ;
2020-06-08 09:45:53 +03:00
} ;
2020-08-22 08:45:50 +03:00
_handleSaveBio = async ( e ) => {
this . setState ( { changingBio : true } ) ;
await Actions . updateViewer ( {
data : {
photo : this . state . photo ,
body : this . state . body ,
2020-08-25 08:00:32 +03:00
name : this . state . name ,
2020-08-22 08:45:50 +03:00
} ,
} ) ;
await this . props . onRehydrate ( ) ;
this . setState ( { changingBio : false } ) ;
} ;
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 ) ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : {
message : "Please include only letters and numbers in your username" ,
} ,
} ,
} ) ;
2020-07-23 11:57:44 +03:00
this . setState ( { changingUsername : false } ) ;
return ;
}
2020-07-22 13:51:40 +03:00
await Actions . updateViewer ( {
username : this . state . username ,
2020-08-22 08:45:50 +03:00
data : {
photo : this . state . photo ,
body : this . state . body ,
2020-08-25 08:00:32 +03:00
name : this . state . name ,
2020-08-22 08:45:50 +03:00
} ,
2020-07-22 13:51:40 +03:00
} ) ;
2020-07-01 09:41:54 +03:00
2020-07-23 11:57:44 +03:00
await this . props . onRehydrate ( ) ;
this . setState ( { changingUsername : false } ) ;
} ;
2020-09-03 19:19:52 +03:00
_handleUsernameChange = ( e ) => {
e . persist ( ) ;
this . setState ( { [ e . target . name ] : e . target . value . toLowerCase ( ) } ) ;
} ;
2020-07-23 11:57:44 +03:00
_handleChangePassword = async ( e ) => {
this . setState ( { changingPassword : true } ) ;
if ( this . state . password !== this . state . confirm ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : { alert : { message : "Passwords did not match" } } ,
} ) ;
2020-07-23 11:57:44 +03:00
this . setState ( { changingPassword : false } ) ;
return ;
}
if ( ! Validations . password ( this . state . password ) ) {
2020-09-12 01:25:33 +03:00
dispatchCustomEvent ( {
name : "create-alert" ,
detail : {
alert : { message : "Password length must be more than 8 characters" } ,
} ,
} ) ;
2020-07-23 11:57:44 +03:00
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 ( ) ;
2020-09-13 05:59:47 +03:00
this . setState ( { deleting : false } ) ;
2020-07-22 08:53:29 +03:00
} ;
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-09-13 04:12:56 +03:00
< System . H1 > 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-22 08:45:50 +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-22 08:45:50 +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-22 08:45:50 +03:00
loading = { this . state . changingAvatar }
>
2020-09-13 03:00:58 +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-25 08:00:32 +03:00
This is your username on Slate . Your username is unique and 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-08-25 08:00:32 +03:00
placeholder = "Username"
2020-09-03 19:19:52 +03:00
onChange = { this . _handleUsernameChange }
2020-04-09 00:29:13 +03:00
/ >
2020-07-01 09:41:54 +03:00
< div style = { { marginTop : 24 } } >
2020-08-22 08:45:50 +03:00
< System . ButtonPrimary
onClick = { this . _handleSave }
loading = { this . state . changingUsername }
>
2020-09-13 03:00:58 +03:00
Change username
2020-07-23 11:57:44 +03:00
< / S y s t e m . B u t t o n P r i m a r y >
< / d i v >
2020-08-25 08:00:32 +03:00
< System . Input
containerStyle = { { marginTop : 48 } }
label = "Name"
description = { ` This is how your name will be publicly shown. ` }
name = "name"
value = { this . state . name }
placeholder = "Your name"
onChange = { this . _handleChange }
/ >
< System . DescriptionGroup label = "Bio" style = { { marginTop : 24 } } / >
2020-08-22 08:45:50 +03:00
< System . Textarea
style = { { marginTop : 24 } }
label = "Bio"
name = "body"
value = { this . state . body }
placeholder = "A user on Slate."
onChange = { this . _handleChange }
/ >
< div style = { { marginTop : 24 } } >
< System . ButtonPrimary
onClick = { this . _handleSaveBio }
loading = { this . state . changingBio }
>
2020-09-13 03:00:58 +03:00
Update information
2020-08-22 08:45:50 +03:00
< / S y s t e m . B u t t o n P r i m a r y >
< / d i v >
2020-07-23 11:57:44 +03:00
< 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-22 08:45:50 +03:00
< System . ButtonPrimary
onClick = { this . _handleChangePassword }
loading = { this . state . changingPassword }
>
2020-09-13 03:00:58 +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-22 08:45:50 +03:00
< System . ButtonPrimary
onClick = { this . _handleDelete }
loading = { this . state . deleting }
>
2020-09-13 03:00:58 +03:00
Delete my account
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 >
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 >
) ;
}
}