2019-10-19 22:14:43 +02:00
import React , { Component } from "react" ;
2019-09-18 19:52:39 +02:00
import {
withStyles ,
Paper ,
Typography ,
Button ,
TextField ,
Fade ,
Link ,
CircularProgress ,
Tooltip ,
Dialog ,
DialogTitle ,
DialogActions ,
2019-10-03 17:16:21 +02:00
DialogContent ,
List ,
ListItem ,
ListItemText ,
ListItemAvatar ,
ListItemSecondaryAction ,
IconButton
2019-09-18 19:52:39 +02:00
} from "@material-ui/core" ;
import { styles } from "./WelcomePage.styles" ;
import Mastodon from "megalodon" ;
import { SaveClientSession } from "../types/SessionData" ;
2019-09-23 23:28:01 +02:00
import {
createHyperspaceApp ,
getRedirectAddress ,
2019-10-19 22:14:43 +02:00
inDisallowedDomains ,
instancesBearerKey
2019-09-23 23:28:01 +02:00
} from "../utilities/login" ;
2019-09-18 19:52:39 +02:00
import { parseUrl } from "query-string" ;
import { getConfig } from "../utilities/settings" ;
import { isDarwinApp } from "../utilities/desktop" ;
import axios from "axios" ;
import { withSnackbar , withSnackbarProps } from "notistack" ;
import { Config } from "../types/Config" ;
2019-10-03 17:16:21 +02:00
import {
addAccountToRegistry ,
getAccountRegistry ,
loginWithAccount ,
removeAccountFromRegistry
} from "../utilities/accounts" ;
import { Account , MultiAccount } from "../types/Account" ;
import AccountCircleIcon from "@material-ui/icons/AccountCircle" ;
import CloseIcon from "@material-ui/icons/Close" ;
2019-04-23 19:06:31 +02:00
interface IWelcomeProps extends withSnackbarProps {
classes : any ;
}
2019-04-07 23:25:39 +02:00
interface IWelcomeState {
logoUrl? : string ;
backgroundUrl? : string ;
brandName? : string ;
registerBase? : string ;
federates? : boolean ;
2019-10-03 17:16:21 +02:00
proceedToGetCode : boolean ;
2019-04-07 23:25:39 +02:00
user : string ;
userInputError : boolean ;
2019-04-09 22:53:00 +02:00
userInputErrorMessage : string ;
2019-04-07 23:25:39 +02:00
clientId? : string ;
clientSecret? : string ;
authUrl? : string ;
foundSavedLogin : boolean ;
2019-10-03 17:16:21 +02:00
authorizing : boolean ;
2019-04-12 20:26:27 +02:00
license? : string ;
repo? : string ;
2019-04-20 20:59:32 +02:00
defaultRedirectAddress : string ;
2019-04-23 01:05:30 +02:00
openAuthDialog : boolean ;
authCode : string ;
emergencyMode : boolean ;
2019-04-26 21:53:40 +02:00
version : string ;
2019-10-03 17:16:21 +02:00
willAddAccount : boolean ;
2019-04-07 23:25:39 +02:00
}
2019-04-23 19:06:31 +02:00
class WelcomePage extends Component < IWelcomeProps , IWelcomeState > {
2019-04-07 23:25:39 +02:00
client : any ;
constructor ( props : any ) {
super ( props ) ;
this . state = {
2019-10-03 17:16:21 +02:00
proceedToGetCode : false ,
2019-04-07 23:25:39 +02:00
user : "" ,
userInputError : false ,
foundSavedLogin : false ,
2019-10-03 17:16:21 +02:00
authorizing : false ,
2019-09-18 19:52:39 +02:00
userInputErrorMessage : "" ,
defaultRedirectAddress : "" ,
2019-04-23 01:05:30 +02:00
openAuthDialog : false ,
2019-09-18 19:52:39 +02:00
authCode : "" ,
2019-04-26 21:53:40 +02:00
emergencyMode : false ,
2019-10-03 17:16:21 +02:00
version : "" ,
willAddAccount : false
2019-09-18 19:52:39 +02:00
} ;
2019-04-07 23:25:39 +02:00
2019-09-18 19:52:39 +02:00
getConfig ( )
. then ( ( result : any ) = > {
if ( result !== undefined ) {
let config : Config = result ;
if ( result . location === "dynamic" ) {
console . warn (
2019-09-23 23:28:01 +02:00
"Redirect URI is set to dynamic, which may affect how sign-in works for some users. Careful!"
) ;
}
if (
inDisallowedDomains ( result . registration . defaultInstance )
) {
console . warn (
` The default instance field in config.json contains an unsupported domain ( ${ result . registration . defaultInstance } ), so it's been reset to mastodon.social. `
2019-09-18 19:52:39 +02:00
) ;
2019-09-23 23:28:01 +02:00
result . registration . defaultInstance = "mastodon.social" ;
2019-09-18 19:52:39 +02:00
}
2019-05-11 18:59:36 +02:00
this . setState ( {
2019-09-18 19:52:39 +02:00
logoUrl : config.branding
? result . branding . logo
: "logo.png" ,
backgroundUrl : config.branding
? result . branding . background
: "background.png" ,
brandName : config.branding
? result . branding . name
: "Hyperspace" ,
registerBase : config.registration
? result . registration . defaultInstance
: "" ,
2019-05-11 18:59:36 +02:00
federates : config.federation.universalLogin ,
license : config.license.url ,
repo : config.repository ,
2019-09-18 19:52:39 +02:00
defaultRedirectAddress :
config . location != "dynamic"
? config . location
: ` https:// ${ window . location . host } ` ,
2019-05-11 18:59:36 +02:00
version : config.version
} ) ;
2019-05-08 15:14:46 +02:00
}
2019-09-18 19:52:39 +02:00
} )
. catch ( ( ) = > {
console . error (
"config.json is missing. If you want to customize Hyperspace, please include config.json"
) ;
} ) ;
2019-04-07 23:25:39 +02:00
}
2019-05-13 17:22:35 +02:00
componentDidMount() {
if ( localStorage . getItem ( "login" ) ) {
this . getSavedSession ( ) ;
this . setState ( {
foundSavedLogin : true
2019-09-18 19:52:39 +02:00
} ) ;
2019-05-13 17:22:35 +02:00
this . checkForToken ( ) ;
}
}
2019-04-23 19:06:31 +02:00
updateUserInfo ( user : string ) {
this . setState ( { user } ) ;
}
updateAuthCode ( code : string ) {
this . setState ( { authCode : code } ) ;
}
toggleAuthDialog() {
this . setState ( { openAuthDialog : ! this . state . openAuthDialog } ) ;
}
readyForAuth() {
2019-09-18 19:52:39 +02:00
if ( localStorage . getItem ( "baseurl" ) ) {
2019-04-23 19:06:31 +02:00
return true ;
} else {
return false ;
}
}
2019-10-03 17:16:21 +02:00
clear() {
localStorage . removeItem ( "access_token" ) ;
localStorage . removeItem ( "baseurl" ) ;
}
2019-04-23 19:06:31 +02:00
getSavedSession() {
let loginData = localStorage . getItem ( "login" ) ;
if ( loginData ) {
let session : SaveClientSession = JSON . parse ( loginData ) ;
this . setState ( {
clientId : session.clientId ,
clientSecret : session.clientSecret ,
authUrl : session.authUrl ,
emergencyMode : session.emergency
2019-09-18 19:52:39 +02:00
} ) ;
2019-04-07 23:25:39 +02:00
}
}
2019-04-23 01:05:30 +02:00
startEmergencyLogin() {
if ( ! this . state . emergencyMode ) {
this . createEmergencyLogin ( ) ;
2019-09-18 19:52:39 +02:00
}
2019-04-23 01:05:30 +02:00
this . toggleAuthDialog ( ) ;
}
2019-04-23 19:06:31 +02:00
startRegistration() {
if ( this . state . registerBase ) {
return "https://" + this . state . registerBase + "/auth/sign_up" ;
} else {
return "https://joinmastodon.org/#getting-started" ;
}
}
2019-05-13 17:22:35 +02:00
watchUsernameField ( event : any ) {
2019-09-18 19:52:39 +02:00
if ( event . keyCode === 13 ) this . startLogin ( ) ;
2019-05-13 17:22:35 +02:00
}
watchAuthField ( event : any ) {
2019-09-18 19:52:39 +02:00
if ( event . keyCode === 13 ) this . authorizeEmergencyLogin ( ) ;
2019-05-13 17:22:35 +02:00
}
2019-04-07 23:25:39 +02:00
getLoginUser ( user : string ) {
2019-04-29 20:44:05 +02:00
if ( user . includes ( "@" ) ) {
if ( this . state . federates ) {
let newUser = user ;
this . setState ( { user : newUser } ) ;
return "https://" + newUser . split ( "@" ) [ 1 ] ;
} else {
2019-09-18 19:52:39 +02:00
let newUser = ` ${ user } @ ${
this . state . registerBase
? this . state . registerBase
: "mastodon.social"
} ` ;
2019-04-29 20:44:05 +02:00
this . setState ( { user : newUser } ) ;
2019-09-18 19:52:39 +02:00
return (
"https://" +
( this . state . registerBase
? this . state . registerBase
: "mastodon.social" )
) ;
2019-04-29 20:44:05 +02:00
}
2019-04-07 23:25:39 +02:00
} else {
2019-09-18 19:52:39 +02:00
let newUser = ` ${ user } @ ${
this . state . registerBase
? this . state . registerBase
: "mastodon.social"
} ` ;
2019-04-07 23:25:39 +02:00
this . setState ( { user : newUser } ) ;
2019-09-18 19:52:39 +02:00
return (
"https://" +
( this . state . registerBase
? this . state . registerBase
: "mastodon.social" )
) ;
2019-04-07 23:25:39 +02:00
}
}
startLogin() {
2019-04-12 20:26:27 +02:00
let error = this . checkForErrors ( ) ;
if ( ! error ) {
2019-09-18 19:52:39 +02:00
const scopes = "read write follow" ;
2019-04-07 23:25:39 +02:00
const baseurl = this . getLoginUser ( this . state . user ) ;
localStorage . setItem ( "baseurl" , baseurl ) ;
2019-04-28 21:50:18 +02:00
createHyperspaceApp (
2019-09-18 19:52:39 +02:00
this . state . brandName ? this . state . brandName : "Hyperspace" ,
scopes ,
baseurl ,
2019-05-11 22:03:40 +02:00
getRedirectAddress ( this . state . defaultRedirectAddress )
2019-04-28 21:50:18 +02:00
) . then ( ( resp : any ) = > {
2019-04-07 23:25:39 +02:00
let saveSessionForCrashing : SaveClientSession = {
clientId : resp.clientId ,
clientSecret : resp.clientSecret ,
2019-04-23 01:05:30 +02:00
authUrl : resp.url ,
emergency : false
2019-09-18 19:52:39 +02:00
} ;
localStorage . setItem (
"login" ,
JSON . stringify ( saveSessionForCrashing )
) ;
2019-04-07 23:25:39 +02:00
this . setState ( {
clientId : resp.clientId ,
clientSecret : resp.clientSecret ,
authUrl : resp.url ,
2019-10-03 17:16:21 +02:00
proceedToGetCode : true
2019-09-18 19:52:39 +02:00
} ) ;
} ) ;
2019-04-07 23:25:39 +02:00
} else {
}
}
2019-04-23 01:05:30 +02:00
createEmergencyLogin() {
2019-09-18 19:52:39 +02:00
console . log ( "Creating an emergency login..." ) ;
2019-04-23 01:05:30 +02:00
const scopes = "read write follow" ;
2019-09-18 19:52:39 +02:00
const baseurl =
localStorage . getItem ( "baseurl" ) ||
this . getLoginUser ( this . state . user ) ;
2019-04-28 21:50:18 +02:00
Mastodon . registerApp (
2019-09-18 19:52:39 +02:00
this . state . brandName ? this . state . brandName : "Hyperspace" ,
2019-04-28 21:50:18 +02:00
{
scopes : scopes
2019-09-18 19:52:39 +02:00
} ,
2019-04-28 21:50:18 +02:00
baseurl
) . then ( ( appData : any ) = > {
2019-04-23 01:05:30 +02:00
let saveSessionForCrashing : SaveClientSession = {
2019-04-23 22:32:57 +02:00
clientId : appData.clientId ,
clientSecret : appData.clientSecret ,
authUrl : appData.url ,
2019-04-23 01:05:30 +02:00
emergency : true
} ;
2019-09-18 19:52:39 +02:00
localStorage . setItem (
"login" ,
JSON . stringify ( saveSessionForCrashing )
) ;
2019-04-23 01:05:30 +02:00
this . setState ( {
2019-04-23 22:32:57 +02:00
clientId : appData.clientId ,
clientSecret : appData.clientSecret ,
authUrl : appData.url
2019-04-23 01:05:30 +02:00
} ) ;
2019-04-23 22:32:57 +02:00
} ) ;
2019-04-23 01:05:30 +02:00
}
authorizeEmergencyLogin() {
2019-11-22 22:22:17 +01:00
let redirAddress =
this . state . defaultRedirectAddress === "desktop"
? "hyperspace://hyperspace/app"
: this . state . defaultRedirectAddress ;
window . location . href = ` ${ redirAddress } /?code= ${ this . state . authCode } #/ ` ;
2019-04-23 01:05:30 +02:00
}
2019-04-07 23:25:39 +02:00
resumeLogin() {
let loginData = localStorage . getItem ( "login" ) ;
if ( loginData ) {
let session : SaveClientSession = JSON . parse ( loginData ) ;
this . setState ( {
clientId : session.clientId ,
clientSecret : session.clientSecret ,
authUrl : session.authUrl ,
2019-04-23 01:05:30 +02:00
emergencyMode : session.emergency ,
2019-10-03 17:16:21 +02:00
proceedToGetCode : true
2019-09-18 19:52:39 +02:00
} ) ;
2019-04-07 23:25:39 +02:00
}
}
2019-04-12 20:26:27 +02:00
checkForErrors ( ) : boolean {
2019-04-09 22:53:00 +02:00
let userInputError = false ;
let userInputErrorMessage = "" ;
if ( this . state . user === "" ) {
userInputError = true ;
2019-04-12 20:26:27 +02:00
userInputErrorMessage = "Username cannot be blank." ;
2019-04-09 22:53:00 +02:00
this . setState ( { userInputError , userInputErrorMessage } ) ;
2019-04-12 20:26:27 +02:00
return true ;
2019-04-09 22:53:00 +02:00
} else {
if ( this . state . user . includes ( "@" ) ) {
2019-09-18 19:52:39 +02:00
if ( this . state . federates && this . state . federates === true ) {
2019-04-27 19:37:36 +02:00
let baseUrl = this . state . user . split ( "@" ) [ 1 ] ;
2019-09-23 23:28:01 +02:00
if ( inDisallowedDomains ( baseUrl ) ) {
this . setState ( {
userInputError : true ,
userInputErrorMessage : ` Signing in with an account from ${ baseUrl } isn't supported. `
2019-09-18 19:52:39 +02:00
} ) ;
2019-09-23 23:28:01 +02:00
return true ;
} else {
axios
. get (
2019-10-19 22:14:43 +02:00
"https://instances.social/api/1.0/instances/show?name=" +
baseUrl ,
{
headers : {
Authorization : ` Bearer ${ instancesBearerKey } `
}
}
2019-09-23 23:28:01 +02:00
)
. catch ( ( err : Error ) = > {
let userInputError = true ;
let userInputErrorMessage =
"Instance name is invalid." ;
this . setState ( {
userInputError ,
userInputErrorMessage
} ) ;
return true ;
} ) ;
}
2019-09-18 19:52:39 +02:00
} else if (
this . state . user . includes (
this . state . registerBase
? this . state . registerBase
: "mastodon.social"
)
) {
2019-04-27 19:37:36 +02:00
this . setState ( { userInputError , userInputErrorMessage } ) ;
return false ;
} else {
userInputError = true ;
2019-09-18 19:52:39 +02:00
userInputErrorMessage =
"You cannot sign in with this username." ;
2019-04-09 22:53:00 +02:00
this . setState ( { userInputError , userInputErrorMessage } ) ;
2019-04-12 20:26:27 +02:00
return true ;
2019-04-27 19:37:36 +02:00
}
2019-04-09 22:53:00 +02:00
} else {
this . setState ( { userInputError , userInputErrorMessage } ) ;
2019-04-12 20:26:27 +02:00
return false ;
2019-04-09 22:53:00 +02:00
}
2019-04-27 19:37:36 +02:00
this . setState ( { userInputError , userInputErrorMessage } ) ;
2019-04-12 20:26:27 +02:00
return false ;
2019-04-09 22:53:00 +02:00
}
2019-04-07 23:25:39 +02:00
}
2019-04-23 19:06:31 +02:00
checkForToken() {
let location = window . location . href ;
if ( location . includes ( "?code=" ) ) {
let code = parseUrl ( location ) . query . code as string ;
2019-10-03 17:16:21 +02:00
this . setState ( { authorizing : true } ) ;
2019-04-23 19:06:31 +02:00
let loginData = localStorage . getItem ( "login" ) ;
if ( loginData ) {
2019-09-18 19:52:39 +02:00
let clientLoginSession : SaveClientSession = JSON . parse (
loginData
) ;
2019-04-23 19:06:31 +02:00
Mastodon . fetchAccessToken (
clientLoginSession . clientId ,
clientLoginSession . clientSecret ,
code ,
2019-09-18 19:52:39 +02:00
localStorage . getItem ( "baseurl" ) as string ,
this . state . emergencyMode
? undefined
: clientLoginSession . authUrl . includes (
2019-10-03 17:16:21 +02:00
"urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob"
)
2019-09-18 19:52:39 +02:00
? undefined
: window . location . protocol === "hyperspace:"
2019-10-03 17:16:21 +02:00
? "hyperspace://hyperspace/app/"
: ` https:// ${ window . location . host } `
2019-09-18 19:52:39 +02:00
)
. then ( ( tokenData : any ) = > {
localStorage . setItem (
"access_token" ,
tokenData . access_token
) ;
window . location . href =
window . location . protocol === "hyperspace:"
? "hyperspace://hyperspace/app/"
: ` https:// ${ window . location . host } /#/ ` ;
} )
. catch ( ( err : Error ) = > {
this . props . enqueueSnackbar (
` Couldn't authorize ${
this . state . brandName
? this . state . brandName
: "Hyperspace"
} : $ { err . name } ` ,
{ variant : "error" }
) ;
console . error ( err . message ) ;
} ) ;
2019-04-23 19:06:31 +02:00
}
2019-04-07 23:25:39 +02:00
}
}
2019-05-12 20:11:21 +02:00
titlebar() {
const { classes } = this . props ;
2019-05-16 17:00:37 +02:00
if ( isDarwinApp ( ) ) {
2019-09-18 19:52:39 +02:00
return (
< div className = { classes . titleBarRoot } >
< Typography className = { classes . titleBarText } >
{ this . state . brandName
? this . state . brandName
: "Hyperspace" }
< / Typography >
< / div >
) ;
2019-05-12 20:11:21 +02:00
}
2019-09-18 19:52:39 +02:00
}
2019-05-12 20:11:21 +02:00
2019-10-03 17:16:21 +02:00
showMultiAccount() {
const { classes } = this . props ;
return (
< div >
< Typography variant = "h5" > Select an account < / Typography >
< Typography > from the list below or add a new one < / Typography >
< List >
{ getAccountRegistry ( ) . map (
( account : MultiAccount , index : number ) = > (
< ListItem
onClick = { ( ) = > {
loginWithAccount ( account ) ;
window . location . href =
window . location . protocol ===
"hyperspace:"
? "hyperspace://hyperspace/app/"
: ` https:// ${ window . location . host } /#/ ` ;
} }
button = { true }
>
< ListItemAvatar >
< AccountCircleIcon color = "action" / >
< / ListItemAvatar >
< ListItemText
primary = { ` @ ${ account . username } ` }
secondary = { account . host }
/ >
< ListItemSecondaryAction >
< IconButton
onClick = { ( e : any ) = > {
e . preventDefault ( ) ;
removeAccountFromRegistry ( index ) ;
window . location . reload ( ) ;
} }
>
< CloseIcon / >
< / IconButton >
< / ListItemSecondaryAction >
< / ListItem >
)
) }
< / List >
< div className = { classes . middlePadding } / >
< Button
onClick = { ( ) = > {
this . setState ( { willAddAccount : true } ) ;
this . clear ( ) ;
} }
color = { "primary" }
variant = { "contained" }
>
Add Account
< / Button >
< / div >
) ;
}
2019-04-07 23:25:39 +02:00
showLanding() {
const { classes } = this . props ;
return (
2019-09-18 19:52:39 +02:00
< div >
< Typography variant = "h5" > Sign in < / Typography >
< Typography > with your Mastodon account < / Typography >
< div className = { classes . middlePadding } / >
< TextField
variant = "outlined"
label = "Username"
fullWidth
placeholder = "example@mastodon.example"
onChange = { event = > this . updateUserInfo ( event . target . value ) }
onKeyDown = { event = > this . watchUsernameField ( event ) }
error = { this . state . userInputError }
onBlur = { ( ) = > this . checkForErrors ( ) }
2019-10-03 17:16:21 +02:00
/ >
2019-09-18 19:52:39 +02:00
{ this . state . userInputError ? (
< Typography color = "error" >
{ this . state . userInputErrorMessage }
< / Typography >
) : null }
< br / >
{ this . state . registerBase && this . state . federates ? (
< Typography variant = "caption" >
Not from { " " }
< b >
{ this . state . registerBase
? this . state . registerBase
: "noinstance" }
< / b >
? Sign in with your { " " }
< Link
href = "https://docs.joinmastodon.org/usage/decentralization/#addressing-people"
target = "_blank"
rel = "noopener noreferrer"
color = "secondary"
>
full username
< / Link >
.
< / Typography >
) : null }
< br / >
{ this . state . foundSavedLogin ? (
< Typography >
Signing in from a previous session ? { " " }
< Link
className = { classes . welcomeLink }
onClick = { ( ) = > this . resumeLogin ( ) }
>
Continue login
< / Link >
.
< / Typography >
) : null }
< div className = { classes . middlePadding } / >
< div style = { { display : "flex" } } >
< Tooltip title = "Create account on site" >
< Button
href = { this . startRegistration ( ) }
target = "_blank"
rel = "noreferrer"
>
Create account
< / Button >
< / Tooltip >
< div className = { classes . flexGrow } / >
< Tooltip title = "Continue sign-in" >
< Button
color = "primary"
variant = "contained"
onClick = { ( ) = > this . startLogin ( ) }
>
Next
< / Button >
< / Tooltip >
2019-04-07 23:25:39 +02:00
< / div >
2019-09-18 19:52:39 +02:00
< / div >
2019-04-07 23:25:39 +02:00
) ;
}
showLoginAuth() {
const { classes } = this . props ;
return (
2019-09-18 19:52:39 +02:00
< div >
< Typography variant = "h5" >
Howdy , { " " }
{ this . state . user ? this . state . user . split ( "@" ) [ 0 ] : "user" }
< / Typography >
< Typography >
To continue , finish signing in on your instance ' s website
and authorize { " " }
{ this . state . brandName ? this . state . brandName : "Hyperspace" }
.
< / Typography >
< div className = { classes . middlePadding } / >
< div style = { { display : "flex" } } >
< div className = { classes . flexGrow } / >
< Button
color = "primary"
variant = "contained"
size = "large"
href = { this . state . authUrl ? this . state . authUrl : "" }
>
Authorize
< / Button >
< div className = { classes . flexGrow } / >
2019-04-07 23:25:39 +02:00
< / div >
2019-09-18 19:52:39 +02:00
< div className = { classes . middlePadding } / >
< Typography >
Having trouble signing in ? { " " }
< Link
onClick = { ( ) = > this . startEmergencyLogin ( ) }
className = { classes . welcomeLink }
>
Sign in with a code .
< / Link >
< / Typography >
< / div >
2019-04-07 23:25:39 +02:00
) ;
}
2019-04-23 01:05:30 +02:00
showAuthDialog() {
2019-09-18 19:52:39 +02:00
const { classes } = this . props ;
2019-04-23 01:05:30 +02:00
return (
< Dialog
open = { this . state . openAuthDialog }
disableBackdropClick
disableEscapeKeyDown
maxWidth = "sm"
fullWidth = { true }
>
2019-09-18 19:52:39 +02:00
< DialogTitle > Authorize with a code < / DialogTitle >
2019-04-23 01:05:30 +02:00
< DialogContent >
< Typography paragraph >
2019-09-18 19:52:39 +02:00
If you ' re having trouble authorizing Hyperspace , you can
manually request for an authorization code . Click
'Request Code' and then paste the code in the
authorization code box to continue .
2019-04-23 01:05:30 +02:00
< / Typography >
< Button
2019-09-18 19:52:39 +02:00
color = "primary"
variant = "contained"
href = { this . state . authUrl ? this . state . authUrl : "" }
2019-04-23 01:05:30 +02:00
target = "_blank"
rel = "noopener noreferrer"
2019-09-18 19:52:39 +02:00
>
Request Code
< / Button >
< br / >
< br / >
2019-04-23 01:05:30 +02:00
< TextField
variant = "outlined"
label = "Authorization code"
fullWidth
2019-09-18 19:52:39 +02:00
onChange = { event = >
this . updateAuthCode ( event . target . value )
}
onKeyDown = { event = > this . watchAuthField ( event ) }
2019-10-03 17:16:21 +02:00
/ >
2019-04-23 01:05:30 +02:00
< / DialogContent >
< DialogActions >
2019-09-18 19:52:39 +02:00
< Button onClick = { ( ) = > this . toggleAuthDialog ( ) } >
Cancel
< / Button >
< Button
color = "secondary"
onClick = { ( ) = > this . authorizeEmergencyLogin ( ) }
>
Authorize
< / Button >
2019-04-23 01:05:30 +02:00
< / DialogActions >
< / Dialog >
) ;
}
2019-10-03 17:16:21 +02:00
showAuthorizationLoader() {
2019-04-07 23:25:39 +02:00
const { classes } = this . props ;
return (
2019-09-18 19:52:39 +02:00
< div >
< Typography variant = "h5" > Authorizing < / Typography >
< Typography >
Please wait while Hyperspace authorizes with Mastodon . This
shouldn ' t take long . . .
< / Typography >
< div className = { classes . middlePadding } / >
< div style = { { display : "flex" } } >
< div className = { classes . flexGrow } / >
< CircularProgress / >
< div className = { classes . flexGrow } / >
2019-04-07 23:25:39 +02:00
< / div >
2019-09-18 19:52:39 +02:00
< div className = { classes . middlePadding } / >
< / div >
2019-04-07 23:25:39 +02:00
) ;
}
render() {
const { classes } = this . props ;
return (
2019-05-12 20:11:21 +02:00
< div >
{ this . titlebar ( ) }
2019-09-18 19:52:39 +02:00
< div
className = { classes . root }
style = { {
backgroundImage : ` url( ${
this . state !== null
? this . state . backgroundUrl
: "background.png"
} ) `
} }
>
2019-05-12 20:11:21 +02:00
< Paper className = { classes . paper } >
2019-09-18 19:52:39 +02:00
< img
className = { classes . logo }
alt = {
this . state ? this . state . brandName : "Hyperspace"
2019-05-12 20:11:21 +02:00
}
2019-09-18 19:52:39 +02:00
src = { this . state ? this . state . logoUrl : "logo.png" }
/ >
< br / >
< Fade in = { true } >
2019-10-03 17:16:21 +02:00
{ this . state . authorizing
? this . showAuthorizationLoader ( )
: this . state . proceedToGetCode
? this . showLoginAuth ( )
: getAccountRegistry ( ) . length > 0 &&
! this . state . willAddAccount
? this . showMultiAccount ( )
: this . showLanding ( ) }
2019-05-12 20:11:21 +02:00
< / Fade >
2019-09-18 19:52:39 +02:00
< br / >
2019-05-12 20:11:21 +02:00
< Typography variant = "caption" >
2019-09-18 19:52:39 +02:00
& copy ; { new Date ( ) . getFullYear ( ) } { " " }
{ this . state . brandName &&
this . state . brandName !== "Hyperspace"
? ` ${ this . state . brandName } developers and the `
: "" } { " " }
< Link
className = { classes . welcomeLink }
href = "https://hyperspace.marquiskurt.net"
target = "_blank"
rel = "noreferrer"
>
Hyperspace
< / Link > { " " }
developers . All rights reserved .
2019-05-12 20:11:21 +02:00
< / Typography >
< Typography variant = "caption" >
2019-09-18 19:52:39 +02:00
{ this . state . repo ? (
< span >
< Link
className = { classes . welcomeLink }
href = {
this . state . repo
? this . state . repo
: "https://github.com/hyperspacedev"
}
target = "_blank"
rel = "noreferrer"
>
Source code
< / Link > { " " }
| { " " }
< / span >
) : null }
< Link
className = { classes . welcomeLink }
href = {
this . state . license
? this . state . license
: "https://www.apache.org/licenses/LICENSE-2.0"
}
target = "_blank"
rel = "noreferrer"
>
License
< / Link > { " " }
|
< Link
className = { classes . welcomeLink }
href = "https://github.com/hyperspacedev/hyperspace/issues/new"
target = "_blank"
rel = "noreferrer"
>
File an Issue
< / Link >
2019-05-12 20:11:21 +02:00
< / Typography >
< Typography variant = "caption" color = "textSecondary" >
2019-09-18 19:52:39 +02:00
{ this . state . brandName
? this . state . brandName
: "Hypersapce" } { " " }
2019-09-23 23:28:01 +02:00
v .
{ this . state . version } { " " }
2019-09-18 19:52:39 +02:00
{ this . state . brandName &&
this . state . brandName !== "Hyperspace"
? "(Hyperspace-like)"
: null }
2019-05-12 20:11:21 +02:00
< / Typography >
< / Paper >
{ this . showAuthDialog ( ) }
< / div >
< / div >
2019-04-07 23:25:39 +02:00
) ;
}
}
2019-10-03 17:16:21 +02:00
export default withStyles ( styles ) ( withSnackbar ( WelcomePage ) ) ;