/
proxies-table.js
142 lines (125 loc) · 5.7 KB
/
proxies-table.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
const { api, avatarURL, handleForm, html } = require('../helpers')
const { animateProxies, reorderProxyRanks } = require('../effects/proxy')
const { icon } = require('@fortawesome/fontawesome-svg-core')
const { faTimes } = require('@fortawesome/free-solid-svg-icons/faTimes')
const { faBars } = require('@fortawesome/free-solid-svg-icons/faBars')
const { faArrowUp } = require('@fortawesome/free-solid-svg-icons/faArrowUp')
const { faArrowDown } = require('@fortawesome/free-solid-svg-icons/faArrowDown')
module.exports = (state, dispatch) => {
const { proxies = [], user } = state
return html`
<style>
.no-border tr td {
border: none;
}
</style>
<table class="table is-fullwidth no-border">
<tbody>
${proxies.map((d, idx) => proxyListItem(proxies, d, idx, user, dispatch))}
</tbody>
</table>
`
}
const proxyListItem = (proxies, proxy, idx, user, dispatch) => {
const { id, to_id, username, first_name, twitter_username } = proxy
// Fix for twitter names like 'jack' appearing as 'jack jack'
let { last_name } = proxy
if (first_name === last_name) { last_name = '' }
return html`
<tr draggable="true" ondragover=${ondragover({ idx, proxies }, dispatch)} ondragstart=${ondragstart({ id, idx })} ondragend=${ondragend({ proxies, user }, dispatch)}>
<td>${idx + 1}.</td>
<td>
<div class="media">
<div class="media-left">
<div class="image is-32x32">
${username || twitter_username
? html`<a href="${username ? `/${username}` : `/twitter/${twitter_username}`}" target="_blank">
<img src=${avatarURL(proxy)} class="is-rounded" />
</a>`
: html`
<img src=${avatarURL(proxy)} class="is-rounded" />
`}
</div>
</div>
<div class="media-content">
${username || twitter_username
? html`<a href="${username ? `/${username}` : `/twitter/${twitter_username}`}" target="_blank">
<span>${first_name} ${last_name}</span>
<span class="has-text-grey is-size-7">@${username || twitter_username}</span>
</a>`
: html`
<span>${first_name} ${last_name}</span>
`}
</div>
<div class="media-right">
${idx > 0 ? moveButton({ id, idx, direction: 'up' }, dispatch) : ''}
${idx < (proxies.length - 1) ? moveButton({ id, idx, direction: 'down' }, dispatch) : ''}
<form style="display: inline;" method="POST" onsubmit=${handleForm(dispatch, { type: 'proxy:removed' })}>
<input value="${to_id}" name="to_id" type="hidden" />
<input value="${id}" name="id" type="hidden" />
<button class="button is-small" type="submit" title="Remove">
<span class="icon has-text-grey">${icon(faTimes)}</span>
</button>
</form>
<span style="cursor: move;" class="icon has-text-grey is-hidden-touch" title="Click and hold to drag to a new position">
${icon(faBars)}
</span>
</div>
</div>
</td>
</tr>
`
}
const moveButton = ({ direction, id, idx }, dispatch) => {
return html`
<form style="display: inline;" method="POST" onsubmit=${handleForm(dispatch, { type: 'proxy:reordered' })}>
<input name="reorder_proxies[proxy_id]" value=${id} type="hidden" />
<input name="reorder_proxies[direction]" value=${direction} type="hidden" />
<input name="reorder_proxies[index]" value=${idx} type="hidden" />
<button class="button is-small" type="submit" title=${`Move ${direction}`}>
<span class="icon has-text-grey">${direction === 'up' ? icon(faArrowUp) : icon(faArrowDown)}</span>
</button>
</form>
`
}
const ondragover = ({ idx, proxies }, dispatch) => (event) => {
const table = event.currentTarget.parentNode
const { animating, childNodes, drag_curr_index } = table
// if we are hovering over the draggable element or animating don't do anything
if (drag_curr_index === idx || animating) return
const list_elements = Array.prototype.filter.call(childNodes, n => n.tagName === 'TR')
// reorder proxies list based on draggable element's new position/index
const reordered = [].concat(proxies)
reordered.splice(drag_curr_index, 1)
reordered.splice(idx, 0, proxies[drag_curr_index])
table.new_rank = proxies[idx].delegate_rank
table.drag_curr_index = idx
// calculate offset before and after list is reordered to add appropriate CSS
// transforms to animate elements into new position
// https://medium.com/developers-writing/animating-the-unanimatable-1346a5aab3cd
animateProxies(table, list_elements)
return dispatch({ type: 'proxy:proxiesUpdated', proxies: reordered })
}
const ondragstart = ({ id, idx }) => (event) => {
// set cursor: move and enable dragging by setting data
event.dataTransfer.dropEffect = 'move'
event.dataTransfer.setData('text/plain', id)
// Save starting draggable element's index for later.
// It changes as it's dragged around the list.
const table = event.currentTarget.parentNode
table.drag_curr_index = idx
}
const ondragend = ({ proxies, user }, dispatch) => (event) => {
const table = event.currentTarget.parentNode
const proxy = proxies[table.drag_curr_index]
const proxy_id = proxy.id
const old_rank = proxy.delegate_rank
const new_rank = table.new_rank
// send new delegate rank to API
dispatch({ type: 'proxy:proxiesUpdated', proxies: reorderProxyRanks(proxies, proxy, old_rank, new_rank) })
return api(dispatch, `/delegations?id=eq.${proxy_id}`, {
method: 'PATCH',
body: JSON.stringify({ delegate_rank: new_rank, updated_at: new Date() }),
user,
})
}