import { useEffect, useState } from "react"; import type { FeedbackDataSharingPreference, FeedbackVoteValue } from "@paperclipai/shared"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { ThumbsDown, ThumbsUp } from "lucide-react"; import { cn } from "../lib/utils"; export function OutputFeedbackButtons({ activeVote, disabled = false, sharingPreference = "prompt", termsUrl = null, onVote, rightSlot, }: { activeVote?: FeedbackVoteValue | null; disabled?: boolean; sharingPreference?: FeedbackDataSharingPreference; termsUrl?: string | null; onVote: (vote: FeedbackVoteValue, options?: { allowSharing?: boolean; reason?: string }) => Promise; rightSlot?: React.ReactNode; }) { const [pendingVote, setPendingVote] = useState<{ vote: FeedbackVoteValue; reason?: string; keepReasonPromptOpen?: boolean; } | null>(null); const [isSaving, setIsSaving] = useState(false); const [downvoteReason, setDownvoteReason] = useState(""); const [collectingDownvoteReason, setCollectingDownvoteReason] = useState(false); const [downvoteAllowSharing, setDownvoteAllowSharing] = useState(undefined); const [optimisticVote, setOptimisticVote] = useState(null); const visibleVote = optimisticVote ?? activeVote ?? null; useEffect(() => { if (optimisticVote && activeVote === optimisticVote) { setOptimisticVote(null); } }, [activeVote, optimisticVote]); async function submitVote( vote: FeedbackVoteValue, options?: { allowSharing?: boolean; reason?: string }, behavior?: { keepReasonPromptOpen?: boolean }, ) { setIsSaving(true); try { await onVote(vote, options); setPendingVote(null); if (!behavior?.keepReasonPromptOpen) { setCollectingDownvoteReason(false); setDownvoteReason(""); setDownvoteAllowSharing(undefined); } } catch (error) { setOptimisticVote(null); throw error; } finally { setIsSaving(false); } } function beginVote( vote: FeedbackVoteValue, reason?: string, behavior?: { keepReasonPromptOpen?: boolean }, ) { if (sharingPreference === "prompt") { setPendingVote({ vote, ...(reason ? { reason } : {}), ...(behavior?.keepReasonPromptOpen ? { keepReasonPromptOpen: true } : {}), }); return; } const allowSharing = sharingPreference === "allowed"; if (vote === "down") { setDownvoteAllowSharing(allowSharing); } void submitVote( vote, { ...(allowSharing ? { allowSharing: true } : {}), ...(reason ? { reason } : {}), }, behavior, ); } function handleVote(vote: FeedbackVoteValue) { setOptimisticVote(vote); if (vote === "down") { setCollectingDownvoteReason(true); setDownvoteReason(""); setDownvoteAllowSharing(undefined); void beginVote("down", undefined, { keepReasonPromptOpen: true }); return; } void beginVote(vote); } return ( <>
{rightSlot ?
{rightSlot}
: null}
{collectingDownvoteReason ? (
What could have been better?