'use client'; import { useEffect, useRef, useState } from 'react'; import { SITE, GITEA_URL, GITEA_USERNAME } from '@/lib/config'; const TURNSTILE_SITE_KEY = process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY; declare global { interface Window { turnstile?: { render: ( container: string | HTMLElement, options: { sitekey: string; theme?: 'light' | 'dark' | 'auto'; callback?: (token: string) => void; 'expired-callback'?: () => void; 'error-callback'?: () => void; } ) => string; reset: (widgetId?: string) => void; }; } } type Status = 'idle' | 'loading' | 'sent' | 'error'; export default function Contact() { const [status, setStatus] = useState('idle'); const [errorMessage, setErrorMessage] = useState(''); const [turnstileToken, setTurnstileToken] = useState(''); const widgetIdRef = useRef(null); const turnstileRef = useRef(null); useEffect(() => { if (!TURNSTILE_SITE_KEY) { setErrorMessage('Captcha is not configured correctly.'); return; } const scriptId = 'cf-turnstile-script'; const renderWidget = () => { if (!window.turnstile || !turnstileRef.current || widgetIdRef.current) return; widgetIdRef.current = window.turnstile.render(turnstileRef.current, { sitekey: TURNSTILE_SITE_KEY, theme: 'dark', callback: token => { setTurnstileToken(token); }, 'expired-callback': () => { setTurnstileToken(''); }, 'error-callback': () => { setTurnstileToken(''); setErrorMessage('Captcha failed to load. Please try again.'); }, }); }; if (document.getElementById(scriptId)) { renderWidget(); return; } const script = document.createElement('script'); script.id = scriptId; script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit'; script.async = true; script.defer = true; script.onload = renderWidget; document.body.appendChild(script); }, []); async function handleSubmit(e: React.FormEvent) { e.preventDefault(); setStatus('loading'); setErrorMessage(''); const form = e.currentTarget; const fd = new FormData(form); const payload = { name: String(fd.get('name') || '').trim(), email: String(fd.get('email') || '').trim(), message: String(fd.get('message') || '').trim(), company: String(fd.get('company') || '').trim(), // honeypot turnstileToken, formStartedAt: String(fd.get('formStartedAt') || ''), }; if (!payload.name || !payload.email || !payload.message) { setStatus('error'); setErrorMessage('Please complete all fields.'); return; } if (!payload.turnstileToken) { setStatus('error'); setErrorMessage('Please complete the captcha.'); return; } try { const res = await fetch('/api/contact', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); const data = await res.json(); if (!res.ok) { throw new Error(data?.error || 'Failed to send message.'); } setStatus('sent'); form.reset(); setTurnstileToken(''); if (window.turnstile && widgetIdRef.current) { window.turnstile.reset(widgetIdRef.current); } } catch (err) { setStatus('error'); setErrorMessage( err instanceof Error ? err.message : 'Something went wrong.', ); } finally { if (status !== 'sent') { setStatus(prev => (prev === 'sent' ? 'sent' : 'idle')); } } } return (
Get in touch

Let’s work together.

Open to interesting roles, collaborations, and serious product ideas.

{/* email + gitea blocks unchanged */} {/* ... */}
{/* Honeypot */} {/* fields unchanged */} {/* ... */}
{TURNSTILE_SITE_KEY ? (
) : (

Captcha is not configured correctly.

)}
{status === 'sent' && (

Thanks — your message has been sent.

)} {errorMessage && (

{errorMessage}

)}
); }