import { useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { CheckCircle2, MessageSquarePlus, X } from 'lucide-react' import { FeedbackApiError, sendFeedback, type FeedbackCategory } from '../services/feedback.js' const SUCCESS_CLOSE_DELAY_MS = 1800 interface FeedbackModalProps { open: boolean onClose: () => void logbookId?: string | null logbookTitle?: string | null tourMode?: boolean } type SubmitState = 'idle' | 'submitting' | 'success' | 'error' export default function FeedbackModal({ open, onClose, logbookId, logbookTitle, tourMode = false }: FeedbackModalProps) { const { t } = useTranslation() const [category, setCategory] = useState('general') const [contactEmail, setContactEmail] = useState('') const [message, setMessage] = useState('') const [website, setWebsite] = useState('') const [submitState, setSubmitState] = useState('idle') const [statusMessage, setStatusMessage] = useState(null) const closeTimerRef = useRef(null) const openedAtRef = useRef(Date.now()) const isBusy = submitState === 'submitting' || submitState === 'success' const clearCloseTimer = () => { if (closeTimerRef.current !== null) { window.clearTimeout(closeTimerRef.current) closeTimerRef.current = null } } useEffect(() => { return () => clearCloseTimer() }, []) useEffect(() => { if (!open) return const onKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape' && !isBusy) onClose() } window.addEventListener('keydown', onKeyDown) return () => window.removeEventListener('keydown', onKeyDown) }, [open, onClose, isBusy]) useEffect(() => { if (!open) { clearCloseTimer() setCategory('general') setContactEmail('') setMessage('') setWebsite('') setSubmitState('idle') setStatusMessage(null) return } openedAtRef.current = Date.now() }, [open]) const handleSubmit = async (event: React.FormEvent) => { event.preventDefault() if (!message.trim() || submitState === 'submitting' || submitState === 'success') return setSubmitState('submitting') setStatusMessage(null) try { await sendFeedback({ category, message: message.trim(), contactEmail: contactEmail.trim() || undefined, logbookId, logbookTitle, openedAt: openedAtRef.current, website }) setSubmitState('success') setStatusMessage(t('feedback.success')) closeTimerRef.current = window.setTimeout(() => { closeTimerRef.current = null onClose() }, SUCCESS_CLOSE_DELAY_MS) } catch (error) { setSubmitState('error') setStatusMessage( error instanceof FeedbackApiError && error.code === 'NOT_CONFIGURED' ? t('feedback.error_not_configured') : error instanceof FeedbackApiError && error.code === 'INVALID_EMAIL' ? t('feedback.error_invalid_email') : error instanceof FeedbackApiError && error.code === 'RATE_LIMITED' ? t('feedback.error_rate_limited') : error instanceof FeedbackApiError && error.code === 'SPAM_DETECTED' ? t('feedback.error_spam') : t('feedback.error_send') ) } } if (!open) return null return (
event.stopPropagation()}>

{t('feedback.title')}

{submitState === 'success' ? (
) : ( <>

{t('feedback.intro')}

{statusMessage && submitState === 'error' && (

{statusMessage}

)}