1import { useEffect, useRef, useState } from "react";
2import { pendingProviderAuthDelivery, clearProviderAuthDelivery } from "../../providerAuthDelivery";
3import { serverEnvironment } from "../../state/server";
4import { useEnvironments } from "../../state/environments";
5import { useAtomCommand } from "../../state/use-atom-command";
6import { toastManager } from "../ui/toast";
7
8/** Hosted web receives only the one-time code; the selected environment verifies and stores tokens. */
9export function ProviderAuthCallbackCoordinator() {
10 const completeAuth = useAtomCommand(serverEnvironment.completeProviderAuth, {
11 reportFailure: false,
12 });
13 const { environments } = useEnvironments();
14 const [delivery, setDelivery] = useState(pendingProviderAuthDelivery);
15 const started = useRef(false);
16 const environmentId = delivery?.environmentId;
17 const connected = environments.some(
18 (environment) =>
19 environment.environmentId === environmentId && environment.connection.phase === "connected",
20 );
21 useEffect(() => {
22 const input = delivery;
23 if (!input || started.current || !connected) return;
24 started.current = true;
25 void completeAuth({
26 environmentId: input.environmentId,
27 input: { instanceId: input.instanceId, flowId: input.flowId, callbackUrl: input.callbackUrl },
28 })
29 .then((result) => {
30 if (result._tag === "Failure")
31 toastManager.add({
32 type: "error",
33 title: "ChatGPT sign-in couldn't finish",
34 description: "Return to the provider and try again.",
35 });
36 })
37 .catch(() =>
38 toastManager.add({
39 type: "error",
40 title: "ChatGPT sign-in couldn't finish",
41 description: "Reconnect to the environment and try again.",
42 }),
43 )
44 .finally(() => {
45 setDelivery(undefined);
46 clearProviderAuthDelivery();
47 });
48 }, [completeAuth, connected, delivery]);
49 return null;
50}