'use client'; /** * Interactive API Widget - Final Variant (Redesigned) * * Minimized layout inspired by Variant C with Final variant design system: * - No inline API key input (uses DocsApiKeyInput component) * - Clean header with method badge, endpoint, and expand button * - Full-width code snippet area * - Compact footer with API key anchor link and Try It button * - Expanded view opens full-screen modal with code + response side-by-side */ import { useState, useEffect } from 'react'; interface InteractiveAPIWidgetFinalProps { endpoint: string; method: 'GET' | 'POST' | 'PUT' | 'DELETE'; description: string; parameters?: Array<{ name: string; type: string; required: boolean; description: string; defaultValue?: string; }>; } type Language = 'curl' | 'javascript' | 'python' | 'go'; const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'; const API_KEY_STORAGE = 'banatie_docs_api_key'; const getMethodColor = (method: string): string => { switch (method) { case 'GET': return 'from-cyan-500 to-cyan-600'; case 'POST': return 'from-purple-500 to-purple-600'; case 'PUT': return 'from-amber-500 to-amber-600'; case 'DELETE': return 'from-red-500 to-red-600'; default: return 'from-purple-500 to-cyan-500'; } }; export const InteractiveAPIWidgetFinal = ({ endpoint, method, description, parameters = [], }: InteractiveAPIWidgetFinalProps) => { const [language, setLanguage] = useState('curl'); const [apiKey, setApiKey] = useState(''); const [isExecuting, setIsExecuting] = useState(false); const [response, setResponse] = useState(null); const [error, setError] = useState(null); const [isExpanded, setIsExpanded] = useState(false); const [paramValues, setParamValues] = useState>({}); // Load API key from localStorage and listen for changes useEffect(() => { const loadApiKey = () => { const stored = localStorage.getItem(API_KEY_STORAGE); if (stored) setApiKey(stored); }; loadApiKey(); // Listen for API key changes from DocsApiKeyInput const handleApiKeyChange = (e: CustomEvent) => { setApiKey(e.detail); }; window.addEventListener('apiKeyChanged', handleApiKeyChange as EventListener); // Initialize parameter defaults const defaults: Record = { prompt: 'a futuristic city at sunset', filename: 'demo', aspectRatio: '16:9', }; parameters.forEach((param) => { if (param.defaultValue) { defaults[param.name] = param.defaultValue; } }); setParamValues(defaults); return () => { window.removeEventListener('apiKeyChanged', handleApiKeyChange as EventListener); }; }, [parameters]); // Generate code examples const generateCode = (): string => { const url = `${API_BASE_URL}${endpoint}`; switch (language) { case 'curl': return `curl -X ${method} "${url}" \\ -H "X-API-Key: ${apiKey || 'YOUR_API_KEY'}" \\ -H "Content-Type: application/json" \\ -d '{ "prompt": "a futuristic city at sunset", "filename": "city", "aspectRatio": "16:9" }'`; case 'javascript': return `const response = await fetch('${url}', { method: '${method}', headers: { 'X-API-Key': '${apiKey || 'YOUR_API_KEY'}', 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: 'a futuristic city at sunset', filename: 'city', aspectRatio: '16:9' }) }); const data = await response.json(); console.log(data);`; case 'python': return `import requests url = '${url}' headers = { 'X-API-Key': '${apiKey || 'YOUR_API_KEY'}', 'Content-Type': 'application/json' } data = { 'prompt': 'a futuristic city at sunset', 'filename': 'city', 'aspectRatio': '16:9' } response = requests.${method.toLowerCase()}(url, headers=headers, json=data) print(response.json())`; case 'go': return `package main import ( "bytes" "encoding/json" "net/http" ) func main() { url := "${url}" data := map[string]interface{}{ "prompt": "a futuristic city at sunset", "filename": "city", "aspectRatio": "16:9", } jsonData, _ := json.Marshal(data) req, _ := http.NewRequest("${method}", url, bytes.NewBuffer(jsonData)) req.Header.Set("X-API-Key", "${apiKey || 'YOUR_API_KEY'}") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() }`; default: return ''; } }; // Execute API request const executeRequest = async () => { if (!apiKey) { setError('Please enter your API key in the top-right corner'); return; } setIsExecuting(true); setError(null); setResponse(null); try { const body = { prompt: paramValues.prompt || 'a futuristic city at sunset', filename: paramValues.filename || 'demo', aspectRatio: paramValues.aspectRatio || '16:9', }; console.log('🔵 API Request:', { url: `${API_BASE_URL}${endpoint}`, method, headers: { 'X-API-Key': apiKey.substring(0, 10) + '...' }, body, }); const res = await fetch(`${API_BASE_URL}${endpoint}`, { method, headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json', }, body: method !== 'GET' ? JSON.stringify(body) : undefined, }); console.log('🟢 Response Status:', res.status, res.statusText); if (!res.ok) { let errorMessage = `HTTP ${res.status}: ${res.statusText}`; try { const errorData = await res.json(); errorMessage = errorData.message || errorData.error || errorMessage; } catch { // Response is not JSON } throw new Error(errorMessage); } const data = await res.json(); console.log('✅ Response Data:', data); setResponse(data); } catch (err) { console.error('❌ API Error:', err); const errorMsg = err instanceof Error ? err.message : 'Failed to execute request'; setError(`Request failed: ${errorMsg}`); } finally { setIsExecuting(false); } }; // Copy code to clipboard const copyCode = () => { navigator.clipboard.writeText(generateCode()); }; // Expand API key input in navigation const expandApiKey = () => { window.dispatchEvent(new CustomEvent('expandApiKeyInput')); }; const isSuccess = response && response.success === true; return ( <> {/* Minimized Widget */}
{/* Header */}
{method}
{endpoint}
{/* Code Section - Full Width */}
{/* Language Tabs */}
{(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang, idx) => { const colors = ['purple', 'cyan', 'amber', 'purple']; const color = colors[idx]; return ( ); })}
{/* Code Display */}
Code Example
                {generateCode()}
              
{/* Footer */}
{/* Inline Response (if any) */} {(response || error) && (

📦 Response

{error ? (
⚠️

Error

{error}

) : (
{isSuccess && (
✓ 200 Success
)}
                  {JSON.stringify(response, null, 2)}
                
)}
)}
{/* Expanded Modal */} {isExpanded && (
{/* Modal Header */}
{method}
{endpoint}
{/* Two-Panel Layout */}
{/* Left: Code */}
{(['curl', 'javascript', 'python', 'go'] as Language[]).map((lang, idx) => { const colors = ['purple', 'cyan', 'amber', 'purple']; const color = colors[idx]; return ( ); })}
Code Example
                      {generateCode()}
                    
{/* Right: Response */}

📦 Response

{response && ( {response.success ? '✓ Success' : '✕ Error'} )}
{error ? (
⚠️

Error

{error}

) : response ? (
                        {JSON.stringify(response, null, 2)}
                      
) : (

🚀

Click "Try It" below to see the response

)}
{/* Try It Button in Expanded View */}
{/* Footer hint */}

{description}

)} ); };