Skip to content

Instantly share code, notes, and snippets.

@wyqydsyq
Last active July 22, 2016 07:01
Show Gist options
  • Save wyqydsyq/5f1ece098f313cd744110a276f144a76 to your computer and use it in GitHub Desktop.
Save wyqydsyq/5f1ece098f313cd744110a276f144a76 to your computer and use it in GitHub Desktop.
Isomorphism
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}) {
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: ((typeof res.error == 'undefined' || !res.error) && res.body.length) ? 'User created.' : 'An unknown error occured, please try again later.'
}))
}
}
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 CreateUser (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)}, 'Create User'),
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.faUserPlus)}),
state.submitting ? ' Creating...' : ' Create'
])
])
])
])
},
vtree$ = state$.map(render);
actions.submit$.map(action => {
console.log(action);
});
return {
DOM: vtree$,
HTTP: xs.combine(state$.take(1), actions.submit$).map(([state, action]) => ({
url: '/users',
category: 'user',
method: 'POST',
type: 'application/x-www-form-urlencoded',
send: state.data
})),
state$
}
};
export default sources => isolate(CreateUser)(sources);
import {div, h1, p, strong, pre, code, hr} from '@cycle/dom';
import {makeHTTPDriver} from '@cycle/http';
import xs from 'xstream';
import classes from 'dependencies/classes';
import CreateUser from 'components/create-user';
function Welcome (sources) {
let response$ = sources.HTTP.select('user')
.map(res$ => res$.replaceError(error => {
let res = error.res;
res.error = true;
return xs.of(res);
}))
.flatten()
.startWith({body: []}).take(1) // response$ never completes on server without .take()
.map(res => {
console.log('users: ', res.body);
return res.body;
}),
getUsers = {
url: '/users',
category: 'user',
method: 'GET'
},
createUser = CreateUser(sources),
render = (users) => { console.log(users)
return div([
h1('Welcome to your new Cycle.js + Hapi application!'),
p('Your ORM has the following users:'),
pre([
code(JSON.stringify(users, null, "\t"))
]),
hr(),
createUser.DOM
])
};
return {
DOM: response$.map(render),
HTTP: xs.merge(
// get users initially
xs.of(getUsers).take(2),
// handle create POST requests
createUser.HTTP,
// map create POST requests to another get to update data
createUser.HTTP.mapTo(getUsers)
)
}
};
export default Welcome;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment