"use client"; import { useState, useEffect, useCallback } from 'react'; import { useAuth } from '@/contexts/AuthContext'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Skeleton } from '@/components/ui/skeleton'; import { Trash2, PlusCircle, Copy, KeyRound } from 'lucide-react'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { format } from 'date-fns'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog" import { Badge } from "@/components/ui/badge" export default function ApiKeys() { const { token } = useAuth(); const [keys, setKeys] = useState([]); const [loading, setLoading] = useState(true); const [newKey, setNewKey] = useState(null); const [expiresInDays, setExpiresInDays] = useState(90); const [filterType, setFilterType] = useState('all'); const [searchTerm, setSearchTerm] = useState(''); const [keyToDelete, setKeyToDelete] = useState(null); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [isCreating, setIsCreating] = useState(false); const fetchKeys = useCallback(async () => { if (!token) return; setLoading(true); try { const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'}/keys`, { headers: { 'Authorization': `Bearer ${token}` } }); const data = await res.json(); setKeys(data); } catch (error) { console.error("Failed to fetch API keys", error); } finally { setLoading(false); } }, [token]); useEffect(() => { fetchKeys(); }, [fetchKeys]); const handleCreateKey = async () => { if (!token) return; setIsCreating(true); try { const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'}/keys`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ expiresInDays }) }); const data = await res.json(); setNewKey(data.key); fetchKeys(); } catch (error) { console.error("Failed to create key", error); } finally { setIsCreating(false); } }; const handleDeleteKey = async (keyToDelete) => { if (!token) return; try { await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'}/keys/${keyToDelete}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); fetchKeys(); } catch (error) { console.error("Failed to delete key", error); } }; const copyToClipboard = (text) => { navigator.clipboard.writeText(text); alert('Key copied to clipboard!'); }; const filteredKeys = keys .filter(key => filterType === 'all' || key.type === filterType) .filter(key => key.key.toLowerCase().includes(searchTerm.toLowerCase())); return (
API Keys Manage your API keys for programmatic access.
{ if (isCreating) return; setIsCreateDialogOpen(open); if (!open) setNewKey(null); }}> {newKey ? 'API Key Created' : 'Create New API Key'} {newKey ? 'Your new API key is shown below. Please save it now. You will not be able to see it again.' : 'Set an expiration for your new key.'} {newKey ? (
{newKey}
) : (
setExpiresInDays(parseInt(e.target.value))} />
)}
setSearchTerm(e.target.value)} className="max-w-xs bg-gray-900 border-gray-700" />
{loading ? (
) : filteredKeys.length > 0 ? ( Key Type IP Address Created Expires Actions {filteredKeys.map(key => { const isCurrentSession = key.type === 'session' && token?.startsWith(key.key); return ( {key.type === 'api' ? `${key.key.substring(0, 12)}...` : key.key} {isCurrentSession && (this session)} {key.type} {key.ipAddress || 'N/A'} {format(new Date(key.createdAt), 'PP')} {key.expiresAt ? format(new Date(key.expiresAt), 'PP') : 'Never'} {!isCurrentSession && ( )} ); })}
) : (

{searchTerm || filterType !== 'all' ? 'No Matching Keys' : 'No API Keys'}

{searchTerm || filterType !== 'all' ? 'Try adjusting your search or filter.' : 'Create your first API key to get started with integrations.'}

)}
Are you absolutely sure? This action cannot be undone. This will permanently delete the key {keyToDelete?.type === 'api' ? `${keyToDelete?.key.substring(0, 12)}...` : keyToDelete?.key} and revoke its access. Cancel { if (keyToDelete) { handleDeleteKey(keyToDelete.key); } setKeyToDelete(null); }} > Delete
); }