"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useAuth } from "@clerk/nextjs"; import { DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { getApiBaseUrl } from "@/lib/api-base"; const apiBase = getApiBaseUrl(); type BoardDraft = { board_type?: string; objective?: string | null; success_metrics?: Record | null; target_date?: string | null; }; type BoardSummary = { id: string; name: string; slug: string; board_type?: string; objective?: string | null; success_metrics?: Record | null; target_date?: string | null; goal_confirmed?: boolean; }; type OnboardingSession = { id: string; board_id: string; session_key: string; status: string; messages?: Array<{ role: string; content: string }> | null; draft_goal?: BoardDraft | null; }; type QuestionOption = { id: string; label: string }; type Question = { question: string; options: QuestionOption[]; }; const parseQuestion = (messages?: Array<{ role: string; content: string }> | null) => { if (!messages?.length) return null; const lastAssistant = [...messages].reverse().find((msg) => msg.role === "assistant"); if (!lastAssistant?.content) return null; try { return JSON.parse(lastAssistant.content) as Question; } catch { const match = lastAssistant.content.match(/```(?:json)?\s*([\s\S]*?)```/); if (match) { try { return JSON.parse(match[1]) as Question; } catch { return null; } } } return null; }; export function BoardOnboardingChat({ boardId, onConfirmed, }: { boardId: string; onConfirmed: (board: BoardSummary) => void; }) { const { getToken } = useAuth(); const [session, setSession] = useState(null); const [loading, setLoading] = useState(false); const [otherText, setOtherText] = useState(""); const [error, setError] = useState(null); const question = useMemo(() => parseQuestion(session?.messages), [session]); const draft = session?.draft_goal ?? null; const authFetch = useCallback( async (url: string, options: RequestInit = {}) => { const token = await getToken(); return fetch(url, { ...options, headers: { "Content-Type": "application/json", ...(token ? { Authorization: `Bearer ${token}` } : {}), ...(options.headers ?? {}), }, }); }, [getToken] ); const startSession = useCallback(async () => { setLoading(true); setError(null); try { const res = await authFetch(`${apiBase}/api/v1/boards/${boardId}/onboarding/start`, { method: "POST", body: JSON.stringify({}), }); if (!res.ok) throw new Error("Unable to start onboarding."); const data = (await res.json()) as OnboardingSession; setSession(data); } catch (err) { setError(err instanceof Error ? err.message : "Failed to start onboarding."); } finally { setLoading(false); } }, [authFetch, boardId]); const refreshSession = useCallback(async () => { try { const res = await authFetch(`${apiBase}/api/v1/boards/${boardId}/onboarding`); if (!res.ok) return; const data = (await res.json()) as OnboardingSession; setSession(data); } catch { // ignore } }, [authFetch, boardId]); useEffect(() => { startSession(); const interval = setInterval(refreshSession, 2000); return () => clearInterval(interval); }, [startSession, refreshSession]); const handleAnswer = useCallback( async (value: string, freeText?: string) => { setLoading(true); setError(null); try { const res = await authFetch( `${apiBase}/api/v1/boards/${boardId}/onboarding/answer`, { method: "POST", body: JSON.stringify({ answer: value, other_text: freeText ?? null, }), } ); if (!res.ok) throw new Error("Unable to submit answer."); const data = (await res.json()) as OnboardingSession; setSession(data); setOtherText(""); } catch (err) { setError(err instanceof Error ? err.message : "Failed to submit answer."); } finally { setLoading(false); } }, [authFetch, boardId] ); const confirmGoal = async () => { if (!draft) return; setLoading(true); setError(null); try { const res = await authFetch( `${apiBase}/api/v1/boards/${boardId}/onboarding/confirm`, { method: "POST", body: JSON.stringify({ board_type: draft.board_type ?? "goal", objective: draft.objective ?? null, success_metrics: draft.success_metrics ?? null, target_date: draft.target_date ?? null, }), } ); if (!res.ok) throw new Error("Unable to confirm board goal."); const updated = await res.json(); onConfirmed(updated); } catch (err) { setError(err instanceof Error ? err.message : "Failed to confirm board goal."); } finally { setLoading(false); } }; return (
Board onboarding {error ? (
{error}
) : null} {draft ? (

Review the lead agent draft and confirm.

Objective

{draft.objective || "—"}

Success metrics

              {JSON.stringify(draft.success_metrics ?? {}, null, 2)}
            

Target date

{draft.target_date || "—"}

Board type

{draft.board_type || "goal"}

) : question ? (

{question.question}

{question.options.map((option) => ( ))}
setOtherText(event.target.value)} />
) : (
{loading ? "Waiting for the lead agent..." : "Preparing onboarding..."}
)}
); }