git ssb

2+

mixmix / ticktack



Tree: 140bd2aa4c9baa0075ccea378b2376a4c90cf8fc

Files: 140bd2aa4c9baa0075ccea378b2376a4c90cf8fc / app / page / threadNew.js

4258 bytesRaw
1const nest = require('depnest')
2const { h, Struct, Value, Array: MutantArray, computed, map, resolve } = require('mutant')
3const suggestBox = require('suggest-box')
4const isEmpty = require('lodash/isEmpty')
5
6exports.gives = nest('app.page.threadNew')
7
8exports.needs = nest({
9 'about.async.suggest': 'first',
10 'about.html.avatar': 'first',
11 'about.obs.name': 'first',
12 'app.html.sideNav': 'first',
13 'app.html.thread': 'first',
14 'history.sync.push': 'first',
15 'keys.sync.id': 'first',
16 'message.html.compose': 'first',
17 'message.sync.unbox': 'first',
18 'translations.sync.strings': 'first'
19})
20
21exports.create = (api) => {
22 return nest('app.page.threadNew', threadNew)
23
24 function threadNew (location) {
25 if (isEmpty(location.participants)) return
26
27 return threadNewFeed(location)
28 }
29
30 function threadNewFeed (location) {
31 const strings = api.translations.sync.strings()
32 const myId = api.keys.sync.id()
33
34 const { participants } = location
35
36 const meta = Struct({
37 type: 'post',
38 recps: MutantArray([
39 myId,
40 ...participants.map(p => {
41 return {
42 link: p,
43 name: resolve(api.about.obs.name(p))
44 }
45 })
46 ]),
47 subject: Value()
48 })
49
50 return h('Page -threadNew', {title: strings.threadNew.pageTitle}, [
51 api.app.html.sideNav(location),
52 h('div.content', [
53 h('div.container', [
54 h('div.field -to', [
55 h('div.label', strings.threadNew.field.to),
56 h('div.recps', [
57 map(meta.recps, Recipient),
58 RecipientInput(meta.recps)
59 ])
60 ]),
61 h('div.field -subject', [
62 h('div.label', strings.threadNew.field.subject),
63 h('input', {
64 'ev-input': e => meta.subject.set(e.target.value),
65 placeholder: strings.optionalField
66 })
67 ]),
68 Composer(meta)
69 ])
70 ])
71 ])
72
73 function Recipient (r) {
74 if (r === myId) return
75
76 return h('div.recp', [
77 api.about.html.avatar(r.link, 'tiny'),
78 h('div.name', r.name)
79 ])
80 }
81
82 function RecipientInput (recps) {
83 const getRecpSuggestions = api.about.async.suggest()
84 const input = h('input', {
85 placeholder: strings.threadNew.action.addMoreRecps
86 // 'ev-input': e => searchInput.set(e.target.value),
87 })
88
89 var boxActive = false
90 addSuggest()
91
92 input.addEventListener('suggestselect', (e) => {
93 const { id, title: name } = e.detail
94 if (!recps.find(r => r === id || r.link === id)) { recps.push({ link: id, name }) }
95
96 boxActive = false
97 e.target.value = ''
98 e.target.placeholder = ''
99 })
100
101 input.addEventListener('keyup', (e) => {
102 // don't pop the previous entry if still entering a name!
103 if (boxActive) {
104 // if you delete a name you were typing completely, mark box inactive
105 // so that further deletes pop names
106 if (e.target.value === '') boxActive = false
107 return
108 }
109
110 if (e.code === 'Backspace' || e.key === 'Backspace' || e.keyCode == 8) {
111 if (recps.getLength() < 3) return // can only delete down to 2 recps (sender + 1 recp)
112
113 recps.pop()
114 }
115 })
116
117 return input
118
119 function addSuggest () {
120 if (!input.parentElement) return setTimeout(addSuggest, 100)
121
122 suggestBox(input, (inputText, cb) => {
123 if (recps.getLength() >= 7) return
124 // TODO - tell the user they're only allowed 6 (or 7?!) people in a message
125
126 boxActive = true
127 const suggestions = getRecpSuggestions(inputText)
128 cb(null, suggestions)
129 }, {cls: 'PatchSuggest'})
130 }
131 }
132
133 function Composer (meta) {
134 return api.message.html.compose(
135 { meta, shrink: false },
136 (err, msg) => {
137 if (err) return api.history.sync.push(err)
138
139 const someRecipient = meta.recps.get(1)
140 if (!someRecipient) return
141
142 api.history.sync.push(Object.assign(
143 api.message.sync.unbox(msg), // for consistency of message sideNav receives D:
144 { feed: someRecipient.link }
145 ))
146 }
147 )
148 }
149 }
150}
151

Built with git-ssb-web