import { getGeneratedImages } from '@/utils/ai/getGeneratedImages'; import { uploadGeneratedImageToMediaLibrary, refreshMediaLibrary } from '@/utils/ai/uploadGeneratedImage'; import { __, _n, sprintf } from '@wordpress/i18n'; import { Button, TextareaControl, __experimentalGrid as Grid } from '@wordpress/components'; import { hideLoadingMessage, showLoadingMessage, showNotice, useAIPlugin } from '@/utils'; import { useState, useEffect } from '@wordpress/element'; import { useSettings } from '@/settings'; import { useSelect } from '@wordpress/data'; import AIServiceNotice from '@/components/aiServiceNotice'; import { useService } from '@/utils/ai/services/useService'; type ImportedImage = { url: string; id?: number; }; type Props = { callback?: (image?: ImportedImage) => void; insertMode?: boolean; }; const GenerateImgTabView = ({ callback, insertMode = false }: Props) => { const [prompt, setPrompt] = useState(''); const [generatedImages, setGeneratedImages] = useState([]); const [selectedIndexes, setSelectedIndexes] = useState([]); const [loading, setLoading] = useState(false); const [importing, setImporting] = useState(false); const { settings } = useSettings(); const aiPlugin = useAIPlugin(); const service = useService('generate_image_prompt_service'); // @ts-expect-error Type 'never' has no call signatures. const AIService = useSelect((select) => select(aiPlugin?.ai?.store)?.getAvailableService(), [aiPlugin]); const handleGenerate = async () => { setLoading(true); showLoadingMessage(__('AI Images', 'filter-ai')); try { const generateImages = await getGeneratedImages(prompt, service?.slug); setGeneratedImages(generateImages); setSelectedIndexes([]); } catch (error) { console.error('Failed to generate images:', error); showNotice({ // @ts-expect-error Property 'message' does not exist on type '{}' message: sprintf(__('Error: %s', 'filter-ai'), error?.message || error), type: 'error', }); } finally { setLoading(false); hideLoadingMessage(); } }; const toggleSelectImage = (index: number) => { if (insertMode) { setSelectedIndexes([index]); } else { setSelectedIndexes((prev) => (prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index])); } }; const handleImportSelected = async () => { if (selectedIndexes.length === 0) { showNotice({ message: __('Please select at least one image to import', 'filter-ai'), type: 'error', }); return; } setImporting(true); showLoadingMessage(__('Images', 'filter-ai'), 'importing'); try { const imported = (await Promise.all( selectedIndexes.map((index) => uploadGeneratedImageToMediaLibrary(generatedImages[index], `filter-ai-image-${index + 1}`, prompt) ) ).catch((error) => { throw new Error(error?.message || error); })) as ImportedImage[]; refreshMediaLibrary(); if (insertMode && callback && imported.length > 0) { const firstImage = imported[0]; callback(firstImage); } else { callback?.(); } showNotice({ message: sprintf( _n(`Successfully imported %d image.`, `Successfully imported %d images.`, imported.length, 'filter-ai'), imported.length ), type: 'notice', }); } catch (error) { showNotice({ // @ts-expect-error Property 'message' does not exist on type '{}' message: sprintf(__('Import failed: %s', 'filter-ai'), error?.message || error), type: 'error', }); } finally { setImporting(false); hideLoadingMessage(); } }; useEffect(() => { const modal = document.querySelector('.filter-ai-generator-modal') as HTMLDivElement; if (!modal) { return; } if (loading || importing) { modal.style.display = 'none'; } else { modal.style.display = ''; } }, [loading, importing]); if (!settings?.generate_image_enabled) { return null; } return ( <>

{__('Enter a prompt to generate images', 'filter-ai')}

{__( 'Be specific by clearly defining the subject of the image, provide context of where the subject is or what they are doing and indicate the desired style and mood you would like your image to have.', 'filter-ai' )}

{insertMode ? __('Once your images are generated, select one to insert into your block.', 'filter-ai') : __( 'Once your images are generated, you can choose one or more of those to import into your Media Library.', 'filter-ai' )}

{generatedImages.length > 0 && ( <>

{insertMode ? __('Select an image to insert', 'filter-ai') : __('Select images to import', 'filter-ai')}

{generatedImages.map((img, i) => { const isSelected = selectedIndexes.includes(i); return ( ); })} )}
); }; export default GenerateImgTabView;