88} from '@phosphor-icons/react' ;
99import dynamic from 'next/dynamic' ;
1010import { useQueryState } from 'nuqs' ;
11+ import { useState } from 'react' ;
12+ import { ApiKeyDetailDialog } from '@/components/organizations/api-key-detail-dialog' ;
1113import { Button } from '@/components/ui/button' ;
1214import {
1315 Card ,
@@ -17,7 +19,7 @@ import {
1719 CardTitle ,
1820} from '@/components/ui/card' ;
1921import { Skeleton } from '@/components/ui/skeleton' ;
20- import { cn } from '@/lib/utils ' ;
22+ import { ApiKeyCreateDialog , ApiKeyList } from './_components ' ;
2123import { type NavItem , SettingsSidebar } from './_components/settings-sidebar' ;
2224
2325const EmailForm = dynamic (
@@ -97,7 +99,12 @@ const TimezonePreferences = dynamic(
9799 }
98100) ;
99101
100- type SettingsTab = 'profile' | 'account' | 'security' | 'notifications' ;
102+ type SettingsTab =
103+ | 'profile'
104+ | 'account'
105+ | 'security'
106+ | 'api-keys'
107+ | 'notifications' ;
101108
102109const tabs : NavItem [ ] = [
103110 {
@@ -115,6 +122,11 @@ const tabs: NavItem[] = [
115122 label : 'Security' ,
116123 icon : ShieldIcon ,
117124 } ,
125+ {
126+ id : 'api-keys' ,
127+ label : 'API keys' ,
128+ icon : GearSixIcon ,
129+ } ,
118130 {
119131 id : 'notifications' ,
120132 label : 'Notifications' ,
@@ -290,6 +302,7 @@ export default function SettingsPage() {
290302 </ CardContent >
291303 </ Card >
292304 ) }
305+ { activeTab === 'api-keys' && < ApiKeysSection /> }
293306 { activeTab === 'notifications' && (
294307 < div className = "flex h-full items-center justify-center" >
295308 < div className = "text-center" >
@@ -308,3 +321,42 @@ export default function SettingsPage() {
308321 </ div >
309322 ) ;
310323}
324+
325+ function ApiKeysSection ( ) {
326+ const [ open , setOpen ] = useState ( false ) ;
327+ const [ createdSecret , setCreatedSecret ] = useState < null | {
328+ id : string ;
329+ secret : string ;
330+ prefix : string ;
331+ start : string ;
332+ } > ( null ) ;
333+ const [ selectedId , setSelectedId ] = useState < string | null > ( null ) ;
334+ return (
335+ < div className = "space-y-4" >
336+ < ApiKeyList
337+ onCreateNew = { ( ) => setOpen ( true ) }
338+ onSelect = { ( id ) => setSelectedId ( id ) }
339+ />
340+ { createdSecret && (
341+ < div className = "rounded border p-3 text-sm" >
342+ < div className = "mb-1 font-medium" > Copy your secret now</ div >
343+ < code className = "block break-all" > { createdSecret . secret } </ code >
344+ </ div >
345+ ) }
346+ < ApiKeyCreateDialog
347+ onCreated = { ( res ) => setCreatedSecret ( res ) }
348+ onOpenChange = { setOpen }
349+ open = { open }
350+ />
351+ < ApiKeyDetailDialog
352+ keyId = { selectedId }
353+ onOpenChange = { ( o ) => {
354+ if ( ! o ) {
355+ setSelectedId ( null ) ;
356+ }
357+ } }
358+ open = { ! ! selectedId }
359+ />
360+ </ div >
361+ ) ;
362+ }
0 commit comments