[9ef46be7] feat(prompter): implement Prompter page, nav entry, chat UI, and task creation wiring (#78) (#79)

- Add Task Assistant nav entry (Sparkles icon) to sidebar between Kanban and Projects
- Create lib/api/prompter.ts with createSession, sendMessage, getDraft API functions
- Create hooks/use-prompter.ts with 6-state machine (empty→chatting→draft_preview→review_modal→launching→success)
- Create ChatMessages with auto-scroll, user/assistant/error rendering, inline DraftProposalCard
- Create ChatComposer with Enter-to-send and Shift+Enter for newline
- Create DraftProposalCard with title, description, acceptance criteria, metadata badges, Keep Chatting/Review & Confirm actions
- Create ConfirmDialog (Radix Dialog, no form element) with MarkdownEditor, AcceptanceCriteriaEditor, metadata selects, warning banner, disabled Confirm & Launch until valid
- Create SuccessCard with task title, team, View Task link, Start Another button
- Create /prompter route page composing all components via usePrompter hook
- TypeScript and ESLint pass with zero errors

Co-authored-by: Frontend Developer 2 <fe-dev-2@agents.roboco.dev>
This commit is contained in:
Renzo F
2026-06-07 22:38:36 +02:00
committed by GitHub
co-authored by Frontend Developer 2
parent 85ffec86b4
commit 5a99140a55
10 changed files with 974 additions and 0 deletions
@@ -0,0 +1,93 @@
"use client";
import { Sparkles } from "lucide-react";
import { usePrompter } from "@/hooks/use-prompter";
import {
ChatMessages,
ChatComposer,
ConfirmDialog,
SuccessCard,
} from "@/components/prompter";
export default function PrompterPage() {
const {
state,
messages,
isSending,
editableDraft,
createdTaskId,
createdTaskTitle,
createdTaskTeam,
send,
openReview,
closeReview,
keepChatting,
updateDraft,
isValidForLaunch,
launchTask,
startAnother,
isLaunching,
} = usePrompter();
const isComposerDisabled =
state === "launching" || state === "success";
return (
<div className="flex h-full flex-col">
{/* Page header */}
<div className="flex items-center gap-3 border-b px-6 py-4">
<Sparkles className="h-5 w-5 text-primary" />
<div>
<h1 className="text-lg font-semibold">Task Assistant</h1>
<p className="text-xs text-muted-foreground">
Describe your idea and I&apos;ll help you create a structured task
</p>
</div>
</div>
{/* Chat area */}
<div className="flex flex-1 flex-col overflow-hidden">
{/* Success overlay in chat area */}
{state === "success" &&
createdTaskId &&
createdTaskTitle &&
createdTaskTeam ? (
<div className="flex flex-1 flex-col items-center justify-center px-8 py-8">
<div className="w-full max-w-md">
<SuccessCard
taskId={createdTaskId}
taskTitle={createdTaskTitle}
team={createdTaskTeam}
onStartAnother={startAnother}
/>
</div>
</div>
) : (
<ChatMessages
messages={messages}
onOpenReview={openReview}
onKeepChatting={keepChatting}
/>
)}
{/* Composer */}
<ChatComposer
onSend={send}
disabled={isComposerDisabled}
isSending={isSending}
/>
</div>
{/* Confirmation dialog (portal) */}
<ConfirmDialog
open={state === "review_modal" || state === "launching"}
draft={editableDraft}
onClose={closeReview}
onUpdate={updateDraft}
onConfirm={launchTask}
isLaunching={isLaunching}
isValid={isValidForLaunch()}
/>
</div>
);
}