import { ReactNode, useState, useEffect } from 'react'; import Switch from '../form/switch/Switch'; import Button from '../ui/button/Button'; import { usePersistentToggle } from '../../hooks/usePersistentToggle'; import { useToast } from '../ui/toast/ToastContainer'; type ValidationStatus = 'not_configured' | 'pending' | 'success' | 'error'; interface ImageServiceCardProps { icon: ReactNode; title: string; description: string; validationStatus: ValidationStatus; onSettings: () => void; onDetails: () => void; } /** * Image Generation Service Card Component * Manages default image generation service and model selection app-wide * This is separate from individual API integrations (OpenAI/Runware) */ export default function ImageServiceCard({ icon, title, description, validationStatus, onSettings, onDetails, }: ImageServiceCardProps) { const toast = useToast(); // Use built-in persistent toggle for image generation service const persistentToggle = usePersistentToggle({ resourceId: 'image_generation', getEndpoint: '/v1/system/settings/integrations/{id}/', saveEndpoint: '/v1/system/settings/integrations/{id}/save/', initialEnabled: false, onToggleSuccess: (enabled) => { toast.success(`Image generation service ${enabled ? 'enabled' : 'disabled'}`); }, onToggleError: (error) => { toast.error(`Failed to update image generation service: ${error.message}`); }, }); const enabled = persistentToggle.enabled; const isToggling = persistentToggle.loading; const [imageSettings, setImageSettings] = useState<{ service?: string; model?: string; runwareModel?: string }>({}); const API_BASE_URL = import.meta.env.VITE_BACKEND_URL || 'https://api.igny8.com/api'; // Load image settings to get provider and model useEffect(() => { const loadSettings = async () => { try { const response = await fetch( `${API_BASE_URL}/v1/system/settings/integrations/image_generation/`, { credentials: 'include' } ); if (response.ok) { const data = await response.json(); if (data.success && data.data) { setImageSettings(data.data); } } } catch (error) { console.error('Error loading image settings:', error); } }; loadSettings(); }, [API_BASE_URL, enabled]); // Reload when enabled changes const handleToggle = (newEnabled: boolean) => { persistentToggle.toggle(newEnabled); }; // Get provider and model display text const getProviderModelText = () => { const service = imageSettings.service || 'openai'; if (service === 'openai') { const model = imageSettings.model || 'dall-e-3'; const modelNames: Record = { 'dall-e-3': 'DALL·E 3', 'dall-e-2': 'DALL·E 2', 'gpt-image-1': 'GPT Image 1 (Full)', 'gpt-image-1-mini': 'GPT Image 1 Mini', }; return `OpenAI ${modelNames[model] || model}`; } else if (service === 'runware') { const model = imageSettings.runwareModel || 'runware:97@1'; // Map model ID to display name const modelDisplayNames: Record = { 'runware:97@1': 'HiDream-I1 Full', 'runware:gen3a_turbo': 'Gen3a Turbo', 'runware:gen3a': 'Gen3a', }; const displayName = modelDisplayNames[model] || model; return `Runware ${displayName}`; } return 'Not configured'; }; // Get text color based on provider and status const getTextColor = () => { const service = imageSettings.service || 'openai'; const isConfigured = service && (imageSettings.model || imageSettings.runwareModel); // Grey if not configured or pending if (!isConfigured || validationStatus === 'not_configured' || validationStatus === 'pending') { return 'text-gray-400 dark:text-gray-500'; } // Black for both OpenAI and Runware when configured return 'text-black dark:text-white'; }; return (
{icon}

{title}

{description}

{/* Provider + Model Text - Same size as heading */}

{getProviderModelText()}

); }