From 58be48a4b083b98f76b1b70a79c1ba2b0ec81854 Mon Sep 17 00:00:00 2001 From: Dave Date: Wed, 16 Sep 2026 18:04:53 +0200 Subject: [PATCH] feat(intake): brief confirmation before submission --- src/components/intake/brief-preview.tsx | 133 ++++++++++++++++++++++-- 1 file changed, 126 insertions(+), 7 deletions(-) diff --git a/src/components/intake/brief-preview.tsx b/src/components/intake/brief-preview.tsx index 500079f..cd5c82e 100644 --- a/src/components/intake/brief-preview.tsx +++ b/src/components/intake/brief-preview.tsx @@ -1,20 +1,139 @@ +"use client"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { Send } from "lucide-react"; + +import { Pill } from "@/components/ui/pill"; import type { Brief } from "@/lib/intake/brief"; import type { SizeBand } from "@/lib/intake/size"; import type { Turn } from "@/lib/intake/turn"; +const BAND_LABEL: Record = { + small: "Looks small", + medium: "Looks medium", + large: "Looks large", +}; + /** - * Stub. Replaced by Phase 4b when the brief-preview UI lands. + * The brief, shown for confirmation before anything is created. * - * The wizard imports this so Task 6 can build standalone; Plan 4b replaces - * this file with the real preview that submits the brief to Plan 4b's - * server action. + * The size band is presented as a first impression and carries no time. The + * spec forbids rendering it next to a date or duration — a band beside a date + * reads as an estimate however it is labelled. */ -export function BriefPreview(_: { +export function BriefPreview({ + brief, + turns, + projectId, + clientSlug, + projectSlug, +}: { brief: Brief & { sizeBand: SizeBand }; turns: Turn[]; projectId: string; clientSlug: string; projectSlug: string; -}): null { - return null; +}) { + const router = useRouter(); + const [sending, setSending] = useState(false); + const [error, setError] = useState(null); + + async function submit() { + setSending(true); + setError(null); + + const response = await fetch("/api/client/intake", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + project: projectId, + brief, + transcript: turns, + sizeBand: brief.sizeBand, + }), + }); + + setSending(false); + + if (!response.ok) { + setError("Could not send that. Please try again."); + return; + } + + router.push(`/p/${clientSlug}/${projectSlug}`); + router.refresh(); + } + + return ( +
+
+
+

{brief.title}

+

{brief.summary}

+
+ {BAND_LABEL[brief.sizeBand]} +
+ + {brief.degraded && ( +

+ Written from your answers directly. +

+ )} + + {brief.subtasks.length > 0 && ( +
+

+ Steps +

+
    + {brief.subtasks.map((task, index) => ( +
  • + + {index + 1}. + + {task} +
  • + ))} +
+
+ )} + + {brief.openQuestions.length > 0 && ( +
+

+ Still to confirm +

+
    + {brief.openQuestions.map((question, index) => ( +
  • + {question} +
  • + ))} +
+
+ )} + +
+ + {error && ( + + {error} + + )} +
+ +

+ This goes to the developer to review. He will confirm what happens next. +

+
+ ); }