import type { MessageBlock } from "@rakazo/contracts"; import { abortableDelay } from "@rakazo/core"; import { useEffect, useRef, useState } from "react"; import { ActivityIndicator, Linking, Pressable, Text, View } from "react-native"; import { rpc } from "../lib/api"; import { appConnectPresentation } from "../lib/app-connect"; import { native } from "../lib/native"; export function AppConnectCard({ botId, block, }: { botId: string; block: Extract; }) { const [busy, setBusy] = useState(false); const [localStatus, setLocalStatus] = useState<"pending" | "connected">(block.status); const [error, setError] = useState(null); const connectionAttempt = useRef(null); const status = block.status === "connected" ? "connected" : localStatus; const view = appConnectPresentation({ ...block, status }, busy); useEffect(() => () => connectionAttempt.current?.abort(), []); async function authorize() { connectionAttempt.current?.abort(); const controller = new AbortController(); connectionAttempt.current = controller; setBusy(true); setError(null); try { const started = await rpc<{ connectionId: string; authorizationUrl: string | null }>( "connections/begin", { provider: block.provider, displayName: block.name, }, { signal: controller.signal }, ); if (controller.signal.aborted) return; if (started.authorizationUrl) await Linking.openURL(started.authorizationUrl); for (let attempt = 0; attempt < 60; attempt += 1) { if (controller.signal.aborted) return; const row = await rpc<{ status: string }>( "connections/complete", { connectionId: started.connectionId }, { signal: controller.signal }, ).catch(() => undefined); if (row?.status === "connected") { if (controller.signal.aborted) return; await rpc("onboarding/appConnected", { botId, provider: block.provider }); if (controller.signal.aborted) return; setLocalStatus("connected"); return; } await abortableDelay(2_000, controller.signal); } if (!controller.signal.aborted) setError("Authorization timed out. Please try again."); } catch (reason) { if (!controller.signal.aborted) { setError(reason instanceof Error ? reason.message : "Could not authorize this app"); } } finally { if (connectionAttempt.current === controller) { connectionAttempt.current = null; setBusy(false); } } } return ( {block.name.slice(0, 1).toUpperCase()} {view.title} {view.description} {view.showAuthorize ? ( void authorize()} style={{ minHeight: 36, paddingHorizontal: 14, borderRadius: 999, backgroundColor: native.fillPressed, alignItems: "center", justifyContent: "center", }} > {busy ? ( ) : ( {view.actionLabel} )} ) : ( {view.actionLabel} )} {error ? {error} : null} ); }