"use client"; import { useState } from "react"; import { CheckCircle2, Loader2, Plug, XCircle } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useTranslations } from "@/lib/i18n/context"; import { apiFetchRaw } from "@/lib/api/api-fetch"; import { translateCode } from "@/lib/i18n/translate-code"; /** * Shared "Test connection" UX for the settings integrations + notifications * sections (A8-UI). POSTs to the given endpoint, expects a `{ data, error, * meta }` envelope, and surfaces success (latency) or a translated * `meta.errorCode` callout. When the route reports what the other end * answered (`meta.upstreamStatus` / `meta.smtpCode` / `meta.upstreamBody`, * the notification test routes since #947), the callout shows the status and * the relay's own words beneath it, as plain text. * * Endpoints are user-scoped, so the button intentionally does NOT send an * Idempotency-Key — each click probes the upstream live. */ export interface TestConnectionButtonProps { endpoint: string; /** Optional disabled flag from the parent — typically "no credentials yet". */ disabled?: boolean; /** Label override for the button (defaults to settings.testConnection.test). */ label?: string; /** * The card's form differs from what is saved. The test route sends through * the saved config, so the button waits for a save and says so instead of * testing something other than what is on screen. */ unsavedChanges?: boolean; } interface TestResponse { data?: { latencyMs?: number; ok?: boolean; sent?: number }; error?: string; meta?: { errorCode?: string; upstreamStatus?: number; smtpCode?: number; upstreamBody?: string; }; } export interface TestConnectionFailureProps { /** The translated error sentence. */ message: string; upstreamStatus?: number; smtpCode?: number; /** What the other end answered, already bounded and cleaned by the server. */ upstreamBody?: string; } /** * The failure callout. Hook-free so it renders without a provider. The * relay's body is a React text child, never markup: whatever it contains is * shown as characters. */ export function TestConnectionFailure({ message, upstreamStatus, smtpCode, upstreamBody, }: TestConnectionFailureProps) { const code = typeof upstreamStatus === "number" ? ` (HTTP ${upstreamStatus})` : typeof smtpCode === "number" ? ` (SMTP ${smtpCode})` : ""; return (
{upstreamBody}
) : null}{t("settings.testConnection.saveFirst")}
)} {!unsavedChanges && result?.kind === "ok" && (