Skip to content

Instantly share code, notes, and snippets.

@witoldsz
Created December 7, 2018 00:00
Show Gist options
  • Save witoldsz/e4d25e318acd310a492bb1e59e534a08 to your computer and use it in GitHub Desktop.
Save witoldsz/e4d25e318acd310a492bb1e59e534a08 to your computer and use it in GitHub Desktop.
My first contact with Cycle.JS
const { h, makeDOMDriver } = require('@cycle/dom')
const { run } = require('@cycle/run')
const { readDb, writeDb, filterDb, findById } = require('./db')
const { banner } = require('./view-extra')
const sampleCombine = require('xstream/extra/sampleCombine').default
const xs = require('xstream').default
const R = require('ramda')
function intent(domSource) {
return {
newPatient: click('button.new-patient'),
cancelPatient: click('button.cancel-patient'),
editPatient$: domSource.select('tr button').events('click').map((ev) => parseInt(ev.target.dataset.id)),
save$: click('button.save'),
changeSearchTerm$: input('input.searchTerm'),
changeFirst$: input('input.edit-first'),
changeLast$: input('input.edit-last'),
changePesel$: input('input.edit-pesel'),
changeLastVisit$: input('input.edit-lastVisit'),
}
function input(selector) {
return domSource.select(selector).events('input').map((ev) => ev.target.value)
}
function click(selector) {
return domSource.select(selector).events('click').mapTo(undefined)
}
}
function model(actions, initialDb$) {
return initialDb$.map((patients) => {
const initialState = {
patient: undefined,
patients,
searchTerm: '',
}
return xs.merge(
actions.cancelPatient.map(() => R.assoc('patient', undefined)),
actions.newPatient.map(() => state => ({
...state,
patient: {},
})),
actions.editPatient$.map(id => state => {
const patient = state.patients[id]
return { ...state, patient }
}),
actions.changeSearchTerm$.map(searchTerm => state => ({ ...state, searchTerm })),
actions.changeFirst$.map(R.assocPath(['patient', 'firstName'])),
actions.changeLast$.map(R.assocPath(['patient', 'lastName'])),
actions.changePesel$.map(R.assocPath(['patient', 'pesel'])),
actions.changeLastVisit$.map(R.assocPath(['patient', 'lastVisit'])),
actions.save$.map(() => state => {
const p = state.patient
const idx = parseInt(p.id)
const patients = idx
? R.update(idx, p, state.patients)
: R.append(p, state.patients)
return { ...state, patients }
})
)
.fold((state, reducer) => reducer(state), initialState)
}).flatten()
}
function view(state$) {
return state$.map((state) => (
h('div', [
(state.patient ? editForm(state.patient) : searchForm(state)),
h('hr'),
h('pre', [ JSON.stringify(state, null, 2)]),
])
))
function searchForm(state) {
return h('div', [
banner(),
h('label', ['Search for a patient:']),
h('input.searchTerm', { props: { value: state.searchTerm }}),
h('button.new-patient', ['new patient']),
h('hr'),
h('table',
filterDb(state.patients, state.searchTerm).map((i) => (
h('tr', { key: i.id }, [
h('td', [h('button', { dataset: { id: i.id }}, [ 'edit' ])]),
h('td', [i.lastName]),
h('td', [i.firstName]),
h('td', [i.pesel]),
h('td', [i.lastVisit])
])
))
),
])
}
function editForm(patient) {
return h('div', [
h('label', ['Last name:']),
h('input.edit-last', { props: { value: patient.lastName }}),
h('label', ['First name:']),
h('input.edit-first', { props: { value: patient.firstName }}),
h('label', ['PESEL:']),
h('input.edit-pesel', { props: { value: patient.pesel }}),
h('label', ['Last visit:']),
h('input.edit-lastVisit', { props: { value: patient.lastVisit }}),
h('button.save', ['save']),
h('button.cancel-patient', ['search mode']),
])
}
}
function updateDb(actions, state$) {
return actions.save$.compose(sampleCombine(state$))
.map(([_, state]) => state.patients)
}
function main(sources) {
const initialDb$ = sources.db
const actions = intent(sources.DOM)
const state$ = model(actions, initialDb$).debug('state$')
return {
DOM: view(state$),
db: updateDb(actions, state$),
}
}
const drivers = {
DOM: makeDOMDriver('#app'),
db: dbDriver,
}
function dbDriver(patients$) {
patients$.addListener({
next(patients) { writeDb(patients) }
})
return xs.of(readDb())
}
run(main, drivers)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment