"use client" import { cn } from "@mdxui/primitives/lib/utils" import { Button } from "@mdxui/primitives/button" import { Textarea } from "@mdxui/primitives/textarea" import { Label } from "@mdxui/primitives/label" import { Tooltip, TooltipContent, TooltipTrigger } from "@mdxui/primitives/tooltip" import { MdOutlineSentimentVeryDissatisfied, MdOutlineSentimentDissatisfied, MdOutlineSentimentNeutral, MdOutlineSentimentSatisfied, MdOutlineSentimentVerySatisfied, } from "react-icons/md" import { useState, useRef } from "react" import type { Sentiment, FeedbackData, FeedbackUser } from "./types" import type { IconType } from "react-icons" const sentiments: Array<{ value: Sentiment; icon: IconType; label: string }> = [ { value: 'very-dissatisfied', icon: MdOutlineSentimentVeryDissatisfied, label: 'Very Dissatisfied' }, { value: 'dissatisfied', icon: MdOutlineSentimentDissatisfied, label: 'Dissatisfied' }, { value: 'neutral', icon: MdOutlineSentimentNeutral, label: 'Neutral' }, { value: 'satisfied', icon: MdOutlineSentimentSatisfied, label: 'Satisfied' }, { value: 'very-satisfied', icon: MdOutlineSentimentVerySatisfied, label: 'Very Satisfied' }, ] interface FeedbackContentProps { user?: FeedbackUser context?: Record captureMetadata?: boolean onSubmit?: (data: FeedbackData) => Promise | void apiEndpoint?: string placeholder?: string submitLabel?: string onSuccess: () => void onError: (error: string) => void } function captureCurrentMetadata() { return { url: window.location.href, timestamp: new Date().toISOString(), viewport: { width: window.innerWidth, height: window.innerHeight }, userAgent: navigator.userAgent, } } export function FeedbackContent({ user, context, captureMetadata = true, onSubmit, apiEndpoint, placeholder = "Write your feedback (optional)", submitLabel = "Submit", onSuccess, onError, }: FeedbackContentProps) { const [selectedSentiment, setSelectedSentiment] = useState(null) const [message, setMessage] = useState("") const [isSubmitting, setIsSubmitting] = useState(false) const [hoveredSentiment, setHoveredSentiment] = useState(null) const hoverTimeoutRef = useRef | null>(null) const handleMouseEnter = (value: Sentiment) => { // Clear any pending timeout if (hoverTimeoutRef.current) { clearTimeout(hoverTimeoutRef.current) } // Delay tooltip by 300ms hoverTimeoutRef.current = setTimeout(() => { setHoveredSentiment(value) }, 300) } const handleMouseLeave = () => { if (hoverTimeoutRef.current) { clearTimeout(hoverTimeoutRef.current) } setHoveredSentiment(null) } const handleSubmit = async () => { if (!selectedSentiment) return setIsSubmitting(true) const data: FeedbackData = { sentiment: selectedSentiment, message: message.trim() || undefined, user, context, metadata: captureMetadata ? captureCurrentMetadata() : undefined, } try { if (onSubmit) { await onSubmit(data) } else if (apiEndpoint) { const response = await fetch(apiEndpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }) if (!response.ok) { throw new Error(`Failed to submit feedback: ${response.statusText}`) } } onSuccess() } catch (err) { onError(err instanceof Error ? err.message : "Failed to submit feedback") } finally { setIsSubmitting(false) } } return (
{/* Sentiment selector */}
{sentiments.map(({ value, icon: Icon, label }) => ( {label} ))}
{/* Labels under icons */}
Unsatisfied Satisfied
{/* Message textarea with label */}