1
1
import { useState , useEffect , useMemo } from "react"
2
2
import { useWalletStore } from "../stores/walletStore"
3
- import { useRefData , useSignup , useClientList , useClientProfile } from "../api/hooks"
3
+ import { useRefData , useSignup , useClientList , useClientProfile , useClientPolling } from "../api/hooks"
4
4
import VpnInstance from "../components/VpnInstance"
5
5
import WalletModal from "../components/WalletModal"
6
6
import { showSuccess , showError } from "../utils/toast"
@@ -20,6 +20,12 @@ const Account = () => {
20
20
} = useWalletStore ( )
21
21
const [ selectedDuration , setSelectedDuration ] = useState < number > ( 0 )
22
22
const [ selectedRegion , setSelectedRegion ] = useState < string > ( "" )
23
+ const [ pendingClients , setPendingClients ] = useState < Array < {
24
+ id : string
25
+ region : string
26
+ duration : string
27
+ purchaseTime : Date
28
+ } > > ( [ ] )
23
29
24
30
const tooltipSteps : TooltipStep [ ] = [
25
31
{
@@ -64,8 +70,20 @@ const Account = () => {
64
70
console . log ( 'Transaction built successfully:' , data )
65
71
66
72
try {
67
- const txHash = await signAndSubmitTransaction ( data . txCbor )
68
- showSuccess ( `VPN purchase successful! Transaction: ${ txHash } ` )
73
+ await signAndSubmitTransaction ( data . txCbor )
74
+ showSuccess ( `VPN purchase successful! Setting up your instance...` )
75
+
76
+ // Add pending client to the list
77
+ const pendingClient = {
78
+ id : data . clientId ,
79
+ region : selectedRegion ,
80
+ duration : selectedOption ? formatDuration ( selectedOption . value ) : 'Unknown' ,
81
+ purchaseTime : new Date ( )
82
+ }
83
+ setPendingClients ( prev => [ ...prev , pendingClient ] )
84
+
85
+ // Start polling for this client
86
+ startPolling ( data . clientId )
69
87
70
88
} catch ( error ) {
71
89
console . error ( 'Transaction error details:' , error )
@@ -144,6 +162,16 @@ const Account = () => {
144
162
}
145
163
} , [ refData ?. regions , selectedRegion ] )
146
164
165
+ // Remove pending clients when they become available in the client list
166
+ useEffect ( ( ) => {
167
+ if ( dedupedClientList && pendingClients . length > 0 ) {
168
+ const availableClientIds = new Set ( dedupedClientList . map ( client => client . id ) )
169
+ setPendingClients ( prev =>
170
+ prev . filter ( pending => ! availableClientIds . has ( pending . id ) )
171
+ )
172
+ }
173
+ } , [ dedupedClientList , pendingClients . length ] )
174
+
147
175
const selectedOption = durationOptions . find ( ( option : { value : number } ) => option . value === selectedDuration )
148
176
149
177
const handlePurchase = ( ) => {
@@ -177,6 +205,7 @@ const Account = () => {
177
205
}
178
206
179
207
const clientProfileMutation = useClientProfile ( )
208
+ const { startPolling } = useClientPolling ( )
180
209
181
210
const handleAction = async ( instanceId : string , action : string ) => {
182
211
if ( action === 'Get Config' ) {
@@ -221,9 +250,7 @@ const Account = () => {
221
250
}
222
251
223
252
const vpnInstances = useMemo ( ( ) => {
224
- if ( ! dedupedClientList ) return [ ]
225
-
226
- return dedupedClientList
253
+ const activeInstances = dedupedClientList ? dedupedClientList
227
254
. map ( ( client : ClientInfo ) => {
228
255
const isActive = new Date ( client . expiration ) > new Date ( )
229
256
@@ -245,8 +272,32 @@ const Account = () => {
245
272
} else {
246
273
return b . expirationDate . getTime ( ) - a . expirationDate . getTime ( )
247
274
}
248
- } )
249
- } , [ dedupedClientList ] )
275
+ } ) : [ ]
276
+
277
+ // Add pending instances
278
+ const pendingInstances = pendingClients . map ( pending => ( {
279
+ id : pending . id ,
280
+ region : pending . region ,
281
+ duration : pending . duration ,
282
+ status : 'Pending' as const ,
283
+ expires : 'Setting up...' ,
284
+ expirationDate : new Date ( pending . purchaseTime . getTime ( ) + 24 * 60 * 60 * 1000 ) // Placeholder
285
+ } ) )
286
+
287
+ // Combine and sort: Pending first, then Active, then Expired
288
+ return [ ...pendingInstances , ...activeInstances ] . sort ( ( a , b ) => {
289
+ if ( a . status === 'Pending' && b . status !== 'Pending' ) return - 1
290
+ if ( a . status !== 'Pending' && b . status === 'Pending' ) return 1
291
+ if ( a . status === 'Active' && b . status === 'Expired' ) return - 1
292
+ if ( a . status === 'Expired' && b . status === 'Active' ) return 1
293
+
294
+ if ( a . status === 'Active' ) {
295
+ return b . expirationDate . getTime ( ) - a . expirationDate . getTime ( )
296
+ } else {
297
+ return b . expirationDate . getTime ( ) - a . expirationDate . getTime ( )
298
+ }
299
+ } )
300
+ } , [ dedupedClientList , pendingClients ] )
250
301
251
302
return (
252
303
< TooltipGuide
@@ -258,9 +309,21 @@ const Account = () => {
258
309
< div className = "min-h-screen min-w-screen flex flex-col items-center justify-start bg-[linear-gradient(180deg,#1C246E_0%,#040617_12.5%)] pt-16" >
259
310
< div className = "flex flex-col items-center justify-center pt-8 gap-6 md:pt-12 md:gap-8 z-20 text-white w-full max-w-none md:max-w-[80rem] px-4 md:px-8" >
260
311
< LoadingOverlay
261
- isVisible = { signupMutation . isPending }
262
- messageTop = { signupMutation . isPending ? 'Awaiting Transaction Confirmation' : '' }
263
- messageBottom = "Processing Purchase"
312
+ isVisible = { signupMutation . isPending || clientProfileMutation . isPending }
313
+ messageTop = {
314
+ signupMutation . isPending
315
+ ? 'Awaiting Transaction Confirmation'
316
+ : clientProfileMutation . isPending
317
+ ? 'Preparing VPN Configuration'
318
+ : ''
319
+ }
320
+ messageBottom = {
321
+ signupMutation . isPending
322
+ ? 'Processing Purchase'
323
+ : clientProfileMutation . isPending
324
+ ? 'Downloading Config File'
325
+ : ''
326
+ }
264
327
/>
265
328
266
329
{ /* VPN PURCHASE SECTION */ }
0 commit comments