"use client"; import { useState, useEffect } from 'react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { auth } from '@/lib/firebase/config'; import { toast } from 'sonner'; import { Key, Plus, Trash2, Eye, EyeOff, ExternalLink, Save } from 'lucide-react'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; interface ApiKey { id: string; service: string; name: string; createdAt: any; lastUsed: any; } const SUPPORTED_SERVICES = [ { id: 'openai', name: 'OpenAI', description: 'For ChatGPT imports and AI features', placeholder: 'sk-...', helpUrl: 'https://platform.openai.com/api-keys', }, { id: 'github', name: 'GitHub', description: 'Personal access token for repository access', placeholder: 'ghp_...', helpUrl: 'https://github.com/settings/tokens', }, { id: 'anthropic', name: 'Anthropic (Claude)', description: 'For Claude AI integrations', placeholder: 'sk-ant-...', helpUrl: 'https://console.anthropic.com/settings/keys', }, ]; export default function KeysPage() { const [keys, setKeys] = useState([]); const [loading, setLoading] = useState(true); const [showAddDialog, setShowAddDialog] = useState(false); const [selectedService, setSelectedService] = useState(''); const [keyValue, setKeyValue] = useState(''); const [showKey, setShowKey] = useState(false); const [saving, setSaving] = useState(false); useEffect(() => { loadKeys(); }, []); const loadKeys = async () => { try { const user = auth.currentUser; if (!user) return; const token = await user.getIdToken(); const response = await fetch('/api/keys', { headers: { 'Authorization': `Bearer ${token}`, }, }); if (response.ok) { const data = await response.json(); setKeys(data.keys); } } catch (error) { console.error('Error loading keys:', error); toast.error('Failed to load API keys'); } finally { setLoading(false); } }; const handleAddKey = async () => { if (!selectedService || !keyValue) { toast.error('Please select a service and enter a key'); return; } setSaving(true); try { const user = auth.currentUser; if (!user) { toast.error('Please sign in'); return; } const token = await user.getIdToken(); const service = SUPPORTED_SERVICES.find(s => s.id === selectedService); const response = await fetch('/api/keys', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ service: selectedService, name: service?.name, keyValue, }), }); if (response.ok) { toast.success(`${service?.name} key saved successfully`); setShowAddDialog(false); setSelectedService(''); setKeyValue(''); loadKeys(); } else { const error = await response.json(); toast.error(error.error || 'Failed to save key'); } } catch (error) { console.error('Error saving key:', error); toast.error('Failed to save key'); } finally { setSaving(false); } }; const handleDeleteKey = async (service: string, name: string) => { try { const user = auth.currentUser; if (!user) return; const token = await user.getIdToken(); const response = await fetch('/api/keys', { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ service }), }); if (response.ok) { toast.success(`${name} key deleted`); loadKeys(); } else { toast.error('Failed to delete key'); } } catch (error) { console.error('Error deleting key:', error); toast.error('Failed to delete key'); } }; const getServiceConfig = (serviceId: string) => { return SUPPORTED_SERVICES.find(s => s.id === serviceId); }; return (
{/* Header */}

API Keys

Manage your third-party API keys for Vibn integrations

Add API Key Add a third-party API key for Vibn to use on your behalf
{selectedService && (

{getServiceConfig(selectedService)?.description}

)}
setKeyValue(e.target.value)} className="pr-10" />
{selectedService && ( Get your API key )}

🔐 Secure Storage: Your API key will be encrypted and stored securely. Vibn will only use it when you explicitly request actions that require it.

{/* Keys List */} {loading ? (

Loading your API keys...

) : keys.length === 0 ? (

No API keys yet

Add your third-party API keys to enable Vibn features like ChatGPT imports and AI analysis

) : (
{keys.map((key) => { const serviceConfig = getServiceConfig(key.service); return (
{key.name} {serviceConfig?.description || key.service}
Delete API Key? This will remove your {key.name} API key. Features using this key will stop working until you add a new one. Cancel handleDeleteKey(key.service, key.name)}> Delete Key

Added: {key.createdAt ? new Date(key.createdAt._seconds * 1000).toLocaleDateString() : 'Unknown'}

{key.lastUsed && (

Last used: {new Date(key.lastUsed._seconds * 1000).toLocaleDateString()}

)}
{serviceConfig && ( Manage on {serviceConfig.name} )}
); })}
)} {/* Info Card */} How API Keys Work

🔐 Encrypted Storage: All API keys are encrypted before being stored in the database.

🎯 Automatic Usage: When you use Vibn features (like ChatGPT import), we'll automatically use your stored keys instead of asking each time.

🔄 Easy Updates: Add a new key with the same service name to replace an existing one.

🗑️ Full Control: Delete keys anytime - you can always add them back later.

); }