1+ 'use client' ;
2+
3+ import { useState } from 'react' ;
4+ import { Plus , Copy , Trash2 , Eye , EyeOff , Webhook } from 'lucide-react' ;
5+ import { Button } from '@/components/ui/button' ;
6+
7+ interface APIKey { id : string ; name : string ; key : string ; created : string ; lastUsed : string }
8+ interface WebhookConfig { id : string ; url : string ; events : string [ ] ; active : boolean }
9+
10+ const MOCK_KEYS : APIKey [ ] = [
11+ { id :'1' , name :'Production App' , key :'sk_live_xxxx...abc1' , created :'2024-01-01' , lastUsed :'2024-01-22' } ,
12+ { id :'2' , name :'Staging' , key :'sk_test_xxxx...def2' , created :'2024-01-10' , lastUsed :'2024-01-20' } ,
13+ ] ;
14+ const MOCK_HOOKS : WebhookConfig [ ] = [
15+ { id :'1' , url :'https://myapp.io/webhook' , events :[ 'asset.created' , 'asset.updated' ] , active :true } ,
16+ ] ;
17+
18+ export default function DeveloperPortalPage ( ) {
19+ const [ keys ] = useState < APIKey [ ] > ( MOCK_KEYS ) ;
20+ const [ hooks ] = useState < WebhookConfig [ ] > ( MOCK_HOOKS ) ;
21+ const [ revealed , setRevealed ] = useState < Set < string > > ( new Set ( ) ) ;
22+
23+ const toggle = ( id : string ) => setRevealed ( prev => { const s = new Set ( prev ) ; s . has ( id ) ? s . delete ( id ) : s . add ( id ) ; return s ; } ) ;
24+
25+ return (
26+ < div >
27+ < div className = "mb-6" > < h1 className = "text-2xl font-bold text-gray-900" > Developer Portal</ h1 > < p className = "text-sm text-gray-500 mt-1" > API key management and webhook configuration</ p > </ div >
28+ < div className = "space-y-6" >
29+ < div className = "bg-white rounded-xl border border-gray-200 overflow-hidden" >
30+ < div className = "flex items-center justify-between px-5 py-4 border-b border-gray-100" >
31+ < h2 className = "text-sm font-semibold text-gray-900" > API Keys</ h2 >
32+ < Button size = "sm" > < Plus size = { 14 } className = "mr-1" /> New Key</ Button >
33+ </ div >
34+ < table className = "w-full text-sm" >
35+ < thead > < tr className = "border-b border-gray-200 bg-gray-50" > { [ "Name" , "Key" , "Created" , "Last Used" , "Actions" ] . map ( h => < th key = { h } className = "text-left px-4 py-3 font-medium text-gray-500" > { h } </ th > ) } </ tr > </ thead >
36+ < tbody > { keys . map ( k => (
37+ < tr key = { k . id } className = "border-b border-gray-100 hover:bg-gray-50" >
38+ < td className = "px-4 py-3 font-medium text-gray-900" > { k . name } </ td >
39+ < td className = "px-4 py-3 font-mono text-xs text-gray-600" > { revealed . has ( k . id ) ? k . key : '••••••••••••••••' } </ td >
40+ < td className = "px-4 py-3 text-gray-500" > { k . created } </ td >
41+ < td className = "px-4 py-3 text-gray-500" > { k . lastUsed } </ td >
42+ < td className = "px-4 py-3 flex items-center gap-2" >
43+ < button onClick = { ( ) => toggle ( k . id ) } className = "text-gray-400 hover:text-gray-700" > { revealed . has ( k . id ) ? < EyeOff size = { 14 } /> : < Eye size = { 14 } /> } </ button >
44+ < button className = "text-gray-400 hover:text-gray-700" > < Copy size = { 14 } /> </ button >
45+ < button className = "text-red-400 hover:text-red-600" > < Trash2 size = { 14 } /> </ button >
46+ </ td >
47+ </ tr >
48+ ) ) } </ tbody >
49+ </ table >
50+ </ div >
51+ < div className = "bg-white rounded-xl border border-gray-200 overflow-hidden" >
52+ < div className = "flex items-center justify-between px-5 py-4 border-b border-gray-100" >
53+ < h2 className = "text-sm font-semibold text-gray-900 flex items-center gap-2" > < Webhook size = { 16 } /> Webhooks</ h2 >
54+ < Button size = "sm" > < Plus size = { 14 } className = "mr-1" /> Add Webhook</ Button >
55+ </ div >
56+ { hooks . map ( w => (
57+ < div key = { w . id } className = "px-5 py-4 border-b border-gray-100 flex items-start justify-between" >
58+ < div > < p className = "text-sm font-medium text-gray-900" > { w . url } </ p > < p className = "text-xs text-gray-500 mt-0.5" > { w . events . join ( ', ' ) } </ p > </ div >
59+ < span className = { px - 2 py - 0.5 rounded - full text - xs font - medium } > { w . active ?'Active' :'Inactive' } </ span >
60+ </ div >
61+ ) ) }
62+ </ div >
63+ </ div >
64+ </ div >
65+ ) ;
66+ }
0 commit comments