"use client"; import { useEffect, useRef, useState } from "react"; import { Loader2, RefreshCw, Trash2, UserCheck, ArrowRight, } from "lucide-react"; import { toast } from "sonner"; import { getApiUrl } from "@/utils/api"; import { MixpanelEvent, trackEvent } from "@/utils/mixpanel"; interface CodexConfigProps { codexModel: string; onInputChange: (value: string | boolean, field: string) => void; } type AuthStatus = "checking" | "unauthenticated" | "polling" | "authenticated"; interface StatusResponse { status: string; account_id?: string; username?: string; email?: string; is_pro?: boolean; detail?: string; } interface CodexModel { id: string; name: string; } export const CHATGPT_MODELS: CodexModel[] = [ { id: "gpt-5.4", name: "GPT-5.4" }, { id: "gpt-5.2-codex", name: "GPT-5.2-Codex" }, { id: "gpt-5.1-codex-max", name: "GPT-5.1-Codex-Max" }, { id: "gpt-5.4-mini", name: "GPT-5.4-Mini" }, { id: "gpt-5.3-codex", name: "GPT-5.3-Codex" }, { id: "gpt-5.2", name: "GPT-5.2" }, ]; export const DEFAULT_CODEX_MODEL = "gpt-5.2"; export default function CodexConfig({ codexModel, onInputChange, }: CodexConfigProps) { const [authStatus, setAuthStatus] = useState("checking"); const [accountId, setAccountId] = useState(null); const [username, setUsername] = useState(null); const [email, setEmail] = useState(null); const [sessionId, setSessionId] = useState(null); const [manualCode, setManualCode] = useState(""); const [isExchanging, setIsExchanging] = useState(false); const [isLoggingOut, setIsLoggingOut] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false); const pollIntervalRef = useRef | null>(null); const stopPolling = () => { if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current); pollIntervalRef.current = null; } }; useEffect(() => { checkCurrentAuthStatus(); return () => stopPolling(); }, []); const applyProfile = (data: Partial) => { setAccountId(data.account_id ?? null); setUsername(data.username ?? null); setEmail(data.email ?? null); }; const checkCurrentAuthStatus = async () => { try { const res = await fetch(getApiUrl("/api/v1/ppt/codex/auth/status")); if (!res.ok) { setAuthStatus("unauthenticated"); applyProfile({}); return; } const data: StatusResponse = await res.json(); if (data.status === "authenticated") { onInputChange('codex', 'LLM'); onInputChange(DEFAULT_CODEX_MODEL, 'codex_model'); setAuthStatus("authenticated"); applyProfile(data); } else { setAuthStatus("unauthenticated"); applyProfile({}); } } catch { setAuthStatus("unauthenticated"); applyProfile({}); } }; const handleSignIn = async () => { try { trackEvent(MixpanelEvent.Codex_SignIn_API_Call); onInputChange('codex', 'LLM'); const res = await fetch(getApiUrl("/api/v1/ppt/codex/auth/initiate"), { method: "POST", }); if (!res.ok) throw new Error("Failed to initiate auth"); const data = await res.json(); const { session_id, url } = data; setSessionId(session_id); setAuthStatus("polling"); window.open(url, "_blank", "noopener,noreferrer"); pollIntervalRef.current = setInterval(async () => { try { const pollRes = await fetch( getApiUrl(`/api/v1/ppt/codex/auth/status/${session_id}`) ); if (!pollRes.ok) return; const pollData: StatusResponse = await pollRes.json(); if (pollData.status === "success") { stopPolling(); setAuthStatus("authenticated"); applyProfile(pollData); setSessionId(null); if (!codexModel) { onInputChange(DEFAULT_CODEX_MODEL, "codex_model"); } toast.success("Signed in to ChatGPT successfully"); } else if (pollData.status === "failed") { stopPolling(); setAuthStatus("unauthenticated"); applyProfile({}); toast.error("Authentication failed. Please try again."); } } catch { // keep polling on transient errors } }, 2000); } catch (err) { toast.error("Failed to start sign-in flow"); setAuthStatus("unauthenticated"); applyProfile({}); } }; const handleManualExchange = async () => { if (!sessionId || !manualCode.trim()) return; setIsExchanging(true); try { const res = await fetch(getApiUrl("/api/v1/ppt/codex/auth/exchange"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ session_id: sessionId, code: manualCode.trim() }), }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.detail || "Exchange failed"); } const data = await res.json(); stopPolling(); setAuthStatus("authenticated"); applyProfile(data); setSessionId(null); setManualCode(""); if (!codexModel) { onInputChange(DEFAULT_CODEX_MODEL, "codex_model"); } toast.success("Signed in to ChatGPT successfully"); } catch (err: any) { toast.error(err.message || "Code exchange failed"); } finally { setIsExchanging(false); } }; const handleCancelPolling = () => { stopPolling(); setSessionId(null); setManualCode(""); setAuthStatus("unauthenticated"); }; const handleSignOut = async () => { setIsLoggingOut(true); try { await fetch(getApiUrl("/api/v1/ppt/codex/auth/logout"), { method: "POST" }); setAuthStatus("unauthenticated"); setAccountId(null); setUsername(null); setEmail(null); onInputChange("openai", "LLM"); onInputChange("", "codex_model"); toast.success("Signed out from ChatGPT"); } catch { toast.error("Sign out failed"); } finally { setIsLoggingOut(false); } }; const handleRefreshToken = async () => { setIsRefreshing(true); try { const res = await fetch(getApiUrl("/api/v1/ppt/codex/auth/refresh"), { method: "POST", }); if (!res.ok) throw new Error("Refresh failed"); const data = await res.json(); applyProfile(data); toast.success("Token refreshed successfully"); } catch { toast.error("Token refresh failed. Please sign in again."); setAuthStatus("unauthenticated"); applyProfile({}); } finally { setIsRefreshing(false); } }; if (authStatus === "checking") { return (

Checking status

Verifying your ChatGPT connection…

); } if (authStatus === "polling") { return (

Waiting for sign-in

Complete sign-in in the browser tab we opened.

Paste redirect URL or code if you were not redirected automatically

setManualCode(e.target.value)} />
); } if (authStatus === "authenticated") { return (
openai Logo

{username || email || (accountId ? `Account ${accountId}` : "ChatGPT Account")}

{email && username && (

{email}

)} {!email && accountId && (

ID: {accountId}

)}

Signed in to ChatGPT

); } return ( ); }