import { useEffect, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { Check, Loader2, Send } from "lucide-react"; import type { SlackTestMessageResult } from "@paperclipai/shared"; import { chatEndpointsApi } from "@/api/chatEndpoints"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { queryKeys } from "@/lib/queryKeys"; export function SlackTestMessageButton({ endpointId }: { endpointId: string }) { const queryClient = useQueryClient(); const [requestId, setRequestId] = useState(() => crypto.randomUUID()); const [accounts, setAccounts] = useState["accounts"] | null>(null); const [nextCursor, setNextCursor] = useState(null); const [selected, setSelected] = useState(""); const [invitationExpired, setInvitationExpired] = useState(false); const [search, setSearch] = useState(""); const send = useMutation({ mutationFn: (input: { slackUserId?: string; accountCursor?: string; requestId?: string }) => chatEndpointsApi.sendSlackTestMessage(endpointId, { requestId, ...input }), onSuccess: (result, input) => { if (result.status === "connection_required") { setAccounts(previous => input.accountCursor ? [...new Map([...(previous ?? []), ...result.accounts].map(account => [account.id, account])).values()] : result.accounts); setNextCursor(result.nextCursor); return; } setAccounts(null); void queryClient.invalidateQueries({ queryKey: queryKeys.chatEndpoints.principals(endpointId) }); }, }); const sent = send.data?.status === "sent"; const pendingConnection = send.data?.status === "connection_pending" ? send.data : null; useEffect(() => { setInvitationExpired(false); if (!pendingConnection) return; const timer = setTimeout(() => setInvitationExpired(true), Math.max(0, new Date(pendingConnection.expiresAt).getTime() - Date.now())); return () => clearTimeout(timer); }, [pendingConnection?.expiresAt]); const principals = useQuery({ queryKey: queryKeys.chatEndpoints.principals(endpointId), queryFn: () => chatEndpointsApi.listPrincipals(endpointId), enabled: Boolean(pendingConnection) && !invitationExpired, refetchInterval: pendingConnection && !invitationExpired ? 3000 : false, }); const confirmed = Boolean(pendingConnection && principals.data?.some(link => link.principalId === pendingConnection.principalId && link.status === "linked")); useEffect(() => { if (confirmed && !send.isPending && !send.isError) send.mutate({ slackUserId: selected }); }, [confirmed, send.isPending, send.isError]); const reset = () => { setRequestId(crypto.randomUUID()); send.reset(); }; const startTest = () => { if (invitationExpired) { const next = crypto.randomUUID(); setRequestId(next); send.mutate({ requestId: next, slackUserId: selected }); } else send.mutate({}); }; return
{pendingConnection &&

{invitationExpired ? "The Slack invitation expired." : "Open the invitation in Slack to connect your account."}

} {send.isError &&
{send.error.message}
} { if (!open && !send.isPending) setAccounts(null); }}> Connect your Slack account Choose your account. Messages to this agent will use your Paperclip permissions. setSearch(event.target.value)} />
{accounts?.filter(account => `${account.name} ${account.id}`.toLowerCase().includes(search.toLowerCase())).map(account => )} {accounts?.length === 0 &&

No available accounts found in this Slack workspace.

}
{nextCursor && } {send.isError &&

{send.error.message}

}
; }