'use client'; import React, { useState, useEffect, useRef } from 'react'; import { SupportTicketSummary } from './types'; interface SupportReportModalProps { isOpen: boolean; onClose: () => void; onSuccess: (ticket: SupportTicketSummary) => void; } export function SupportReportModal({ isOpen, onClose, onSuccess }: SupportReportModalProps) { const [ticketType, setTicketType] = useState('general'); const [reporterEmail, setReporterEmail] = useState(''); const [subject, setSubject] = useState(''); const [description, setDescription] = useState(''); const [severity, setSeverity] = useState('medium'); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); const modalRef = useRef(null); const firstInputRef = useRef(null); useEffect(() => { if (isOpen) { setTicketType('general'); setReporterEmail(''); setSubject(''); setDescription(''); setSeverity('medium'); setError(null); // Focus first input after render setTimeout(() => firstInputRef.current?.focus(), 100); } }, [isOpen]); // Keyboard accessibility useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (!isOpen) return; if (e.key === 'Escape') { onClose(); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [isOpen, onClose]); if (!isOpen) return null; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (isSubmitting) return; const trimmedEmail = reporterEmail.trim(); const trimmedSubject = subject.trim(); const trimmedDescription = description.trim(); if (!trimmedSubject) { setError('Subject cannot be empty or contain only whitespace.'); return; } if (!trimmedDescription) { setError('Description cannot be empty or contain only whitespace.'); return; } setIsSubmitting(true); setError(null); try { const resp = await fetch('/api/ops/support/tickets', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ticket_type: ticketType, reporter_email: trimmedEmail, subject: trimmedSubject, description: trimmedDescription, severity, }) }); const data = await resp.json().catch(() => null); if (resp.ok) { onSuccess(data); onClose(); } else { setError(data?.detail || 'Failed to submit report'); } } catch { setError('Network error during submission'); } finally { setIsSubmitting(false); } }; return (
{error && (
{error}
)}
setReporterEmail(e.target.value)} className="w-full px-3 py-2 bg-surface-container-lowest border border-outline-variant/50 rounded-lg text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/50" placeholder="user@example.com" />
setSubject(e.target.value)} className="w-full px-3 py-2 bg-surface-container-lowest border border-outline-variant/50 rounded-lg text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/50" placeholder="Brief summary" />