'use client'; import { Send, X } from 'lucide-react'; import { useCallback, useEffect, useRef, useState } from 'react'; interface ResolveHookModalProps { /** Whether the modal is open */ isOpen: boolean; /** Callback when the modal should be closed */ onClose: () => void; /** Callback when the form is submitted with the parsed JSON payload */ onSubmit: (payload: unknown) => Promise; /** Whether the submission is in progress */ isSubmitting?: boolean; } /** * Modal component for resolving a hook by entering a JSON payload. * * Styled to match the Geist design-system dialog component used in the * Vercel dashboard so it looks native when rendered inside `front`. */ export function ResolveHookModal({ isOpen, onClose, onSubmit, isSubmitting = false, }: ResolveHookModalProps): React.JSX.Element | null { const [jsonInput, setJsonInput] = useState(''); const [parseError, setParseError] = useState(null); const textareaRef = useRef(null); // Focus the textarea when the modal opens useEffect(() => { if (isOpen && textareaRef.current) { textareaRef.current.focus(); } }, [isOpen]); // Reset state when modal closes useEffect(() => { if (!isOpen) { setJsonInput(''); setParseError(null); } }, [isOpen]); // Handle escape key to close useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape' && isOpen && !isSubmitting) { onClose(); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [isOpen, isSubmitting, onClose]); const submitPayload = useCallback(async () => { setParseError(null); // Parse the JSON input let payload: unknown; try { // Allow empty string as null payload if (jsonInput.trim() === '') { payload = null; } else { payload = JSON.parse(jsonInput); } } catch { setParseError('Invalid JSON. Please check your input.'); return; } await onSubmit(payload); }, [jsonInput, onSubmit]); const handleSubmit = useCallback( (e: React.FormEvent) => { e.preventDefault(); void submitPayload(); }, [submitPayload] ); const isMacPlatform = typeof navigator !== 'undefined' && ( (navigator as Navigator & { userAgentData?: { platform?: string } }) .userAgentData?.platform ?? navigator.userAgent ) .toLowerCase() .includes('mac'); // Handle Cmd/Ctrl + Enter to submit const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === 'Enter' && !isSubmitting) { e.preventDefault(); handleSubmit(e as unknown as React.FormEvent); } }, [handleSubmit, isSubmitting] ); if (!isOpen) { return null; } return (
{/* Backdrop — matches Geist dialog ::backdrop */}
{/* Modal card — matches Geist dialog.geist-dialog */}
{/* Header */}

Resolve Hook

{/* Body */}

Enter a JSON value to send to the hook. Leave empty to send{' '} null .