Skip to content

Commit b2ecab5

Browse files
committed
feat(ui): ✨ add transactions list component
1 parent db40325 commit b2ecab5

File tree

4 files changed

+286
-22
lines changed

4 files changed

+286
-22
lines changed
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
import { lit as html } from '../helpers/lit.js'
2+
import {
3+
envoy,
4+
restate,
5+
// sortContactsByAlias,
6+
// filterPairedContacts,
7+
// filterUnpairedContacts,
8+
// timeago,
9+
// getAvatar,
10+
} from '../helpers/utils.js'
11+
12+
let _handlers = []
13+
14+
const initialState = {
15+
id: 'Transactions',
16+
name: 'List',
17+
placement: 'transactions',
18+
rendered: null,
19+
responsive: true,
20+
showUnpaired: false,
21+
delay: 500,
22+
wallet: {},
23+
transactions: [],
24+
restate,
25+
render(
26+
renderState = {},
27+
position = 'beforeend',
28+
) {},
29+
header: state => html`
30+
<header>
31+
<h5 class="lh-2">Transactions</h5>
32+
</header>
33+
`,
34+
list: async state => {
35+
if (state.transactions?.length === 0) {
36+
return html`<span class="flex flex-fill center">No Transactions found</span>`
37+
}
38+
39+
return (
40+
await Promise.all(
41+
state.transactions
42+
// .filter(
43+
// state.showUnpaired
44+
// ? filterUnpairedContacts
45+
// : filterPairedContacts
46+
// )
47+
// .sort(sortContactsByAlias)
48+
.map(async c => await state.item(c)),
49+
)
50+
).join('')
51+
},
52+
content: async state => html`
53+
${state.header(state)}
54+
55+
<div>
56+
${await state.list(state)}
57+
</div>
58+
`,
59+
item: async c => {
60+
// if ('string' === typeof c) {
61+
return html`
62+
<article>
63+
<address>
64+
<h4><!-- Encrypted --> Transaction</h4>
65+
</address>
66+
</article>
67+
`
68+
// }
69+
70+
// let outgoing = Object.values(c?.outgoing || {})
71+
// let paired = outgoing.length > 0
72+
// let out = outgoing?.[0]
73+
// let created = c.createdAt
74+
// ? timeago(Date.now() - (new Date(c.createdAt)).getTime())
75+
// : ''
76+
// let user = c.alias || c.info?.preferred_username
77+
// let finishPairing = !paired
78+
// ? 'Finish pairing with contact'
79+
// : ''
80+
// let enterContactInfo = !paired || !user
81+
// ? `Enter contact information for`
82+
// : ''
83+
// let name = c.info?.name
84+
85+
// if (
86+
// !name &&
87+
// !user &&
88+
// !out?.xkeyId &&
89+
// out?.address
90+
// ) {
91+
// name = out?.address
92+
// } else if (!name) {
93+
// name = created
94+
// }
95+
96+
// let inId = Object.keys(c?.incoming || {})?.[0]?.split('/')[1]
97+
98+
// let atUser = user
99+
// ? `@${user}`
100+
// : ''
101+
// let itemAlias = user
102+
// ? `${atUser}${ !paired ? ' - ' : '' }${finishPairing}`
103+
// : finishPairing || enterContactInfo
104+
// let itemName = name
105+
// ? `${name}`
106+
// : ''
107+
// let itemSub = inId
108+
// ? `href="/#!/contact/${atUser || inId}" data-id="${inId}"`
109+
// : ''
110+
// let itemCtrls = paired
111+
// ? html`<aside class="inline row">
112+
// <button class="pill rounded">
113+
// <svg width="24" height="24" viewBox="0 0 24 24">
114+
// <use xlink:href="#icon-arrow-circle-up"></use>
115+
// </svg>
116+
// </button>
117+
// <button class="pill rounded">
118+
// <svg width="24" height="24" viewBox="0 0 24 24">
119+
// <use xlink:href="#icon-arrow-circle-down"></use>
120+
// </svg>
121+
// </button>
122+
// </aside>`
123+
// : ''
124+
125+
// itemCtrls = '' // temp override
126+
127+
// return html`
128+
// <a ${itemSub}>
129+
// ${await getAvatar(c)}
130+
// <address>
131+
// <h4>${itemAlias}</h4>
132+
// <h5>${itemName}</h5>
133+
// </address>
134+
// ${itemCtrls}
135+
// </a>
136+
// `
137+
},
138+
footer: async state => html``,
139+
slugs: {
140+
},
141+
elements: {
142+
},
143+
events: {
144+
handleClick: state => event => {
145+
event.preventDefault()
146+
event.stopPropagation()
147+
console.log(
148+
'handle transactions click',
149+
event,
150+
state,
151+
)
152+
},
153+
handleTransactionsChange: (newState, oldState) => {
154+
if (newState.transactions !== oldState.transactions) {
155+
newState.render?.({
156+
transactions: newState.transactions
157+
})
158+
}
159+
}
160+
},
161+
}
162+
163+
let state = envoy(
164+
initialState,
165+
initialState.events.handleTransactionsChange,
166+
)
167+
168+
export async function setupTransactionsList(
169+
el, setupState = {}
170+
) {
171+
restate(state, setupState)
172+
173+
state.slugs.section = `${state.name}_${state.id}`
174+
.toLowerCase().replace(' ', '_')
175+
176+
const section = document.createElement('section')
177+
178+
section.id = state.slugs.section
179+
section.classList.add(state.placement || '')
180+
section.innerHTML = await state.content(state)
181+
182+
state.elements.section = section
183+
184+
const list = section.querySelector('& > div')
185+
186+
state.elements.list = list
187+
188+
function addListener(
189+
node,
190+
event,
191+
handler,
192+
capture = false
193+
) {
194+
_handlers.push({ node, event, handler, capture })
195+
node.addEventListener(event, handler, capture)
196+
}
197+
198+
function removeAllListeners(
199+
targets = [state.elements.section],
200+
) {
201+
_handlers = _handlers
202+
.filter(({ node, event, handler, capture }) => {
203+
if (targets.includes(node)) {
204+
node.removeEventListener(event, handler, capture)
205+
return false
206+
}
207+
return true
208+
})
209+
}
210+
211+
function addListeners() {
212+
addListener(
213+
state.elements.section,
214+
'click',
215+
state.events.handleClick(state),
216+
)
217+
}
218+
219+
state.removeAllListeners = removeAllListeners
220+
state.addListeners = addListeners
221+
222+
async function render(
223+
renderState = {},
224+
position = 'beforeend',
225+
) {
226+
await restate(state, renderState)
227+
228+
state.elements.section.id = state.slugs.section
229+
230+
state.elements.list.innerHTML = await state.list(state)
231+
232+
state.removeAllListeners()
233+
state.addListeners()
234+
235+
if (!state.rendered) {
236+
el.insertAdjacentElement(position, section)
237+
state.rendered = section
238+
}
239+
}
240+
241+
state.render = render
242+
243+
return {
244+
element: section,
245+
render,
246+
restate: async newState => await restate(state, newState),
247+
}
248+
}
249+
250+
export default setupTransactionsList

src/helpers/db.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,18 @@ export async function DatabaseSetup() {
4848
...localForageBaseCfg,
4949
storeName: 'addresses',
5050
});
51+
var transactions = localforage.createInstance({
52+
...localForageBaseCfg,
53+
storeName: 'transactions',
54+
});
5155

5256
return {
5357
wallets,
5458
addresses,
5559
contacts,
5660
accounts,
5761
aliases,
62+
transactions,
5863
}
5964
}
6065

src/main.js

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import setupNav from './components/nav.js'
4646
import setupMainFooter from './components/main-footer.js'
4747
import setupSendRequestBtns from './components/send-request-btns.js'
4848
import setupContactsList from './components/contacts-list.js'
49+
import setupTransactionsList from './components/transactions-list.js'
4950
import setupSVGSprite from './components/svg-sprite.js'
5051
import setupDialog from './components/dialog.js'
5152

@@ -85,6 +86,11 @@ let appState = envoy(
8586
sentTransactions: {},
8687
account: {},
8788
},
89+
// async (state, oldState, prop) => {
90+
// if (prop === 'sentTransactions') {
91+
// console.log(prop, state[prop])
92+
// }
93+
// },
8894
)
8995
let appTools = envoy(
9096
{
@@ -115,7 +121,7 @@ let userInfo = envoy(
115121
false,
116122
)
117123
}
118-
}
124+
},
119125
)
120126

121127
// rigs
@@ -368,6 +374,21 @@ let contactsList = await setupContactsList(
368374
},
369375
}
370376
)
377+
let transactionsList = await setupTransactionsList(mainAppGrid, {
378+
events: {
379+
handleClick: state => async event => {
380+
event.preventDefault()
381+
382+
let txArticle = event.target?.closest('a, article')
383+
384+
console.log(
385+
'setupTransactionsList click event',
386+
event.target,
387+
txArticle,
388+
)
389+
},
390+
},
391+
})
371392

372393
async function getUserInfo() {
373394
let ks = wallets?.[appState.selectedWallet]?.keystore
@@ -831,16 +852,10 @@ async function main() {
831852
</div>
832853
</section>
833854
`)
834-
mainAppGrid.insertAdjacentHTML('beforeend', html`
835-
<section class="transactions">
836-
<header>
837-
<h5 class="lh-2">Transactions</h5>
838-
</header>
839-
<div>
840-
<span class="flex flex-fill center">Coming soon</span>
841-
</div>
842-
</section>
843-
`)
855+
856+
await transactionsList.render({
857+
// transactions: appState.transactions,
858+
})
844859

845860
document.addEventListener('click', async event => {
846861
let {
@@ -1141,7 +1156,9 @@ async function main() {
11411156
1000
11421157
)
11431158
}
1159+
11441160
let txs = appState?.sentTransactions
1161+
let txsStartLen = Object.keys(txs).length
11451162

11461163
Object.keys(txUpdates).forEach(
11471164
txid => {
@@ -1151,7 +1168,9 @@ async function main() {
11511168
}
11521169
)
11531170

1154-
appState.sentTransactions = txs
1171+
if (txsStartLen > Object.keys(txs).length) {
1172+
appState.sentTransactions = txs
1173+
}
11551174
},
11561175
})
11571176
}

src/styles/theme.css

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -477,16 +477,6 @@ th {
477477
background-color: var(--dark-500);
478478
}
479479

480-
.cols > .transactions {
481-
opacity: 0.4;
482-
cursor: not-allowed;
483-
cursor: wait;
484-
user-select: none;
485-
}
486-
/* .cols > .transactions > div {
487-
background-color: var(--dark-500);
488-
} */
489-
490480
.avatar {
491481
background-color: var(--dark-500);
492482
color: var(--dark-100);

0 commit comments

Comments
 (0)