From 00146a63dc30df159f560274cab509160ac2b380 Mon Sep 17 00:00:00 2001 From: mawkone Date: Tue, 19 May 2026 19:10:17 -0700 Subject: [PATCH] fix(ui): combine PRD tabs and remove redundant headers --- .../project/[projectId]/(home)/plan/page.tsx | 389 ++++++------------ 1 file changed, 119 insertions(+), 270 deletions(-) diff --git a/vibn-frontend/app/[workspace]/project/[projectId]/(home)/plan/page.tsx b/vibn-frontend/app/[workspace]/project/[projectId]/(home)/plan/page.tsx index 096ded1..b913753 100644 --- a/vibn-frontend/app/[workspace]/project/[projectId]/(home)/plan/page.tsx +++ b/vibn-frontend/app/[workspace]/project/[projectId]/(home)/plan/page.tsx @@ -14,7 +14,7 @@ type Plan = { decisions: Array<{ id: string; title: string; choice: string; why?: string }>; }; -type Tab = "objective" | "stories" | "features" | "architecture"; +type Tab = "objective" | "prd"; // Shared Theme Variables const INK = { @@ -78,9 +78,7 @@ export default function PlanPageV2() { paddingBottom: 0 }}> setActiveTab("objective")} icon={} label="Objective" /> - setActiveTab("stories")} icon={} label="User Stories" /> - setActiveTab("features")} icon={} label="Features" /> - setActiveTab("architecture")} icon={} label="Architecture" /> + setActiveTab("prd")} icon={} label="PRD" /> @@ -93,16 +91,8 @@ export default function PlanPageV2() { -
- -
- -
- -
- -
- +
+
@@ -179,237 +169,133 @@ function ObjectiveView({ plan, projectId, onChange }: { plan: Plan, projectId: s } // ────────────────────────────────────────────────── -// 2. USER STORIES VIEW +// 2. PRD VIEW // ────────────────────────────────────────────────── -// MOCK DATA: In production, this would be parsed from the AI's spec markdown or a JSON array in the database. -const MOCK_JOURNEYS = [ - { - id: "j1", - name: "User Dashboard", - persona: "Admin", - goal: "Provides a centralized view of all active jobs, metrics, and pending approvals.", - stories: [ - { - id: "s1", - title: "View active jobs", - description: "As an Admin, I want to see a map of today's jobs so I know where my team is.", - criteria: [ - { text: "Map centers on user's GPS location.", done: false }, - { text: "Clicking a pin opens a detail modal.", done: true } - ] - }, - { - id: "s2", - title: "Approve pending payouts", - description: "As an Admin, I want to review completed jobs and click 'Approve' to trigger Stripe payouts.", - criteria: [ - { text: "List displays jobs with 'completed' status.", done: false }, - { text: "Approve button triggers success toast.", done: false } - ] - } - ] - }, - { - id: "j2", - name: "Authentication & Onboarding", - persona: "Customer", - goal: "Allows a new user to securely create an account and fill out their initial profile.", - stories: [ - { - id: "s3", - title: "Sign up via Email", - description: "As a Customer, I want to sign up with my email and a password so my data is secure.", - criteria: [ - { text: "Form validates email format.", done: false }, - { text: "Password must be > 8 characters.", done: false } - ] - } - ] - } -]; - -function UserStoriesView({ plan, projectId, onChange }: { plan: Plan, projectId: string, onChange: (p: Plan) => void }) { - const [activeJourneyId, setActiveJourneyId] = useState(MOCK_JOURNEYS[0].id); - const activeJourney = MOCK_JOURNEYS.find(j => j.id === activeJourneyId); +function PRDView({ plan, projectId, onChange }: { plan: Plan, projectId: string, onChange: (p: Plan) => void }) { + const [activeDoc, setActiveDoc] = useState("spec"); return ( -
- - -
- - {/* LEFT COLUMN: The Index */} -
- {MOCK_JOURNEYS.map(j => { - const isActive = j.id === activeJourneyId; - return ( - - ); - })} - - -
- - {/* RIGHT COLUMN: The Details */} -
- {activeJourney ? ( - <> -
-
-

- {activeJourney.name} -

- - {activeJourney.persona} - -
-

- Goal: {activeJourney.goal} -

-
- -
- {activeJourney.stories.map((story, i) => ( -
-
- US{i + 1} -

{story.title}

-
-

- "{story.description}" -

- -
-
- Acceptance Criteria -
-
    - {story.criteria.map((c, idx) => ( -
  • -
    - {c.done && } -
    - - {c.text} - -
  • - ))} -
-
-
- ))} -
- - ) : ( -
Select a journey to view stories
- )} -
- -
-
- ); -} - -// ────────────────────────────────────────────────── -// 3. FEATURES VIEW (Replaces Tasks) -// ────────────────────────────────────────────────── -function FeaturesView({ plan, projectId }: { plan: Plan, projectId: string, onChange: (p: Plan) => void }) { - const features = plan.tasks.filter(t => t.status !== "done"); // Simplification for prototype - - return ( -
-
-
-

Features Queue

-

High-level capabilities to be delegated to the AI.

-
- + +
-
- {features.length > 0 ? features.map(f => ( -
-
-
{f.title}
- {f.description &&
{f.description}
} + {/* RIGHT COLUMN: The Document Content */} +
+ {activeDoc === "spec" && ( +
+

Product Specification

+

The Product Specification document outlines the core user journeys, functional requirements, and acceptance criteria.

+
+
+ +

Spec is empty.

+

Use Architect mode to generate the Product Spec.

-
- )) : ( -
- No features defined yet. Use Architect mode to brainstorm. + )} + + {activeDoc === "plan" && ( +
+

Technical Architecture

+

The Technical Architecture plan defines the tech stack, database models, and API interfaces required to support the product spec.

+
+
+ +

Plan is empty.

+

Use Architect mode to define the technical approach.

+
+
+ )} + + {activeDoc === "tasks" && ( +
+
+

Execution Plan

+ +
+

The atomic, dependency-ordered tasks the AI will execute to build the application.

+
+
+ +

No tasks queued.

+

Generate the task breakdown from the Product Spec.

+
)}
@@ -417,43 +303,6 @@ function FeaturesView({ plan, projectId }: { plan: Plan, projectId: string, onCh ); } -// ────────────────────────────────────────────────── -// 4. ARCHITECTURE VIEW -// ────────────────────────────────────────────────── -function ArchitectureView({ plan, projectId }: { plan: Plan, projectId: string, onChange: (p: Plan) => void }) { - return ( -
-
-

Technical Architecture

-

Decisions made regarding the tech stack, database, and integrations.

-
- -
- {plan.decisions.length > 0 ? plan.decisions.map(d => ( -
-
- {d.title} -
-
- {d.choice} -
- {d.why && ( -
- {d.why} -
- )} -
- )) : ( -
- No technical decisions logged yet. -
- )} -
-
- ); -} - - // ── Shared UI Components ────────────────────────────────────────────────────── function TabButton({ active, onClick, icon, label }: { active: boolean, onClick: () => void, icon: React.ReactNode, label: string }) {