1
1
import { useState , useEffect , useRef } from 'react' ;
2
- import { RequestQuery , OfferOptions , contractConfig , serverAddress } from '../../shared/index.js' ;
3
- import {
4
- Client ,
5
- ClientOptions ,
6
- RequestRecord ,
7
- createClient ,
8
- storage ,
9
- utils ,
10
- } from '../../../src/index.js' ; //@windingtree /sdk
2
+ import { Client , ClientOptions , createClient , storage } from '../../../src/index.js' ; // @windingtree /sdk
3
+ import { RequestQuery , OfferOptions , chainConfig , serverAddress } from '../../shared/index.js' ;
4
+ import { OfferData } from '../../../src/shared/types.js' ;
5
+ import { useWallet } from './providers/WalletProvider/WalletProviderContext.js' ;
6
+ import { AccountWidget } from './providers/WalletProvider/AccountWidget.js' ;
7
+ import { FormValues , RequestForm } from './components/RequestForm.js' ;
8
+ import { Tabs , TabPanel } from './components/Tabs.js' ;
9
+ import { Requests , RequestsRegistryRecord } from './components/Requests.js' ;
10
+ import { MakeDeal } from './components/MakeDeal.js' ;
11
+ import { Offers } from './components/Offers.js' ;
12
+ import { Deals , DealsRegistryRecord } from './components/Deals.js' ;
11
13
12
14
/** Default request expiration time */
13
15
const defaultExpire = '30s' ;
14
16
15
17
/** Default topic to publish requests the same as for the supplier node */
16
18
const defaultTopic = 'hello' ;
17
19
18
- type RequestsRegistryRecord = Required < RequestRecord < RequestQuery , OfferOptions > > ;
19
-
20
- interface FormValues {
21
- topic : string ;
22
- message : string ;
23
- }
24
-
25
- interface RequestFormProps {
26
- connected : boolean ;
27
- onSubmit ( query : FormValues ) : void ;
28
- }
29
-
30
- interface RequestsProps {
31
- requests : RequestsRegistryRecord [ ] ;
32
- subscribed ?: ( id : string ) => boolean ;
33
- onClear ( ) : void ;
34
- onCancel ( id : string ) : void ;
35
- }
36
-
37
- /**
38
- * Accepts user input
39
- */
40
- export const RequestForm = ( { connected, onSubmit } : RequestFormProps ) => {
41
- const [ topic , setTopic ] = useState < string > ( defaultTopic ) ;
42
- const [ message , setMessage ] = useState < string > ( '' ) ;
43
-
44
- if ( ! connected ) {
45
- return null ;
46
- }
47
-
48
- return (
49
- < div style = { { marginTop : 20 } } >
50
- < form
51
- onSubmit = { ( e ) => {
52
- e . preventDefault ( ) ;
53
- if ( message === '' ) {
54
- return ;
55
- }
56
- onSubmit ( {
57
- topic,
58
- message,
59
- } ) ;
60
- } }
61
- >
62
- < div style = { { marginBottom : 20 } } >
63
- < div >
64
- < strong > Topic:</ strong >
65
- </ div >
66
- < div style = { { marginBottom : 5 } } >
67
- < input value = { topic } onChange = { ( e ) => setTopic ( e . target . value ) } />
68
- </ div >
69
- < div >
70
- < strong > Request:</ strong >
71
- </ div >
72
- < div >
73
- < input value = { message } onChange = { ( e ) => setMessage ( e . target . value ) } />
74
- </ div >
75
- < div style = { { display : 'flex' , alignItems : 'center' , marginTop : 10 } } >
76
- < div >
77
- < button type = "submit" > Send</ button >
78
- </ div >
79
- </ div >
80
- </ div >
81
- </ form >
82
- </ div >
83
- ) ;
84
- } ;
85
-
86
20
/**
87
- * Published requests table
21
+ * Main application component
88
22
*/
89
- export const Requests = ( { requests, subscribed, onClear, onCancel } : RequestsProps ) => {
90
- if ( requests . length === 0 ) {
91
- return null ;
92
- }
93
-
94
- return (
95
- < div style = { { marginTop : 20 } } >
96
- < table border = { 1 } cellPadding = { 5 } >
97
- < thead >
98
- < tr >
99
- < td > Topic</ td >
100
- < td > Id</ td >
101
- < td > Query</ td >
102
- < td > Subscribed</ td >
103
- < td > Expired</ td >
104
- < td > Offers</ td >
105
- < td > Cancel</ td >
106
- </ tr >
107
- </ thead >
108
- < tbody >
109
- { requests . map ( ( r , index ) => (
110
- < tr key = { index } >
111
- < td > { r . data . topic } </ td >
112
- < td > { r . data . id } </ td >
113
- < td > { JSON . stringify ( r . data . query ) } </ td >
114
- < td > { subscribed && subscribed ( r . data . id ) ? '✅' : 'no' } </ td >
115
- < td > { utils . isExpired ( r . data . expire ) || r . cancelled ? '✅' : 'no' } </ td >
116
- < td > { r . offers . length } </ td >
117
- < td >
118
- { ! r . cancelled && ! utils . isExpired ( r . data . expire ) ? (
119
- < button
120
- onClick = { ( ) => {
121
- onCancel ( r . data . id ) ;
122
- } }
123
- >
124
- Cancel
125
- </ button >
126
- ) : (
127
- 'cancelled'
128
- ) }
129
- </ td >
130
- </ tr >
131
- ) ) }
132
- </ tbody >
133
- </ table >
134
- < div style = { { marginTop : 10 } } >
135
- < button
136
- onClick = { ( e ) => {
137
- e . preventDefault ( ) ;
138
- onClear ( ) ;
139
- } }
140
- >
141
- Clear
142
- </ button >
143
- </ div >
144
- </ div >
145
- ) ;
146
- } ;
147
-
148
23
export const App = ( ) => {
149
24
const client = useRef < Client < RequestQuery , OfferOptions > | undefined > ( ) ;
25
+ const { publicClient } = useWallet ( ) ;
150
26
const [ connected , setConnected ] = useState < boolean > ( false ) ;
27
+ const [ selectedTab , setSelectedTab ] = useState < number > ( 0 ) ;
151
28
const [ requests , setRequests ] = useState < RequestsRegistryRecord [ ] > ( [ ] ) ;
29
+ const [ deals , setDeals ] = useState < DealsRegistryRecord [ ] > ( [ ] ) ;
30
+ const [ offers , setOffers ] = useState < OfferData < RequestQuery , OfferOptions > [ ] | undefined > ( ) ;
31
+ const [ offer , setOffer ] = useState < OfferData < RequestQuery , OfferOptions > | undefined > ( ) ;
152
32
const [ error , setError ] = useState < string | undefined > ( ) ;
153
33
154
34
/** This hook starts the client that will be available via `client.current` */
@@ -158,21 +38,35 @@ export const App = () => {
158
38
setError ( undefined ) ;
159
39
160
40
const options : ClientOptions = {
161
- contractConfig ,
41
+ chain : chainConfig ,
162
42
serverAddress,
163
43
storageInitializer : storage . localStorage . createInitializer ( {
164
- session : true ,
44
+ session : false , // session or local storage
165
45
} ) ,
166
- requestRegistryPrefix : 'requestsRegistry' ,
46
+ dbKeysPrefix : 'wt_' ,
47
+ publicClient,
48
+ } ;
49
+
50
+ const updateRequests = ( ) => {
51
+ if ( client . current ) {
52
+ setRequests ( client . current . requests . getAll ( ) ) ;
53
+ }
54
+ } ;
55
+
56
+ const updateDeals = ( ) => {
57
+ if ( client . current ) {
58
+ client . current . deals . getAll ( ) . then ( ( newDeals ) => {
59
+ setDeals ( newDeals ) ;
60
+ } ) . catch ( console . error ) ;
61
+ }
167
62
} ;
168
63
169
64
client . current = createClient < RequestQuery , OfferOptions > ( options ) ;
170
65
171
66
client . current . addEventListener ( 'start' , ( ) => {
172
67
console . log ( '🚀 Client started at:' , new Date ( ) . toISOString ( ) ) ;
173
- if ( client . current ) {
174
- setRequests ( client . current . requests . getAll ( ) ) ;
175
- }
68
+ updateRequests ( ) ;
69
+ updateDeals ( ) ;
176
70
} ) ;
177
71
178
72
client . current . addEventListener ( 'stop' , ( ) => {
@@ -189,14 +83,7 @@ export const App = () => {
189
83
console . log ( '🔌 Client disconnected from server at:' , new Date ( ) . toISOString ( ) ) ;
190
84
} ) ;
191
85
192
- const updateRequests = ( ) => {
193
- if ( ! client . current ) {
194
- return ;
195
- }
196
- setRequests ( client . current . requests . getAll ( ) ) ;
197
- } ;
198
-
199
- /** Listening for requests events and update the table */
86
+ /** Listening for requests events and update tables */
200
87
client . current . addEventListener ( 'request:create' , updateRequests ) ;
201
88
client . current . addEventListener ( 'request:subscribe' , updateRequests ) ;
202
89
client . current . addEventListener ( 'request:publish' , updateRequests ) ;
@@ -206,6 +93,7 @@ export const App = () => {
206
93
client . current . addEventListener ( 'request:delete' , updateRequests ) ;
207
94
client . current . addEventListener ( 'request:offer' , updateRequests ) ;
208
95
client . current . addEventListener ( 'request:clear' , updateRequests ) ;
96
+ client . current . addEventListener ( 'deal:changed' , updateDeals ) ;
209
97
210
98
await client . current . start ( ) ;
211
99
} catch ( error ) {
@@ -215,7 +103,7 @@ export const App = () => {
215
103
} ;
216
104
217
105
startClient ( ) ;
218
- } , [ ] ) ;
106
+ } , [ publicClient ] ) ;
219
107
220
108
/** Publishing of request */
221
109
const sendRequest = async ( { topic, message } : FormValues ) => {
@@ -229,7 +117,7 @@ export const App = () => {
229
117
const request = await client . current . requests . create ( {
230
118
topic,
231
119
expire : defaultExpire ,
232
- nonce : 1 ,
120
+ nonce : BigInt ( 1 ) ,
233
121
query : {
234
122
greeting : message ,
235
123
} ,
@@ -244,26 +132,59 @@ export const App = () => {
244
132
245
133
return (
246
134
< >
135
+ < div style = { { display : 'flex' , flexDirection : 'row' , alignItems : 'center' } } >
136
+ < div style = { { flex : 1 } } >
137
+ < h1 > Client</ h1 >
138
+ </ div >
139
+ < AccountWidget />
140
+ </ div >
247
141
{ client . current && < div > ✅ Client started</ div > }
248
142
{ connected && < div > ✅ Connected to the coordination server</ div > }
249
- < RequestForm connected = { connected } onSubmit = { sendRequest } />
250
- < Requests
251
- requests = { requests }
252
- subscribed = { ( id ) => {
253
- console . log ( '###' , id ) ;
254
- return client . current ?. requests . subscribed ( id ) || false ;
255
- } }
256
- onClear = { ( ) => {
257
- if ( client . current ) {
258
- client . current ?. requests . clear ( ) ;
259
- }
260
- } }
261
- onCancel = { ( id ) => {
262
- if ( client . current ) {
263
- client . current . requests . cancel ( id ) ;
264
- }
265
- } }
143
+ < RequestForm connected = { connected } onSubmit = { sendRequest } defaultTopic = { defaultTopic } />
144
+ < Tabs
145
+ tabs = { [
146
+ {
147
+ id : 0 ,
148
+ title : 'Requests' ,
149
+ active : true ,
150
+ } ,
151
+ {
152
+ id : 1 ,
153
+ title : 'Deals' ,
154
+ } ,
155
+ ] }
156
+ onChange = { setSelectedTab }
266
157
/>
158
+ < TabPanel id = { 0 } activeTab = { selectedTab } >
159
+ < Requests
160
+ requests = { requests }
161
+ subscribed = { ( id ) => client . current ?. requests . subscribed ( id ) || false }
162
+ onClear = { ( ) => {
163
+ if ( client . current ) {
164
+ client . current ?. requests . clear ( ) ;
165
+ }
166
+ } }
167
+ onCancel = { ( id ) => {
168
+ if ( client . current ) {
169
+ client . current . requests . cancel ( id ) ;
170
+ }
171
+ } }
172
+ onOffers = { setOffers }
173
+ />
174
+ < Offers
175
+ offers = { offers }
176
+ onAccept = { setOffer }
177
+ onClose = { ( ) => {
178
+ setOffer ( undefined ) ;
179
+ setOffers ( undefined ) ;
180
+ } }
181
+ />
182
+ < MakeDeal offer = { offer } client = { client . current } />
183
+ </ TabPanel >
184
+ < TabPanel id = { 1 } activeTab = { selectedTab } >
185
+ < Deals deals = { deals } client = { client . current } />
186
+ </ TabPanel >
187
+
267
188
{ error && < div style = { { marginTop : 20 } } > 🚨 { error } </ div > }
268
189
</ >
269
190
) ;
0 commit comments