git ssb

1+

Daan Patchwork / patchwork



Tree: 455af00799601cb57c6ea54edad5e85c516b799f

Files: 455af00799601cb57c6ea54edad5e85c516b799f / lib / depject / message / html / render / gathering.js

5923 bytesRaw
1const { h, computed, when, map, send } = require('mutant')
2const nest = require('depnest')
3const extend = require('xtend')
4const moment = require('moment-timezone')
5const addContextMenu = require('../../../../message/html/decorate/context-menu')
6
7exports.needs = nest({
8 'message.html.markdown': 'first',
9 'message.html.layout': 'first',
10 'message.async.publish': 'first',
11 'keys.sync.id': 'first',
12 'about.html.image': 'first',
13 'about.obs.latestValue': 'first',
14 'about.obs.socialValues': 'first',
15 'about.obs.valueFrom': 'first',
16 'about.obs.name': 'first',
17 'contact.obs.following': 'first',
18 'blob.sync.url': 'first',
19 'gathering.sheet.edit': 'first'
20})
21
22exports.gives = nest('message.html', {
23 canRender: true,
24 render: true
25})
26
27exports.create = function (api) {
28 let following = null
29
30 return nest('message.html', {
31 canRender: isRenderable,
32 render: function (msg, opts) {
33 if (!isRenderable(msg)) return
34
35 const yourId = api.keys.sync.id()
36
37 // passed in from sbot/public-feed/roots
38 const suppliedGathering = msg.gathering || {}
39
40 // allow override of resolved about messages for preview in modules/gathering/sheet/edit.js
41 const about = msg.key
42 ? extend({
43 hidden: api.about.obs.valueFrom(msg.key, 'hidden', yourId),
44 image: suppliedGathering.image || api.about.obs.latestValue(msg.key, 'image'),
45 title: suppliedGathering.title || api.about.obs.latestValue(msg.key, 'title'),
46 description: suppliedGathering.description || api.about.obs.latestValue(msg.key, 'description'),
47 location: suppliedGathering.location || api.about.obs.latestValue(msg.key, 'location'),
48 startDateTime: suppliedGathering.startDateTime || api.about.obs.latestValue(msg.key, 'startDateTime')
49 }, msg.previewAbout)
50 : msg.previewAbout
51
52 const attendees = msg.key ? computed([api.about.obs.socialValues(msg.key, 'attendee')], getAttendees) : []
53 const disableActions = !!msg.previewAbout
54
55 const attending = computed([attendees, yourId], (attendees, yourId) => attendees.includes(yourId))
56
57 if (!following) {
58 following = api.contact.obs.following(yourId)
59 }
60
61 const imageUrl = computed(about.image, (id) => api.blob.sync.url(id))
62 const imageId = computed(about.image, (link) => (link && link.link) || link)
63 const content = h('GatheringCard', [
64 h('div.title', [
65 h('a', {
66 href: msg.key
67 }, about.title),
68 h('button', {
69 disabled: disableActions,
70 'ev-click': send(api.gathering.sheet.edit, msg.key)
71 }, 'Edit Details')
72 ]),
73 h('div.time', computed(about.startDateTime, formatTime)),
74 when(about.image, h('a.image', {
75 href: imageId,
76 style: {
77 'background-image': computed(imageUrl, (url) => `url(${url})`)
78 }
79 })),
80 h('div.attending', [
81 h('div.title', ['Attendees', ' (', computed([attendees], (x) => x.length), ')']),
82 h('div.attendees', [
83 map(attendees, (attendee) => {
84 return h('a.attendee', {
85 href: attendee,
86 title: nameAndFollowWarning(attendee)
87 }, api.about.html.image(attendee))
88 })
89 ]),
90 h('div.actions', [
91 h('button -attend', {
92 disabled: computed([attending, disableActions], (...args) => args.some(Boolean)),
93 'ev-click': send(publishAttending, msg)
94 }, 'Attending'),
95 h('button -attend', {
96 disabled: disableActions,
97 'ev-click': send(publishNotAttending, msg)
98 }, 'Can\'t Attend')
99 ])
100 ]),
101 h('div.location', markdown(about.location)),
102 when(about.description, h('div.description', markdown(about.description)))
103 ])
104
105 const editPreview = msg.previewAbout && msg.key
106
107 const element = api.message.html.layout(msg, extend({
108 content,
109 miniContent: editPreview ? 'Edited a gathering' : 'Added a gathering',
110 actions: !msg.previewAbout,
111 layout: 'mini'
112 }, opts))
113
114 return addContextMenu(element, {
115 msg
116 })
117 }
118 })
119
120 function publishAttending (msg) {
121 const yourId = api.keys.sync.id()
122 const content = {
123 type: 'about',
124 about: msg.key,
125 attendee: {
126 link: yourId
127 }
128 }
129
130 // what starts in private, stays in private!
131 if (msg.value.content.recps) {
132 content.recps = msg.value.content.recps
133 }
134
135 // publish with confirm
136 api.message.async.publish(content)
137 }
138
139 function publishNotAttending (msg) {
140 const yourId = api.keys.sync.id()
141 const content = {
142 type: 'about',
143 about: msg.key,
144 attendee: {
145 link: yourId,
146 remove: true
147 }
148 }
149
150 // what starts in private, stays in private!
151 if (msg.value.content.recps) {
152 content.recps = msg.value.content.recps
153 }
154
155 // publish with confirm
156 api.message.async.publish(content)
157 }
158
159 function nameAndFollowWarning (id) {
160 const yourId = api.keys.sync.id()
161 return computed([api.about.obs.name(id), id, following], function nameAndFollowWarning (name, id, following) {
162 if (id === yourId) {
163 return `${name} (you)`
164 } else if (following.includes(id)) {
165 return `${name}`
166 } else {
167 return `${name} (not following)`
168 }
169 })
170 }
171
172 function markdown (obs) {
173 return computed(obs, (text) => {
174 if (typeof text === 'string') return api.message.html.markdown(text)
175 })
176 }
177}
178
179function formatTime (time) {
180 if (time && time.epoch) {
181 return moment(time.epoch).format('LLLL zz')
182 }
183}
184
185function getAttendees (lookup) {
186 return Object.keys(lookup)
187}
188
189function isRenderable (msg) {
190 return (msg.value.content.type === 'gathering') ? true : undefined
191}
192

Built with git-ssb-web