"use client"; import { useState, useEffect } from "react"; import AIProviderPanel from "@/components/admin/AIProviderPanel"; import { savePaymentSettings } from "@/actions/payments"; import { saveResendCredentials, saveTwilioCredentials, testResendConnection, testTwilioConnection, getResendCredentials, getTwilioCredentials } from "@/actions/integrations/credentials"; type CredentialField = { key: string; label: string; placeholder: string; isSecret?: boolean; }; type SyncOption = { key: string; label: string; description?: string; }; type Integration = { id: string; name: string; icon: string; description: string; accentColor: string; credentials: CredentialField[]; syncOptions: SyncOption[]; }; const INTEGRATIONS: Integration[] = [ { id: "openai", name: "OpenAI", icon: "AI", description: "Power AI tools like Campaign Writer, Report Explainer, and Pricing Advisor.", accentColor: "border-violet-200", credentials: [ { key: "OPENAI_API_KEY", label: "API Key", placeholder: "sk-...", isSecret: true }, { key: "OPENAI_ORG_ID", label: "Organization ID", placeholder: "org-... (optional)" }, ], syncOptions: [ { key: "campaign_writer", label: "Campaign Idea Generator" }, { key: "product_writer", label: "Product Description Writer" }, { key: "report_explainer", label: "Report Explainer" }, { key: "pricing_advisor", label: "Pricing Advisor" }, ], }, { id: "resend", name: "Resend", icon: "Email", description: "Send transactional and marketing emails via Harvest Reach.", accentColor: "border-amber-200", credentials: [ { key: "RESEND_API_KEY", label: "API Key", placeholder: "re_...", isSecret: true }, { key: "RESEND_FROM_EMAIL", label: "From Email Address", placeholder: "orders@yourbrand.com" }, { key: "RESEND_FROM_NAME", label: "From Name", placeholder: "Your Brand Name" }, ], syncOptions: [ { key: "transactional", label: "Transactional Email" }, { key: "marketing", label: "Marketing Campaigns" }, ], }, { id: "stripe", name: "Stripe", icon: "Stripe", description: "Process online payments for orders.", accentColor: "border-stone-300", credentials: [ { key: "STRIPE_PUBLISHABLE_KEY", label: "Publishable Key", placeholder: "pk_live_..." }, { key: "STRIPE_SECRET_KEY", label: "Secret Key", placeholder: "sk_live_...", isSecret: true }, { key: "STRIPE_WEBHOOK_SECRET", label: "Webhook Secret", placeholder: "whsec_...", isSecret: true }, ], syncOptions: [ { key: "checkout", label: "Online Checkout" }, { key: "refunds", label: "Refund Processing" }, ], }, { id: "twilio", name: "Twilio", icon: "SMS", description: "Send SMS campaigns and alerts via Harvest Reach.", accentColor: "border-blue-200", credentials: [ { key: "TWILIO_ACCOUNT_SID", label: "Account SID", placeholder: "AC..." }, { key: "TWILIO_AUTH_TOKEN", label: "Auth Token", placeholder: "Your Twilio auth token", isSecret: true }, { key: "TWILIO_PHONE_NUMBER", label: "Phone Number", placeholder: "+1234567890" }, ], syncOptions: [ { key: "sms_campaigns", label: "SMS Campaigns" }, { key: "alerts", label: "Order Alerts" }, ], }, ]; const iconColors: Record = { AI: "bg-violet-100 text-violet-700", Email: "bg-amber-100 text-amber-700", Stripe: "bg-stone-100 text-stone-700", SMS: "bg-blue-100 text-blue-700", }; function IntegrationCard({ integration, initialCredentials, brandId, }: { integration: Integration; initialCredentials?: Record; brandId: string; }) { const [credentials, setCredentials] = useState>( initialCredentials ?? {} ); const [showSecrets, setShowSecrets] = useState>({}); const [testResult, setTestResult] = useState<{ ok: boolean; message: string } | null>(null); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); async function handleTest() { setTestResult(null); setError(null); if (integration.id === "resend") { const apiKey = credentials["RESEND_API_KEY"]; if (!apiKey?.trim()) { setTestResult({ ok: false, message: "API key is required" }); return; } const result = await testResendConnection(apiKey); setTestResult(result); } else if (integration.id === "twilio") { const accountSid = credentials["TWILIO_ACCOUNT_SID"]; const authToken = credentials["TWILIO_AUTH_TOKEN"]; if (!accountSid?.trim() || !authToken?.trim()) { setTestResult({ ok: false, message: "Account SID and Auth Token are required" }); return; } const result = await testTwilioConnection(accountSid, authToken); setTestResult(result); } else { // Default test (placeholder) await new Promise((r) => setTimeout(r, 500)); const hasKey = Object.values(credentials).some((v) => v.trim().length > 0); setTestResult( hasKey ? { ok: true, message: `Successfully connected to ${integration.name}` } : { ok: false, message: `No API key configured for ${integration.name}` } ); } } async function handleSave() { setSaving(true); setError(null); setTestResult(null); try { if (integration.id === "resend") { const result = await saveResendCredentials(brandId, { api_key: credentials["RESEND_API_KEY"]?.trim() || null, from_email: credentials["RESEND_FROM_EMAIL"]?.trim() || null, from_name: credentials["RESEND_FROM_NAME"]?.trim() || null, }); if (!result.success) { setError(result.error ?? "Failed to save"); return; } setTestResult({ ok: true, message: "Resend credentials saved successfully" }); } else if (integration.id === "twilio") { const result = await saveTwilioCredentials(brandId, { account_sid: credentials["TWILIO_ACCOUNT_SID"]?.trim() || null, auth_token: credentials["TWILIO_AUTH_TOKEN"]?.trim() || null, phone_number: credentials["TWILIO_PHONE_NUMBER"]?.trim() || null, }); if (!result.success) { setError(result.error ?? "Failed to save"); return; } setTestResult({ ok: true, message: "Twilio credentials saved successfully" }); } else if (integration.id === "stripe") { const result = await savePaymentSettings({ brandId, provider: "stripe", stripePublishableKey: credentials["STRIPE_PUBLISHABLE_KEY"]?.trim() || undefined, stripeSecretKey: credentials["STRIPE_SECRET_KEY"]?.trim() || undefined, }); if (!result.success) { setError(result.error ?? "Failed to save"); return; } setTestResult({ ok: true, message: "Stripe credentials saved successfully" }); } else { // Other integrations - just show success for now setTestResult({ ok: true, message: `${integration.name} settings saved` }); } } catch (err) { setError(err instanceof Error ? err.message : "Failed to save settings"); } finally { setSaving(false); } } function toggleSecret(key: string) { setShowSecrets((prev) => ({ ...prev, [key]: !prev[key] })); } return (
{integration.icon}

{integration.name}

{integration.description}

{integration.credentials.map((field) => (
setCredentials((p) => ({ ...p, [field.key]: e.target.value }))} placeholder={field.placeholder} className="w-full rounded-lg border border-stone-200 bg-white px-3 py-2.5 text-sm pr-16 text-stone-900 placeholder:text-stone-400 outline-none focus:border-emerald-500" />
{field.isSecret && ( )}
))}
{testResult && (
{testResult.ok ? "✓" : "✗"} {testResult.message}
)} {error && (
{error}
)}
); } type Props = { brandId: string; brands: { id: string; name: string }[]; }; export default function IntegrationsInner({ brandId, brands }: Props) { const [selectedBrandId, setSelectedBrandId] = useState(brandId); const [initialCredentials, setInitialCredentials] = useState>>({}); // Fetch initial credentials for each integration useEffect(() => { async function fetchCredentials() { const [resendCreds, twilioCreds] = await Promise.all([ getResendCredentials(selectedBrandId), getTwilioCredentials(selectedBrandId), ]); setInitialCredentials({ resend: { RESEND_API_KEY: resendCreds.api_key ?? "", RESEND_FROM_EMAIL: resendCreds.from_email ?? "", RESEND_FROM_NAME: resendCreds.from_name ?? "", }, twilio: { TWILIO_ACCOUNT_SID: twilioCreds.account_sid ?? "", TWILIO_AUTH_TOKEN: twilioCreds.auth_token ?? "", TWILIO_PHONE_NUMBER: twilioCreds.phone_number ?? "", }, }); } fetchCredentials(); }, [selectedBrandId]); return (
{/* AI Provider — separate panel */}

AI Provider

Configure AI →
{/* Payment & email integrations grid */}
{INTEGRATIONS.filter(i => i.id !== "openai").map((integration) => ( ))}
); }