@@ -2,35 +2,93 @@ import {
2
2
SlButton ,
3
3
SlCard ,
4
4
SlDialog ,
5
+ SlDivider ,
5
6
SlIcon ,
6
7
SlInput ,
8
+ SlRadio ,
9
+ SlRadioGroup ,
7
10
} from "@shoelace-style/shoelace/dist/react" ;
8
11
import type SlInputElement from "@shoelace-style/shoelace/dist/components/input/input" ;
9
- import React , { FC , useState } from "react" ;
10
- import { useAppDispatch } from "../../app/hooks" ;
12
+ import React , { FC , useEffect , useRef , useState } from "react" ;
13
+ import { useAppDispatch , useAppSelector } from "../../app/hooks" ;
11
14
import styles from "./AddContract.module.css" ;
12
- import { importContract } from "./accountsSlice" ;
15
+ import {
16
+ importContract ,
17
+ instantiateContract ,
18
+ selectedAccount ,
19
+ setImportContractOpen ,
20
+ uploadContract ,
21
+ } from "./accountsSlice" ;
22
+ import { useSelector } from "react-redux" ;
23
+ import Editor from "react-simple-code-editor" ;
24
+ import formatHighlight from "json-format-highlight" ;
25
+ import { highlightColors } from "../console/consoleSlice" ;
13
26
14
- interface ImportContractProps {
15
- open : boolean ;
16
- setOpen : ( open : boolean ) => void ;
27
+ enum UploadType {
28
+ File = "file" ,
29
+ Code = "code" ,
17
30
}
18
31
19
- export const ImportContract : FC < ImportContractProps > = ( { open , setOpen } ) => {
32
+ export const ImportContract : FC = ( ) => {
20
33
const dispatch = useAppDispatch ( ) ;
34
+ const wasmInput = useRef < HTMLInputElement > ( null ) ;
21
35
const [ address , setAddress ] = useState ( "" ) ;
36
+ const [ label , setLabel ] = useState ( "" ) ;
37
+ const [ message , setMessage ] = useState ( "" ) ;
38
+ const [ codeId , setCodeId ] = useState ( "" ) ;
39
+ const [ uploadType , setUploadType ] = useState ( UploadType . File ) ;
40
+ const open = useAppSelector ( ( state ) => state . accounts . importContractOpen ) ;
41
+ const account = useSelector ( selectedAccount ) ;
42
+
43
+ useEffect ( ( ) => {
44
+ if ( ! open ) {
45
+ setAddress ( "" ) ;
46
+ setLabel ( "" ) ;
47
+ setMessage ( "" ) ;
48
+ setCodeId ( "" ) ;
49
+ }
50
+ } , [ open ] ) ;
22
51
23
52
function doImport ( ) {
24
53
dispatch ( importContract ( address ) ) ;
25
- setAddress ( "" ) ;
26
- setOpen ( false ) ;
54
+ }
55
+
56
+ async function doUpload ( ) {
57
+ if ( ! account ) throw new Error ( "No account selected" ) ;
58
+
59
+ const instantiateMsg = JSON . parse ( message ) ;
60
+
61
+ if ( uploadType === UploadType . File ) {
62
+ const wasmFile = wasmInput . current ?. files ?. [ 0 ] ;
63
+ if ( wasmFile ) {
64
+ const wasmBuffer = await wasmFile . arrayBuffer ( ) ;
65
+ const wasm = new Uint8Array ( wasmBuffer ) ;
66
+ dispatch (
67
+ uploadContract ( {
68
+ address : account . address ,
69
+ wasm,
70
+ instantiateMsg,
71
+ label,
72
+ } )
73
+ ) ;
74
+ }
75
+ } else {
76
+ dispatch (
77
+ instantiateContract ( {
78
+ address : account . address ,
79
+ codeId : Number ( codeId ) ,
80
+ instantiateMsg,
81
+ label,
82
+ } )
83
+ ) ;
84
+ }
27
85
}
28
86
29
87
return (
30
88
< SlDialog
31
- label = "Add contract"
89
+ label = "Import contract"
32
90
open = { open }
33
- onSlAfterHide = { ( ) => setOpen ( false ) }
91
+ onSlAfterHide = { ( ) => dispatch ( setImportContractOpen ( false ) ) }
34
92
>
35
93
< div className = { styles . importGroup } >
36
94
< SlInput
@@ -42,28 +100,93 @@ export const ImportContract: FC<ImportContractProps> = ({ open, setOpen }) => {
42
100
}
43
101
/>
44
102
< SlButton className = { styles . importButton } onClick = { ( ) => doImport ( ) } >
45
- Add
103
+ Import
46
104
</ SlButton >
47
105
</ div >
48
- < div className = { styles . importGroup } >
49
- < input className = { styles . file } type = "file" accept = ".wasm" />
50
- < SlButton className = { styles . importButton } onClick = { ( ) => doImport ( ) } >
51
- Upload
52
- </ SlButton >
106
+ < SlDivider />
107
+ < div className = { styles . uploadHeader } >
108
+ < div className = { styles . uploadTitle } > Create contract</ div >
109
+ < div className = { styles . instantiateFrom } >
110
+ < SlRadioGroup className = { styles . choices } >
111
+ < SlRadio
112
+ onSlFocus = { ( ) => setUploadType ( UploadType . File ) }
113
+ className = { styles . choice }
114
+ checked = { uploadType === UploadType . File }
115
+ >
116
+ From file
117
+ </ SlRadio >
118
+ < SlRadio
119
+ onSlFocus = { ( ) => setUploadType ( UploadType . Code ) }
120
+ className = { styles . choice }
121
+ checked = { uploadType === UploadType . Code }
122
+ >
123
+ From code
124
+ </ SlRadio >
125
+ </ SlRadioGroup >
126
+ </ div >
127
+ </ div >
128
+ < div className = { styles . upload } >
129
+ < div className = { styles . uploadGroup } >
130
+ < SlInput
131
+ placeholder = "Label"
132
+ value = { label }
133
+ className = { styles . label }
134
+ onSlChange = { ( e ) =>
135
+ setLabel ( ( e . target as SlInputElement ) . value . trim ( ) )
136
+ }
137
+ />
138
+ { uploadType === UploadType . File ? (
139
+ < input
140
+ className = { styles . file }
141
+ type = "file"
142
+ accept = ".wasm"
143
+ ref = { wasmInput }
144
+ />
145
+ ) : (
146
+ < SlInput
147
+ placeholder = "Code ID"
148
+ value = { codeId }
149
+ type = "number"
150
+ min = "1"
151
+ className = { styles . code }
152
+ onSlChange = { ( e ) =>
153
+ setCodeId ( ( e . target as SlInputElement ) . value . trim ( ) )
154
+ }
155
+ />
156
+ ) }
157
+ </ div >
158
+ < div className = { styles . msgWrapper } >
159
+ < Editor
160
+ className = { styles . instantiateMsg }
161
+ highlight = { ( code ) => formatHighlight ( code , highlightColors ) }
162
+ placeholder = "Instantiate message"
163
+ value = { message }
164
+ padding = { 10 }
165
+ onValueChange = { ( code ) => setMessage ( code ) }
166
+ />
167
+ </ div >
168
+ < div className = { styles . uploadButton } >
169
+ < SlButton onClick = { ( ) => doUpload ( ) } disabled = { ! account } >
170
+ { uploadType === UploadType . File ? "Upload and i" : "I" } nstantiate
171
+ </ SlButton >
172
+ </ div >
53
173
</ div >
54
174
</ SlDialog >
55
175
) ;
56
176
} ;
57
177
58
178
export const AddContract : FC = ( ) => {
59
- const [ importOpen , setImportOpen ] = useState ( false ) ;
179
+ const dispatch = useAppDispatch ( ) ;
60
180
61
181
return (
62
182
< >
63
- < SlCard className = { styles . adder } onClick = { ( ) => setImportOpen ( true ) } >
183
+ < SlCard
184
+ className = { styles . adder }
185
+ onClick = { ( ) => dispatch ( setImportContractOpen ( true ) ) }
186
+ >
64
187
< SlIcon name = "plus-lg" className = { styles . plus } /> Add contract
65
188
</ SlCard >
66
- < ImportContract open = { importOpen } setOpen = { setImportOpen } />
189
+ < ImportContract />
67
190
</ >
68
191
) ;
69
192
} ;
0 commit comments