Files: 5408d3118894220a8d70afa1754390b36514ba45 / contact / html / relationships.js
4815 bytesRaw
1 | const nest = require('depnest') |
2 | const { h, map, computed, when, Value } = require('mutant') |
3 | |
4 | exports.gives = nest('contact.html.relationships') |
5 | |
6 | exports.needs = nest({ |
7 | // 'about.html.image': 'first', |
8 | 'about.html.avatar': 'first', |
9 | // 'about.obs.name': 'first', |
10 | 'contact.async.follow': 'first', |
11 | 'contact.async.unfollow': 'first', |
12 | 'contact.async.block': 'first', |
13 | 'contact.async.unblock': 'first', |
14 | 'contact.obs.followers': 'first', |
15 | 'contact.obs.following': 'first', |
16 | 'contact.obs.blockers': 'first', |
17 | 'contact.obs.blocking': 'first', |
18 | 'keys.sync.id': 'first' |
19 | }) |
20 | |
21 | exports.create = function (api) { |
22 | return nest({ |
23 | 'contact.html.relationships': relationships |
24 | }) |
25 | |
26 | function relationships (feedId) { |
27 | const rawFollowing = api.contact.obs.following(feedId) |
28 | const rawFollowers = api.contact.obs.followers(feedId) |
29 | |
30 | // mix: TODO rework this |
31 | const friends = computed([rawFollowing, rawFollowers], (following, followers) => { |
32 | return [...following].filter(follow => followers.includes(follow)) |
33 | }) |
34 | const following = computed([rawFollowing, friends], (following, friends) => { |
35 | return [...following].filter(follow => !friends.includes(follow)) |
36 | }) |
37 | const followers = computed([rawFollowers, friends], (followers, friends) => { |
38 | return [...followers].filter(follower => !friends.includes(follower)) |
39 | }) |
40 | const blockers = api.contact.obs.blockers(feedId) |
41 | const blocking = api.contact.obs.blocking(feedId) |
42 | |
43 | const modes = [ |
44 | { label: 'Friends', data: friends }, |
45 | { label: 'Follows', data: following }, |
46 | { label: 'Followers', data: followers }, |
47 | { label: 'Blocked by', data: blockers, hideEmpty: true }, |
48 | { label: 'Blocking', data: blocking, hideEmpty: true } |
49 | ] |
50 | const mode = Value(0) |
51 | const setMode = (i) => { |
52 | if (mode() === i) mode.set() |
53 | else mode.set(i) |
54 | } |
55 | |
56 | const avatar = api.about.html.avatar |
57 | |
58 | return h('Relationships', [ |
59 | h('header', 'Relationships'), |
60 | RelationshipStatus({ feedId, rawFollowing, blockers, api }), |
61 | |
62 | h('div.groups', [ |
63 | h('div.tabs', modes.map(({ label, data, hideEmpty }, i) => { |
64 | return computed([data, mode], (d, mode) => { |
65 | if (hideEmpty && !d.length) return |
66 | |
67 | return h('div.tab', |
68 | { |
69 | className: mode === i ? '-active' : '', |
70 | 'ev-click': () => setMode(i) |
71 | }, |
72 | [ |
73 | h('div.label', label), |
74 | h('div.count', d.length > 50 ? '50+' : d.length) |
75 | ] |
76 | ) |
77 | }) |
78 | })), |
79 | h('div.group', computed(mode, i => { |
80 | if (i === null) return |
81 | |
82 | const { data } = modes[i] |
83 | return map(data, avatar) |
84 | })) |
85 | ]) |
86 | ]) |
87 | } |
88 | } |
89 | |
90 | function RelationshipStatus ({ feedId, rawFollowing, blockers, api }) { |
91 | const myId = api.keys.sync.id() |
92 | if (feedId === myId) return |
93 | |
94 | // mix: TODO oh lord this is ugly, refactor it ! |
95 | const ImFollowing = api.contact.obs.following(myId) |
96 | const IFollowThem = computed([ImFollowing], ImFollowing => ImFollowing.includes(feedId)) |
97 | const theyFollowMe = computed([rawFollowing], following => following.includes(myId)) |
98 | const ImBlockingThem = computed(blockers, blockers => blockers.includes(myId)) |
99 | |
100 | const relationshipStatus = computed([IFollowThem, theyFollowMe], (IFollowThem, theyFollowMe) => { |
101 | return IFollowThem && theyFollowMe ? '- you are friends' |
102 | : IFollowThem ? '- you follow them' |
103 | : theyFollowMe ? '- they follow you' |
104 | : '' |
105 | }) |
106 | const { unfollow, follow, block, unblock } = api.contact.async |
107 | |
108 | return h('div.relationship-status', [ |
109 | h('section -friendship', [ |
110 | when(ImFollowing.sync, |
111 | when(IFollowThem, |
112 | h('button', { 'ev-click': () => unfollow(feedId) }, 'Unfollow'), |
113 | h('button', { 'ev-click': () => follow(feedId) }, 'Follow') |
114 | ), |
115 | h('button', { disabled: 'disabled' }, 'Loading...') |
116 | ), |
117 | when(ImFollowing.sync, h('div.relationship-status', relationshipStatus)) |
118 | ]), |
119 | h('section -blocking', [ |
120 | when(ImBlockingThem, |
121 | h('button -subtle', { 'ev-click': () => unblock(feedId, console.log) }, [ h('i.fa.fa-ban'), 'unblock' ]), |
122 | h('button -subtle', { 'ev-click': () => block(feedId, console.log) }, [ h('i.fa.fa-ban'), 'BLOCK' ]) |
123 | ), |
124 | h('div.explainer', [ |
125 | "Blocking tells everyone you don't want to communicate with a person.", |
126 | h('ul', [ |
127 | h('li', 'You will no longer receive messages from this person'), |
128 | h('li', "This person won't get any new information about you (including this block)"), |
129 | h('li', "Your followers will see you have blocked this person - their apps need to know so that they don't pass your information on.") |
130 | ]) |
131 | ]) |
132 | ]) |
133 | ]) |
134 | } |
135 |
Built with git-ssb-web