mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-06 20:37:44 +00:00
Co-authored-by: Bereket Engida <86073083+Bekacru@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
171 lines
4.3 KiB
TypeScript
171 lines
4.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Check, Copy, ThumbsDown, ThumbsUp } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
import {
|
|
submitFeedbackToInkeep,
|
|
logEventToInkeep,
|
|
} from "@/lib/inkeep-analytics";
|
|
|
|
interface MessageFeedbackProps {
|
|
messageId: string;
|
|
userMessageId?: string;
|
|
content: string;
|
|
className?: string;
|
|
}
|
|
|
|
export function MessageFeedback({
|
|
messageId,
|
|
userMessageId,
|
|
content,
|
|
className,
|
|
}: MessageFeedbackProps) {
|
|
const [feedback, setFeedback] = useState<"positive" | "negative" | null>(
|
|
null,
|
|
);
|
|
const [copied, setCopied] = useState(false);
|
|
const [isSubmittingFeedback, setIsSubmittingFeedback] = useState(false);
|
|
const [showSuccessCheckmark, setShowSuccessCheckmark] = useState<
|
|
"positive" | "negative" | null
|
|
>(null);
|
|
|
|
const handleFeedback = async (type: "positive" | "negative") => {
|
|
if (isSubmittingFeedback || feedback === type) return;
|
|
|
|
const feedbackMessageId = userMessageId || messageId;
|
|
|
|
setIsSubmittingFeedback(true);
|
|
|
|
try {
|
|
await submitFeedbackToInkeep(feedbackMessageId, type, [
|
|
{
|
|
label:
|
|
type === "positive" ? "helpful_response" : "unhelpful_response",
|
|
details:
|
|
type === "positive"
|
|
? "The response was helpful"
|
|
: "The response was not helpful",
|
|
},
|
|
]);
|
|
|
|
setFeedback(type);
|
|
setShowSuccessCheckmark(type);
|
|
|
|
setTimeout(() => {
|
|
setShowSuccessCheckmark(null);
|
|
}, 1000);
|
|
} catch (error) {
|
|
} finally {
|
|
setIsSubmittingFeedback(false);
|
|
}
|
|
};
|
|
|
|
const handleCopy = async () => {
|
|
if (copied) return;
|
|
|
|
const eventMessageId = userMessageId || messageId;
|
|
|
|
try {
|
|
await navigator.clipboard.writeText(content);
|
|
setCopied(true);
|
|
|
|
await logEventToInkeep("message:copied", "message", eventMessageId);
|
|
|
|
setTimeout(() => setCopied(false), 2000);
|
|
} catch (error) {
|
|
// Silently handle error
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"flex items-center gap-1 mt-3 pt-2 border-t border-fd-border/30",
|
|
className,
|
|
)}
|
|
>
|
|
<button
|
|
type="button"
|
|
onClick={() => handleFeedback("positive")}
|
|
disabled={isSubmittingFeedback}
|
|
className={cn(
|
|
buttonVariants({
|
|
size: "icon-sm",
|
|
color: feedback === "positive" ? "primary" : "ghost",
|
|
className: cn(
|
|
"h-7 w-7 transition-colors",
|
|
isSubmittingFeedback && "opacity-50 cursor-not-allowed",
|
|
feedback === "positive"
|
|
? "bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400 dark:hover:bg-green-900/50"
|
|
: "hover:bg-fd-accent hover:text-fd-accent-foreground",
|
|
),
|
|
}),
|
|
)}
|
|
title={
|
|
showSuccessCheckmark === "positive"
|
|
? "Feedback submitted!"
|
|
: "Helpful"
|
|
}
|
|
>
|
|
{showSuccessCheckmark === "positive" ? (
|
|
<Check className="h-3.5 w-3.5 text-green-600 animate-in fade-in duration-200" />
|
|
) : (
|
|
<ThumbsUp className="h-3.5 w-3.5 transition-all duration-200" />
|
|
)}
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={() => handleFeedback("negative")}
|
|
disabled={isSubmittingFeedback}
|
|
className={cn(
|
|
buttonVariants({
|
|
size: "icon-sm",
|
|
color: feedback === "negative" ? "primary" : "ghost",
|
|
className: cn(
|
|
"h-7 w-7 transition-colors",
|
|
isSubmittingFeedback && "opacity-50 cursor-not-allowed",
|
|
feedback === "negative"
|
|
? "bg-red-100 text-red-700 hover:bg-red-200 dark:bg-red-900/30 dark:text-red-400 dark:hover:bg-red-900/50"
|
|
: "hover:bg-fd-accent hover:text-fd-accent-foreground",
|
|
),
|
|
}),
|
|
)}
|
|
title={
|
|
showSuccessCheckmark === "negative"
|
|
? "Feedback submitted!"
|
|
: "Not helpful"
|
|
}
|
|
>
|
|
{showSuccessCheckmark === "negative" ? (
|
|
<Check className="h-3.5 w-3.5 text-green-600 animate-in fade-in duration-200" />
|
|
) : (
|
|
<ThumbsDown className="h-3.5 w-3.5 transition-all duration-200" />
|
|
)}
|
|
</button>
|
|
|
|
<button
|
|
type="button"
|
|
onClick={handleCopy}
|
|
className={cn(
|
|
buttonVariants({
|
|
size: "icon-sm",
|
|
color: "ghost",
|
|
className:
|
|
"h-7 w-7 hover:bg-fd-accent hover:text-fd-accent-foreground transition-colors",
|
|
}),
|
|
)}
|
|
title={copied ? "Copied!" : "Copy message"}
|
|
>
|
|
{copied ? (
|
|
<Check className="h-3.5 w-3.5 text-green-600" />
|
|
) : (
|
|
<Copy className="h-3.5 w-3.5" />
|
|
)}
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|