import React, { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; // Simple toast replacement const useToast = () => ({ toast: ({ title, description, variant }: { title: string; description: string; variant?: string }) => { if (variant === 'destructive') { alert(`Error: ${title}\n${description}`); } else { alert(`${title}\n${description}`); } } }); interface ImageData { id: number; url: string; preview_url: string; width?: number; height?: number; } interface LLMImage { id: number; position: 'before' | 'after'; } interface MultipleImageSelectorProps { currentImages: LLMImage[]; onImagesChange: (images: LLMImage[]) => void; isPremium: boolean; } export function MultipleImageSelector({ currentImages, onImagesChange, isPremium }: MultipleImageSelectorProps) { const { toast } = useToast(); const [isUploading, setIsUploading] = useState(false); const [imageDataCache, setImageDataCache] = useState<{ [key: number]: ImageData }>({}); // Load image data for display React.useEffect(() => { const loadImageData = async () => { for (const image of currentImages) { if (!imageDataCache[image.id]) { // In a real implementation, you'd fetch image data from WordPress // For now, we'll use the wp.media library or AJAX calls const attachment = wp.media.attachment(image.id); attachment.fetch().then(() => { const data = { id: image.id, url: attachment.get('url'), preview_url: attachment.get('sizes')?.medium?.url || attachment.get('url'), width: attachment.get('width'), height: attachment.get('height'), }; setImageDataCache(prev => ({ ...prev, [image.id]: data })); }); } } }; if (currentImages.length > 0) { loadImageData(); } }, [currentImages]); const handleFileUpload = async (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (!file) return; if (!file.type.startsWith('image/')) { toast({ title: "Error", description: "Please select an image file.", variant: "destructive", }); return; } setIsUploading(true); try { const formData = new FormData(); formData.append('action', 'llmagnet_ai_seo_upload_image'); formData.append('nonce', (window as any).llmagnetDashboardData?.nonce || ''); formData.append('image', file); const response = await fetch((window as any).llmagnetDashboardData?.ajaxUrl || '/wp-admin/admin-ajax.php', { method: 'POST', body: formData, credentials: 'same-origin', }); const result = await response.json(); if (result.success) { const newImage: LLMImage = { id: result.data.attachment_id, position: 'after' }; const newImages = [...currentImages, newImage]; onImagesChange(newImages); // Cache the image data setImageDataCache(prev => ({ ...prev, [result.data.attachment_id]: result.data })); toast({ title: "Success", description: "Image uploaded successfully!", }); } else { toast({ title: "Upload Error", description: result.data?.message || "Failed to upload image.", variant: "destructive", }); } } catch (error) { console.error('Upload error:', error); toast({ title: "Upload Error", description: "An error occurred while uploading the image.", variant: "destructive", }); } finally { setIsUploading(false); // Reset the input event.target.value = ''; } }; const openMediaLibrary = () => { if (typeof wp !== 'undefined' && wp.media) { const mediaUploader = wp.media({ title: 'Select LLM Response Images', button: { text: 'Select Images' }, multiple: true }); mediaUploader.on('select', () => { const attachments = mediaUploader.state().get('selection').toJSON(); const newImages: LLMImage[] = []; const newImageData: { [key: number]: ImageData } = {}; attachments.forEach((attachment: any) => { newImages.push({ id: attachment.id, position: 'after' }); newImageData[attachment.id] = { id: attachment.id, url: attachment.url, preview_url: attachment.sizes?.medium?.url || attachment.url, width: attachment.width, height: attachment.height, }; }); const updatedImages = [...currentImages, ...newImages]; onImagesChange(updatedImages); setImageDataCache(prev => ({ ...prev, ...newImageData })); toast({ title: "Success", description: `${attachments.length} image(s) selected successfully!`, }); }); mediaUploader.open(); } }; const handleRemoveImage = (imageId: number) => { const updatedImages = currentImages.filter(img => img.id !== imageId); onImagesChange(updatedImages); // Remove from cache setImageDataCache(prev => { const newCache = { ...prev }; delete newCache[imageId]; return newCache; }); toast({ title: "Success", description: "Image removed successfully!", }); }; const handlePositionChange = (imageId: number, position: 'before' | 'after') => { const updatedImages = currentImages.map(img => img.id === imageId ? { ...img, position } : img ); onImagesChange(updatedImages); }; if (!isPremium) { return (

LLM Response Images (Premium Feature)

Attach multiple images that will be displayed with responses from all Large Language Models (ChatGPT, Claude, Gemini, GPT-4, etc.) and included in the llms.txt file.

Premium Feature: This feature is available for premium users only. Upgrade to attach multiple images to your LLM responses.
); } return (
{/* Current Images */} {currentImages.length > 0 && (

Current Images ({currentImages.length})

{currentImages.map((image, index) => { const imageData = imageDataCache[image.id]; return (
{imageData && (
{`LLM
{index + 1}
)}
Image {index + 1}
{imageData && (
{imageData.width} × {imageData.height}px
)}
); })}
)} {/* Add New Images */}

Add New Images

You can select multiple images from the media library or upload them one by one.

); }