@@ -14,20 +14,43 @@ function matches(org, query) {
1414 )
1515}
1616
17+ const EMPTY = { orgId : '' , name : '' , shortName : '' , url : '' , description : '' }
18+
1719export function Organisations ( ) {
1820 const { data, loading, error, refresh } = useApi ( api . getOrganisations )
1921 const showToast = useContext ( ToastContext )
2022
21- const [ form , setForm ] = useState ( { orgId : '' , name : '' , shortName : '' , url : '' , description : '' } )
23+ const [ query , setQuery ] = useState ( '' )
24+ const [ form , setForm ] = useState ( EMPTY )
2225 const [ formError , setFormError ] = useState ( null )
2326 const [ submitting , setSubmitting ] = useState ( false )
24- const [ query , setQuery ] = useState ( '' )
27+
28+ // Edit modal state
29+ const [ editing , setEditing ] = useState ( null ) // org object being edited
30+ const [ editForm , setEditForm ] = useState ( EMPTY )
31+ const [ editError , setEditError ] = useState ( null )
32+ const [ editSaving , setEditSaving ] = useState ( false )
2533
2634 const filtered = data ? data . filter ( o => matches ( o , query ) ) : [ ]
2735
2836 function set ( field , value ) { setForm ( p => ( { ...p , [ field ] : value } ) ) }
37+ function setEdit ( field , value ) { setEditForm ( p => ( { ...p , [ field ] : value } ) ) }
38+
39+ function openEdit ( org ) {
40+ setEditForm ( {
41+ orgId : org . orgId || '' ,
42+ name : org . name || '' ,
43+ shortName : org . shortName || '' ,
44+ url : org . url || '' ,
45+ description : org . description || ''
46+ } )
47+ setEditError ( null )
48+ setEditing ( org )
49+ }
50+
51+ function closeEdit ( ) { setEditing ( null ) ; setEditError ( null ) }
2952
30- async function handleSubmit ( e ) {
53+ async function handleCreate ( e ) {
3154 e . preventDefault ( )
3255 setFormError ( null )
3356 setSubmitting ( true )
@@ -40,7 +63,7 @@ export function Organisations() {
4063 description : form . description || null
4164 } )
4265 await refresh ( )
43- setForm ( { orgId : '' , name : '' , shortName : '' , url : '' , description : '' } )
66+ setForm ( EMPTY )
4467 showToast ( 'Organisation registered successfully.' )
4568 } catch ( e ) {
4669 setFormError ( e . message )
@@ -49,11 +72,33 @@ export function Organisations() {
4972 }
5073 }
5174
75+ async function handleUpdate ( e ) {
76+ e . preventDefault ( )
77+ setEditError ( null )
78+ setEditSaving ( true )
79+ try {
80+ await api . updateOrganisation ( editing . id , {
81+ orgId : editForm . orgId || null ,
82+ name : editForm . name ,
83+ shortName : editForm . shortName || null ,
84+ url : editForm . url || null ,
85+ description : editForm . description || null
86+ } )
87+ await refresh ( )
88+ closeEdit ( )
89+ showToast ( 'Organisation updated successfully.' )
90+ } catch ( e ) {
91+ setEditError ( e . message )
92+ } finally {
93+ setEditSaving ( false )
94+ }
95+ }
96+
5297 return (
5398 < div >
5499 < h2 > Organisations</ h2 >
55100
56- { /* Search box */ }
101+ { /* Search */ }
57102 < div className = { styles . searchRow } >
58103 < input
59104 className = { styles . searchInput }
@@ -82,16 +127,18 @@ export function Organisations() {
82127 { o . orgId && < p > < strong > Org ID:</ strong > { o . orgId } </ p > }
83128 { o . shortName && < p > < strong > Short name:</ strong > { o . shortName } </ p > }
84129 { o . description && < p > { o . description } </ p > }
85- { o . url && < p > < strong > URL:</ strong > < a href = { o . url } target = "_blank" rel = "noopener" > { o . url } </ a > </ p > }
130+ { o . url && < p > < strong > URL:</ strong > < a href = { o . url } target = "_blank" rel = "noopener" > { o . url } </ a > </ p > }
131+ < button className = { styles . editBtn } onClick = { ( ) => openEdit ( o ) } > Edit</ button >
86132 </ div >
87133 ) ) }
88134 </ div >
89135 ) }
90136
137+ { /* Register form */ }
91138 < div className = { styles . formCard } >
92139 < h3 > Register New Organisation</ h3 >
93140 { formError && < div className = { styles . formError } > { formError } </ div > }
94- < form onSubmit = { handleSubmit } className = { styles . form } >
141+ < form onSubmit = { handleCreate } className = { styles . form } >
95142 < div className = { styles . row } >
96143 < div >
97144 < label > Organisation ID *</ label >
@@ -121,6 +168,58 @@ export function Organisations() {
121168 </ button >
122169 </ form >
123170 </ div >
171+
172+ { /* Edit modal */ }
173+ { editing && (
174+ < div
175+ className = { styles . modalBackdrop }
176+ onMouseDown = { e => { if ( e . target === e . currentTarget ) closeEdit ( ) } }
177+ >
178+ < div className = { styles . modal } >
179+ < div className = { styles . modalHeader } >
180+ < h3 > Edit Organisation</ h3 >
181+ < button className = { styles . modalClose } onClick = { closeEdit } title = "Close" > ×</ button >
182+ </ div >
183+ < div className = { styles . modalBody } >
184+ { editError && < div className = { styles . formError } > { editError } </ div > }
185+ < form onSubmit = { handleUpdate } className = { styles . form } >
186+ < div className = { styles . row } >
187+ < div >
188+ < label > Organisation ID *</ label >
189+ < input value = { editForm . orgId } onChange = { e => setEdit ( 'orgId' , e . target . value ) } placeholder = "e.g. org.ga4gh" required />
190+ </ div >
191+ < div >
192+ < label > Name *</ label >
193+ < input value = { editForm . name } onChange = { e => setEdit ( 'name' , e . target . value ) } required />
194+ </ div >
195+ </ div >
196+ < div className = { styles . row } >
197+ < div >
198+ < label > Short Name</ label >
199+ < input value = { editForm . shortName } onChange = { e => setEdit ( 'shortName' , e . target . value ) } />
200+ </ div >
201+ < div >
202+ < label > Organisation URL</ label >
203+ < input type = "url" value = { editForm . url } onChange = { e => setEdit ( 'url' , e . target . value ) } placeholder = "https://..." />
204+ </ div >
205+ </ div >
206+ < div >
207+ < label > Description</ label >
208+ < textarea value = { editForm . description } onChange = { e => setEdit ( 'description' , e . target . value ) } />
209+ </ div >
210+ < div className = { styles . modalActions } >
211+ < button type = "submit" className = { styles . btnPrimary } disabled = { editSaving } >
212+ { editSaving ? 'Saving…' : 'Save Changes' }
213+ </ button >
214+ < button type = "button" className = { styles . btnSecondary } onClick = { closeEdit } >
215+ Cancel
216+ </ button >
217+ </ div >
218+ </ form >
219+ </ div >
220+ </ div >
221+ </ div >
222+ ) }
124223 </ div >
125224 )
126225}
0 commit comments