/** * WordPress Integration Form Component * Simplified - uses only Site.wp_api_key, no SiteIntegration model needed */ import React, { useState, useEffect } from 'react'; import { Card } from '../ui/card'; import Button from '../ui/button/Button'; import IconButton from '../ui/button/IconButton'; import Label from '../form/Label'; import Input from '../form/input/InputField'; import Checkbox from '../form/input/Checkbox'; import Switch from '../form/switch/Switch'; import { useToast } from '../ui/toast/ToastContainer'; import { fetchAPI, API_BASE_URL } from '../../services/api'; import { CheckCircleIcon, AlertIcon, DownloadIcon, PlusIcon, CopyIcon, TrashBinIcon, GlobeIcon, KeyIcon, RefreshCwIcon, InfoIcon } from '../../icons'; interface WordPressIntegrationFormProps { siteId: number; siteName?: string; siteUrl?: string; wpApiKey?: string; // API key from Site.wp_api_key onApiKeyUpdate?: (apiKey: string | null) => void; } export default function WordPressIntegrationForm({ siteId, siteName, siteUrl, wpApiKey, onApiKeyUpdate, }: WordPressIntegrationFormProps) { const toast = useToast(); const [loading, setLoading] = useState(false); const [generatingKey, setGeneratingKey] = useState(false); const [apiKey, setApiKey] = useState(''); const [apiKeyVisible, setApiKeyVisible] = useState(false); const [pluginInfo, setPluginInfo] = useState(null); const [loadingPlugin, setLoadingPlugin] = useState(false); // Connection status state const [connectionStatus, setConnectionStatus] = useState<'unknown' | 'testing' | 'connected' | 'api_key_pending' | 'plugin_missing' | 'error'>('unknown'); const [connectionMessage, setConnectionMessage] = useState(''); const [testingConnection, setTestingConnection] = useState(false); // Load API key from wpApiKey prop (from Site.wp_api_key) on mount or when it changes useEffect(() => { if (wpApiKey) { setApiKey(wpApiKey); } else { setApiKey(''); } }, [wpApiKey]); // Fetch plugin information useEffect(() => { const fetchPluginInfo = async () => { try { setLoadingPlugin(true); const response = await fetchAPI('/plugins/wordpress/latest/'); setPluginInfo(response); } catch (error) { console.error('Failed to fetch plugin info:', error); } finally { setLoadingPlugin(false); } }; fetchPluginInfo(); }, []); // Test connection when API key exists const testConnection = async () => { if (!apiKey || !siteUrl) { setConnectionStatus('unknown'); setConnectionMessage('API key or site URL missing'); return; } try { setTestingConnection(true); setConnectionStatus('testing'); setConnectionMessage('Testing connection...'); // Call backend to test connection to WordPress // Backend reads API key from Site.wp_api_key (single source of truth) const response = await fetchAPI('/v1/integration/integrations/test-connection/', { method: 'POST', body: JSON.stringify({ site_id: siteId, }), }); if (response.success) { // Check the health checks from response const healthChecks = response.health_checks || {}; // CRITICAL: api_key_verified confirms WordPress accepts our API key if (healthChecks.api_key_verified) { setConnectionStatus('connected'); setConnectionMessage('WordPress is connected and API key verified'); toast.success('WordPress connection verified!'); } else if (healthChecks.plugin_has_api_key && !healthChecks.api_key_verified) { // WordPress has A key, but it's NOT the same as IGNY8's key setConnectionStatus('api_key_pending'); setConnectionMessage('API key mismatch - copy the key from IGNY8 to WordPress plugin'); toast.warning('WordPress has different API key. Please update WordPress with the key shown above.'); } else if (healthChecks.plugin_installed && !healthChecks.plugin_has_api_key) { setConnectionStatus('api_key_pending'); setConnectionMessage('Plugin installed - please add API key in WordPress'); toast.warning('Plugin found but API key not configured in WordPress'); } else if (!healthChecks.plugin_installed) { setConnectionStatus('plugin_missing'); setConnectionMessage('IGNY8 plugin not installed on WordPress site'); toast.warning('WordPress site reachable but plugin not found'); } else { setConnectionStatus('error'); setConnectionMessage(response.message || 'Connection verification incomplete'); toast.error(response.message || 'Connection test incomplete'); } } else { setConnectionStatus('error'); setConnectionMessage(response.message || 'Connection test failed'); toast.error(response.message || 'Connection test failed'); } } catch (error: any) { setConnectionStatus('error'); setConnectionMessage(error.message || 'Connection test failed'); toast.error(`Connection test failed: ${error.message}`); } finally { setTestingConnection(false); } }; // DON'T auto-test - only test when user clicks Test button // Just set status based on whether key exists useEffect(() => { if (apiKey && siteUrl) { // Key exists - show as configured, but not yet tested/connected setConnectionStatus('unknown'); setConnectionMessage('Click Test to verify connection'); } else { setConnectionStatus('unknown'); setConnectionMessage(''); } }, [apiKey, siteUrl]); const handleGenerateApiKey = async () => { try { setGeneratingKey(true); // Call the simplified generate-api-key endpoint const response = await fetchAPI('/v1/integration/integrations/generate-api-key/', { method: 'POST', body: JSON.stringify({ site_id: siteId }), }); const newKey = response.api_key; setApiKey(newKey); setApiKeyVisible(true); // Notify parent component if (onApiKeyUpdate) { onApiKeyUpdate(newKey); } toast.success('API key generated successfully'); } catch (error: any) { toast.error(`Failed to generate API key: ${error.message}`); } finally { setGeneratingKey(false); } }; const handleRegenerateApiKey = async () => { if (!confirm('Are you sure you want to regenerate the API key? The old key will no longer work.')) { return; } try { setGeneratingKey(true); // Call the generate-api-key endpoint to create a new key const response = await fetchAPI('/v1/integration/integrations/generate-api-key/', { method: 'POST', body: JSON.stringify({ site_id: siteId }), }); const newKey = response.api_key; setApiKey(newKey); setApiKeyVisible(true); // Notify parent component if (onApiKeyUpdate) { onApiKeyUpdate(newKey); } toast.success('API key regenerated successfully'); } catch (error: any) { toast.error(`Failed to regenerate API key: ${error.message}`); } finally { setGeneratingKey(false); } }; const handleRevokeApiKey = async () => { if (!confirm('Are you sure you want to revoke the API key? Your WordPress plugin will stop working until you generate a new key.')) { return; } try { setGeneratingKey(true); // Revoke API key via dedicated endpoint (single source of truth: Site.wp_api_key) await fetchAPI('/v1/integration/integrations/revoke-api-key/', { method: 'POST', body: JSON.stringify({ site_id: siteId }), }); setApiKey(''); setApiKeyVisible(false); setConnectionStatus('unknown'); setConnectionMessage(''); // Notify parent component if (onApiKeyUpdate) { onApiKeyUpdate(null); } toast.success('API key revoked successfully'); } catch (error: any) { toast.error(`Failed to revoke API key: ${error.message}`); } finally { setGeneratingKey(false); } }; const handleCopyApiKey = () => { if (apiKey) { navigator.clipboard.writeText(apiKey); toast.success('API key copied to clipboard'); } }; const handleDownloadPlugin = () => { // Use the backend API endpoint for plugin download (must use full API URL, not relative) const pluginUrl = `${API_BASE_URL}/plugins/igny8-wp-bridge/download/`; window.open(pluginUrl, '_blank'); toast.success('Plugin download started'); }; const maskApiKey = (key: string) => { if (!key) return ''; if (key.length <= 12) return key; return key.substring(0, 8) + '**********' + key.substring(key.length - 4); }; return (
{/* Header */}

WordPress Integration

Connect your WordPress site using the IGNY8 WP Bridge plugin

{/* Connection Status & Test Button */} {apiKey && (
{/* Status Indicator - Uses theme colors from design-system */}
{connectionStatus === 'connected' && ( <> Connected )} {connectionStatus === 'testing' && ( <> Testing... )} {connectionStatus === 'api_key_pending' && ( <> Pending Setup )} {connectionStatus === 'plugin_missing' && ( <> Plugin Missing )} {connectionStatus === 'error' && ( <> Error )} {connectionStatus === 'unknown' && ( <> Not Tested )}
{/* Test Connection Button - IconButton only */} } />
)}
{/* API Keys Table */}

API Keys

API keys are used to authenticate requests to the IGNY8 API

{!apiKey && (
)}
{apiKey ? (
Name Status Created Action
{}} // No-op to satisfy React /> } />
} />
Regenerate
setApiKeyVisible(!apiKeyVisible)} variant="outline" > {apiKeyVisible ? ( ) : ( )}
Active {new Date().toLocaleDateString('en-US', { day: 'numeric', month: 'short', year: 'numeric' })}
} /> } />
) : (

No API key generated yet. Click "Add API Key" to generate one.

)}
{/* Plugin Download Section */} {apiKey && (

IGNY8 WP Bridge Plugin

Download and install the plugin on your WordPress site

{/* Plugin Details */} {pluginInfo && (

Version

{pluginInfo.version}

File Size

{(pluginInfo.file_size / 1024).toFixed(1)} KB

WordPress Version

5.0+

PHP Version

7.4+

{/* Requirements & Instructions */}

Installation Steps

  1. Download the plugin ZIP file
  2. Go to your WordPress admin → Plugins → Add New
  3. Click "Upload Plugin" and select the ZIP file
  4. Activate the plugin after installation
  5. Configure plugin with your API key from above
{/* Changelog */} {pluginInfo.changelog && (

What's New:

{pluginInfo.changelog}

)}
)} {loadingPlugin && (

Loading plugin information...

)}
)}
); }