feat(frontend): Integrate ReportDialog into CommentSection
Some checks are pending
Deploy Elmeg / deploy (push) Waiting to run

This commit is contained in:
fullsizemalt 2025-12-21 02:47:17 -08:00
commit 5d27045819
3 changed files with 135 additions and 3 deletions

View file

@ -287,8 +287,8 @@ class PerformanceNicknameRead(PerformanceNicknameBase):
# --- Report Schemas ---
class ReportBase(SQLModel):
target_type: str
target_id: int
entity_type: str
entity_id: int
reason: str
class ReportCreate(ReportBase):

View file

@ -0,0 +1,121 @@
"use client"
import { useState } from "react"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
import { Flag } from "lucide-react"
import { getApiUrl } from "@/lib/api-config"
import { Textarea } from "@/components/ui/textarea"
interface ReportDialogProps {
entityType: "comment" | "review" | "nickname"
entityId: number
trigger?: React.ReactNode
}
export function ReportDialog({ entityType, entityId, trigger }: ReportDialogProps) {
const [open, setOpen] = useState(false)
const [reason, setReason] = useState("spam")
const [details, setDetails] = useState("")
const [loading, setLoading] = useState(false)
const handleSubmit = async () => {
const token = localStorage.getItem("token")
if (!token) return
setLoading(true)
try {
const res = await fetch(`${getApiUrl()}/moderation/reports`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`
},
body: JSON.stringify({
entity_type: entityType,
entity_id: entityId,
reason: reason,
details: details // Schema might not have details yet, check backend
})
})
if (res.ok) {
setOpen(false)
alert("Report submitted. Thank you for helping keep the community safe.")
} else {
alert("Failed to submit report.")
}
} catch (error) {
console.error(error)
} finally {
setLoading(false)
}
}
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
{trigger || (
<Button variant="ghost" size="sm" className="h-6 w-6 p-0 text-muted-foreground hover:text-red-500">
<Flag className="h-3 w-3" />
<span className="sr-only">Report</span>
</Button>
)}
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Report Content</DialogTitle>
<DialogDescription>
Help us understand what's wrong with this content.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<RadioGroup value={reason} onValueChange={setReason} className="gap-3">
<div className="flex items-center space-x-2">
<RadioGroupItem value="spam" id="spam" />
<Label htmlFor="spam">Spam or unwanted commercial content</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="harassment" id="harassment" />
<Label htmlFor="harassment">Harassment or hate speech</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="spoiler" id="spoiler" />
<Label htmlFor="spoiler">Spoiler or incorrect info</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="other" id="other" />
<Label htmlFor="other">Other</Label>
</div>
</RadioGroup>
{reason === "other" && (
<Textarea
placeholder="Please provide more details..."
value={details}
onChange={(e) => setDetails(e.target.value)}
/>
)}
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>Cancel</Button>
<Button variant="destructive" onClick={handleSubmit} disabled={loading}>
{loading ? "Submitting..." : "Submit Report"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}

View file

@ -6,8 +6,9 @@ import { Textarea } from "@/components/ui/textarea"
import { Card, CardContent } from "@/components/ui/card"
import { formatDistanceToNow } from "date-fns"
import { getApiUrl } from "@/lib/api-config"
import { MessageCircle, CornerDownRight, Heart } from "lucide-react"
import { MessageCircle, CornerDownRight, Heart, Flag } from "lucide-react"
import { cn } from "@/lib/utils"
import { ReportDialog } from "@/components/moderation/report-dialog"
interface Comment {
id: number
@ -186,6 +187,16 @@ function CommentItem({ comment, getReplies, onReply }: {
<Heart className="h-3 w-3" />
Like
</Button>
<ReportDialog
entityType="comment"
entityId={comment.id}
trigger={
<Button variant="ghost" size="sm" className="h-6 px-2 text-xs text-muted-foreground gap-1 hover:text-red-500">
<Flag className="h-3 w-3" />
Report
</Button>
}
/>
</div>
{isReplying && (