From d6a32b73c752dfe43517812d1300e18aab03e9e0 Mon Sep 17 00:00:00 2001 From: Roald de Vries Date: Wed, 16 Nov 2016 17:16:23 +0100 Subject: add a form and use fetch --- .gitignore | 3 ++ web-ui/package.json | 3 +- web-ui/react/dummy.json | 1 + web-ui/react/src/index.js | 106 ++++++++++++++++++++++++++++++++++++---------- 4 files changed, 89 insertions(+), 24 deletions(-) create mode 100644 web-ui/react/dummy.json diff --git a/.gitignore b/.gitignore index 0c347bf8..d60eade0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ web-ui/node_modules web-ui/app/bower_components web-ui/target +web-ui/react/bundle.css +web-ui/react/bundle.js +web-ui/react/lib/ .tmp .sass-cache/ dist/ diff --git a/web-ui/package.json b/web-ui/package.json index c85889e9..7b454d8c 100644 --- a/web-ui/package.json +++ b/web-ui/package.json @@ -52,7 +52,8 @@ "immutable": "^3.8.1", "react": "^15.3.2", "react-dom": "^15.3.2", - "redux": "^3.6.0" + "redux": "^3.6.0", + "whatwg-fetch": "^2.0.0" }, "babel": { "presets": [ diff --git a/web-ui/react/dummy.json b/web-ui/react/dummy.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/web-ui/react/dummy.json @@ -0,0 +1 @@ +{} diff --git a/web-ui/react/src/index.js b/web-ui/react/src/index.js index ae52867f..35de6407 100644 --- a/web-ui/react/src/index.js +++ b/web-ui/react/src/index.js @@ -2,6 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import {createStore} from 'redux'; import {Map} from 'immutable'; +import 'whatwg-fetch'; class PixelatedComponent extends React.Component { @@ -10,19 +11,37 @@ class PixelatedComponent extends React.Component { } componentWillMount() { - console.debug('mounting', this); this.unsubscribe = this.props.store.subscribe(() => this._updateStateFromStore()); this._updateStateFromStore(); } componentWillUnmount() { - console.debug('unmounting', this); this.unsubscribe() } } -class InviteCodeForm extends PixelatedComponent { +class PixelatedForm extends PixelatedComponent { + _fetchAndDispatch(url, actionProperties) { + const immutableActionProperties = new Map(actionProperties); + this.props.store.dispatch(immutableActionProperties.merge({status: 'STARTED'}).toJS()); + fetch(url).then((response) => { + console.debug('got a reply', response); + return response.json() + }).then((json) => { + console.debug('got json', json); + setTimeout(() => { + this.props.store.dispatch(immutableActionProperties.merge({status: 'SUCCESS', json: json}).toJS()); + }, 3000); + }).catch((error) => { + console.error('something went wrong', error); + this.props.store.dispatch(immutableActionProperties.merge({status: 'ERROR', error: error}).toJS()); + }); + } +} + + +class InviteCodeForm extends PixelatedForm { render() { return (
@@ -38,12 +57,12 @@ class InviteCodeForm extends PixelatedComponent { _handleClick(event) { event.stopPropagation(); event.preventDefault(); - this.props.store.dispatch({type: 'SUBMIT_INVITE_CODE'}); + this.props.store.dispatch({type: 'SUBMIT_INVITE_CODE', inviteCode: event.target['invite-code'].value}); } } -class CreateAccountForm extends PixelatedComponent { +class CreateAccountForm extends PixelatedForm { render() { return ( @@ -58,11 +77,6 @@ class CreateAccountForm extends PixelatedComponent { -
- - -
-
); @@ -71,27 +85,44 @@ class CreateAccountForm extends PixelatedComponent { _handleClick(event) { event.stopPropagation(); event.preventDefault(); - this.props.store.dispatch({type: 'SUBMIT_CREATE_ACCOUNT'}); + this.props.store.dispatch({type: 'SUBMIT_CREATE_ACCOUNT', username: event.target['username'].value, password: event.target['password'].value}); } } -class BackupEmailForm extends PixelatedComponent { +class BackupEmailForm extends PixelatedForm { render() { return (
- @domain.com
- - + +
-
- - -
+ +

+ I didn't receive anything. Send the email again +

+
+ ); + } - + _handleClick(event) { + event.stopPropagation(); + event.preventDefault(); + this._fetchAndDispatch('dummy.json', {type: 'SUBMIT_BACKUP_EMAIL', backupEmail: event.target['backup-email'].value}); + } +} + + +class BackupEmailSentForm extends PixelatedForm { + render() { + return ( +
+ {this.state.isFetching || I received the codes.
Go to my inbox
} +

+ I didn't receive anything. Send the email again +

); } @@ -99,7 +130,6 @@ class BackupEmailForm extends PixelatedComponent { _handleClick(event) { event.stopPropagation(); event.preventDefault(); - this.props.store.dispatch({type: 'SUBMIT_CREATE_ACCOUNT'}); } } @@ -110,6 +140,7 @@ class SignUp extends PixelatedComponent {

{this.state.header}

+ {this.state.icon}

{this.state.summary}

@@ -124,16 +155,19 @@ class SignUp extends PixelatedComponent { case 'invite_code': return ; case 'create_account': return ; case 'backup_email': return ; - default: throw Exception('TODO'); + case 'backup_email_sent': return ; + default: throw Error('TODO'); } } } const initialState = new Map({ + isFetching: false, form: 'invite_code', header: 'Welcome', - summary: ['Do you have an invite code?',
, 'Type it below'], + icon: null, + summary: ['Do you have an invite code?',
, 'Type it below'], }); @@ -141,16 +175,42 @@ const store = createStore((state=initialState, action) => { switch (action.type) { case 'SUBMIT_INVITE_CODE': return state.merge({ + inviteCode: action.inviteCode, form: 'create_account', header: 'Create your account', summary: 'Choose your username, and be careful about your password, it must be strong and easy to remember. If you have a password manager, we strongly advise you to use one.', }); case 'SUBMIT_CREATE_ACCOUNT': return state.merge({ + username: action.username, + password: action.password, form: 'backup_email', header: 'In case you lose your password...', summary: 'Set up a backup email account. You\'ll receive an email with a code so you can recover your account in the future, other will be sent to your account administrator.', }); + case 'SUBMIT_BACKUP_EMAIL': + switch (action.status) { + case 'STARTED': + return state.merge({ + isFetching: true, + backupEmail: action.backupEmail, + form: 'backup_email_sent', + icon:

, + summary: 'An email was sent to the email you provided. Check your spam folder, just in case.', + }); + case 'SUCCESS': + return state.merge({ + isFetching: false, + }); + case 'ERROR': + return state.merge({ + isFetching: false, + }); + default: + return state; + } + case 'SUBMIT_BACKUP_EMAIL_SENT': + return state.merge({}); default: return state; } -- cgit v1.2.3