'use client' import { useEffect, useState, useTransition, type SyntheticEvent } from 'react' import { ThumbsUp, ThumbsDown, Loader2 } from 'lucide-react' import { usePathname } from 'next/navigation' import { Collapsible, CollapsibleContent } from 'fumadocs-ui/components/ui/collapsible' import { submitFeedback } from '@/app/actions/feedback' type Opinion = 'good' | 'bad' interface StoredFeedback { opinion: Opinion message: string url: string } function useStoredFeedback(url: string) { const key = `docs-feedback-${url}` const [stored, setStored] = useState(null) useEffect(() => { const item = localStorage.getItem(key) if (!item) return try { const parsed = JSON.parse(item) as StoredFeedback if (parsed.opinion && parsed.url) setStored(parsed) } catch { // ignore invalid data } }, [key]) function save(feedback: StoredFeedback | null) { if (feedback) { localStorage.setItem(key, JSON.stringify(feedback)) } else { localStorage.removeItem(key) } setStored(feedback) } return { stored, save } } export function Feedback() { const url = usePathname() ?? '/' const { stored, save } = useStoredFeedback(url) const [opinion, setOpinion] = useState(null) const [message, setMessage] = useState('') const [pending, startTransition] = useTransition() function submit(e?: SyntheticEvent) { if (!opinion) return e?.preventDefault() const payload = { opinion, message, url } save(payload) setMessage('') setOpinion(null) startTransition(async () => { await submitFeedback(payload) }) } const activeOpinion = stored?.opinion ?? opinion return ( { if (!open) setOpinion(null) }} className="not-prose border-y border-fd-border py-3" >

How is this guide?

{stored ? (

{pending && } Thank you for your feedback!

) : (