3
3
EuiButton ,
4
4
EuiButtonIcon ,
5
5
EuiCallOut ,
6
- EuiCode ,
7
6
EuiConfirmModal ,
8
7
EuiFieldPassword ,
9
8
EuiFieldText ,
@@ -19,6 +18,7 @@ import {
19
18
import type { ReactNode } from 'react' ;
20
19
import type React from 'react' ;
21
20
import { useCallback , useEffect , useMemo , useState } from 'react' ;
21
+ import { Controller , useForm } from 'react-hook-form' ;
22
22
import { isBlank } from '../../../common/string/is-blank.js' ;
23
23
import { runInBackground } from '../../lib/async/run-in-background.js' ;
24
24
@@ -31,50 +31,15 @@ interface FormRecord {
31
31
accountPassword ?: string ;
32
32
}
33
33
34
- interface FormErrors {
35
- accountName ?: string ;
36
- accountPassword ?: string ;
37
- }
38
-
39
34
export const SidebarItemAccounts : React . FC = ( ) : ReactNode => {
40
35
const [ showAddAccountModal , setShowAddAccountModal ] = useState ( false ) ;
41
36
const [ showEditAccountModal , setShowEditAccountModal ] = useState ( false ) ;
42
37
const [ showRemoveAccountModal , setShowRemoveAccountModal ] = useState ( false ) ;
43
38
44
- // All the table row items (accounts) to display.
45
39
const [ tableRowItems , setTableRowItems ] = useState < Array < TableRowItem > > ( [ ] ) ;
40
+ const [ tableRowItem , setTableRowItem ] = useState < TableRowItem > ( ) ;
46
41
47
- // The contextual form record (account) for the current action.
48
- const [ formRecord , setFormRecord ] = useState < FormRecord > ( { } ) ;
49
- const [ formErrors , setFormErrors ] = useState < FormErrors > ( { } ) ;
50
-
51
- const validateAccountName = useCallback ( ( ) => {
52
- if ( isBlank ( formRecord . accountName ) ) {
53
- setFormErrors ( {
54
- ...formErrors ,
55
- accountName : 'Name is required.' ,
56
- } ) ;
57
- } else {
58
- setFormErrors ( {
59
- ...formErrors ,
60
- accountName : undefined ,
61
- } ) ;
62
- }
63
- } , [ formRecord , formErrors ] ) ;
64
-
65
- const validateAccountPassword = useCallback ( ( ) => {
66
- if ( isBlank ( formRecord . accountPassword ) ) {
67
- setFormErrors ( {
68
- ...formErrors ,
69
- accountPassword : 'Password is required.' ,
70
- } ) ;
71
- } else {
72
- setFormErrors ( {
73
- ...formErrors ,
74
- accountPassword : undefined ,
75
- } ) ;
76
- }
77
- } , [ formRecord , formErrors ] ) ;
42
+ const { handleSubmit, control, reset } = useForm < FormRecord > ( ) ;
78
43
79
44
const loadAccounts = useCallback ( async ( ) => {
80
45
const accounts = await window . api . listAccounts ( ) ;
@@ -85,9 +50,9 @@ export const SidebarItemAccounts: React.FC = (): ReactNode => {
85
50
setShowAddAccountModal ( false ) ;
86
51
setShowEditAccountModal ( false ) ;
87
52
setShowRemoveAccountModal ( false ) ;
88
- setFormRecord ( { } ) ;
89
- setFormErrors ( { } ) ;
90
- } , [ ] ) ;
53
+ setTableRowItem ( undefined ) ;
54
+ reset ( { } ) ;
55
+ } , [ reset ] ) ;
91
56
92
57
const onAddAccountClick = useCallback ( ( ) => {
93
58
closeModals ( ) ;
@@ -97,58 +62,46 @@ export const SidebarItemAccounts: React.FC = (): ReactNode => {
97
62
const onEditAccountClick = useCallback (
98
63
( tableRowItem : TableRowItem ) => {
99
64
closeModals ( ) ;
100
- setFormRecord ( tableRowItem ) ;
101
- setFormErrors ( { } ) ;
65
+ setTableRowItem ( tableRowItem ) ;
102
66
setShowEditAccountModal ( true ) ;
103
67
} ,
104
- [ closeModals ]
68
+ [ setTableRowItem , closeModals ]
105
69
) ;
106
70
107
71
const onRemoveAccountClick = useCallback (
108
72
( tableRowItem : TableRowItem ) => {
109
73
closeModals ( ) ;
110
- setFormRecord ( tableRowItem ) ;
111
- setFormErrors ( { } ) ;
74
+ setTableRowItem ( tableRowItem ) ;
112
75
setShowRemoveAccountModal ( true ) ;
113
76
} ,
114
- [ closeModals ]
77
+ [ setTableRowItem , closeModals ]
115
78
) ;
116
79
117
80
const onAccountSaveConfirm = useCallback ( ( ) => {
118
81
runInBackground ( async ( ) => {
119
- validateAccountName ( ) ;
120
- validateAccountPassword ( ) ;
121
- if ( formErrors . accountName || formErrors . accountPassword ) {
122
- return ;
123
- }
124
- await window . api . saveAccount ( {
125
- accountName : formRecord . accountName ! ,
126
- accountPassword : formRecord . accountPassword ! ,
127
- } ) ;
128
- await loadAccounts ( ) ;
129
- closeModals ( ) ;
82
+ await handleSubmit ( async ( data : FormRecord ) => {
83
+ await window . api . saveAccount ( {
84
+ accountName : data . accountName ! ,
85
+ accountPassword : data . accountPassword ! ,
86
+ } ) ;
87
+ await loadAccounts ( ) ;
88
+ closeModals ( ) ;
89
+ } ) ( ) ;
130
90
} ) ;
131
- } , [
132
- formRecord ,
133
- formErrors ,
134
- validateAccountName ,
135
- validateAccountPassword ,
136
- loadAccounts ,
137
- closeModals ,
138
- ] ) ;
91
+ } , [ handleSubmit , loadAccounts , closeModals ] ) ;
139
92
140
93
const onAccountRemoveConfirm = useCallback ( ( ) => {
141
94
runInBackground ( async ( ) => {
142
- if ( isBlank ( formRecord . accountName ) ) {
95
+ if ( isBlank ( tableRowItem ? .accountName ) ) {
143
96
return ;
144
97
}
145
98
await window . api . removeAccount ( {
146
- accountName : formRecord . accountName ,
99
+ accountName : tableRowItem . accountName ,
147
100
} ) ;
148
101
await loadAccounts ( ) ;
149
102
closeModals ( ) ;
150
103
} ) ;
151
- } , [ formRecord , loadAccounts , closeModals ] ) ;
104
+ } , [ tableRowItem , loadAccounts , closeModals ] ) ;
152
105
153
106
const accountAddModal = useMemo ( ( ) => {
154
107
return (
@@ -162,65 +115,105 @@ export const SidebarItemAccounts: React.FC = (): ReactNode => {
162
115
defaultFocusedButton = "cancel"
163
116
>
164
117
< EuiForm component = "form" >
165
- < EuiFormRow
166
- label = "Name"
167
- isInvalid = { ! ! formErrors . accountName ?. length }
168
- error = { formErrors . accountName }
169
- >
170
- < EuiFieldText
118
+ < EuiFormRow label = "Name" >
119
+ < Controller
171
120
name = "accountName"
172
- onChange = { ( event ) => {
173
- setFormRecord ( {
174
- ...formRecord ,
175
- accountName : event . target . value ,
176
- } ) ;
177
- validateAccountName ( ) ;
121
+ control = { control }
122
+ rules = { { required : true } }
123
+ render = { ( { field, fieldState } ) => {
124
+ return (
125
+ < EuiFieldText
126
+ name = { field . name }
127
+ onBlur = { field . onBlur }
128
+ onChange = { field . onChange }
129
+ isInvalid = { fieldState . invalid }
130
+ />
131
+ ) ;
178
132
} }
179
- isInvalid = { ! ! formErrors . accountName ?. length }
180
133
/>
181
134
</ EuiFormRow >
182
- < EuiFormRow
183
- label = "Password"
184
- isInvalid = { ! ! formErrors . accountPassword ?. length }
185
- error = { formErrors . accountPassword }
186
- >
187
- < EuiFieldPassword
135
+ < EuiFormRow label = "Password" >
136
+ < Controller
188
137
name = "accountPassword"
189
- onChange = { ( event ) => {
190
- setFormRecord ( {
191
- ...formRecord ,
192
- accountPassword : event . target . value ,
193
- } ) ;
194
- validateAccountPassword ( ) ;
138
+ control = { control }
139
+ rules = { { required : true } }
140
+ render = { ( { field, fieldState } ) => {
141
+ return (
142
+ < EuiFieldPassword
143
+ name = { field . name }
144
+ onBlur = { field . onBlur }
145
+ onChange = { field . onChange }
146
+ isInvalid = { fieldState . invalid }
147
+ type = "dual"
148
+ />
149
+ ) ;
195
150
} }
196
- isInvalid = { ! ! formErrors . accountPassword ?. length }
197
- type = "dual"
198
151
/>
199
152
</ EuiFormRow >
200
153
</ EuiForm >
201
154
</ EuiConfirmModal >
202
155
) ;
203
- } , [
204
- formRecord ,
205
- formErrors ,
206
- validateAccountName ,
207
- validateAccountPassword ,
208
- onAccountSaveConfirm ,
209
- closeModals ,
210
- ] ) ;
156
+ } , [ control , onAccountSaveConfirm , closeModals ] ) ;
211
157
212
158
const accountEditModal = useMemo ( ( ) => {
213
- return < > edit</ > ;
214
- } , [ ] ) ;
159
+ return (
160
+ < EuiConfirmModal
161
+ title = "Change Password"
162
+ onCancel = { closeModals }
163
+ onConfirm = { onAccountSaveConfirm }
164
+ cancelButtonText = "Cancel"
165
+ confirmButtonText = "Save"
166
+ buttonColor = "primary"
167
+ defaultFocusedButton = "cancel"
168
+ >
169
+ < EuiForm component = "form" >
170
+ < EuiFormRow label = "Name" >
171
+ < Controller
172
+ name = "accountName"
173
+ defaultValue = { tableRowItem ?. accountName }
174
+ control = { control }
175
+ rules = { { required : true } }
176
+ render = { ( { field, fieldState } ) => {
177
+ return (
178
+ < EuiFieldText
179
+ name = { field . name }
180
+ onBlur = { field . onBlur }
181
+ onChange = { field . onChange }
182
+ isInvalid = { fieldState . invalid }
183
+ readOnly = { true }
184
+ value = { tableRowItem ?. accountName }
185
+ />
186
+ ) ;
187
+ } }
188
+ />
189
+ </ EuiFormRow >
190
+ < EuiFormRow label = "Password" >
191
+ < Controller
192
+ name = "accountPassword"
193
+ control = { control }
194
+ rules = { { required : true } }
195
+ render = { ( { field, fieldState } ) => {
196
+ return (
197
+ < EuiFieldPassword
198
+ name = { field . name }
199
+ onBlur = { field . onBlur }
200
+ onChange = { field . onChange }
201
+ isInvalid = { fieldState . invalid }
202
+ type = "dual"
203
+ />
204
+ ) ;
205
+ } }
206
+ />
207
+ </ EuiFormRow >
208
+ </ EuiForm >
209
+ </ EuiConfirmModal >
210
+ ) ;
211
+ } , [ tableRowItem , control , onAccountSaveConfirm , closeModals ] ) ;
215
212
216
213
const accountRemoveModal = useMemo ( ( ) => {
217
214
return (
218
215
< EuiConfirmModal
219
- title = {
220
- < >
221
- Remove account < EuiCode > { formRecord . accountName } </ EuiCode > ?
222
- </ >
223
- }
216
+ title = { < > Remove account { tableRowItem ?. accountName } ?</ > }
224
217
onCancel = { closeModals }
225
218
onConfirm = { onAccountRemoveConfirm }
226
219
cancelButtonText = "Cancel"
@@ -231,7 +224,7 @@ export const SidebarItemAccounts: React.FC = (): ReactNode => {
231
224
Associated characters will also be removed.
232
225
</ EuiConfirmModal >
233
226
) ;
234
- } , [ formRecord , onAccountRemoveConfirm , closeModals ] ) ;
227
+ } , [ tableRowItem , onAccountRemoveConfirm , closeModals ] ) ;
235
228
236
229
useEffect ( ( ) => {
237
230
runInBackground ( async ( ) => {
@@ -252,9 +245,9 @@ export const SidebarItemAccounts: React.FC = (): ReactNode => {
252
245
return (
253
246
< EuiFlexGroup responsive = { true } gutterSize = "s" alignItems = "center" >
254
247
< EuiFlexItem grow = { false } >
255
- < EuiToolTip content = "Edit Account " position = "bottom" >
248
+ < EuiToolTip content = "Change Password " position = "bottom" >
256
249
< EuiButtonIcon
257
- aria-label = "Edit Account "
250
+ aria-label = "Change Password "
258
251
iconType = "pencil"
259
252
display = "base"
260
253
color = "warning"
0 commit comments