Created
July 19, 2016 05:32
-
-
Save wyqydsyq/c83a5aab4269f69189c6f9e974dd849c to your computer and use it in GitHub Desktop.
Login Form
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {div, form, fieldset, legend, label, input, button, i, strong} from '@cycle/dom'; | |
import {makeHTTPDriver} from '@cycle/http'; | |
import isolate from '@cycle/isolate'; | |
import xs from 'xstream'; | |
import classes from 'dependencies/classes'; | |
import styles from '../form/styles.less'; | |
import LabelInput from 'components/label-input'; | |
const dataIni = { | |
email: '', | |
password: '', | |
remember: null | |
}, | |
stateIni = { | |
alerts: [], | |
submitting: false, | |
data: dataIni | |
}; | |
function action (type, data = {}) { | |
return { | |
type, | |
effect: data | |
} | |
} | |
function intent ({DOM, HTTP, state$}) { | |
return { | |
input$: DOM.select('input').events('input').map(ev => action('input', {target: ev.target.name, value: ev.target.value})), | |
submit$: DOM.select('button').events('click').map(ev => action('submit', {target: ev.target.name})), | |
responses$: HTTP.select('user') | |
.map(response$ => response$.replaceError(error => { | |
let res = error.response; | |
res.error = true; | |
return xs.of(res); | |
})) | |
.flatten() | |
.map(res => action('response', { | |
success: (typeof res.error == 'undefined' || !res.error), | |
text: res.body.text | |
})) | |
} | |
} | |
function model (intent) { | |
return xs.merge( | |
intent.input$, | |
intent.submit$, | |
intent.responses$ | |
).map(action => state => { | |
switch (action.type) { | |
case 'input': | |
state.data[action.effect.target] = action.effect.value; | |
break; | |
case 'submit': | |
state.submitting = true; | |
state.alerts = []; | |
break; | |
case 'response': | |
state.submitting = false; | |
let alert = { | |
title: action.effect.title || '', | |
text: action.effect.text | |
}; | |
if (action.effect.success) alert.className = 'alert-success'; | |
else alert.className = 'alert-danger'; | |
state.alerts.push(alert); | |
break; | |
} | |
return state; | |
}).fold((state, method) => method(state), stateIni) | |
} | |
function LoginForm (sources) { | |
let actions = intent(sources), | |
state$ = model(actions), | |
render = (state) => { | |
let emailField = LabelInput({state, props: { | |
name: 'email', | |
type: 'email', | |
label: 'Email' | |
}}), | |
passwordField = LabelInput({state, props: { | |
name: 'password', | |
type: 'password', | |
label: 'Password' | |
}}); | |
return form({class: classes(styles.form, styles.formHorizontal)}, [ | |
fieldset([ | |
// show alerts if there's any | |
state.alerts.length ? div('.alerts', | |
state.alerts.map(alert => div({class: classes(styles.alert, styles[alert.className || 'alert-info'])}, [ | |
(typeof alert.title != 'undefined' && alert.title) ? strong(alert.title): '', | |
alert.text | |
])) | |
) : '', | |
legend({class: classes(styles.legend)}, 'Login'), | |
emailField.DOM, | |
passwordField.DOM, | |
div([ | |
button({class: classes(styles.submit), props: {type: 'button', disabled: state.submitting}}, [ | |
state.submitting | |
? i({class: classes(styles.fa, styles.faSpinner, styles.faSpin)}) | |
: i({class: classes(styles.fa, styles.faSignIn)}), | |
state.submitting ? ' Logging in...' : ' Login' | |
]) | |
]) | |
]) | |
]) | |
}, | |
vtree$ = state$.map(render); | |
return { | |
DOM: vtree$, | |
HTTP: xs.combine(actions.submit$, state$.take(1)).map(([action, state]) => ({ | |
url: '/login', | |
category: 'user', | |
method: 'POST', | |
type: 'application/x-www-form-urlencoded', | |
send: state.data | |
})), | |
state$ | |
} | |
}; | |
export default sources => isolate(LoginForm)(sources); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment