import React, { useState, useCallback } from "react"; import { useFetcher } from "@remix-run/react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "~/components/ui/dialog"; import { Button } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; import { FormButtons } from "~/components/ui/FormButtons"; interface IntegrationAuthDialogProps { integration: { id: string; name: string; description?: string; spec: any; }; children: React.ReactNode; onOpenChange?: (open: boolean) => void; } function parseSpec(spec: any) { if (!spec) return {}; if (typeof spec === "string") { try { return JSON.parse(spec); } catch { return {}; } } return spec; } export function IntegrationAuthDialog({ integration, children, onOpenChange, }: IntegrationAuthDialogProps) { const [apiKey, setApiKey] = useState(""); const [isLoading, setIsLoading] = useState(false); const [isConnecting, setIsConnecting] = useState(false); const [isMCPConnecting, setIsMCPConnecting] = useState(false); const apiKeyFetcher = useFetcher(); const oauthFetcher = useFetcher<{ redirectURL: string }>(); const mcpFetcher = useFetcher<{ redirectURL: string }>(); const specData = parseSpec(integration.spec); const hasApiKey = !!specData?.auth?.api_key; const hasOAuth2 = !!specData?.auth?.OAuth2; const hasMCPAuth = !!specData?.mcpAuth; const handleApiKeyConnect = useCallback(() => { if (!apiKey.trim()) return; setIsLoading(true); apiKeyFetcher.submit( { integrationDefinitionId: integration.id, apiKey, }, { method: "post", action: "/api/v1/integration_account", encType: "application/json", }, ); }, [integration.id, apiKey, apiKeyFetcher]); const handleOAuthConnect = useCallback(() => { setIsConnecting(true); oauthFetcher.submit( { integrationDefinitionId: integration.id, redirectURL: window.location.href, }, { method: "post", action: "/api/v1/oauth", encType: "application/json", }, ); }, [integration.id, oauthFetcher]); const handleMCPConnect = useCallback(() => { setIsMCPConnecting(true); mcpFetcher.submit( { integrationDefinitionId: integration.id, redirectURL: window.location.href, mcp: true, }, { method: "post", action: "/api/v1/oauth", encType: "application/json", }, ); }, [integration.id, mcpFetcher]); // Watch for fetcher completion React.useEffect(() => { if (apiKeyFetcher.state === "idle" && isLoading) { if (apiKeyFetcher.data !== undefined) { window.location.reload(); } } }, [apiKeyFetcher.state, apiKeyFetcher.data, isLoading]); React.useEffect(() => { if (oauthFetcher.state === "idle" && isConnecting) { if (oauthFetcher.data?.redirectURL) { window.location.href = oauthFetcher.data.redirectURL; } else { setIsConnecting(false); } } }, [oauthFetcher.state, oauthFetcher.data, isConnecting]); React.useEffect(() => { if (mcpFetcher.state === "idle" && isMCPConnecting) { if (mcpFetcher.data?.redirectURL) { window.location.href = mcpFetcher.data.redirectURL; } else { setIsMCPConnecting(false); } } }, [mcpFetcher.state, mcpFetcher.data, isMCPConnecting]); return ( { if (open) { setApiKey(""); } onOpenChange?.(open); }} > {children} Connect to {integration.name} {integration.description || `Connect your ${integration.name} account to enable integration.`} {/* API Key Authentication */} {hasApiKey && (
setApiKey(e.target.value)} /> {specData?.auth?.api_key?.description && (

{specData.auth.api_key.description}

)}
{isLoading || apiKeyFetcher.state === "submitting" ? "Connecting..." : "Connect"} } />
)} {/* OAuth Authentication */} {hasOAuth2 && (
)} {/* MCP Authentication */} {hasMCPAuth && (

MCP Authentication

This integration requires MCP (Model Context Protocol) authentication.

)} {/* No authentication method found */} {!hasApiKey && !hasOAuth2 && !hasMCPAuth && (
This integration doesn't specify an authentication method.
)}
By connecting, you agree to the {integration.name} terms of service.
); }