1
1
import { A , useNavigate } from "@solidjs/router" ;
2
- import { Shuffle , Users } from "lucide-solid" ;
3
- import { createMemo , Match , Show , Suspense , Switch } from "solid-js" ;
2
+ import { Plus , Shuffle , Trash , Users } from "lucide-solid" ;
3
+ import {
4
+ createMemo ,
5
+ createResource ,
6
+ createSignal ,
7
+ Match ,
8
+ Show ,
9
+ Suspense ,
10
+ Switch
11
+ } from "solid-js" ;
4
12
5
13
import {
6
14
AmountFiat ,
@@ -11,6 +19,7 @@ import {
11
19
InfoBox ,
12
20
MediumHeader ,
13
21
NiceP ,
22
+ SubtleButton ,
14
23
VStack
15
24
} from "~/components" ;
16
25
import { useI18n } from "~/i18n/context" ;
@@ -47,10 +56,14 @@ const STYLE =
47
56
"px-2 py-1 rounded-xl text-sm flex gap-2 items-center font-semibold" ;
48
57
49
58
export function BalanceBox ( props : { loading ?: boolean ; small ?: boolean } ) {
50
- const [ state , _actions ] = useMegaStore ( ) ;
59
+ const [ state , _actions , sw ] = useMegaStore ( ) ;
51
60
const navigate = useNavigate ( ) ;
52
61
const i18n = useI18n ( ) ;
53
62
63
+ const [ nodeManagerLoading , setNodeManagerLoading ] = createSignal ( false ) ;
64
+
65
+ const lightningBalance = ( ) => state . balance ?. lightning || 0n ;
66
+
54
67
const totalOnchain = createMemo (
55
68
( ) =>
56
69
( state . balance ?. confirmed || 0n ) +
@@ -64,6 +77,35 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) {
64
77
( state . balance ?. unconfirmed || 0n )
65
78
) ;
66
79
80
+ const [ hasSelfCustody , { refetch } ] = createResource ( async ( ) => {
81
+ // short circuit if we have a balance
82
+ if ( totalOnchain ( ) > 0 || state . balance ?. lightning || 0n > 0n ) {
83
+ return true ;
84
+ }
85
+
86
+ // otherwise check if we have created a node
87
+ const nodes : string [ ] = await sw . list_nodes ( ) ;
88
+ return nodes . length > 0 ;
89
+ } ) ;
90
+
91
+ const createNodeManager = async ( ) => {
92
+ if ( confirm ( "Pass this test:" ) ) {
93
+ setNodeManagerLoading ( true ) ;
94
+ await sw . create_node_manager_if_needed ( ) ;
95
+ await refetch ( ) ;
96
+ setNodeManagerLoading ( false ) ;
97
+ }
98
+ } ;
99
+
100
+ const removeNodeManager = async ( ) => {
101
+ if ( confirm ( "Are you sure:" ) ) {
102
+ setNodeManagerLoading ( true ) ;
103
+ await sw . remove_node_manager ( ) ;
104
+ await refetch ( ) ;
105
+ setNodeManagerLoading ( false ) ;
106
+ }
107
+ } ;
108
+
67
109
return (
68
110
< VStack >
69
111
< Switch >
@@ -131,81 +173,123 @@ export function BalanceBox(props: { loading?: boolean; small?: boolean }) {
131
173
</ Match >
132
174
</ Switch >
133
175
< MediumHeader > { i18n . t ( "profile.self_custody" ) } </ MediumHeader >
134
- < FancyCard >
135
- < Show when = { ! props . loading } fallback = { < LoadingShimmer /> } >
136
- < Switch >
137
- < Match when = { state . safe_mode } >
138
- < div class = "flex flex-col gap-1" >
139
- < InfoBox accent = "red" >
140
- { i18n . t ( "common.error_safe_mode" ) }
141
- </ InfoBox >
142
- </ div >
143
- </ Match >
144
- < Match when = { true } >
145
- < div class = "flex flex-col gap-1" >
146
- < div class = "text-2xl" >
147
- < AmountSats
148
- amountSats = {
149
- state . balance ?. lightning || 0
150
- }
151
- icon = "lightning"
152
- denominationSize = "lg"
153
- />
154
- </ div >
155
- < div class = "text-lg text-white/70" >
156
- < Suspense >
157
- < AmountFiat
158
- amountSats = {
159
- state . balance ?. lightning || 0
160
- }
161
- denominationSize = "sm"
162
- />
163
- </ Suspense >
164
- </ div >
165
- </ div >
166
- </ Match >
167
- </ Switch >
168
- </ Show >
169
- < hr class = "my-2 border-m-grey-750" />
170
- < Show when = { ! props . loading } fallback = { < LoadingShimmer /> } >
171
- < div class = "flex justify-between" >
172
- < div class = "flex flex-col gap-1" >
173
- < div class = "text-2xl" >
174
- < AmountSats
175
- amountSats = { totalOnchain ( ) }
176
- icon = "chain"
177
- denominationSize = "lg"
178
- />
179
- </ div >
180
- < div class = "text-lg text-white/70" >
181
- < Suspense >
182
- < AmountFiat
183
- amountSats = { totalOnchain ( ) }
184
- denominationSize = "sm"
185
- />
186
- </ Suspense >
187
- </ div >
188
- </ div >
189
- < div class = "flex flex-col items-end justify-between gap-1" >
190
- < Show when = { state . balance ?. unconfirmed != 0n } >
191
- < Indicator >
192
- { i18n . t ( "common.pending" ) }
193
- </ Indicator >
194
- </ Show >
195
- < Show when = { state . balance ?. unconfirmed === 0n } >
196
- < div />
176
+ < Suspense >
177
+ < Switch >
178
+ < Match when = { hasSelfCustody ( ) } >
179
+ < FancyCard >
180
+ < Show
181
+ when = { ! props . loading }
182
+ fallback = { < LoadingShimmer /> }
183
+ >
184
+ < Switch >
185
+ < Match when = { state . safe_mode } >
186
+ < div class = "flex flex-col gap-1" >
187
+ < InfoBox accent = "red" >
188
+ { i18n . t (
189
+ "common.error_safe_mode"
190
+ ) }
191
+ </ InfoBox >
192
+ </ div >
193
+ </ Match >
194
+ < Match when = { true } >
195
+ < div class = "flex flex-col gap-1" >
196
+ < div class = "text-2xl" >
197
+ < AmountSats
198
+ amountSats = { lightningBalance ( ) }
199
+ icon = "lightning"
200
+ denominationSize = "lg"
201
+ />
202
+ </ div >
203
+ < div class = "text-lg text-white/70" >
204
+ < Suspense >
205
+ < AmountFiat
206
+ amountSats = { lightningBalance ( ) }
207
+ denominationSize = "sm"
208
+ />
209
+ </ Suspense >
210
+ </ div >
211
+ </ div >
212
+ </ Match >
213
+ </ Switch >
197
214
</ Show >
198
- < Show when = { usableOnchain ( ) > 0n } >
199
- < div class = "self-end justify-self-end" >
200
- < A href = "/swap" class = { STYLE } >
201
- < Shuffle class = "h-6 w-6" />
202
- </ A >
215
+ < hr class = "my-2 border-m-grey-750" />
216
+ < Show
217
+ when = { ! props . loading }
218
+ fallback = { < LoadingShimmer /> }
219
+ >
220
+ < div class = "flex justify-between" >
221
+ < div class = "flex flex-col gap-1" >
222
+ < div class = "text-2xl" >
223
+ < AmountSats
224
+ amountSats = { totalOnchain ( ) }
225
+ icon = "chain"
226
+ denominationSize = "lg"
227
+ />
228
+ </ div >
229
+ < div class = "text-lg text-white/70" >
230
+ < Suspense >
231
+ < AmountFiat
232
+ amountSats = { totalOnchain ( ) }
233
+ denominationSize = "sm"
234
+ />
235
+ </ Suspense >
236
+ </ div >
237
+ </ div >
238
+ < div class = "flex flex-col items-end justify-between gap-1" >
239
+ < Show
240
+ when = {
241
+ state . balance ?. unconfirmed != 0n
242
+ }
243
+ >
244
+ < Indicator >
245
+ { i18n . t ( "common.pending" ) }
246
+ </ Indicator >
247
+ </ Show >
248
+ < Show
249
+ when = {
250
+ state . balance ?. unconfirmed ===
251
+ 0n
252
+ }
253
+ >
254
+ < div />
255
+ </ Show >
256
+ < Show when = { usableOnchain ( ) > 0n } >
257
+ < div class = "self-end justify-self-end" >
258
+ < A href = "/swap" class = { STYLE } >
259
+ < Shuffle class = "h-6 w-6" />
260
+ </ A >
261
+ </ div >
262
+ </ Show >
263
+ </ div >
203
264
</ div >
265
+ < Show
266
+ when = {
267
+ totalOnchain ( ) === 0n &&
268
+ lightningBalance ( ) === 0n &&
269
+ state . federations &&
270
+ state . federations . length
271
+ }
272
+ >
273
+ < SubtleButton
274
+ onClick = { removeNodeManager }
275
+ loading = { nodeManagerLoading ( ) }
276
+ >
277
+ < Trash class = "h-4 w-4" />
278
+ </ SubtleButton >
279
+ </ Show >
204
280
</ Show >
205
- </ div >
206
- </ div >
207
- </ Show >
208
- </ FancyCard >
281
+ </ FancyCard >
282
+ </ Match >
283
+ < Match when = { true } >
284
+ < SubtleButton
285
+ onClick = { createNodeManager }
286
+ loading = { nodeManagerLoading ( ) }
287
+ >
288
+ < Plus class = "h-4 w-4" />
289
+ </ SubtleButton >
290
+ </ Match >
291
+ </ Switch >
292
+ </ Suspense >
209
293
</ VStack >
210
294
) ;
211
295
}
0 commit comments