This repository has been archived by the owner on Nov 14, 2017. It is now read-only.
/
user.create.js
129 lines (111 loc) · 4.12 KB
/
user.create.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
let {assoc, filter, identity, values} = require("ramda")
let {Observable: $} = require("rx")
let {derive, pluck, setState, store, toOverState, toState, view} = require("rx-utils")
let {br, button, div, input, label, h1, p} = require("@cycle/dom")
let {validate} = require("../../../rx-utils")
let {flattenObject} = require("../../../helpers")
let {parseString, parseInteger} = require("../../../parsers")
let {formatString, formatInteger} = require("../../../formatters")
let {User} = require("../types")
let {makeUser} = require("../makers")
let seeds = require("../seeds/user.create")
let menu = require("../chunks/menu")
let filterX = filter(identity)
let Username = User.meta.props.username
let Email = User.meta.props.email
let Points = User.meta.props.points
let Bonus = User.meta.props.bonus
// :: {Observable *} -> {Observable *}
module.exports = function (src) {
let textFrom = (s) => src.DOM.select(s).events("input")::pluck("target.value").map(parseString).share()
let numberFrom = (s) => src.DOM.select(s).events("input")::pluck("target.value").map(parseInteger).share()
let clickFrom = (s) => src.DOM.select(s).events("click").map((e) => true).share()
// DERIVED STATE
let model = derive((form) => {
try {
return makeUser(form)
} catch (err) {
if (err instanceof TypeError) { return null }
else { throw err }
}
}, src.state2)
let errors = store(seeds, $.merge(
src.state2::view("username").skip(1)::validate(Username)::toState("username"),
src.state2::view("email").skip(1)::validate(Email)::toState("email"),
src.state2::view("points").skip(1)::validate(Points)::toState("points"),
src.state2::view("bonus").skip(1)::validate(Bonus)::toState("bonus")
))
let hasErrors = derive((es) => Boolean(filterX(values(flattenObject(es))).length), errors)
// INTENTS
let intents = {
changeUsername: textFrom("#username"),
changeEmail: textFrom("#email"),
changePoints: numberFrom("#points"),
changeBonus: numberFrom("#bonus"),
createUser: clickFrom("#submit").debounce(100),
}
// ACTIONS
let actions = {
createUser: model.filter(identity)
.sample(intents.createUser)
.share(),
}
// STATE 2
let state2 = store(seeds, $.merge(
// Reset form on page enter
src.navi::view("route")::setState("", seeds),
// Track fields
intents.changeUsername::toState("username"),
intents.changeEmail::toState("email"),
intents.changePoints::toState("points"),
intents.changeBonus::toState("bonus")
))
// DOM
let DOM = $
.combineLatest(src.navi, state2, model, errors).debounce(1)
.map(([navi, form, model, errors]) => {
console.log("render user.create")
return div([
h1("Create User"),
menu({navi}),
br(),
div(".form-element", [
label({htmlFor: "username"}, "Username:"),
br(),
input("#username", {type: "text", value: formatString(form.username), autocomplete: "off"}),
p(errors.username),
]),
div(".form-element", [
label({htmlFor: "email"}, "Email:"),
br(),
input("#email", {type: "text", value: formatString(form.email), autocomplete: "off"}),
p(errors.email),
]),
div(".form-element", [
label({htmlFor: "points"}, "Points:"),
br(),
input("#points", {type: "text", value: formatInteger(form.points), autocomplete: "off"}),
p(errors.points),
]),
div(".form-element", [
label({htmlFor: "bonus"}, "Bonus:"),
br(),
input("#bonus", {type: "text", value: formatInteger(form.bonus), autocomplete: "off"}),
p(errors.bonus),
]),
button("#submit.form-element", {type: "submit", disabled: !model}, "Create"),
])
}
)
// UPDATE
let update = $.merge(
actions.createUser::toOverState("users", (u) => assoc(u.id, u))
)
// REDIRECT
let redirect = $.merge(
// Redirect to edit page after valid submit
actions.createUser.delay(1).map((user) => window.unroute(`/users/:id`, {id: user.id}))
)
// SINKS
return {DOM, update, redirect, state2}
}