import { KeyRound, Plus, Trash2, Copy, CheckCircle2, AlertCircle, ShieldCheck, Sparkles, Globe, Clock, Sliders, Terminal, Activity, Database } from "lucide-react"; import { useState, useEffect } from "react"; import { useApiKey } from "../context/ApiKeyContext"; import { apiClient } from "../lib/apiClient"; import FormDrawer from "../components/FormDrawer"; import ConfirmModal from "../components/ConfirmModal"; import toast from "react-hot-toast"; import { supabase, isSupabaseConfigured, supabaseProjectRef, supabaseDashboardUrl } from "../lib/supabaseClient"; export default function Settings() { const { apiKeys, activeKeyId, setActiveKeyId, addApiKey, removeApiKey, renameApiKey } = useApiKey(); const [activeTab, setActiveTab] = useState<"keys" | "preferences" | "sandbox" | "database">("keys"); const [isAddKeyOpen, setIsAddKeyOpen] = useState(false); const [keyToDelete, setKeyToDelete] = useState(null); const [testResult, setTestResult] = useState<{ status: "idle" | "testing" | "success" | "error"; message?: string; latency?: number }>({ status: "idle" }); const [supabaseStatus, setSupabaseStatus] = useState<"testing" | "connected" | "error" | "unconfigured">("testing"); useEffect(() => { async function checkSupabase() { if (!isSupabaseConfigured() || !supabase) { setSupabaseStatus("unconfigured"); return; } try { // Simple ping to check if credentials are valid // Using auth.getSession() as a lightweight check const { error } = await supabase.auth.getSession(); if (error) throw error; setSupabaseStatus("connected"); } catch (err) { console.error("Supabase connection error:", err); setSupabaseStatus("error"); } } if (activeTab === "database") { checkSupabase(); } }, [activeTab]); const testActiveConnection = async () => { setTestResult({ status: "testing" }); const startTime = Date.now(); try { const res = await apiClient.get("/campaigns"); const latency = Date.now() - startTime; setTestResult({ status: "success", message: `Connected successfully. Response latency: ${latency}ms. Found ${res.data?.length || 0} campaigns.`, latency, }); toast.success("API Key verified successfully"); } catch (err: any) { setTestResult({ status: "error", message: err.response?.data?.error || "Failed to reach BRIDGEModulE API gateway", }); toast.error("API connection test failed"); } }; return (
{/* Header */}

Settings & API Credentials

Manage BRIDGEModulE API keys, system preferences, and test live gateway endpoints.

{/* Tabs */}
{/* TAB 1: API KEYS */} {activeTab === "keys" && (

Configured BRIDGEModulE API Keys

Store multiple keys for distinct environments or client workspaces.

{/* Test Connection Banner */} {testResult.status === "success" && (
{testResult.message}
)} {testResult.status === "error" && (
{testResult.message}
)} {/* Keys List */}
{apiKeys.map((k) => { const isActive = k.id === activeKeyId; const maskedKey = k.key.length > 8 ? `${k.key.substring(0, 4)}••••••••••••••••${k.key.substring(k.key.length - 4)}` : "••••••••••••"; return (
{k.name} {isActive && ( Active Key )}
{maskedKey}
{!isActive && ( )}
); })} {apiKeys.length === 0 && (
No custom API keys saved. The app is currently operating in high-fidelity mock database mode.
)}
)} {/* TAB 2: PREFERENCES */} {activeTab === "preferences" && (

Workspace Outreach Defaults

Maximum outbound emails per mailbox / 24 hours
)} {/* TAB 3: SANDBOX */} {activeTab === "sandbox" && (

Backend Gateway Architecture

All requests from the frontend client route securely through the Node.js/Express proxy (`/api/*`). The proxy attaches the active API key as a query parameter (`?api_key=...`) to the core REST API endpoint (`https://server.smartlead.ai/api/v1`).

# Example Proxy Request
GET /api/campaigns → https://server.smartlead.ai/api/v1/campaigns?api_key={KEY}
POST /api/leads/search → https://server.smartlead.ai/api/v1/leads/?api_key={KEY}
)} {/* TAB 4: DATABASE / SUPABASE */} {activeTab === "database" && (

Supabase Integration Status

Check the connection to your Supabase project instance ({supabaseProjectRef()}). To configure, provide your URL and Anon Key in your environment variables.

{supabaseStatus === "connected" && } {supabaseStatus === "unconfigured" && } {supabaseStatus === "error" && } {supabaseStatus === "testing" && }

{supabaseStatus === "connected" ? "Connection Established" : supabaseStatus === "unconfigured" ? "Missing Credentials" : supabaseStatus === "error" ? "Connection Failed" : "Testing Connection..."}

{supabaseStatus === "connected" ? `Successfully communicating with Supabase project ${supabaseProjectRef()}.` : supabaseStatus === "unconfigured" ? "Cannot connect to Supabase. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set in your environment variables (.env file)." : supabaseStatus === "error" ? "Failed to establish a connection with the provided credentials. Please verify your Project URL and Anon Key." : "Pinging Supabase endpoints..."}

Configuration Guide

  1. Go to your Supabase Dashboard: Project {supabaseProjectRef()}
  2. Navigate to Project Settings {"->"} API.
  3. Copy the Project URL and add it to VITE_SUPABASE_URL.
  4. Copy the anon public key and add it to VITE_SUPABASE_ANON_KEY.
)} {/* Add Key Drawer */} setIsAddKeyOpen(false)} title="Add BRIDGEModulE API Key" subtitle="Retrieve your API key from Settings -> Profile -> API Keys" >
{ e.preventDefault(); const form = e.target as HTMLFormElement; const name = (form.elements.namedItem("name") as HTMLInputElement).value; const key = (form.elements.namedItem("key") as HTMLInputElement).value; addApiKey(name, key); toast.success("API Key saved & activated"); setIsAddKeyOpen(false); }} className="space-y-4 text-xs" >
{/* Delete Key Modal */} setKeyToDelete(null)} onConfirm={() => { if (keyToDelete) { removeApiKey(keyToDelete); toast.success("API key deleted"); setKeyToDelete(null); } }} title="Delete API Key" description="Are you sure you want to remove this stored API key?" />
); }