import { useState } from 'react'; import { Star } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { Checkbox } from '@/components/ui/checkbox'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { usePublishReview, useUserBookReview } from '@/hooks/useBookReviews'; import { useToast } from '@/hooks/useToast'; import { cn } from '@/lib/utils'; import type { BookReview } from '@/lib/bookstr'; interface BookReviewFormDialogProps { isbn: string; children: React.ReactNode; } /** Dialog wrapper that opens a review form. */ export function BookReviewFormDialog({ isbn, children }: BookReviewFormDialogProps) { const [open, setOpen] = useState(false); const { data: existingReview } = useUserBookReview(isbn); return ( {children} {existingReview ? 'Edit Review' : 'Write a Review'} setOpen(false)} /> ); } interface BookReviewFormProps { isbn: string; existingReview?: BookReview; onClose?: () => void; } /** Inline review form with star rating, text, and spoiler support. */ function BookReviewForm({ isbn, existingReview, onClose }: BookReviewFormProps) { const { user } = useCurrentUser(); const { toast } = useToast(); const [content, setContent] = useState(existingReview?.content ?? ''); const [rating, setRating] = useState(existingReview?.rating !== undefined ? Math.round(existingReview.rating * 5) : 0); const [hasSpoiler, setHasSpoiler] = useState(!!existingReview?.contentWarning); const [contentWarning, setContentWarning] = useState(existingReview?.contentWarning ?? ''); const { mutate: publishReview, isPending } = usePublishReview(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!content.trim() && rating === 0) { toast({ title: 'Please provide either a written review or a rating', variant: 'destructive' }); return; } const review: BookReview = { isbn, content: content.trim(), rating: rating > 0 ? rating / 5 : undefined, contentWarning: hasSpoiler && contentWarning.trim() ? contentWarning.trim() : undefined, }; publishReview(review, { onSuccess: () => { toast({ title: existingReview ? 'Review updated' : 'Review published' }); onClose?.(); }, onError: () => { toast({ title: 'Failed to publish review', variant: 'destructive' }); }, }); }; if (!user) return null; return (
{/* Star rating */}
{[...Array(5)].map((_, i) => ( ))}
{rating > 0 && (
{rating}/5
)}
{/* Review text */}