-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathPlanner.jsx
141 lines (127 loc) · 4.66 KB
/
Planner.jsx
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
130
131
132
133
134
135
136
137
138
139
140
141
'use strict';
var forms = require('newforms')
var React = require('react')
var extend = require('./utils/extend')
var speech = require('./utils/speech')
var ItemForm = forms.Form.extend({
name: forms.CharField(),
time: forms.IntegerField({minValue: 1, maxLength: 3,
widget: forms.TextInput({attrs: {size: 3}})
}),
tend: forms.ChoiceField({required: false, choices: ['', 'Flip', 'Rotate']}),
errorCssClass: 'error',
requiredCssClass: 'required',
validCssClass: 'valid'
})
var ItemFormSet = forms.FormSet.extend({
form: ItemForm,
extra: 3,
clean() {
var cleanedData = this.cleanedData()
if (cleanedData.length === 0) {
throw forms.ValidationError('Add details of at least one thing to cook.')
}
}
})
var OptionsForm = forms.Form.extend({
sayInstructions: forms.BooleanField({required: false, label: 'Say instructions aloud'}),
playStepSound: forms.BooleanField({required: false, label: 'Play a sound for new steps'})
})
var Planner = React.createClass({
propTypes: {
onStartCooking: React.PropTypes.func.isRequired
},
getInitialState() {
return {
itemFormset: new ItemFormSet({onChange: this.onFormChange})
, optionsForm: new OptionsForm({
onChange: this.onFormChange
, initial: {sayInstructions: speech.hasSpeech, playStepSound: true}
})
}
},
onFormChange() {
this.forceUpdate()
},
addItem() {
this.state.itemFormset.addAnother()
},
deleteItem(index) {
this.state.itemFormset.removeForm(index)
},
onSubmit(e) {
e.preventDefault()
// Validate all forms' current input data (set by onChange events)
var itemFormset = this.state.itemFormset
var optionsForm = this.state.optionsForm
if ([itemFormset.validate(),
optionsForm.validate()].indexOf(false) != -1) {
return this.forceUpdate()
}
// If we're good, call back to our parent component
this.props.onStartCooking(extend(optionsForm.cleanedData, {
items: itemFormset.cleanedData()
}))
},
render() {
var itemCount = this.state.itemFormset.totalFormCount()
var nonFormErrors = this.state.itemFormset.nonFormErrors()
var optionFields = this.state.optionsForm.boundFieldsObj()
return <div className="Wrapper">
<div className="Main"><div className="Content">
<div className="Input__header">Dinner Time!</div>
<p>Enter details of what you need to cook below and Dinner Time! will tell you when to do what.</p>
<div className="Input">
{nonFormErrors.isPopulated() && <p className="error">{nonFormErrors.first()}</p>}
<form onSubmit={this.onSubmit}>
<table>
<thead>
<tr>
<th>Cook</th>
<th>For</th>
<th>Tend</th>
<th> </th>
</tr>
</thead>
<tbody>
{this.state.itemFormset.forms().map((itemForm, index) => {
var fields = itemForm.boundFieldsObj()
return <tr key={index} className={itemForm.notEmpty() && 'notempty'}>
<td className={fields.name.cssClasses()}>{fields.name.render({attrs: {title: fields.name.errorMessage()}})}</td>
<td className={fields.time.cssClasses()}>{fields.time.render({attrs: {title: fields.time.errorMessage()}})} mins</td>
<td className={fields.tend.cssClasses()}>
{fields.tend.render()}{' '}
{fields.tend.data() && 'halfway'}{/* TODO Make configurable */}
</td>
<td>
{itemCount > 1 && <button type="button" onClick={this.deleteItem.bind(this, index)} title="Remove this food">
× Delete
</button>}
</td>
</tr>
})}
</tbody>
</table>
<button type="button" onClick={this.addItem} title="Add more food">+ Add More</button>
<div className="Input__options">
{speech.hasSpeech && <div className="Input__option">
<label>
{optionFields.sayInstructions.render()}{' '}
{optionFields.sayInstructions.label}
</label>
</div>}
<div className="Input__option">
<label>
{optionFields.playStepSound.render()}{' '}
{optionFields.playStepSound.label}
</label>
</div>
</div>
<button type="submit">Start Cooking</button>
</form>
</div>
</div></div>
</div>
}
})
module.exports = Planner