@@ -8,25 +8,25 @@ import { toast } from "sonner";
88export default function ApiKeysPage ( ) {
99 const storedApiKey = useMerchantApiKey ( ) ;
1010 const [ isRotating , setIsRotating ] = useState ( false ) ;
11+ const [ revealed , setRevealed ] = useState ( false ) ;
1112
12- const handleRotate = async ( ) => {
13- if ( ! confirm ( "Are you sure you want to rotate your API key? The old one will be invalidated immediately." ) ) {
14- return ;
15- }
13+ const displayKey = storedApiKey
14+ ? revealed
15+ ? storedApiKey
16+ : storedApiKey . slice ( 0 , 7 ) + "•" . repeat ( storedApiKey . length - 13 ) + storedApiKey . slice ( - 6 )
17+ : "sk_••••••••••••••••••••••••" ;
1618
19+ const handleRotate = async ( ) => {
20+ if ( ! confirm ( "Rotate your API key? The old one will be invalidated immediately." ) ) return ;
1721 setIsRotating ( true ) ;
1822 try {
1923 const apiUrl = process . env . NEXT_PUBLIC_API_URL || "http://localhost:4000" ;
2024 const res = await fetch ( `${ apiUrl } /api/rotate-key` , {
2125 method : "POST" ,
2226 headers : { "x-api-key" : storedApiKey || "" } ,
2327 } ) ;
24-
2528 if ( ! res . ok ) throw new Error ( "Rotation failed" ) ;
26-
27- toast . success ( "API key rotated successfully. Please update your env files." ) ;
28- // Note: The store will handle the update if it's wired with cookies or session
29- // For now, we tell the user to refresh or rely on the store's hydration.
29+ toast . success ( "API key rotated. Update your integrations." ) ;
3030 } catch {
3131 toast . error ( "Failed to rotate API key" ) ;
3232 } finally {
@@ -35,45 +35,55 @@ export default function ApiKeysPage() {
3535 } ;
3636
3737 return (
38- < div className = "flex flex-col gap-8" >
38+ < div className = "flex flex-col gap-8 animate-in fade-in duration-500 " >
3939 < div >
40- < h1 className = "text-3xl font-bold text-white" > API Keys</ h1 >
41- < p className = "mt-2 text-slate-400" >
40+ < p className = "text-[10px] font-bold uppercase tracking-[0.4em] text-[#6B6B6B] mb-2" > Security</ p >
41+ < h1 className = "text-4xl font-bold text-[#0A0A0A] tracking-tight" > API Keys</ h1 >
42+ < p className = "mt-2 text-sm font-medium text-[#6B6B6B]" >
4243 Manage your secret keys to authenticate server-side requests.
4344 </ p >
4445 </ div >
4546
46- < div className = "rounded-2xl border border-white/10 bg-white/5 p-8" >
47- < div className = "flex flex-col gap-6 " >
48- < div className = "flex flex-col gap-2 " >
49- < label className = "text-xs font-medium uppercase tracking-wider text-slate-500 " >
47+ < div className = "max-w-xl rounded-2xl border border-[#E8E8E8] bg-white p-8 flex flex-col gap-6 " >
48+ < div className = "flex flex-col gap-2 " >
49+ < div className = "flex items-center justify-between " >
50+ < label className = "text-[10px] font-bold uppercase tracking-widest text-[#6B6B6B] " >
5051 Live API Key
5152 </ label >
52- < div className = "flex items-center gap-3" >
53- < code className = "flex-1 rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-mint" >
54- { storedApiKey || "sk_test_••••••••••••••••••••••••" }
55- </ code >
56- < CopyButton text = { storedApiKey || "" } />
57- </ div >
58- </ div >
59-
60- < div className = "rounded-xl border border-yellow-500/20 bg-yellow-500/5 p-4 text-sm text-yellow-200/80" >
61- < p className = "font-semibold" > Security Warning</ p >
62- < p className = "mt-1" >
63- Never share your secret API keys in publicly accessible areas
64- like GitHub, client-side code, or public forums.
65- </ p >
66- </ div >
67-
68- < div className = "flex justify-end" >
6953 < button
70- onClick = { handleRotate }
71- disabled = { isRotating }
72- className = "rounded-xl border border-red-500/30 bg-red-500/10 px-6 py-2.5 text-sm font-semibold text-red-400 transition hover:bg-red-500/20 disabled:opacity-50 "
54+ type = "button"
55+ onClick = { ( ) => setRevealed ( v => ! v ) }
56+ className = "text-[10px] font-bold uppercase tracking-widest text-[#6B6B6B] hover: text-[#0A0A0A] transition-colors "
7357 >
74- { isRotating ? "Rotating... " : "Rotate API Key " }
58+ { revealed ? "Hide " : "Reveal " }
7559 </ button >
7660 </ div >
61+ < div className = "flex items-center gap-2 overflow-hidden rounded-xl border border-[#E8E8E8] bg-[#F9F9F9] p-1 pl-4" >
62+ < code className = { `flex-1 truncate text-sm font-bold tracking-widest transition-colors ${ revealed ? "text-[#0A0A0A]" : "text-[#E8E8E8]" } ` } >
63+ { displayKey }
64+ </ code >
65+ { revealed && storedApiKey && < CopyButton text = { storedApiKey } /> }
66+ </ div >
67+ < p className = "text-[10px] font-medium text-[#6B6B6B]" >
68+ Pass this as the < code className = "text-[#0A0A0A]" > x-api-key</ code > header on every API request.
69+ </ p >
70+ </ div >
71+
72+ < div className = "rounded-xl border border-yellow-200 bg-yellow-50 p-4 text-sm text-yellow-800" >
73+ < p className = "font-bold mb-1" > Security Warning</ p >
74+ < p className = "text-yellow-700 text-xs leading-relaxed" >
75+ Never share your secret API keys in publicly accessible areas like GitHub, client-side code, or public forums.
76+ </ p >
77+ </ div >
78+
79+ < div className = "flex justify-end" >
80+ < button
81+ onClick = { handleRotate }
82+ disabled = { isRotating }
83+ className = "rounded-xl border border-red-200 bg-red-50 px-6 py-2.5 text-sm font-bold text-red-600 transition hover:bg-red-100 disabled:opacity-50"
84+ >
85+ { isRotating ? "Rotating..." : "Rotate API Key" }
86+ </ button >
7787 </ div >
7888 </ div >
7989 </ div >
0 commit comments