feat(intake): brief confirmation before submission
This commit is contained in:
parent
04e78aef6d
commit
58be48a4b0
1 changed files with 126 additions and 7 deletions
|
|
@ -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<SizeBand, string> = {
|
||||
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<string | null>(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 (
|
||||
<section className="space-y-4 rounded-[var(--radius-tile)] border border-border-subtle bg-surface p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h2 className="text-base font-semibold text-text-primary">{brief.title}</h2>
|
||||
<p className="mt-1 text-sm text-text-secondary">{brief.summary}</p>
|
||||
</div>
|
||||
<Pill tone="neutral">{BAND_LABEL[brief.sizeBand]}</Pill>
|
||||
</div>
|
||||
|
||||
{brief.degraded && (
|
||||
<p className="text-xs text-text-muted">
|
||||
Written from your answers directly.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{brief.subtasks.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wide text-text-secondary">
|
||||
Steps
|
||||
</h3>
|
||||
<ul className="space-y-1">
|
||||
{brief.subtasks.map((task, index) => (
|
||||
<li key={index} className="flex gap-2 text-sm text-text-secondary">
|
||||
<span aria-hidden className="text-text-muted">
|
||||
{index + 1}.
|
||||
</span>
|
||||
{task}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{brief.openQuestions.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-wide text-text-secondary">
|
||||
Still to confirm
|
||||
</h3>
|
||||
<ul className="space-y-1">
|
||||
{brief.openQuestions.map((question, index) => (
|
||||
<li key={index} className="text-sm text-text-muted">
|
||||
{question}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-3 border-t border-border-subtle pt-3">
|
||||
<button
|
||||
type="button"
|
||||
disabled={sending}
|
||||
onClick={submit}
|
||||
className="inline-flex items-center gap-1.5 rounded-lg bg-brand px-3 py-1.5 text-sm font-medium text-brand-fg hover:bg-brand-hover disabled:opacity-50"
|
||||
>
|
||||
<Send size={14} strokeWidth={2} />
|
||||
{sending ? "Sending…" : "Send this to Dave"}
|
||||
</button>
|
||||
{error && (
|
||||
<span role="alert" className="text-xs text-accent">
|
||||
{error}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="text-[11px] text-text-muted">
|
||||
This goes to the developer to review. He will confirm what happens next.
|
||||
</p>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue