git ssb

16+

Dominic / patchbay



Tree: 6aed4c72a3b36330eb67723b515b426ec7f5f06d

Files: 6aed4c72a3b36330eb67723b515b426ec7f5f06d / app / page / thread.js

3818 bytesRaw
1const { h, Struct, Value, when, computed, map, resolve, onceTrue } = require('mutant')
2const nest = require('depnest')
3const get = require('lodash/get')
4const { isFeed } = require('ssb-ref')
5
6exports.gives = nest('app.page.thread')
7
8exports.needs = nest({
9 'about.html.avatar': 'first',
10 'app.html.scroller': 'first',
11 'app.html.tabs': 'first',
12 'app.sync.locationId': 'first',
13 'contact.obs.following': 'first',
14 'feed.obs.thread': 'first',
15 'keys.sync.id': 'first',
16 'message.html.compose': 'first',
17 'message.html.render': 'first',
18 'message.async.name': 'first',
19 'message.sync.unbox': 'first',
20 'sbot.async.get': 'first',
21 'sbot.pull.links': 'first'
22})
23
24exports.create = function (api) {
25 return nest('app.page.thread', threadPage)
26
27 function threadPage (location) {
28 const root = get(location, 'value.content.root', location.key)
29 const msg = location.key
30 if (msg !== root) scrollDownToMessage(msg)
31
32 const myId = api.keys.sync.id()
33 const ImFollowing = api.contact.obs.following(myId)
34 const { messages, isPrivate, rootId, lastId, channel, recps } = api.feed.obs.thread(root)
35 const meta = Struct({
36 type: 'post',
37 root: rootId,
38 branch: lastId,
39 channel,
40 recps
41 })
42 const contactWarning = Value(false)
43 const header = when(isPrivate, [
44 h('section.recipients', map(recps, r => {
45 const id = isFeed(r) ? r : r.link
46
47 var className
48 if (contactIsTrouble(id)) {
49 className = 'warning'
50 contactWarning.set(true)
51 }
52 return h('div', { className }, api.about.html.avatar(id))
53 })),
54 when(contactWarning,
55 h('section.info -warning', 'There is a person in this thread you do not follow (bordered in red). If you think you know this person it might be worth checking their profile to confirm they are who they say they are.'),
56 h('section.info', 'These are the other participants in this thread. Once a private thread is started you cannot add people to it.')
57 )
58 ])
59 function contactIsTrouble (id) {
60 if (id === myId) return false
61 if (Array.from(ImFollowing()).includes(id)) return false
62 return true
63 }
64
65 const composer = api.message.html.compose({
66 meta,
67 location,
68 feedIdsInThread: computed(messages, msgs => msgs.map(m => m.value.author)),
69 placeholder: 'Write a reply',
70 shrink: false
71 })
72 const content = map(messages, m => {
73 return api.message.html.render(resolve(m), {pageId: root})
74 })
75 const { container } = api.app.html.scroller({ prepend: header, content, append: composer })
76
77 container.classList.add('Thread')
78 container.title = msg
79 api.message.async.name(root, (err, name) => {
80 if (err) throw err
81 container.title = name
82 })
83
84 onceTrue(channel, ch => {
85 const channelInput = composer.querySelector('input')
86 channelInput.value = `#${ch}`
87 channelInput.disabled = true
88 })
89
90 container.scrollDownToMessage = scrollDownToMessage
91 container.addQuote = addQuote
92 return container
93
94 function scrollDownToMessage (id) {
95 const locationId = api.app.sync.locationId(location)
96 const tabs = api.app.html.tabs()
97 locateKey()
98
99 function locateKey () {
100 // wait till we're on the right page
101 if (tabs.currentPage().id !== locationId) return setTimeout(locateKey, 200)
102
103 if (!tabs.currentPage().scroll) return setTimeout(locateKey, 200)
104
105 tabs.currentPage().scroll('first')
106 const msg = tabs.currentPage().querySelector(`[data-id='${id}']`)
107 if (!msg) return setTimeout(locateKey, 200)
108
109 ;(msg.scrollIntoViewIfNeeded || msg.scrollIntoView).call(msg)
110 msg.focus()
111 }
112 }
113
114 function addQuote (value) {
115 composer.addQuote(value)
116 }
117 }
118}
119

Built with git-ssb-web