import { type JSX, Switch, Match, For, Show, createSignal } from 'solid-js'; import { cn } from '../utils/cn'; import { ThumbsUp, ThumbsDown, X, Check } from 'lucide-solid'; import { Button } from '../ui/button'; import { Textarea } from '../ui/textarea'; export type FeedbackValue = 'helpful' | 'not-helpful'; /** Payload of the optional detail form (phase 2). */ export interface FeedbackDetail { value: FeedbackValue; /** The selected category chip, if any. */ category?: string; /** The free-text comment, if entered. */ comment?: string; } export interface FeedbackBarProps { class?: string; /** Prompt shown in the initial "ask" state. */ title?: string; /** Optional leading icon shown before the title. */ icon?: JSX.Element; /** When set, a not-helpful vote opens an optional detail form before the * thank-you confirmation. Off → a vote goes straight to thanks. */ collectDetail?: boolean; /** Optional category chips offered in the detail form. */ categories?: string[]; /** Heading for the detail form. */ detailTitle?: string; /** Placeholder for the detail comment box. */ detailPlaceholder?: string; /** Submit button label in the detail form. */ submitLabel?: string; /** Confirmation copy shown after a vote/submit. */ thanksMessage?: string; /** Fired immediately when a rating button is clicked (the vote is recorded * even if the user never fills in the detail form). */ onFeedback?: (value: FeedbackValue) => void; /** Fired when the optional detail form is submitted. */ onSubmitDetail?: (detail: FeedbackDetail) => void; /** Fired when the bar is dismissed via the close (X) button. */ onClose?: () => void; } type Phase = 'ask' | 'detail' | 'thanks'; /** * An inline thumbs up/down feedback bar that owns its own flow: it asks, then * (optionally, on a not-helpful vote) collects a category + comment, then * confirms with a thank-you — all in place, the way ChatGPT/Claude do it. The * vote fires `onFeedback` immediately; the optional detail fires * `onSubmitDetail`; `onClose` dismisses the bar. */ export function FeedbackBar(props: FeedbackBarProps) { const [phase, setPhase] = createSignal('ask'); const [vote, setVote] = createSignal(); const [category, setCategory] = createSignal(); const [comment, setComment] = createSignal(''); const rate = (value: FeedbackValue) => { setVote(value); props.onFeedback?.(value); setPhase(value === 'not-helpful' && props.collectDetail ? 'detail' : 'thanks'); }; const submitDetail = () => { props.onSubmitDetail?.({ value: vote()!, category: category(), comment: comment() || undefined }); setPhase('thanks'); }; const iconBtn = 'text-muted-foreground hover:text-foreground flex size-8 items-center justify-center rounded-md transition-colors'; return (
{/* ── Ask ── */}
{props.icon} {props.title}
{/* ── Detail (phase 2, not-helpful only) ── */}
{props.detailTitle ?? 'What went wrong?'}
{(c) => ( )}