"use client"; import { useEffect, useState } from "react"; import { useParams } from "next/navigation"; // Maps each PRD section to the discovery phase that populates it const PRD_SECTIONS = [ { id: "executive_summary", label: "Executive Summary", phaseId: "big_picture" }, { id: "problem_statement", label: "Problem Statement", phaseId: "big_picture" }, { id: "vision_metrics", label: "Vision & Success Metrics", phaseId: "big_picture" }, { id: "users_personas", label: "Users & Personas", phaseId: "users_personas" }, { id: "user_flows", label: "User Flows", phaseId: "users_personas" }, { id: "feature_requirements", label: "Feature Requirements", phaseId: "features_scope" }, { id: "screen_specs", label: "Screen Specs", phaseId: "screens_data" }, { id: "business_model", label: "Business Model", phaseId: "business_model" }, { id: "integrations", label: "Integrations & Dependencies", phaseId: "features_scope" }, { id: "non_functional", label: "Non-Functional Reqs", phaseId: null }, { id: "risks", label: "Risks & Mitigations", phaseId: "risks_questions" }, { id: "open_questions", label: "Open Questions", phaseId: "risks_questions" }, ]; interface SavedPhase { phase: string; title: string; summary: string; data: Record; saved_at: string; } function formatValue(v: unknown): string { if (v === null || v === undefined) return "—"; if (Array.isArray(v)) return v.map(item => typeof item === "object" ? JSON.stringify(item) : String(item)).join(", "); return String(v); } function PhaseDataCard({ phase }: { phase: SavedPhase }) { const [expanded, setExpanded] = useState(false); const entries = Object.entries(phase.data).filter(([, v]) => v !== null && v !== undefined && v !== ""); return (
{expanded && entries.length > 0 && (
{entries.map(([k, v]) => (
{k.replace(/_/g, " ")}
{formatValue(v)}
))}
)}
); } interface ArchApp { name: string; type: string; description: string; tech?: string[]; screens?: string[] } interface ArchInfra { name: string; reason: string } interface ArchPackage { name: string; description: string } interface ArchIntegration { name: string; required?: boolean; notes?: string } interface Architecture { productName?: string; productType?: string; summary?: string; apps?: ArchApp[]; packages?: ArchPackage[]; infrastructure?: ArchInfra[]; integrations?: ArchIntegration[]; designSurfaces?: string[]; riskNotes?: string[]; } function ArchitectureView({ arch }: { arch: Architecture }) { const Section = ({ title, children }: { title: string; children: React.ReactNode }) => (
{title}
{children}
); const Card = ({ children }: { children: React.ReactNode }) => (
{children}
); const Tag = ({ label }: { label: string }) => ( {label} ); return (
{arch.summary && (
{arch.summary}
)} {(arch.apps ?? []).length > 0 && (
{arch.apps!.map(a => (
{a.name} {a.type}
{a.description}
{a.tech?.map(t => )} {a.screens && a.screens.length > 0 && (
Screens: {a.screens.join(", ")}
)}
))}
)} {(arch.packages ?? []).length > 0 && (
{arch.packages!.map(p => (
{p.name} {p.description}
))}
)} {(arch.infrastructure ?? []).length > 0 && (
{arch.infrastructure!.map(i => (
{i.name}
{i.reason}
))}
)} {(arch.integrations ?? []).length > 0 && (
{arch.integrations!.map(i => (
{i.name} {i.required && required}
{i.notes &&
{i.notes}
}
))}
)} {(arch.riskNotes ?? []).length > 0 && (
{arch.riskNotes!.map((r, i) => (
{r}
))}
)}
); } export default function PRDPage() { const params = useParams(); const projectId = params.projectId as string; const [prd, setPrd] = useState(null); const [architecture, setArchitecture] = useState(null); const [savedPhases, setSavedPhases] = useState([]); const [loading, setLoading] = useState(true); const [activeTab, setActiveTab] = useState<"prd" | "architecture">("prd"); useEffect(() => { Promise.all([ fetch(`/api/projects/${projectId}`).then(r => r.json()).catch(() => ({})), fetch(`/api/projects/${projectId}/save-phase`).then(r => r.json()).catch(() => ({ phases: [] })), ]).then(([projectData, phaseData]) => { setPrd(projectData?.project?.prd ?? null); setArchitecture(projectData?.project?.architecture ?? null); setSavedPhases(phaseData?.phases ?? []); setLoading(false); }); }, [projectId]); const phaseMap = new Map(savedPhases.map(p => [p.phase, p])); const savedPhaseIds = new Set(savedPhases.map(p => p.phase)); const sections = PRD_SECTIONS.map(s => ({ ...s, savedPhase: s.phaseId ? phaseMap.get(s.phaseId) ?? null : null, isDone: s.phaseId ? savedPhaseIds.has(s.phaseId) : false, })); const doneCount = sections.filter(s => s.isDone).length; const totalPct = Math.round((doneCount / sections.length) * 100); if (loading) { return (
Loading…
); } const tabs = [ { id: "prd" as const, label: "PRD", available: true }, { id: "architecture" as const, label: "Architecture", available: !!architecture }, ]; return (
{/* Tab bar — only when at least one doc exists */} {(prd || architecture) && (
{tabs.map(t => { const isActive = activeTab === t.id; return ( ); })}
)} {/* Architecture tab */} {activeTab === "architecture" && architecture && ( )} {/* PRD tab — finalized */} {activeTab === "prd" && prd && (

Product Requirements

PRD complete
{prd}
)} {/* PRD tab — section progress (no finalized PRD yet) */} {activeTab === "prd" && !prd && ( /* ── Section progress view ── */
{/* Progress bar */}
{totalPct}%
{doneCount}/{sections.length} sections
{/* Sections */} {sections.map((s, i) => (
{/* Status icon */}
{s.isDone ? "✓" : "○"}
{s.label} {s.isDone && s.savedPhase && ( saved )} {!s.isDone && !s.phaseId && ( generated )}
{/* Expandable phase data */} {s.isDone && s.savedPhase && ( )} {/* Pending hint */} {!s.isDone && (
{s.phaseId ? `Complete the ${s.savedPhase ? s.savedPhase.title : "discovery"} phase in Atlas` : "Will be generated when PRD is finalized"}
)}
))} {doneCount === 0 && (

Continue chatting with Atlas — saved phases will appear here automatically.

)}
)}
); }