'use client'; import { useState, useRef, useEffect } from 'react'; import { PenLine, X, Loader2 } from 'lucide-react'; type Sentiment = 'positive' | 'neutral' | 'negative' | null; interface FeedbackProps { page: string; } export function Feedback({ page }: FeedbackProps) { const [isOpen, setIsOpen] = useState(false); const [sentiment, setSentiment] = useState(null); const [message, setMessage] = useState(''); const [email, setEmail] = useState(''); const [state, setState] = useState<'idle' | 'loading' | 'success' | 'error'>('idle'); const closeTimeoutRef = useRef | null>(null); useEffect(() => { return () => { if (closeTimeoutRef.current) { clearTimeout(closeTimeoutRef.current); } }; }, []); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!message.trim()) return; setState('loading'); try { const response = await fetch('/api/feedback', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ page, pageTitle: document.title, sentiment, message: message.trim(), email: email.trim() || undefined, userAgent: navigator.userAgent, referrer: document.referrer || undefined, viewport: `${window.innerWidth}x${window.innerHeight}`, timestamp: new Date().toISOString(), }), }); if (!response.ok) throw new Error('Failed to send'); setState('success'); closeTimeoutRef.current = setTimeout(() => { setIsOpen(false); setState('idle'); setSentiment(null); setMessage(''); setEmail(''); }, 2000); } catch { setState('error'); } }; const handleClose = () => { if (closeTimeoutRef.current) { clearTimeout(closeTimeoutRef.current); closeTimeoutRef.current = null; } setIsOpen(false); setState('idle'); setSentiment(null); setMessage(''); setEmail(''); }; return ( <> {isOpen && (
e.stopPropagation()} >

Share feedback

{state === 'success' ? (

Thank you!

Your feedback helps us improve.

) : (

Help us improve our documentation by sharing your thoughts.

How would you rate this page?
{[ { value: 'positive', emoji: '😊', label: 'Positive' }, { value: 'neutral', emoji: '😐', label: 'Neutral' }, { value: 'negative', emoji: '😞', label: 'Negative' }, ].map((option) => ( ))}