From 82736fd051dceda0831fea10ec659cf2b66c3ffd Mon Sep 17 00:00:00 2001 From: Scrum4Me Agent <30029041+madhura68@users.noreply.github.com> Date: Tue, 5 May 2026 17:46:04 +0200 Subject: [PATCH] =?UTF-8?q?feat(ST-0vtnydpi):=20Chat=20&=20Timeline=20tab?= =?UTF-8?q?=20=E2=80=94=20userQuestion=20rendering=20+=20UserChatInput?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IdeaTimeline: merge user_question entries into timeline (MessageCircle icon, pending/answered states); show UserChatInput below ol when planMd present - UserChatInput: Textarea + submit button calling createUserQuestionAction, router.refresh() on success, sonner toast for errors - IdeaDetailLayout: rename tab label to 'Chat & Timeline'; pass userQuestions, planMd, ideaId props to IdeaTimeline; export IdeaUserQuestionDto interface Co-Authored-By: Claude Sonnet 4.6 --- components/ideas/idea-detail-layout.tsx | 12 ++- components/ideas/idea-timeline.tsx | 104 +++++++++++++++++++++++- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/components/ideas/idea-detail-layout.tsx b/components/ideas/idea-detail-layout.tsx index a10c968..f977779 100644 --- a/components/ideas/idea-detail-layout.tsx +++ b/components/ideas/idea-detail-layout.tsx @@ -44,7 +44,7 @@ const TABS: { key: TabKey; label: string }[] = [ { key: 'idee', label: 'Idee' }, { key: 'grill', label: 'Grill' }, { key: 'plan', label: 'Plan' }, - { key: 'timeline', label: 'Timeline' }, + { key: 'timeline', label: 'Chat & Timeline' }, ] interface IdeaLog { @@ -221,7 +221,15 @@ export function IdeaDetailLayout({ ideaId={idea.id} /> )} - {tab === 'timeline' && } + {tab === 'timeline' && ( + + )} ) } diff --git a/components/ideas/idea-timeline.tsx b/components/ideas/idea-timeline.tsx index 133e176..42f52a7 100644 --- a/components/ideas/idea-timeline.tsx +++ b/components/ideas/idea-timeline.tsx @@ -15,6 +15,7 @@ import { FileText, HelpCircle, Lightbulb, + MessageCircle, RefreshCw, StickyNote, Wrench, @@ -24,6 +25,7 @@ import { toast } from 'sonner' import { Button } from '@/components/ui/button' import { Textarea } from '@/components/ui/textarea' import { answerQuestion } from '@/actions/questions' +import { createUserQuestionAction } from '@/actions/user-questions' import type { IdeaLogType } from '@prisma/client' @@ -45,9 +47,20 @@ export interface TimelineQuestion { expires_at: string } +export interface TimelineUserQuestion { + id: string + question: string + answer: string | null + status: 'pending' | 'answered' + created_at: string +} + interface Props { logs: TimelineLog[] questions: TimelineQuestion[] + userQuestions: TimelineUserQuestion[] + planMd: string | null + ideaId: string } const LOG_ICON: Record = { @@ -75,7 +88,7 @@ const QUESTION_STATUS_LABEL: Record = { expired: 'Verlopen', } -export function IdeaTimeline({ logs, questions }: Props) { +export function IdeaTimeline({ logs, questions, userQuestions, planMd, ideaId }: Props) { const merged = [ ...logs.map((l) => ({ kind: 'log' as const, @@ -87,9 +100,14 @@ export function IdeaTimeline({ logs, questions }: Props) { created_at: q.created_at, data: q, })), + ...userQuestions.map((uq) => ({ + kind: 'user_question' as const, + created_at: uq.created_at, + data: uq, + })), ].sort((a, b) => (a.created_at < b.created_at ? 1 : -1)) - if (merged.length === 0) { + if (merged.length === 0 && !planMd) { return (

Nog geen activiteit op dit idee. @@ -98,6 +116,7 @@ export function IdeaTimeline({ logs, questions }: Props) { } return ( +

    {merged.map((entry, i) => { // Expliciete locale + format om SSR/CSR hydration-mismatch te voorkomen @@ -138,6 +157,37 @@ export function IdeaTimeline({ logs, questions }: Props) { ) } + if (entry.kind === 'user_question') { + const uq = entry.data + return ( +
  1. + + + +
    +
    + Jouw vraag + · + +
    +

    {uq.question}

    + {uq.status === 'pending' ? ( +

    + Wacht op antwoord van Claude... +

    + ) : uq.answer ? ( +
    + + Claude + + {uq.answer} +
    + ) : null} +
    +
  2. + ) + } + const q = entry.data return (
  3. @@ -179,6 +229,12 @@ export function IdeaTimeline({ logs, questions }: Props) { ) })}
+ {planMd && ( +
+ +
+ )} +
) } @@ -269,3 +325,47 @@ function AnswerForm({ ) } + +// --------------------------------------------------------------------------- +// UserChatInput — stel een vraag aan Claude over het plan van dit idee. + +function UserChatInput({ ideaId }: { ideaId: string }) { + const router = useRouter() + const [question, setQuestion] = useState('') + const [isPending, startTransition] = useTransition() + + function submit() { + const trimmed = question.trim() + if (!trimmed) return + startTransition(async () => { + const res = await createUserQuestionAction(ideaId, trimmed) + if ('success' in res && res.success) { + setQuestion('') + toast.success('Vraag verstuurd — Claude antwoordt zodra mogelijk.') + router.refresh() + } else if ('error' in res) { + toast.error(res.error) + } + }) + } + + return ( +
+

+ Stel een vraag aan Claude +

+