diff options
Diffstat (limited to 'ui/app/components')
| -rw-r--r-- | ui/app/components/center.js | 6 | ||||
| -rw-r--r-- | ui/app/components/greeter_panel.js | 6 | ||||
| -rw-r--r-- | ui/app/components/layout/index.js | 41 | ||||
| -rw-r--r-- | ui/app/components/layout/layout.less | 25 | ||||
| -rw-r--r-- | ui/app/components/list_editor/index.js (renamed from ui/app/components/list_edit.js) | 65 | ||||
| -rw-r--r-- | ui/app/components/list_editor/list_editor.less | 29 | ||||
| -rw-r--r-- | ui/app/components/login.js | 130 | ||||
| -rw-r--r-- | ui/app/components/main_panel/email_section.js | 2 | ||||
| -rw-r--r-- | ui/app/components/main_panel/index.js | 2 | ||||
| -rw-r--r-- | ui/app/components/main_panel/user_section.js | 10 | ||||
| -rw-r--r-- | ui/app/components/panel_switcher.js | 11 | ||||
| -rw-r--r-- | ui/app/components/wizard/add_provider_modal.js | 61 | ||||
| -rw-r--r-- | ui/app/components/wizard/index.js | 19 | ||||
| -rw-r--r-- | ui/app/components/wizard/provider_select_stage.js | 168 | ||||
| -rw-r--r-- | ui/app/components/wizard/register_stage.js | 102 | 
15 files changed, 544 insertions, 133 deletions
| diff --git a/ui/app/components/center.js b/ui/app/components/center.js index 6fa62128..5e47d0cc 100644 --- a/ui/app/components/center.js +++ b/ui/app/components/center.js @@ -7,7 +7,8 @@ import React from 'react'  class Center extends React.Component {    static get defaultProps() {return{ -    width: null +    width: null, +    direction: 'both',    }}    constructor(props) { @@ -19,8 +20,9 @@ class Center extends React.Component {      if (this.props.width) {        style = {width: this.props.width + 'px'}      } +    let className = "center-container center-" + this.props.direction      return ( -      <div className="center-container"> +      <div className={className}>          <div className="center-item" style={style}>            {this.props.children}          </div> diff --git a/ui/app/components/greeter_panel.js b/ui/app/components/greeter_panel.js index 4552db18..c95b183a 100644 --- a/ui/app/components/greeter_panel.js +++ b/ui/app/components/greeter_panel.js @@ -16,12 +16,16 @@ export default class GreeterPanel extends React.Component {      App.show('wizard')    } +  onLogin(account) { +    App.show('main', {initialAccount: account}) +  } +    render () {      return <div>        <Splash speed="slow" mask={false} />        <Center width="400">          <Area position="top" type="light" className="greeter"> -          <Login {...this.props} rememberAllowed={false}/> +          <Login onLogin={this.onLogin.bind(this)} rememberAllowed={false}/>          </Area>          <Area position="bottom" type="dark" className="greeter">            <Glyphicon glyph="user" /> diff --git a/ui/app/components/layout/index.js b/ui/app/components/layout/index.js new file mode 100644 index 00000000..8e7c4b58 --- /dev/null +++ b/ui/app/components/layout/index.js @@ -0,0 +1,41 @@ +import React from 'react' + +import './layout.less' + +class HorizontalLayout extends React.Component { +  static get defaultProps() {return{ +    equalWidths: false +  }} + +  constructor(props) { +    super(props) +  } + +  render() { +    let className = "horizontal-layout" +    if (this.props.equalWidths) { +      className = className + " equal" + this.props.children.length +    } +    return ( +      <div className={className}> +        {this.props.children} +      </div> +    ) +  } +} + +class Column extends React.Component { +  constructor(props) { +    super(props) +  } + +  render() { +    return ( +      <div className="layout-column"> +        {this.props.children} +      </div> +    ) +  } +} + +export {HorizontalLayout, Column}
\ No newline at end of file diff --git a/ui/app/components/layout/layout.less b/ui/app/components/layout/layout.less new file mode 100644 index 00000000..dae99aa3 --- /dev/null +++ b/ui/app/components/layout/layout.less @@ -0,0 +1,25 @@ +@gutter: 20px; + +.horizontal-layout { +  display: -webkit-flex; +  display: flex; +  -webkit-flex-direction: row; +  flex-direction: row; +  -webkit-flex: 1 1 auto; +  flex: 1 1 auto; +  > .layout-column { +    display: -webkit-flex; +    display: flex; +    -webkit-flex: 1 1 auto; +    flex: 1 1 auto; +    margin-right: @gutter; +  } +  > .layout-column:last-child { +    margin-right: 0px; +  } +} + +.horizontal-layout.equal1 > .layout-column {width: 100%;} +.horizontal-layout.equal2 > .layout-column {width: 50%;} +.horizontal-layout.equal3 > .layout-column {width: 33.33%;} +.horizontal-layout.equal4 > .layout-column {width: 25%;}
\ No newline at end of file diff --git a/ui/app/components/list_edit.js b/ui/app/components/list_editor/index.js index 0d557d22..58b6ec44 100644 --- a/ui/app/components/list_edit.js +++ b/ui/app/components/list_editor/index.js @@ -6,22 +6,7 @@  import React from 'react'  import {Button, ButtonGroup, ButtonToolbar, Glyphicon, FormControl} from 'react-bootstrap' -const CONTAINER_CSS = { -  display: "flex", -  flexDirection: "column" -} -const SELECT_CSS = { -  padding: "0px", -  flex: "1 1 1000px", -  overflowY: "scroll" -} -const OPTION_CSS = { -  padding: "10px" -} -const TOOLBAR_CSS = { -  paddingTop: "10px", -  flex: "0 0 auto" -} +import './list_editor.less'  class ListEdit extends React.Component { @@ -32,35 +17,29 @@ class ListEdit extends React.Component {        'bbbbbbb',        'ccccccc'      ], -    selected: null, +    selected: null,  // string of the selected item      onRemove: null,      onAdd: null, +    onSelect: null    }}    constructor(props) {      super(props) -    let index = 0 -    if (props.selected) { -      index = props.items.indexOf(props.selected) -    } -    this.state = { -      selected: index -    }      this.click  = this.click.bind(this)      this.add    = this.add.bind(this)      this.remove = this.remove.bind(this)    } -  setSelected(index) { -    this.setState({ -      selected: index -    }) +  row(str) { +    return this.props.items.indexOf(str)    }    click(e) {      let row = parseInt(e.target.value)      if (row >= 0) { -      this.setState({selected: row}) +      if (this.props.onSelect) { +        this.props.onSelect(this.props.items[row]) +      }      }    } @@ -71,13 +50,17 @@ class ListEdit extends React.Component {    }    remove() { -    if (this.state.selected >= 0 && this.props.onRemove) { -      if (this.props.items.length == this.state.selected + 1) { -        // if we remove the last item, set the selected item -        // to the one right before it. -        this.setState({selected: (this.state.selected - 1)}) +    if (this.props.onRemove) { +      let currentRow = this.row(this.props.selected) +      let newSelected = null +      if (this.props.items.length == currentRow + 1) { +        // if we remove the last item, set the new selected to be +        // the new last item. +        newSelected = this.props.items[currentRow - 1] +      } else { +        newSelected = this.props.items[currentRow + 1]        } -      this.props.onRemove(this.props.items[this.state.selected]) +      this.props.onRemove(this.props.selected, newSelected)      }    } @@ -85,23 +68,23 @@ class ListEdit extends React.Component {      let options = null      if (this.props.items) {        options = this.props.items.map((item, i) => { -        return <option style={OPTION_CSS} key={i} value={i}>{item}</option> +        return <option className="list-option" key={i} value={i}>{item}</option>        }, this)      }      return( -      <div style={CONTAINER_CSS}> +      <div className="list-editor">          <FormControl -          value={this.state.selected} -          style={SELECT_CSS} className="select-list" +          value={this.row(this.props.selected)} +          className="list-select"            componentClass="select" size="5" onChange={this.click}>            {options}          </FormControl> -        <ButtonToolbar className="pull-right" style={TOOLBAR_CSS}> +        <ButtonToolbar className="pull-right list-toolbar">            <ButtonGroup>              <Button onClick={this.add}>                <Glyphicon glyph="plus" />              </Button> -            <Button disabled={this.state.selected < 0} onClick={this.remove}> +            <Button disabled={this.props.selected < 0} onClick={this.remove}>                <Glyphicon glyph="minus" />              </Button>            </ButtonGroup> diff --git a/ui/app/components/list_editor/list_editor.less b/ui/app/components/list_editor/list_editor.less new file mode 100644 index 00000000..e2d2e55c --- /dev/null +++ b/ui/app/components/list_editor/list_editor.less @@ -0,0 +1,29 @@ +.list-editor { + +  display: -webkit-flex; +  display: flex; + +  -webkit-flex-direction: column; +  flex-direction: column; + +  -webkit-flex: 1 1 auto; +  flex: 1 1 auto; + +  .list-select { +    padding: 0px; +    flex: 1 1 1000px; +    -webkit-flex: 1 1 1000px; +    overflow-y: scroll; +  } + +  .list-option { +    padding: 10px; +  } + +  .list-toolbar { +    padding-top: 10px; + +    -webkit-flex: 0 0 auto; +    flex: 0 0 auto; +  } +} diff --git a/ui/app/components/login.js b/ui/app/components/login.js index fe4ef5b2..562ab5ac 100644 --- a/ui/app/components/login.js +++ b/ui/app/components/login.js @@ -14,7 +14,9 @@ class Login extends React.Component {    static get defaultProps() {return{      rememberAllowed: false,   // if set, show remember password checkbox      domain: null,             // if set, only allow this domain -    onLogin: null +    address: null,            // if set, only allow this username@domain +    onLogin: null,            // callback +    mode: "login"             // one of "login" or "signup"    }}    constructor(props) { @@ -27,14 +29,18 @@ class Login extends React.Component {        authError: false,     // authentication error message -      username: "etest1@riseup.net", +      username: this.props.address,        usernameState: null,  // username validation state        usernameError: false, // username help message -      password: "whatever", +      password: null,        passwordState: null,  // password validation state        passwordError: false, // password help message +      password2: null,         // password confirmation +      password2State: null,  // password confirm validation state +      password2Error: false, // password confirm help message +        disabled: false,        remember: false       // remember is checked?      } @@ -42,9 +48,10 @@ class Login extends React.Component {      // prebind:      this.onUsernameChange = this.onUsernameChange.bind(this)      this.onUsernameBlur   = this.onUsernameBlur.bind(this) -    this.onPassword = this.onPassword.bind(this) -    this.onSubmit   = this.onSubmit.bind(this) -    this.onRemember = this.onRemember.bind(this) +    this.onPassword  = this.onPassword.bind(this) +    this.onPassword2 = this.onPassword2.bind(this) +    this.onSubmit    = this.onSubmit.bind(this) +    this.onRemember  = this.onRemember.bind(this)    }    componentDidMount() { @@ -56,8 +63,14 @@ class Login extends React.Component {      let submitButton  = ""      let usernameHelp  = null      let passwordHelp  = null +    let password2Help  = null +    let password2Elem  = null      let message = null +    let buttonText = "Log In" +    /* +     * disabled for now +     *      if (this.props.rememberAllowed) {        let props = {          style: {marginTop: "0px"}, @@ -74,6 +87,7 @@ class Login extends React.Component {          </Checkbox>        }      } +    */      if (this.state.authError) {        // style may be: success, warning, danger, info @@ -108,6 +122,25 @@ class Login extends React.Component {        //passwordHelp = <HelpBlock> </HelpBlock>      } +    if (this.props.mode == 'signup') { +      buttonText = 'Sign Up' +      if (this.state.password2Error) { + +      } +      password2Elem = ( +        <FormGroup controlId="loginPassword2" validationState={this.state.password2State}> +          <ControlLabel>Repeat Password</ControlLabel> +          <FormControl +            type="password" +            ref="password" +            value={this.state.password2 || ""} +            onChange={this.onPassword2} /> +          {this.state.password2State == 'success' ? null : <FormControl.Feedback/>} +          {password2Help} +        </FormGroup> +      ) +    } +      let buttonProps = {        type: "button",        onClick: this.onSubmit, @@ -116,11 +149,16 @@ class Login extends React.Component {      if (this.state.loading) {         submitButton = <Button block {...buttonProps}><Spinner /></Button>      } else { -       submitButton = <Button block {...buttonProps}>Log In</Button> +       submitButton = <Button block {...buttonProps}>{buttonText}</Button>      }      let usernameref = null -    if (this.props.domain) { +    let usernameDisabled = false +    let usernameValue = this.state.username || "" +    if (this.props.address) { +      usernameDisabled = true +      usernameValue = this.props.address +    } else if (this.props.domain) {        usernameref = function(c) {          if (c != null) {            let textarea = ReactDOM.findDOMNode(c) @@ -142,7 +180,8 @@ class Login extends React.Component {            rows="1"            ref={usernameref}            autoFocus -          value={this.state.username} +          value={usernameValue} +          disabled={usernameDisabled}            onChange={this.onUsernameChange}            onBlur={this.onUsernameBlur} />          {this.state.usernameState == 'success' ? null : <FormControl.Feedback/>} @@ -154,12 +193,13 @@ class Login extends React.Component {          <FormControl            type="password"            ref="password" -          value={this.state.password} +          value={this.state.password || ""}            onChange={this.onPassword} />          {this.state.passwordState == 'success' ? null : <FormControl.Feedback/>}          {passwordHelp}        </FormGroup> +      {password2Elem}        {submitButton}        {rememberCheck}      </form> @@ -226,6 +266,12 @@ class Login extends React.Component {      }    } +  onPassword2(e) { +    let password2 = e.target.value +    this.setState({password2: password2}) +    this.validatePassword2(password2, this.state.password) +  } +    onRemember(e) {      let currentValue = e.target.value == 'on' ? true : false      let value = !currentValue @@ -258,15 +304,43 @@ class Login extends React.Component {        passwordState: state,        passwordError: message      }) +    this.validatePassword2(this.state.password2, password) +  } + +  validatePassword2(password2, password) { +    if (password2) { +      if (password != password2) { +        this.setState({ +          password2State: 'error', +          password2Error: "Does not match" +        }) +      } else { +        this.setState({ +          password2State: 'success', +          password2Error: null +        }) +      } +    } else { +      this.setState({ +        password2State: null, +        password2Error: null +      }) +    }    }    maySubmit() { -    return( +    let ok = (        !this.stateLoading &&        !this.state.usernameError && -      this.state.username != "" && -      this.state.password != "" +      this.state.username && +      this.state.password      ) + +    if (this.props.mode == 'login') { +      return ok +    } else if (this.props.mode == 'signup') { +      return ok && this.state.password2 == this.state.password +    }    }    onSubmit(e) { @@ -274,6 +348,14 @@ class Login extends React.Component {      if (!this.maySubmit()) { return }      this.setState({loading: true}) +    if (this.props.mode == 'login') { +      this.doLogin() +    } else if (this.props.mode == 'signup') { +      this.doSignup() +    } +  } + +  doLogin() {      let account = Account.find(this.state.username)      account.login(this.state.password).then(        account => { @@ -283,9 +365,27 @@ class Login extends React.Component {          }        },        error => { -        console.log(error)          if (error == "") { -          error = 'Something failed, but we did not get a message' +          error = "Something failed, but we did not get a message" +        } +        this.setState({ +          loading: false, +          usernameState: 'error', +          passwordState: 'error', +          authError: error +        }) +      } +    ) +  } + +  doSignup() { +    Account.create(this.state.username, this.state.password).then( +      account => { +        this.doLogin() +      }, +      error => { +        if (error == "") { +          error = "Something failed, but we did not get a message"          }          this.setState({            loading: false, diff --git a/ui/app/components/main_panel/email_section.js b/ui/app/components/main_panel/email_section.js index a6525d92..a3ff11c2 100644 --- a/ui/app/components/main_panel/email_section.js +++ b/ui/app/components/main_panel/email_section.js @@ -19,8 +19,6 @@ export default class EmailSection extends React.Component {      this.openKeys  = this.openKeys.bind(this)      this.openApp   = this.openApp.bind(this)      this.openPrefs = this.openPrefs.bind(this) - -    console.log('email constructor')    }    openKeys() {} diff --git a/ui/app/components/main_panel/index.js b/ui/app/components/main_panel/index.js index 3cc6c11f..a05f3077 100644 --- a/ui/app/components/main_panel/index.js +++ b/ui/app/components/main_panel/index.js @@ -32,9 +32,7 @@ export default class MainPanel extends React.Component {    componentWillMount() {      if (this.props.initialAccount) { -      console.log(Account.list)        Account.add(this.props.initialAccount) -      Account.add(new DummyAccount(this.props.initialAccount))        this.setState({          account: this.props.initialAccount,          accounts: Account.list diff --git a/ui/app/components/main_panel/user_section.js b/ui/app/components/main_panel/user_section.js index 0b4ba136..acaea234 100644 --- a/ui/app/components/main_panel/user_section.js +++ b/ui/app/components/main_panel/user_section.js @@ -61,9 +61,17 @@ export default class UserSection extends React.Component {          </SectionLayout>        )      } else { +      let address = null +      if (this.props.account.userpart) { +        address = this.props.account.address +      }        return (          <SectionLayout icon="user" className="wide-margin"> -          <Login onLogin={this.props.onLogin} domain={this.props.account.domain} /> +          <Login +            onLogin={this.props.onLogin} +            domain={this.props.account.domain} +            address={address} +          />          </SectionLayout>        )      } diff --git a/ui/app/components/panel_switcher.js b/ui/app/components/panel_switcher.js index aaf2dc5b..2746f005 100644 --- a/ui/app/components/panel_switcher.js +++ b/ui/app/components/panel_switcher.js @@ -17,7 +17,7 @@ export default class PanelSwitcher extends React.Component {      this.state = {        panel: null,        panel_properties: null, -      debug: false +      debug: true      }      App.switcher = this    } @@ -33,10 +33,11 @@ export default class PanelSwitcher extends React.Component {          this.panelRender(this.state.panel, this.state.panel_properties)        )      } -    if (this.state.debug) { -      elems.push( -        elem(DebugPanel, {key: 'debug'}) -      ) +    if (this.state.debug && this.state.panel) { +      window.location.hash = this.state.panel +      //elems.push( +      //  elem(DebugPanel, {key: 'debug'}) +      //)      }      return <div id="root">{elems}</div>    } 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> </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> +    ) +  } +} | 
