11'use client'
22
3- import { useState , useEffect } from 'react'
4- import { authClient } from '@/lib/auth-client '
3+ import { useState } from 'react'
4+ import { useApiKeys , useCreateApiKey , useRevokeApiKey } from '@/hooks/use-api-keys '
55import { formatShortDate } from '@/lib/format'
66import CopyButton from '@/components/ui/CopyButton'
77import EmptyState from '@/components/ui/EmptyState'
88import ErrorMessage from '@/components/ui/ErrorMessage'
99
10- interface ApiKey {
11- id : string
12- name : string | null
13- start : string | null
14- createdAt : Date
15- }
16-
1710export default function ApiKeyManager ( ) {
18- const [ keys , setKeys ] = useState < ApiKey [ ] > ( [ ] )
19- const [ loading , setLoading ] = useState ( true )
20- const [ error , setError ] = useState ( '' )
21- const [ creating , setCreating ] = useState ( false )
11+ const { data : keys , isLoading , error } = useApiKeys ( )
12+ const createKey = useCreateApiKey ( )
13+ const revokeKey = useRevokeApiKey ( )
14+
2215 const [ newKeyName , setNewKeyName ] = useState ( '' )
2316 const [ showCreate , setShowCreate ] = useState ( false )
2417 const [ newKeyValue , setNewKeyValue ] = useState < string | null > ( null )
25- const [ revoking , setRevoking ] = useState < Set < string > > ( new Set ( ) )
26-
27- useEffect ( ( ) => {
28- loadKeys ( )
29- } , [ ] )
3018
31- async function loadKeys ( ) {
32- setError ( '' )
33- try {
34- const { data, error : authError } = await authClient . apiKey . list ( )
35- if ( authError ) {
36- setError ( authError . message ?? 'Failed to load API keys' )
37- return
38- }
39- setKeys ( data ?? [ ] )
40- } catch {
41- setError ( 'Failed to load API keys' )
42- } finally {
43- setLoading ( false )
44- }
45- }
46-
47- async function handleCreate ( e : React . FormEvent < HTMLFormElement > ) {
19+ function handleCreate ( e : React . FormEvent < HTMLFormElement > ) {
4820 e . preventDefault ( )
49- setError ( '' )
50- setCreating ( true )
51-
52- try {
53- const { data, error : authError } = await authClient . apiKey . create ( {
54- name : newKeyName . trim ( ) || undefined ,
55- } )
56-
57- if ( authError ) {
58- setError ( authError . message ?? 'Failed to create API key' )
59- setCreating ( false )
60- return
61- }
62-
63- if ( data ?. key ) {
64- setNewKeyValue ( data . key )
65- }
66-
67- setNewKeyName ( '' )
68- await loadKeys ( )
69- } catch {
70- setError ( 'Failed to create API key' )
71- } finally {
72- setCreating ( false )
73- }
21+ createKey . mutate ( newKeyName . trim ( ) || undefined , {
22+ onSuccess : ( data ) => {
23+ if ( data ?. key ) {
24+ setNewKeyValue ( data . key )
25+ }
26+ setNewKeyName ( '' )
27+ } ,
28+ } )
7429 }
7530
76- async function handleRevoke ( keyId : string ) {
77- setRevoking ( ( prev ) => new Set ( prev ) . add ( keyId ) )
78- try {
79- const { error : authError } = await authClient . apiKey . delete ( { keyId } )
80- if ( authError ) {
81- setError ( authError . message ?? 'Failed to revoke API key' )
82- return
83- }
84- setKeys ( ( prev ) => prev . filter ( ( k ) => k . id !== keyId ) )
85- } catch {
86- setError ( 'Failed to revoke API key' )
87- } finally {
88- setRevoking ( ( prev ) => {
89- const next = new Set ( prev )
90- next . delete ( keyId )
91- return next
92- } )
93- }
94- }
31+ const mutationError = createKey . error ?? revokeKey . error
9532
9633 return (
9734 < div >
@@ -102,13 +39,27 @@ export default function ApiKeyManager() {
10239 onClick = { ( ) => {
10340 setShowCreate ( ! showCreate )
10441 setNewKeyValue ( null )
42+ createKey . reset ( )
10543 } }
10644 >
10745 { showCreate ? 'Cancel' : 'Create key' }
10846 </ button >
10947 </ div >
11048
111- { error && < ErrorMessage message = { error } /> }
49+ { error && (
50+ < ErrorMessage
51+ message = { error instanceof Error ? error . message : 'Failed to load API keys' }
52+ />
53+ ) }
54+ { mutationError && (
55+ < ErrorMessage
56+ message = {
57+ mutationError instanceof Error
58+ ? mutationError . message
59+ : 'Operation failed'
60+ }
61+ />
62+ ) }
11263
11364 { newKeyValue && (
11465 < div className = "dash-key-reveal" >
@@ -143,18 +94,22 @@ export default function ApiKeyManager() {
14394 value = { newKeyName }
14495 onChange = { ( e ) => setNewKeyName ( e . target . value ) }
14596 className = "dash-input"
146- disabled = { creating }
97+ disabled = { createKey . isPending }
14798 autoFocus
14899 />
149- < button type = "submit" className = "dash-primary-btn" disabled = { creating } >
150- { creating ? 'Creating...' : 'Create' }
100+ < button
101+ type = "submit"
102+ className = "dash-primary-btn"
103+ disabled = { createKey . isPending }
104+ >
105+ { createKey . isPending ? 'Creating...' : 'Create' }
151106 </ button >
152107 </ form >
153108 ) }
154109
155- { loading ? (
110+ { isLoading ? (
156111 < EmptyState message = "Loading API keys..." />
157- ) : keys . length === 0 ? (
112+ ) : ! keys || keys . length === 0 ? (
158113 < EmptyState message = "No API keys yet. Create one to authenticate SDK and CLI requests." />
159114 ) : (
160115 < div className = "dash-table-wrap" >
@@ -180,10 +135,14 @@ export default function ApiKeyManager() {
180135 < td >
181136 < button
182137 className = "dash-action-btn danger"
183- onClick = { ( ) => handleRevoke ( key . id ) }
184- disabled = { revoking . has ( key . id ) }
138+ onClick = { ( ) => revokeKey . mutate ( key . id ) }
139+ disabled = {
140+ revokeKey . isPending && revokeKey . variables === key . id
141+ }
185142 >
186- { revoking . has ( key . id ) ? 'Revoking...' : 'Revoke' }
143+ { revokeKey . isPending && revokeKey . variables === key . id
144+ ? 'Revoking...'
145+ : 'Revoke' }
187146 </ button >
188147 </ td >
189148 </ tr >
0 commit comments