summaryrefslogtreecommitdiff
path: root/ui/app/components/wizard
diff options
context:
space:
mode:
authorelijah <elijah@riseup.net>2016-09-21 15:39:03 -0700
committerKali Kaneko (leap communications) <kali@leap.se>2016-09-22 11:40:14 -0400
commit7569ac8bd58174095f3f897548e26d0ba905236c (patch)
tree839c300d7dff62900bcc91672a3b55cf62c31f6c /ui/app/components/wizard
parent61b5734c12d6ab6733d3a832df8d99f1041bf355 (diff)
[feat] the setup wizard for the new ui
Diffstat (limited to 'ui/app/components/wizard')
-rw-r--r--ui/app/components/wizard/add_provider_modal.js61
-rw-r--r--ui/app/components/wizard/index.js19
-rw-r--r--ui/app/components/wizard/provider_select_stage.js168
-rw-r--r--ui/app/components/wizard/register_stage.js102
4 files changed, 286 insertions, 64 deletions
diff --git a/ui/app/components/wizard/add_provider_modal.js b/ui/app/components/wizard/add_provider_modal.js
index bc5e0236..d54ec085 100644
--- a/ui/app/components/wizard/add_provider_modal.js
+++ b/ui/app/components/wizard/add_provider_modal.js
@@ -3,12 +3,13 @@
//
import React from 'react'
-import { FormGroup, ControlLabel, FormControl, HelpBlock, Button, Modal } from 'react-bootstrap'
-import Spinner from '../spinner'
-import Validate from '../../lib/validate'
-import App from '../../app'
+import { FormGroup, ControlLabel, FormControl, HelpBlock, Button, ButtonToolbar, Modal } from 'react-bootstrap'
-class AddProviderModal extends React.Component {
+import Spinner from 'components/spinner'
+import Validate from 'lib/validate'
+import Provider from 'models/provider'
+
+export default class AddProviderModal extends React.Component {
static get defaultProps() {return{
title: 'Add a provider',
@@ -18,20 +19,36 @@ class AddProviderModal extends React.Component {
constructor(props) {
super(props)
this.state = {
- validationState: null,
+ validationState: null, // one of 'success', 'error', 'warning'
errorMsg: null,
- domain: ""
+ domain: "",
+ working: false, // true if waiting for something
}
this.accept = this.accept.bind(this)
this.cancel = this.cancel.bind(this)
this.changed = this.changed.bind(this)
}
- accept() {
+ accept(e=null) {
+ if (e) {
+ e.preventDefault() // don't reload the page please!
+ }
if (this.state.domain) {
- App.providers.add(this.state.domain)
+ this.setState({working: true})
+ Provider.setup(this.state.domain).then(
+ provider => {
+ this.props.onClose(provider)
+ // this.setState({working: false})
+ },
+ error => {
+ this.setState({
+ validationState: 'warning',
+ errorMsg: error,
+ working: false
+ })
+ }
+ )
}
- this.props.onClose()
}
cancel() {
@@ -44,9 +61,9 @@ class AddProviderModal extends React.Component {
let newMsg = null
if (domain.length > 0) {
- let error = Validate.domain(domain)
- newState = error ? 'error' : 'success'
- newMsg = error
+ let msg = Validate.domain(domain)
+ newState = msg ? 'error' : 'success'
+ newMsg = msg
}
this.setState({
domain: domain,
@@ -57,11 +74,21 @@ class AddProviderModal extends React.Component {
render() {
let help = null
+ let addButton = null
if (this.state.errorMsg) {
help = <HelpBlock>{this.state.errorMsg}</HelpBlock>
} else {
help = <HelpBlock>&nbsp;</HelpBlock>
}
+ if (this.state.working) {
+ addButton = <Button><Spinner /></Button>
+ } else if (this.state.validationState == 'warning') {
+ addButton = <Button onClick={this.accept}>Retry</Button>
+ } else if (this.state.validationState == 'error') {
+ addButton = <Button disabled={true}>Add</Button>
+ } else {
+ addButton = <Button onClick={this.accept}>Add</Button>
+ }
let form = <form onSubmit={this.accept} autoComplete="off">
<FormGroup controlId="addprovider" validationState={this.state.validationState}>
<ControlLabel>Domain</ControlLabel>
@@ -72,10 +99,12 @@ class AddProviderModal extends React.Component {
value={this.state.domain}
onChange={this.changed}
onBlur={this.changed} />
- <FormControl.Feedback/>
{help}
</FormGroup>
- <Button onClick={this.accept}>Add</Button>
+ <ButtonToolbar>
+ {addButton}
+ <Button onClick={this.cancel}>Cancel</Button>
+ </ButtonToolbar>
</form>
return(
@@ -90,5 +119,3 @@ class AddProviderModal extends React.Component {
)
}
}
-
-export default AddProviderModal \ No newline at end of file
diff --git a/ui/app/components/wizard/index.js b/ui/app/components/wizard/index.js
index 613b88fd..75e3a1d8 100644
--- a/ui/app/components/wizard/index.js
+++ b/ui/app/components/wizard/index.js
@@ -6,26 +6,27 @@ import React from 'react'
import App from 'app'
import ProviderSelectStage from './provider_select_stage'
+import RegisterStage from './register_stage'
import './wizard.less'
export default class Wizard extends React.Component {
+ static get defaultProps() {return{
+ stage: "provider"
+ }}
+
constructor(props) {
super(props)
- this.state = {
- stage: 'provider'
- }
- }
-
- setStage(stage) {
- this.setState({stage: stage})
}
render() {
let stage = null
- switch(this.state.stage) {
+ switch(this.props.stage) {
case 'provider':
- stage = <ProviderSelectStage />
+ stage = <ProviderSelectStage {...this.props}/>
+ break
+ case 'register':
+ stage = <RegisterStage {...this.props}/>
break
}
return(
diff --git a/ui/app/components/wizard/provider_select_stage.js b/ui/app/components/wizard/provider_select_stage.js
index 20674be1..19799f86 100644
--- a/ui/app/components/wizard/provider_select_stage.js
+++ b/ui/app/components/wizard/provider_select_stage.js
@@ -2,7 +2,11 @@ import React from 'react'
import {Button, ButtonGroup, ButtonToolbar, Glyphicon} from 'react-bootstrap'
import App from 'app'
-import ListEdit from 'components/list_edit'
+import Provider from 'models/provider'
+
+import ListEditor from 'components/list_editor'
+import {HorizontalLayout, Column} from 'components/layout'
+
import StageLayout from './stage_layout'
import AddProviderModal from './add_provider_modal'
@@ -10,75 +14,163 @@ export default class ProviderSelectStage extends React.Component {
static get defaultProps() {return{
title: "Choose a provider",
- subtitle: "This doesn't work yet"
+ initialProvider: null
}}
constructor(props) {
super(props)
- let domains = this.currentDomains()
this.state = {
- domains: domains,
- showModal: false
+ domains: [], // array of domains, as strings
+ showModal: false,
+ selected: null, // domain of selected item
+ provider: null, // Provider object, if selected
+ error: null // error message
}
- this.add = this.add.bind(this)
- this.remove = this.remove.bind(this)
- this.close = this.close.bind(this)
- this.previous = this.previous.bind(this)
+ this.add = this.add.bind(this)
+ this.remove = this.remove.bind(this)
+ this.select = this.select.bind(this)
+ this.close = this.close.bind(this)
+ this.cancel = this.cancel.bind(this)
+ this.next = this.next.bind(this)
+ }
+
+ componentWillMount() {
+ this.refreshList({
+ provider: this.props.initialProvider,
+ selected: (this.props.initialProvider ? this.props.initialProvider.domain : null)
+ })
}
- currentDomains() {
- // return(App.providers.domains().slice() || [])
- return ['domain1', 'domain2', 'domain3']
+ //
+ // newState is the state to apply after
+ // domains are refreshed
+ //
+ refreshList(newState=null) {
+ Provider.list(true).then(domains => {
+ this.setState(Object.assign({domains: domains}, newState))
+ if (domains.length > 0) {
+ let domain = this.state.selected
+ if (domains.includes(domain)) {
+ this.select(domain)
+ } else {
+ this.select(domains[0])
+ }
+ } else {
+ this.select(null)
+ }
+ })
}
add() {
this.setState({showModal: true})
}
- remove(provider) {
- // App.providers.remove(provider)
- this.setState({domains: this.currentDomains()})
+ remove(domain, newactive) {
+ Provider.delete(domain).then(
+ response => {
+ this.refreshList({selected: newactive})
+ },
+ error => {
+ console.log(error)
+ }
+ )
}
- close() {
- let domains = this.currentDomains()
- if (domains.length != this.state.domains.length) {
- // this is ugly, but i could not get selection working
- // by passing it as a property
- this.refs.list.setSelected(0)
- }
+ select(domain) {
this.setState({
- domains: domains,
- showModal: false
+ selected: domain
})
+ if (domain) {
+ Provider.get(domain).then(
+ provider => {
+ this.setState({
+ provider: provider
+ })
+ },
+ error => {
+ this.setState({
+ provider: null,
+ error: error
+ })
+ }
+ )
+ } else {
+ this.setState({
+ provider: null,
+ error: null
+ })
+ }
+ }
+
+ close(provider=null) {
+ if (provider) {
+ this.refreshList({
+ showModal: false,
+ provider: provider,
+ selected: provider.domain
+ })
+ } else {
+ this.setState({
+ showModal: false
+ })
+ }
}
- previous() {
+ cancel() {
App.start()
}
+ next() {
+ App.show('wizard', {
+ stage: 'register',
+ provider: this.state.provider
+ })
+ }
+
render() {
let modal = null
+ let info = null
+ if (this.state.provider) {
+ info = (
+ <div>
+ <h1 className="first">{this.state.provider.name}</h1>
+ <h3>{this.state.provider.domain}</h3>
+ <p>{this.state.provider.description}</p>
+ <p><b>Enrollment Policy:</b> {this.state.provider.enrollment_policy}</p>
+ <p><b>Services</b>: {this.state.provider.services}</p>
+ <p><b>Languages</b>: {this.state.provider.languages.join(', ')}</p>
+ </div>
+ )
+ } else if (this.state.error) {
+ info = <div>{this.state.error}</div>
+ }
if (this.state.showModal) {
modal = <AddProviderModal onClose={this.close} />
}
let buttons = (
- <ButtonToolbar className="pull-right">
- <Button onClick={this.previous}>
- <Glyphicon glyph="chevron-left" />
- Previous
- </Button>
- <Button>
- Next
- <Glyphicon glyph="chevron-right" />
- </Button>
- </ButtonToolbar>
+ <div>
+ <ButtonToolbar className="pull-left">
+ <Button onClick={this.cancel}>
+ Cancel
+ </Button>
+ </ButtonToolbar>
+ <ButtonToolbar className="pull-right">
+ <Button onClick={this.next}>
+ Next
+ <Glyphicon glyph="chevron-right" />
+ </Button>
+ </ButtonToolbar>
+ </div>
)
- let select = <ListEdit ref="list" items={this.state.domains}
- onRemove={this.remove} onAdd={this.add} />
+ let editlist = <ListEditor ref="list" items={this.state.domains}
+ selected={this.state.selected} onRemove={this.remove} onAdd={this.add}
+ onSelect={this.select} />
return(
<StageLayout title={this.props.title} subtitle={this.props.subtitle} buttons={buttons}>
- {select}
+ <HorizontalLayout equalWidths={true}>
+ <Column>{editlist}</Column>
+ <Column>{info}</Column>
+ </HorizontalLayout>
{modal}
</StageLayout>
)
diff --git a/ui/app/components/wizard/register_stage.js b/ui/app/components/wizard/register_stage.js
new file mode 100644
index 00000000..9afa9587
--- /dev/null
+++ b/ui/app/components/wizard/register_stage.js
@@ -0,0 +1,102 @@
+import React from 'react'
+import {Button, ButtonGroup, ButtonToolbar,
+ Glyphicon, Tabs, Tab} from 'react-bootstrap'
+
+import App from 'app'
+import Provider from 'models/provider'
+import Login from 'components/login'
+import Center from 'components/center'
+
+import StageLayout from './stage_layout'
+
+export default class RegisterStage extends React.Component {
+
+ static get defaultProps() {return{
+ provider: null
+ }}
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ activeTab: 'signup', // either 'login' or 'signup'
+ error: null // error message
+ }
+ // this.add = this.add.bind(this)
+ // this.remove = this.remove.bind(this)
+ // this.select = this.select.bind(this)
+ this.selectTab = this.selectTab.bind(this)
+ this.previous = this.previous.bind(this)
+ this.cancel = this.cancel.bind(this)
+ this.login = this.login.bind(this)
+ }
+
+ previous() {
+ App.show('wizard', {
+ stage: 'provider',
+ initialProvider: this.props.provider
+ })
+ }
+
+ cancel() {
+ App.start()
+ }
+
+ login(account) {
+ App.show('main', {initialAccount: account})
+ }
+
+ selectTab(key) {
+ this.setState({
+ activeTab: key
+ })
+ }
+
+ render() {
+ let info = null
+ if (this.props.provider) {
+ info = (
+ <div>
+ <h1 className="first">{this.props.provider.name}</h1>
+ <h3>{this.props.provider.domain}</h3>
+ <p>{this.props.provider.description}</p>
+ <p><b>Enrollment Policy:</b> {this.props.provider.enrollment_policy}</p>
+ <p><b>Services</b>: {this.props.provider.services}</p>
+ <p><b>Languages</b>: {this.props.provider.languages.join(', ')}</p>
+ </div>
+ )
+ }
+ let buttons = (
+ <div>
+ <ButtonToolbar className="pull-left">
+ <Button onClick={this.cancel}>
+ Cancel
+ </Button>
+ </ButtonToolbar>
+ <ButtonToolbar className="pull-right">
+ <Button onClick={this.previous}>
+ <Glyphicon glyph="chevron-left" />
+ Previous
+ </Button>
+ </ButtonToolbar>
+ </div>
+ )
+ return(
+ <StageLayout title={this.props.provider.domain} buttons={buttons}>
+ <Tabs activeKey={this.state.activeTab} onSelect={this.selectTab} animation={false} id="login-tabs">
+ <Tab eventKey="signup" title="Sign up">
+ <div className="vspacer" />
+ <Center direction="horizontal" width={400}>
+ <Login mode="signup" domain={this.props.provider.domain} onLogin={this.login} />
+ </Center>
+ </Tab>
+ <Tab eventKey="login" title="Log In">
+ <div className="vspacer" />
+ <Center direction="horizontal" width={400}>
+ <Login domain={this.props.provider.domain} onLogin={this.login} />
+ </Center>
+ </Tab>
+ </Tabs>
+ </StageLayout>
+ )
+ }
+}