Skip to content

Instantly share code, notes, and snippets.

@artalar
Last active June 18, 2018 07:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save artalar/f762c65f68565e8690daa1a8dc256891 to your computer and use it in GitHub Desktop.
Save artalar/f762c65f68565e8690daa1a8dc256891 to your computer and use it in GitHub Desktop.
/* eslint-disable */
/******************************************
~/form/address.jsx
*/
import { service } from '~/service.js';
import { workflow } from './workflow.js';
export const Autocomplete = service.connect([workflow, 'address'])(
({ value, suggestions, onChange }) => (
<Autocomplete name="address" value={value} suggestions={suggestions} onChange={onChange} />
),
);
/******************************************
~/form/workflow.js
*/
import { path } from 'pathon';
function* initiate(service) {
const { AUTOCOMPLETE_STATES } = yield service.reference;
const initialState = {
address: '',
suggestions: { address: AUTOCOMPLETE_STATES.NONE },
};
return {
...this,
private: {
...this.private,
state: path('form', initialState),
},
};
}
// `service` - global shared services;
// `this` - local domain services;
function* change(payload, service) {
const { state } = this.private;
const { dom, debounce, reference, all, api, preventRaceCondition, notification } = service;
const { name, value } = yield dom.fromEvent(['name', 'value'], payload);
yield () => state.path(name).set(value);
if (name !== 'address') return;
yield () => debounce(change, 300);
const suggestions = yield () => state.path('suggestions').path(name);
const { AUTOCOMPLETE_STATES } = yield reference;
yield () => suggestions.set(AUTOCOMPLETE_STATES.LOADING);
try {
const [list] = yield all([() => api.address.get(value), () => preventRaceCondition(change)]);
yield () => suggestions.set(list);
} catch (error) {
yield () => notification.error(error);
yield () => suggestions.set(AUTOCOMPLETE_STATES.NONE);
// `throw` for `onError` handler
return;
}
}
const connect = {
*address({ watch, unwatch }, service) {
const { state, change: onChange } = this.private;
const address = state.path('address');
const suggestions = state.path('suggestions').path('address');
unwatch(address.watch(value => watch({ value })));
unwatch(suggestions.watch(suggestions => watch({ suggestions })));
return {
value: address,
suggestions,
onChange,
};
},
};
// domain handler
// for example, usually useful default handler from root workflow
function* onError({ error, lastPayload }, service) {
yield () => this.state.reset(initialState);
}
const log = ({ name, payload, isError }) => console[isError ? 'error' : 'log'](name, payload);
export const workflow = {
name: 'form',
initiate,
private: {
change,
},
public: {
connect,
},
handler: {
onError,
log,
},
};
/******************************************
~/service.js - root
*/
import { createService } from 'bus';
import { workflow as formWorkflow } from './form/workflow';
export const service = createService();
service.register({
form: formWorkflow,
/*
connect, dom, debounce, reference, api, preventRaceCondition, notification
*/
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment