diff --git a/client/package.json b/client/package.json index a3af71b..af1d454 100644 --- a/client/package.json +++ b/client/package.json @@ -10,13 +10,14 @@ "preview": "vite preview" }, "dependencies": { + "@stripe/react-stripe-js": "^3.1.0", + "@stripe/stripe-js": "^5.0.0", + "lucide-react": "^0.469.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-router-dom": "^7.1.0", - "socket.io-client": "^4.8.0", - "@stripe/stripe-js": "^5.0.0", - "@stripe/react-stripe-js": "^3.1.0", - "lucide-react": "^0.469.0" + "recharts": "^3.7.0", + "socket.io-client": "^4.8.0" }, "devDependencies": { "@eslint/js": "^9.17.0", diff --git a/client/src/components/ReportModal.tsx b/client/src/components/ReportModal.tsx new file mode 100644 index 0000000..eec3b9d --- /dev/null +++ b/client/src/components/ReportModal.tsx @@ -0,0 +1,97 @@ +import { useState } from 'react'; +import { Modal } from './ui/Modal'; +import { Button } from './ui/Button'; +import { GradientButton } from './ui/GradientButton'; +import { api } from '../api/client'; +import type { ReportReason } from '../types'; + +interface ReportModalProps { + isOpen: boolean; + onClose: () => void; + targetType: 'LISTING' | 'USER'; + targetId: string; +} + +const REASONS: { value: ReportReason; label: string }[] = [ + { value: 'SPAM', label: 'Spam' }, + { value: 'INAPPROPRIATE', label: 'Inappropriate content' }, + { value: 'SCAM', label: 'Scam / Fraud' }, + { value: 'COUNTERFEIT', label: 'Counterfeit item' }, + { value: 'PROHIBITED_ITEM', label: 'Prohibited item' }, + { value: 'HARASSMENT', label: 'Harassment' }, + { value: 'OTHER', label: 'Other' }, +]; + +export function ReportModal({ isOpen, onClose, targetType, targetId }: ReportModalProps) { + const [reason, setReason] = useState(''); + const [description, setDescription] = useState(''); + const [submitting, setSubmitting] = useState(false); + const [success, setSuccess] = useState(false); + const [error, setError] = useState(''); + + const handleSubmit = async () => { + if (!reason) return; + setSubmitting(true); + setError(''); + try { + await api.post('/reports', { targetType, targetId, reason, description: description || undefined }); + setSuccess(true); + setTimeout(() => { + onClose(); + setSuccess(false); + setReason(''); + setDescription(''); + }, 1500); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to submit report'); + } finally { + setSubmitting(false); + } + }; + + return ( + + {success ? ( +
+

Report submitted. Thank you!

+
+ ) : ( + <> + {error &&

{error}

} +

Why are you reporting this?

+
+ {REASONS.map((r) => ( + + ))} +
+
+ +