"use client" import { cn } from "@mdxui/primitives/lib/utils" import { Button } from "@mdxui/primitives/button" import { Input } from "@mdxui/primitives/input" import { Textarea } from "@mdxui/primitives/textarea" import { Label } from "@mdxui/primitives/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@mdxui/primitives/select" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@mdxui/primitives/tabs" import { useState } from "react" import type { MessageType, ReportIssueData, ReportIssueUser, ReportIssueSeverity, SeverityOption, } from "./types" const DEFAULT_TOPICS = [ "API", "Webhooks", "Events & Logs", "Account & Billing", "Other", ] const DEFAULT_SEVERITY_OPTIONS: SeverityOption[] = [ { value: "critical", label: "Critical — Service down or data loss" }, { value: "high", label: "High — Feature broken, no workaround" }, { value: "medium", label: "Medium — Feature impaired, workaround exists" }, { value: "low", label: "Low — Minor issue or cosmetic" }, { value: "question-feature-req", label: "Question / Feature Request — No impact" }, ] const TAB_CONFIG: Record< MessageType, { label: string; placeholder: string } > = { question: { label: "What can we help you with?", placeholder: "Describe your question...", }, feedback: { label: "What feedback do you have?", placeholder: "Share your thoughts, suggestions...", }, bug: { label: "What's the bug?", placeholder: "Describe the bug or paste error details...", }, } const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ interface ReportIssueContentProps { defaultTab?: MessageType defaultValues?: { message?: string topic?: string severity?: ReportIssueSeverity } topics?: string[] severityOptions?: SeverityOption[] user?: ReportIssueUser context?: Record captureMetadata?: boolean onSubmit?: (data: ReportIssueData) => Promise | void apiEndpoint?: string apiHeaders?: Record submitLabel?: string onSuccess: () => void onError: (error: string) => void onTabChange?: (tab: MessageType) => void } function captureCurrentMetadata() { return { url: window.location.href, timestamp: new Date().toISOString(), viewport: { width: window.innerWidth, height: window.innerHeight }, userAgent: navigator.userAgent, } } export function ReportIssueContent({ defaultTab = "question", defaultValues, topics = DEFAULT_TOPICS, severityOptions = DEFAULT_SEVERITY_OPTIONS, user, context, captureMetadata = true, onSubmit, apiEndpoint, apiHeaders, submitLabel = "Submit", onSuccess, onError, onTabChange, }: ReportIssueContentProps) { const [name, setName] = useState(user?.name ?? "") const [email, setEmail] = useState(user?.email ?? "") const [messageType, setMessageType] = useState(defaultTab) const [topic, setTopic] = useState(defaultValues?.topic ?? "") const [message, setMessage] = useState(defaultValues?.message ?? "") const [severity, setSeverity] = useState( defaultValues?.severity ?? "medium" ) const [isSubmitting, setIsSubmitting] = useState(false) const [errors, setErrors] = useState>({}) const validate = (): boolean => { const newErrors: Record = {} if (name.trim().length < 2) { newErrors.name = "Name must be at least 2 characters" } if (!EMAIL_REGEX.test(email.trim())) { newErrors.email = "Please enter a valid email" } if (message.trim().length < 10) { newErrors.message = "Message must be at least 10 characters" } setErrors(newErrors) return Object.keys(newErrors).length === 0 } const handleSubmit = async () => { if (!validate()) return setIsSubmitting(true) const data: ReportIssueData = { name: name.trim(), email: email.trim(), messageType, topic: topic || undefined, message: message.trim(), severity, user, context, metadata: captureMetadata ? captureCurrentMetadata() : undefined, } try { if (onSubmit) { await onSubmit(data) } else if (apiEndpoint) { const response = await fetch(apiEndpoint, { method: "POST", headers: { "Content-Type": "application/json", ...apiHeaders, }, body: JSON.stringify(data), }) if (!response.ok) { throw new Error(`Failed to submit: ${response.statusText}`) } } onSuccess() } catch (err) { onError(err instanceof Error ? err.message : "Failed to submit report") } finally { setIsSubmitting(false) } } const isValid = name.trim().length >= 2 && EMAIL_REGEX.test(email.trim()) && message.trim().length >= 10 const selectedSeverityOption = severityOptions.find( (opt) => opt.value === severity ) const tabConfig = TAB_CONFIG[messageType] return (
{/* Name / Email */}
setName(e.target.value)} placeholder="Your name" className={cn(errors.name && "border-destructive")} /> {errors.name && (

{errors.name}

)}
setEmail(e.target.value)} placeholder="you@example.com" className={cn(errors.email && "border-destructive")} /> {errors.email && (

{errors.email}

)}
{/* Message Type Tabs */}
{ const tab = value as MessageType setMessageType(tab) onTabChange?.(tab) }} > Question Feedback Bug {/* Shared content below tabs — not inside TabsContent so state is preserved */}
{/* Topic */}
{/* Message textarea — label/placeholder changes per tab */}