import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { CheckCircle2, Copy, ExternalLink, Loader2 } from "lucide-react"; import { authApi } from "@/api/auth"; import { healthApi } from "@/api/health"; import { chatEndpointsApi } from "@/api/chatEndpoints"; import { Button } from "@/components/ui/button"; import { copyTextToClipboard } from "@/lib/clipboard"; import { queryKeys } from "@/lib/queryKeys"; export function SlackIdentityStep({ endpointId, command, testStartedAt, onConnected, onSaveExit }: { endpointId: string; command: string; testStartedAt?: string | null; onConnected: () => void; onSaveExit: () => void; }) { const client = useQueryClient(); const [copied, setCopied] = useState(false); const [copyError, setCopyError] = useState(false); const session = useQuery({ queryKey: queryKeys.auth.session, queryFn: authApi.getSession, retry: false }); const health = useQuery({ queryKey: queryKeys.health, queryFn: healthApi.get }); const identities = useQuery({ queryKey: queryKeys.chatEndpoints.principals(endpointId), queryFn: () => chatEndpointsApi.listPrincipals(endpointId), refetchInterval: 1_500, }); const local = health.data?.deploymentMode === "local_trusted"; const userId = local ? "local-board" : session.data?.user.id; const userLabel = local ? "Local Board" : session.data?.user.name || session.data?.user.email; const candidates = (identities.data ?? []).filter((identity) => identity.lastConnectAt && (!testStartedAt || Date.parse(identity.lastConnectAt) >= Date.parse(testStartedAt))); const linkedToMe = candidates.some((identity) => identity.status === "linked" && identity.paperclipUserId === userId); const connectCommand = `${command} connect`; const link = useMutation({ mutationFn: async (principalId: string) => { const { confirmationUrl } = await chatEndpointsApi.createLinkIntent(endpointId, principalId); const token = new URL(confirmationUrl, window.location.origin).searchParams.get("token"); if (!token) throw new Error("Could not create the account confirmation. Try again."); await chatEndpointsApi.confirmIdentityLink(token); }, onSuccess: () => client.invalidateQueries({ queryKey: queryKeys.chatEndpoints.principals(endpointId) }), }); return (
Send this command in Slack so we can identify your account. It won't start agent work.
{connectCommand}
Couldn't copy the command. Select and copy it above.
}
Open Slack
Couldn't check for your Slack account. We'll keep trying.
) : candidates.length === 0 ? (Choose your Slack account below to link it to {userLabel ?? "your Paperclip account"}. Only confirm an account that belongs to you. Future messages will use your Paperclip permissions.
{candidates.map((identity) => { const mine = identity.status === "linked" && identity.paperclipUserId === userId; return ({identity.externalLabel}
{identity.externalDetail}
Linked to {identity.paperclipUserLabel ?? "another Paperclip account"}
: }Sign in to Paperclip to link your Slack account. Refresh this page after signing in.
} {link.isError &&Couldn't link your account. Check that you are a member of this company and try again.
}