"use client"; import { useEffect, useState } from "react"; import { useRouter, useParams } from "next/navigation"; interface ArchRow { category: string; item: string; status: "found" | "partial" | "missing"; detail?: string; } interface AnalysisResult { summary: string; rows: ArchRow[]; suggestedSurfaces: string[]; } interface CodeImportMainProps { projectId: string; projectName: string; sourceData?: { repoUrl?: string }; analysisResult?: AnalysisResult; creationStage?: string; } type Stage = "input" | "cloning" | "mapping" | "surfaces"; const STATUS_COLORS = { found: { bg: "#f0fdf4", text: "#15803d", label: "Found" }, partial: { bg: "#fffbeb", text: "#b45309", label: "Partial" }, missing: { bg: "#fff1f2", text: "#be123c", label: "Missing" }, }; const CATEGORY_ORDER = [ "Tech Stack", "Infrastructure", "Database", "API Surface", "Frontend", "Auth", "Third-party", "Missing / Gaps", ]; const PROGRESS_STEPS = [ { key: "cloning", label: "Cloning repository" }, { key: "reading", label: "Reading key files" }, { key: "analyzing", label: "Mapping architecture" }, { key: "done", label: "Analysis complete" }, ]; export function CodeImportMain({ projectId, projectName, sourceData, analysisResult: initialResult, creationStage, }: CodeImportMainProps) { const router = useRouter(); const params = useParams(); const workspace = params?.workspace as string; const hasRepo = !!sourceData?.repoUrl; const getInitialStage = (): Stage => { if (initialResult) return "mapping"; if (creationStage === "surfaces") return "surfaces"; if (hasRepo) return "cloning"; return "input"; }; const [stage, setStage] = useState(getInitialStage); const [repoUrl, setRepoUrl] = useState(sourceData?.repoUrl ?? ""); const [progressStep, setProgressStep] = useState("cloning"); const [error, setError] = useState(null); const [result, setResult] = useState(initialResult ?? null); const [confirmedSurfaces, setConfirmedSurfaces] = useState( initialResult?.suggestedSurfaces ?? [] ); // Kick off analysis when in cloning stage useEffect(() => { if (stage !== "cloning") return; startAnalysis(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [stage]); // Poll for analysis status when cloning useEffect(() => { if (stage !== "cloning") return; const interval = setInterval(async () => { try { const res = await fetch(`/api/projects/${projectId}/analysis-status`); const data = await res.json(); setProgressStep(data.stage ?? "cloning"); if (data.stage === "done" && data.analysisResult) { setResult(data.analysisResult); setConfirmedSurfaces(data.analysisResult.suggestedSurfaces ?? []); clearInterval(interval); setStage("mapping"); } } catch { /* keep polling */ } }, 2500); return () => clearInterval(interval); // eslint-disable-next-line react-hooks/exhaustive-deps }, [stage]); const startAnalysis = async () => { setError(null); try { await fetch(`/api/projects/${projectId}/analyze-repo`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ repoUrl }), }); } catch (e) { setError(e instanceof Error ? e.message : "Failed to start analysis"); setStage("input"); } }; const handleConfirmSurfaces = async () => { try { await fetch(`/api/projects/${projectId}/design-surfaces`, { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ surfaces: confirmedSurfaces }), }); router.push(`/${workspace}/project/${projectId}/design`); } catch { /* navigate anyway */ } }; const toggleSurface = (s: string) => { setConfirmedSurfaces(prev => prev.includes(s) ? prev.filter(x => x !== s) : [...prev, s] ); }; // ── Stage: input ────────────────────────────────────────────────────────── if (stage === "input") { const isValid = repoUrl.trim().startsWith("http"); return (

Import your repository

{projectName} — paste a clone URL to map your existing stack.

{error && (
{error}
)} setRepoUrl(e.target.value)} placeholder="https://github.com/yourorg/your-repo" style={{ width: "100%", padding: "12px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box", }} onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")} onBlur={e => (e.currentTarget.style.borderColor = "#e0dcd4")} onKeyDown={e => { if (e.key === "Enter" && isValid) setStage("cloning"); }} autoFocus />
Atlas will clone and map your stack — tech, database, auth, APIs, and what's missing for a complete go-to-market build.
); } // ── Stage: cloning ──────────────────────────────────────────────────────── if (stage === "cloning") { const currentIdx = PROGRESS_STEPS.findIndex(s => s.key === progressStep); return (

Mapping your codebase

{repoUrl || sourceData?.repoUrl || "Repository"}

{PROGRESS_STEPS.map((step, i) => { const done = i < currentIdx; const active = i === currentIdx; return (
{done ? "✓" : active ? : ""}
{step.label}
); })}
); } // ── Stage: mapping ──────────────────────────────────────────────────────── if (stage === "mapping" && result) { const byCategory: Record = {}; for (const row of result.rows) { const cat = row.category || "Other"; if (!byCategory[cat]) byCategory[cat] = []; byCategory[cat].push(row); } const categories = [ ...CATEGORY_ORDER.filter(c => byCategory[c]), ...Object.keys(byCategory).filter(c => !CATEGORY_ORDER.includes(c)), ]; return (

Architecture map

{projectName} — {result.summary}

{categories.map((cat, catIdx) => (
{catIdx > 0 &&
}
{cat}
{byCategory[cat].map((row, i) => { const sc = STATUS_COLORS[row.status]; return (
{row.item}
{row.detail &&
{row.detail}
}
{sc.label}
); })}
))}
); } // ── Stage: surfaces ─────────────────────────────────────────────────────── const SURFACE_OPTIONS = [ { id: "marketing", label: "Marketing Site", icon: "◎", desc: "Landing page, pricing, blog" }, { id: "web-app", label: "Web App", icon: "⬡", desc: "Core SaaS product with auth" }, { id: "admin", label: "Admin Panel", icon: "◫", desc: "Ops dashboard, content management" }, { id: "api", label: "API Layer", icon: "⌁", desc: "REST/GraphQL endpoints" }, ]; return (

What should Atlas build?

Based on the gap analysis, Atlas suggests the surfaces below. Confirm or adjust.

{SURFACE_OPTIONS.map(s => { const selected = confirmedSurfaces.includes(s.id); return ( ); })}
); }