"use client"; import type { McpAiCopy } from "./copy"; import CheckCircleIcon from "@mui/icons-material/CheckCircle"; import OpenInNewIcon from "@mui/icons-material/OpenInNew"; import { useEffect, useState } from "react"; import { type GuidedNav } from "@12-apps/onboarding"; import { Progress } from "@12-apps/ui/data-display/Progress"; import { Button } from "@12-apps/ui/form/Button"; import { Box } from "@12-apps/ui/mui/Box"; import { Stack } from "@12-apps/ui/mui/Stack"; import { Text } from "@12-apps/ui/typography/Text"; import type { AiHostConfigureStage, AiHostGuide } from "../guide"; import { activeAgo, connectionForHost, hostLabel, type AiConnection } from "./ai-connection-utils"; import { EndpointCopyBlock, HostConnectHeader, HostDocsLink, HostOpenButton, HostStepList, PromptCopyBlock, } from "./host-connect-guide"; /** The host's connect steps split across the Configurar / Conectar stages. */ const CONFIGURE_STEP_COUNT = 3; /** How often the Confirmar step re-checks the live connection while waiting. */ const POLL_INTERVAL_MS = 3000; /** A step's continue/back controls (Voltar left, primary next right). */ function StepNav({ nav, onNext, nextLabel, nextDisabled = false, nextTestId, copy, }: { nav: GuidedNav; onNext: () => void; nextLabel?: string; nextDisabled?: boolean; nextTestId?: string; copy: McpAiCopy; }): React.JSX.Element { return ( ); } /** Step 2 — copy the store URL; copying is the action that advances the wizard. */ export function CopyUrlStep({ nav, endpointUrl, copy, }: { nav: GuidedNav; endpointUrl: string; copy: McpAiCopy; }): React.JSX.Element { return ( {copy.flow.copyUrlTitle} {copy.flow.urlCaption} nav.next()} /> ); } /** Step 3 — open the host's connectors and add + configure the custom connector. */ export function ConfigureStep({ nav, host, copy, }: { nav: GuidedNav; host: AiHostGuide; copy: McpAiCopy; }): React.JSX.Element { // Hosts with no direct link (e.g. Claude Desktop) have nothing to open, so // "Próximo" is available immediately; otherwise it unlocks on the open click. const [opened, setOpened] = useState(!host.link); return ( setOpened(true)} /> nav.next()} nextDisabled={!opened} nextTestId="ai-configure-next" /> ); } /** * One stage of a host's per-stage configuration (e.g. ChatGPT's "enable * developer mode" then "configurar"). Each stage has its OWN deep link — opening * it unlocks "Próximo" — and its own instructions. */ export function ConfigureStageStep({ nav, host, stage, copy, }: { nav: GuidedNav; host: AiHostGuide; stage: AiHostConfigureStage; copy: McpAiCopy; }): React.JSX.Element { const [opened, setOpened] = useState(!stage.link); return ( {stage.link && ( )} nav.next()} nextDisabled={!opened} nextTestId={`ai-stage-next-${stage.id}`} /> ); } /** Step 4 — connect: log in, authorize and activate the connector. */ export function ConnectStep({ nav, host, connectPrompt, copy, }: { nav: GuidedNav; host: AiHostGuide; connectPrompt: string; copy: McpAiCopy; }): React.JSX.Element { return ( nav.next()} nextLabel={copy.flow.advance} nextTestId="ai-connect-done" /> ); } /** * Simplified-flow step (host has a published `pluginUrl`): open the one-click * plugin (install + authorize), then paste the prompt asking the assistant to * connect. No URL to copy, no manual connector. The next step (Confirmar) waits. */ export function InstallStep({ nav, host, connectPrompt, copy, }: { nav: GuidedNav; host: AiHostGuide; connectPrompt: string; copy: McpAiCopy; }): React.JSX.Element { const [opened, setOpened] = useState(false); return ( {copy.flow.installBody} {host.pluginUrl && ( )} nav.next()} nextLabel={copy.flow.advance} nextDisabled={!opened} nextTestId="ai-install-done" /> ); } /** * Step 5: auto-detect the live connection. While waiting it polls the server * (the sign-in / `announceAiConnection` tool call registers the connection * server-side), showing a spinner — the owner never clicks "verify". Completes * when the selected host's connection appears. */ export function ConfirmStep({ nav, connections, hosts, onRetest, copy, }: { nav: GuidedNav; connections: readonly AiConnection[]; hosts: readonly AiHostGuide[]; onRetest: () => void; copy: McpAiCopy; }): React.JSX.Element { const selectedHostId = nav.data.selectedHost as string | undefined; const connection = connectionForHost(connections, selectedHostId); const label = connection?.clientName ?? hostLabel(hosts, selectedHostId); // Auto-detect: re-check on an interval until the connection shows up. The // interval is cleared as soon as `connection` is non-null (and on unmount). useEffect(() => { if (connection) return undefined; const id = setInterval(() => onRetest(), POLL_INTERVAL_MS); return () => clearInterval(id); }, [connection, onRetest]); if (connection) { return ( {copy.flow.connectedTo(label)} {activeAgo(connection.lastActiveAt, copy.summary)} ); } return ( {copy.flow.waitingTitle} {copy.flow.waitingBody(label)} ); }