forked from koshikraj/ottopus
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwallet-list.tsx
More file actions
115 lines (108 loc) · 3.79 KB
/
Copy pathwallet-list.tsx
File metadata and controls
115 lines (108 loc) · 3.79 KB
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
'use client'
import { useState } from 'react'
import { Button, Dialog } from '@/components/ui'
import type { Arm } from '@/lib/api'
import { truncateAddress } from '@/lib/format'
import { armName, walletClientName } from './naming'
import { ProofMark } from './proof-mark'
export interface WalletListProps {
wallets: Arm[]
onUnlink: (arm: Arm) => Promise<void>
}
/**
* The Settings rows, per P6: name, what kind of wallet, the address, and the
* one destructive action. Denser than the portfolio card because nothing here
* competes with a balance.
*/
export function WalletList({ wallets, onUnlink }: WalletListProps) {
const [confirming, setConfirming] = useState<Arm | null>(null)
const [busy, setBusy] = useState(false)
const [error, setError] = useState<string | null>(null)
function dismiss() {
if (busy) return
setConfirming(null)
setError(null)
}
async function confirm() {
if (!confirming) return
setBusy(true)
setError(null)
try {
await onUnlink(confirming)
setConfirming(null)
} catch {
// The dialog stays open holding the error. Closing it on failure would
// look exactly like success, and the wallet would still be linked.
//
// Rejecting the signature in the wallet lands here too, which is why the
// wording does not assert that anything went wrong on our side.
setError('That wallet is still linked. Nothing changed — try again.')
} finally {
setBusy(false)
}
}
return (
<>
<ul className="flex flex-col">
{wallets.map((arm) => {
const client = walletClientName(arm)
return (
<li
key={arm.id}
className="flex items-center justify-between gap-3.5 border-t border-[var(--ot-border)] px-[22px] py-3.5 first:border-t-0"
>
<div className="flex min-w-0 flex-col gap-[3px]">
<span className="flex items-center gap-2 text-[14px] font-semibold">
<span className="truncate">{armName(arm)}</span>
<ProofMark isWatchOnly={arm.isWatchOnly} />
<span className="font-normal text-[var(--ot-text-3)]">
{[client, arm.isWatchOnly ? 'watch only' : null].filter(Boolean).join(', ') ||
null}
</span>
</span>
<code className="font-mono text-[12px] text-[var(--ot-text-3)]">
{truncateAddress(arm.address)}
</code>
</div>
<Button
variant="secondary"
size="sm"
onClick={() => setConfirming(arm)}
aria-label={`Unlink ${armName(arm)}`}
>
Unlink
</Button>
</li>
)
})}
</ul>
<Dialog
open={confirming !== null}
onClose={dismiss}
tone="destructive"
title={`Unlink ${confirming ? armName(confirming) : ''}?`}
description={
confirming?.isWatchOnly
? 'Ottopus stops reading its balances and stops counting it when planning.'
: 'Ottopus stops planning with this wallet. Anything already signed is unaffected, and you can link it again whenever you like.'
}
actions={
<>
<Button variant="ghost" onClick={dismiss} disabled={busy} fullWidth>
Keep it
</Button>
<Button variant="destructive" onClick={() => void confirm()} disabled={busy} fullWidth>
{busy ? 'Unlinking…' : 'Unlink'}
</Button>
</>
}
>
{error ? (
<p role="alert" className="text-[13px] leading-[1.5] text-[var(--ot-block-text)]">
{error}
</p>
) : null}
</Dialog>
</>
)
}