git ssb

2+

mixmix / ticktack



Tree: a893a560b31905d216fdb21487f862a094bb7d6f

Files: a893a560b31905d216fdb21487f862a094bb7d6f / app / page / statsShow.js

5821 bytesRaw
1const nest = require('depnest')
2const { h, Value, Struct, Array: MutantArray, Dict, onceTrue, map, computed, dictToCollection, throttle } = require('mutant')
3const pull = require('pull-stream')
4const marksum = require('markdown-summary')
5
6exports.gives = nest('app.page.statsShow')
7
8exports.needs = nest({
9 'sbot.obs.connection': 'first',
10 'history.sync.push': 'first'
11})
12
13exports.create = (api) => {
14 return nest('app.page.statsShow', statsShow)
15
16 function statsShow (location) {
17 var store = Struct({
18 blogs: MutantArray([]),
19 comments: Dict(),
20 likes: Dict()
21 })
22
23 var howFarBack = Value(0)
24 // stats show a moving window of 30 days
25 const thirtyDays = 30 * 24 * 60 * 60 * 1000
26
27 // TODO
28 var range = computed([howFarBack], howFarBack => {
29 const now = Date.now()
30 return {
31 upper: now - howFarBack * thirtyDays,
32 lower: now - (howFarBack + 1) * thirtyDays
33 }
34 })
35
36 var rangeComments = computed([throttle(dictToCollection(store.comments), 1000), range], (comments, range) => {
37 return comments
38 .map(c => c.value)
39 .reduce((n, sofar) => [...n, ...sofar], [])
40 .filter(msg => {
41 const ts = msg.value.timestamp
42 return ts >= range.lower && ts <= range.upper
43 })
44 })
45
46 var rangeLikes = computed([throttle(dictToCollection(store.likes), 1000), range], (likes, range) => {
47 return likes
48 .map(c => c.value)
49 .reduce((n, sofar) => [...n, ...sofar], [])
50 .filter(msg => {
51 const ts = msg.value.timestamp
52 return ts >= range.lower && ts <= range.upper
53 })
54 })
55
56 onceTrue(api.sbot.obs.connection, server => {
57 fetchBlogs({ server, store })
58 // fetches blogs and all associated data
59
60 // ///// test code /////
61 // var blogKey = '%3JeEg7voZF4aplk9xCEAfhFOx+zocbKhgstzvfD3G8w=.sha256'
62 // console.log('fetching comments', blogKey) // has 2 comments, 1 like
63
64 // pull(
65 // server.blogStats.read({
66 // gt: ['L', blogKey, null],
67 // lt: ['L', blogKey+'~', undefined],
68 // // gt: ['L', blogKey, null],
69 // // lte: ['L', blogKey+'~', undefined],
70 // // limit: 100,
71 // keys: true,
72 // values: true,
73 // seqs: false,
74 // reverse: true
75 // }),
76 // // pull.filter(o => o.key[1] === blogKey),
77 // pull.log(() => console.log('DONE'))
78 // )
79 /// ///// test code /////
80 })
81
82 return h('Page -statsShow', [
83 h('div.content', [
84 h('h1', 'Stats'),
85 h('section.totals', [
86 h('div.comments', [
87 h('div.count', computed(rangeComments, msgs => msgs.length)),
88 h('strong', 'Comments'),
89 '(30 days)'
90 ]),
91 h('div.likes', [
92 h('div.count', computed(rangeLikes, msgs => msgs.length)),
93 h('strong', 'Likes'),
94 '(30 days)'
95 ]),
96 h('div.shares', [
97 ])
98 ]),
99 h('section.graph', [
100 // TODO insert actual graph
101 h('div', [
102 // h('div', [ 'Comments ', map(rangeComments, msg => [new Date(msg.value.timestamp).toDateString(), ' ']) ]),
103 // h('div', [ 'Likes ', map(rangeLikes, msg => [new Date(msg.value.timestamp).toDateString(), ' ']) ])
104 ]),
105 h('div', [
106 h('a', { href: '#', 'ev-click': () => howFarBack.set(howFarBack() + 1) }, '< Prev 30 days'),
107 ' | ',
108 h('a', { href: '#', 'ev-click': () => howFarBack.set(howFarBack() - 1) }, 'Next 30 days >'),
109 h('div', ['howFarBack:', howFarBack]) // TODO change - this is temporary
110 ])
111 ]),
112 h('table.blogs', [
113 h('thead', [
114 h('tr', [
115 h('th.details'),
116 h('th.comment', 'Comments'),
117 h('th.likes', 'Likes')
118 ])
119 ]),
120 h('tbody', map(store.blogs, blog => h('tr.blog', { id: blog.key }, [
121 h('td.details', [
122 h('div.title', {}, getTitle(blog)),
123 h('a',
124 {
125 href: '#',
126 'ev-click': viewBlog(blog)
127 },
128 'View blog'
129 )
130 ]),
131 h('td.comments', computed(store.comments.get(blog.key), msgs => msgs ? msgs.length : 0)),
132 h('td.likes', computed(store.likes.get(blog.key), msgs => msgs ? msgs.length : 0))
133 // ]), { comparer: (a, b) => a === b }))
134 ])))
135 ])
136 ])
137 ])
138 }
139
140 function viewBlog (blog) {
141 return () => api.history.sync.push(blog)
142 }
143}
144
145function getTitle (blog) {
146 if (blog.value.content.title) return blog.value.content.title
147 else if (blog.value.content.text) return marksum.title(blog.value.content.text)
148 else return blog.key
149}
150
151function fetchBlogs ({ server, store }) {
152 pull(
153 server.blogStats.readBlogs({ reverse: false }),
154 pull.drain(blog => {
155 store.blogs.push(blog)
156
157 fetchComments({ server, store, blog })
158 fetchLikes({ server, store, blog })
159 })
160 )
161}
162
163function fetchComments ({ server, store, blog }) {
164 if (!store.comments.has(blog.key)) store.comments.put(blog.key, MutantArray())
165
166 pull(
167 server.blogStats.readComments(blog),
168 pull.drain(msg => {
169 store.comments.get(blog.key).push(msg)
170 // TODO remove my comments from count?
171 })
172 )
173}
174
175function fetchLikes ({ server, store, blog }) {
176 if (!store.likes.has(blog.key)) store.likes.put(blog.key, MutantArray())
177
178 pull(
179 server.blogStats.readLikes(blog),
180 pull.drain(msg => {
181 store.likes.get(blog.key).push(msg)
182 // TODO this needs reducing... like + unlike are muddled in here
183 // find any thing by same author
184 // if exists - over-write or delete
185 })
186 )
187}
188

Built with git-ssb-web