"use client";
import { useState, useRef, useEffect, useCallback } from "react";
import { Textarea } from "@/components/ui/textarea";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Send,
Loader2,
User,
RotateCcw,
FileText,
CheckCircle2,
ChevronDown,
ChevronUp,
} from "lucide-react";
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
interface Message {
role: "user" | "assistant";
content: string;
}
interface AtlasChatProps {
projectId: string;
projectName?: string;
initialMessage?: string;
}
// ---------------------------------------------------------------------------
// Atlas avatar — distinct from orchestrator
// ---------------------------------------------------------------------------
function AtlasAvatar() {
return (
A
);
}
// ---------------------------------------------------------------------------
// PRD preview panel
// ---------------------------------------------------------------------------
function PrdPanel({ content }: { content: string }) {
const [expanded, setExpanded] = useState(false);
const preview = content.split("\n").slice(0, 6).join("\n");
return (
PRD Generated
Ready for architecture phase
{expanded ? content : preview}
{!expanded && (
)}
);
}
// ---------------------------------------------------------------------------
// Main component
// ---------------------------------------------------------------------------
export function AtlasChat({ projectId, projectName, initialMessage }: AtlasChatProps) {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState("");
const [loading, setLoading] = useState(false);
const [prdContent, setPrdContent] = useState(null);
const [error, setError] = useState(null);
const [started, setStarted] = useState(false);
const bottomRef = useRef(null);
const textareaRef = useRef(null);
// Auto-scroll to latest message
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages, loading]);
// Kick off Atlas with its opening message on first load
useEffect(() => {
if (started) return;
setStarted(true);
sendMessage(
initialMessage ||
`Hey — I'm starting a new project called "${projectName || "my project"}". I'd love your help defining what we're building.`
);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const sendMessage = useCallback(
async (text: string) => {
if (!text.trim() || loading) return;
setError(null);
const userMsg: Message = { role: "user", content: text };
setMessages((prev) => [...prev, userMsg]);
setInput("");
setLoading(true);
try {
const res = await fetch(
`/api/projects/${projectId}/atlas-chat`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ message: text }),
}
);
const data = await res.json();
if (!res.ok) {
setError(data.error || "Something went wrong. Please try again.");
setMessages((prev) => prev.slice(0, -1));
return;
}
const assistantMsg: Message = {
role: "assistant",
content: data.reply || "...",
};
setMessages((prev) => [...prev, assistantMsg]);
if (data.prdContent) {
setPrdContent(data.prdContent);
}
} catch {
setError("Couldn't reach Atlas. Check your connection and try again.");
setMessages((prev) => prev.slice(0, -1));
} finally {
setLoading(false);
setTimeout(() => textareaRef.current?.focus(), 50);
}
},
[loading, projectId]
);
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
sendMessage(input);
}
};
const handleReset = async () => {
if (!confirm("Start the discovery conversation over from scratch?")) return;
await fetch(`/api/projects/${projectId}/atlas-chat`, { method: "DELETE" });
setMessages([]);
setPrdContent(null);
setStarted(false);
setError(null);
};
return (
{/* Header */}
Atlas
Product Requirements
{prdContent && (
PRD ready
)}
{/* Messages */}
{messages.map((msg, i) => (
{msg.role === "assistant" &&
}
{msg.role === "user" && (
)}
))}
{/* Typing indicator */}
{loading && (
)}
{/* Error */}
{error && (
{error}
)}
{/* PRD panel */}
{prdContent &&
}
{/* Input */}
{prdContent ? (
PRD complete — the platform is now architecting your solution.
) : (
)}
);
}