Eliminates the two-chat experience on the overview page:
- CooChat now pre-loads Atlas conversation history on mount, showing
the full discovery conversation in the left panel. Atlas messages
render with a blue "A" avatar; COO messages use the dark "◈" icon.
A "Discovery · COO" divider separates historical from new messages.
- FreshIdeaMain detects when a PRD already exists and replaces the
duplicate AtlasChat with a clean completion view ("Discovery complete")
that links to the PRD and Build pages. Atlas chat only shows when
discovery is still in progress.
Made-with: Cursor
198 lines
6.9 KiB
TypeScript
198 lines
6.9 KiB
TypeScript
"use client";
|
||
|
||
import { useEffect, useState } from "react";
|
||
import { AtlasChat } from "@/components/AtlasChat";
|
||
import { useRouter, useParams } from "next/navigation";
|
||
import Link from "next/link";
|
||
|
||
const DISCOVERY_PHASES = [
|
||
"big_picture",
|
||
"users_personas",
|
||
"features_scope",
|
||
"business_model",
|
||
"screens_data",
|
||
"risks_questions",
|
||
];
|
||
|
||
interface FreshIdeaMainProps {
|
||
projectId: string;
|
||
projectName: string;
|
||
}
|
||
|
||
export function FreshIdeaMain({ projectId, projectName }: FreshIdeaMainProps) {
|
||
const router = useRouter();
|
||
const params = useParams();
|
||
const workspace = params?.workspace as string;
|
||
|
||
const [savedPhaseIds, setSavedPhaseIds] = useState<Set<string>>(new Set());
|
||
const [allDone, setAllDone] = useState(false);
|
||
const [prdLoading, setPrdLoading] = useState(false);
|
||
const [dismissed, setDismissed] = useState(false);
|
||
const [hasPrd, setHasPrd] = useState(false);
|
||
|
||
useEffect(() => {
|
||
// Check if PRD already exists on the project
|
||
fetch(`/api/projects/${projectId}`)
|
||
.then(r => r.json())
|
||
.then(d => { if (d.project?.prd) setHasPrd(true); })
|
||
.catch(() => {});
|
||
|
||
const poll = () => {
|
||
fetch(`/api/projects/${projectId}/save-phase`)
|
||
.then(r => r.json())
|
||
.then(d => {
|
||
const ids = new Set<string>((d.phases ?? []).map((p: { phase: string }) => p.phase));
|
||
setSavedPhaseIds(ids);
|
||
const done = DISCOVERY_PHASES.every(id => ids.has(id));
|
||
setAllDone(done);
|
||
})
|
||
.catch(() => {});
|
||
};
|
||
poll();
|
||
const interval = setInterval(poll, 8_000);
|
||
return () => clearInterval(interval);
|
||
}, [projectId]);
|
||
|
||
const handleGeneratePRD = async () => {
|
||
if (prdLoading) return;
|
||
setPrdLoading(true);
|
||
try {
|
||
router.push(`/${workspace}/project/${projectId}/prd`);
|
||
} finally {
|
||
setPrdLoading(false);
|
||
}
|
||
};
|
||
|
||
const handleMVP = () => {
|
||
router.push(`/${workspace}/project/${projectId}/build`);
|
||
};
|
||
|
||
// Once the PRD exists, show a clean "done" state in the main panel.
|
||
// The Atlas conversation history lives in the left CooChat sidebar.
|
||
if (hasPrd) {
|
||
return (
|
||
<div style={{
|
||
height: "100%", display: "flex", flexDirection: "column",
|
||
alignItems: "center", justifyContent: "center",
|
||
fontFamily: "Outfit, sans-serif", padding: "32px",
|
||
}}>
|
||
<div style={{
|
||
maxWidth: 420, textAlign: "center",
|
||
display: "flex", flexDirection: "column", alignItems: "center", gap: 20,
|
||
}}>
|
||
<div style={{
|
||
width: 48, height: 48, borderRadius: 14, background: "#1a1a1a",
|
||
display: "flex", alignItems: "center", justifyContent: "center",
|
||
fontSize: "1.2rem", color: "#fff",
|
||
}}>✦</div>
|
||
<div>
|
||
<div style={{ fontSize: "1.05rem", fontWeight: 700, color: "#1a1a1a", marginBottom: 6 }}>
|
||
Discovery complete
|
||
</div>
|
||
<div style={{ fontSize: "0.82rem", color: "#6b6560", lineHeight: 1.65 }}>
|
||
Your PRD is saved. The full discovery conversation is in the left panel — talk to your COO to plan what to build next.
|
||
</div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 10 }}>
|
||
<Link
|
||
href={`/${workspace}/project/${projectId}/prd`}
|
||
style={{
|
||
padding: "10px 20px", borderRadius: 8, border: "none",
|
||
background: "#1a1a1a", color: "#fff",
|
||
fontSize: "0.82rem", fontWeight: 600,
|
||
textDecoration: "none", display: "inline-block",
|
||
}}
|
||
>
|
||
View PRD →
|
||
</Link>
|
||
<Link
|
||
href={`/${workspace}/project/${projectId}/build`}
|
||
style={{
|
||
padding: "10px 20px", borderRadius: 8,
|
||
border: "1px solid #e8e4dc",
|
||
background: "#fff", color: "#1a1a1a",
|
||
fontSize: "0.82rem", fontWeight: 500,
|
||
textDecoration: "none", display: "inline-block",
|
||
}}
|
||
>
|
||
Go to Build
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div style={{ height: "100%", display: "flex", flexDirection: "column", position: "relative" }}>
|
||
{/* Decision banner — shown when all 6 phases are saved */}
|
||
{allDone && !dismissed && (
|
||
<div style={{
|
||
background: "linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%)",
|
||
padding: "18px 28px",
|
||
display: "flex", alignItems: "center", justifyContent: "space-between",
|
||
gap: 16, flexShrink: 0, flexWrap: "wrap",
|
||
borderBottom: "1px solid #333",
|
||
}}>
|
||
<div>
|
||
<div style={{ fontSize: "0.88rem", fontWeight: 700, color: "#fff", fontFamily: "Outfit, sans-serif", marginBottom: 3 }}>
|
||
✦ Discovery complete — what's next?
|
||
</div>
|
||
<div style={{ fontSize: "0.75rem", color: "#a09a90", fontFamily: "Outfit, sans-serif" }}>
|
||
Atlas has captured all 6 discovery phases. Choose your next step.
|
||
</div>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 10, flexShrink: 0 }}>
|
||
<button
|
||
onClick={handleGeneratePRD}
|
||
disabled={prdLoading}
|
||
style={{
|
||
padding: "10px 20px", borderRadius: 8, border: "none",
|
||
background: "#fff", color: "#1a1a1a",
|
||
fontSize: "0.84rem", fontWeight: 700,
|
||
fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
||
transition: "opacity 0.12s",
|
||
}}
|
||
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
||
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
||
>
|
||
{prdLoading ? "Navigating…" : "Generate PRD →"}
|
||
</button>
|
||
<button
|
||
onClick={handleMVP}
|
||
style={{
|
||
padding: "10px 20px", borderRadius: 8,
|
||
border: "1px solid rgba(255,255,255,0.2)",
|
||
background: "transparent", color: "#fff",
|
||
fontSize: "0.84rem", fontWeight: 600,
|
||
fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
||
transition: "background 0.12s",
|
||
}}
|
||
onMouseEnter={e => (e.currentTarget.style.background = "rgba(255,255,255,0.08)")}
|
||
onMouseLeave={e => (e.currentTarget.style.background = "transparent")}
|
||
>
|
||
Plan MVP Test →
|
||
</button>
|
||
<button
|
||
onClick={() => setDismissed(true)}
|
||
style={{
|
||
background: "none", border: "none", cursor: "pointer",
|
||
color: "#666", fontSize: "1rem", padding: "4px 6px",
|
||
fontFamily: "Outfit, sans-serif",
|
||
}}
|
||
title="Dismiss"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<AtlasChat
|
||
projectId={projectId}
|
||
projectName={projectName}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|