git ssb

0+

mixmix / patchbay-scry



Tree: 6071577daff8cc01e7241b5799fb112902aec545

Files: 6071577daff8cc01e7241b5799fb112902aec545 / views / show.js

5824 bytesRaw
1const { h, Struct, computed, resolve } = require('mutant')
2const pull = require('pull-stream')
3const printTime = require('../lib/print-time')
4
5module.exports = function ScryShow (opts) {
6 const {
7 poll,
8 myFeedId,
9 scuttle,
10 name = k => k.slice(0, 9),
11 avatar = k => h('img'),
12 testing = false
13 } = opts
14
15 const state = Struct(initialState())
16 fetchState()
17 watchForUpdates(fetchState)
18
19 return h('ScryShow', [
20 h('h1', state.now.title),
21 h('div.closes-at', [
22 'Closes at ',
23 computed(state.now.closesAt, t => t ? t.toString() : '')
24 ]),
25 ScryShowResults(),
26 h('div.actions', [
27 PublishBtn()
28 ])
29 ])
30
31 function PublishBtn () {
32 return computed([state.now, state.next], (current, next) => {
33 if (!next.isEditing) return
34 if (next.isPublishing) return h('button', h('i.fa.fa-spin.fa-pulse'))
35
36 const newPosition = current.position.join() !== next.position.join()
37 return h('button',
38 {
39 className: newPosition ? '-primary' : '',
40 disabled: !newPosition,
41 'ev-click': () => {
42 state.next.isPublishing.set(true)
43 const choices = next.position.reduce((acc, el, i) => {
44 if (el) acc.push(i)
45 return acc
46 }, [])
47
48 scuttle.position.async.publishMeetingTime({ poll, choices }, (err, data) => {
49 if (err) throw err
50 console.log(data)
51 })
52 }
53 }, 'Publish'
54 )
55 })
56 }
57
58 function ScryShowResults () {
59 return computed(state.now, ({ title, closesAt, times, rows }) => {
60 const style = {
61 display: 'grid',
62 'grid-template-columns': `minmax(10rem, auto) repeat(${times.length}, 4rem)`
63 }
64
65 return [
66 h('ScryShowResults', { style }, [
67 times.map(ScryShowTime),
68 rows.map(ScryShowRow)
69 ])
70 ]
71 })
72 }
73
74 function ScryShowRow ({ author, position }) {
75 if (author !== myFeedId) {
76 return [
77 h('div.about', [
78 avatar(author),
79 name(author)
80 ]),
81 position.map(pos => pos
82 ? h('div.position.-yes', tick())
83 : h('div.position.-no')
84 )
85 ]
86 }
87
88 const toggleEditing = () => {
89 const isEditing = !resolve(state.next.isEditing)
90 state.next.isEditing.set(isEditing)
91 }
92
93 return [
94 h('div.about', [
95 avatar(author),
96 name(author),
97 h('i.fa.fa-pencil', { 'ev-click': toggleEditing })
98 ]),
99 computed([state.next, state.now.position], ({ isEditing, position }, currentPosition) => {
100 if (isEditing) {
101 return position.map((pos, i) => {
102 return h('div.position.-edit',
103 {
104 'ev-click': () => {
105 const nextPosition = resolve(state.next.position)
106 nextPosition[i] = !pos
107 state.next.position.set(nextPosition)
108 }
109 },
110 pos ? checkedBox() : uncheckedBox()
111 )
112 })
113 }
114
115 return currentPosition.map(pos => pos
116 ? h('div.position.-yes', tick())
117 : h('div.position.-no')
118 )
119 })
120 ]
121 }
122
123 function fetchState () {
124 scuttle.poll.async.get(poll.key, (err, doc) => {
125 if (err) return console.error(err)
126
127 const { title, closesAt, positions } = doc
128 const times = doc.results.map(result => result.choice)
129 const results = times.map(t => doc.results.find(result => result.choice === t))
130 // this ensures results Array is in same order as a times Array
131
132 const rows = positions
133 .reduce((acc, pos) => {
134 if (!acc.includes(pos.value.author)) acc.push(pos.value.author)
135 return acc
136 }, [])
137 .map(author => {
138 const position = times.map((time, i) => {
139 return results[i].voters.hasOwnProperty(author)
140 })
141 return { author, position }
142 })
143
144 const myRow = rows.find(r => r.author === myFeedId)
145 const myPosition = myRow ? myRow.position : Array(times.length).fill(null)
146
147 var isEditing = false
148 if (!myRow) {
149 rows.push({ author: myFeedId, position: myPosition })
150 isEditing = true
151 }
152
153 state.now.set({
154 title,
155 closesAt,
156 times,
157 rows,
158 position: myPosition
159 })
160 state.next.set({
161 position: Array.from(myPosition),
162 isEditing,
163 isPublishing: false
164 })
165 })
166 }
167
168 function watchForUpdates (cb) {
169 // TODO check if isEditing before calling cb
170 // start a loop to trigger cb after finished editing
171 pull(
172 scuttle.poll.pull.updates(poll.key),
173 pull.filter(m => !m.sync),
174 pull.drain(m => {
175 cb()
176 })
177 )
178 }
179
180 function tick () { return '✔' }
181 function checkedBox () { return testing ? '☑' : h('i.fa.fa-check-square-o') }
182 function uncheckedBox () { return testing ? '☐' : h('i.fa.fa-square-o') }
183}
184
185function initialState () {
186 return {
187 now: Struct({
188 title: '',
189 times: [],
190 closesAt: undefined,
191 rows: [],
192 position: []
193 }),
194 next: Struct({
195 position: [],
196 isEditing: false,
197 isPublishing: false
198 })
199 }
200}
201
202// component: show-time
203
204function ScryShowTime (time, i) {
205 const style = { 'grid-column': i + 2 }
206
207 return h('ScryShowTime', { style }, [
208 h('div.month', month(time)),
209 h('div.date', time.getDate()),
210 h('div.day', day(time)),
211 h('div.time', printTime(time))
212 ])
213}
214
215function month (date) {
216 const months = ['Jan', 'Feb', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
217
218 return months[date.getMonth()]
219}
220
221function day (date) {
222 const days = ['Sun', 'Mon', 'Tues', 'Wed', 'Thu', 'Fri', 'Sat']
223
224 return days[date.getDay()]
225}
226

Built with git-ssb-web