import { useState } from 'react'; import { useNostrPublish } from '@/hooks/useNostrPublish'; import { useCurrentUser } from '@/hooks/useCurrentUser'; import { useToast } from '@/hooks/useToast'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Textarea } from '@/components/ui/textarea'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { Loader2, Flag, AlertTriangle, CheckCircle2 } from 'lucide-react'; import { useTranslation } from '@/contexts/language'; import { cn } from '@/lib/utils'; // NIP-56 Report types with skate-specific labels. `labelKey`/`descriptionKey` // resolve to `spotUi.report.*` translations. const REPORT_REASONS = [ { id: 'other', labelKey: 'spotUi.report.notASkateSpot.label', descriptionKey: 'spotUi.report.notASkateSpot.description', icon: '🛹', subtype: 'not-a-skate-spot', }, { id: 'spam', labelKey: 'spotUi.report.fakeSpot.label', descriptionKey: 'spotUi.report.fakeSpot.description', icon: '📍', }, { id: 'other', labelKey: 'spotUi.report.stolenPhotos.label', descriptionKey: 'spotUi.report.stolenPhotos.description', icon: '📸', }, { id: 'spam', labelKey: 'spotUi.report.spamAd.label', descriptionKey: 'spotUi.report.spamAd.description', icon: '🗑️', subtype: 'spam-ad', }, { id: 'illegal', labelKey: 'spotUi.report.dangerousLocation.label', descriptionKey: 'spotUi.report.dangerousLocation.description', icon: '⚠️', }, { id: 'nudity', labelKey: 'spotUi.report.inappropriateContent.label', descriptionKey: 'spotUi.report.inappropriateContent.description', icon: '🔞', }, { id: 'impersonation', labelKey: 'spotUi.report.impersonation.label', descriptionKey: 'spotUi.report.impersonation.description', icon: '👤', }, { id: 'other', labelKey: 'spotUi.report.other.label', descriptionKey: 'spotUi.report.other.description', icon: '📝', subtype: 'other-general', }, ] as const; interface ReportDialogProps { open: boolean; onOpenChange: (open: boolean) => void; // What we're reporting targetType: 'spot' | 'event' | 'tour' | 'shop' | 'user' | 'listing' | 'coach' | 'filmer'; targetPubkey: string; targetEventId?: string; targetTitle?: string; // Callback after report onReported?: () => void; } export function ReportDialog({ open, onOpenChange, targetType, targetPubkey, targetEventId, targetTitle, onReported, }: ReportDialogProps) { const { t } = useTranslation(); const { user } = useCurrentUser(); const { mutateAsync: publishEvent, isPending } = useNostrPublish(); const { toast } = useToast(); const [selectedReason, setSelectedReason] = useState(''); const [additionalDetails, setAdditionalDetails] = useState(''); const [step, setStep] = useState<'form' | 'success'>('form'); const handleSubmit = async () => { if (!user || !selectedReason) return; const reason = REPORT_REASONS.find( (r) => r.id === selectedReason || ('subtype' in r && r.subtype === selectedReason) ); if (!reason) return; try { // Build NIP-56 report tags const tags: string[][] = []; // Always include the pubkey being reported if (targetEventId) { // Reporting an event (spot, tour, etc.) tags.push(['e', targetEventId, reason.id]); tags.push(['p', targetPubkey]); } else { // Reporting just a user/profile tags.push(['p', targetPubkey, reason.id]); } // Build content with context let content = ''; if (additionalDetails.trim()) { content = additionalDetails.trim(); } if (targetTitle) { content = content ? `${content}\n\nReported: ${targetTitle} (${targetType})` : `Reported: ${targetTitle} (${targetType})`; } await publishEvent({ kind: 1984, // NIP-56 Report content, tags, }); setStep('success'); onReported?.(); toast({ title: t('spotUi.reportSubmitted'), description: t('spotUi.reportSubmittedDesc'), }); } catch (error) { toast({ title: t('spotUi.failedToSubmitReport'), description: error instanceof Error ? error.message : t('spotUi.pleaseTryAgain'), variant: 'destructive', }); } }; const handleClose = () => { onOpenChange(false); // Reset form after animation setTimeout(() => { setSelectedReason(''); setAdditionalDetails(''); setStep('form'); }, 200); }; const getReasonKey = (reason: typeof REPORT_REASONS[number]) => { return ('subtype' in reason ? reason.subtype : undefined) || reason.id; }; if (!user) { return ( {t('spotUi.reportContent')}

{t('spotUi.logInToReport')}

); } return ( {t('spotUi.reportContent')} {step === 'form' && ( {t('spotUi.reportContentDesc')} )} {step === 'form' ? (
{/* Target info */} {targetTitle && (

{t('spotUi.reportingType', { type: t(`spotUi.targetType.${targetType}`) })}

{targetTitle}

)} {/* Reason selection */}
{REPORT_REASONS.map((reason) => { const key = getReasonKey(reason); return (
setSelectedReason(key)} >

{t(reason.descriptionKey)}

); })}
{/* Additional details */}