const { useState, useEffect, useRef } = React; // --- Configuración --- const API_URL = 'https://tryon.likemedia.ai/api_proxy.php'; // Apunta al backend principal const STORAGE_KEY = 'lm_tryon_history_v3'; const MOCK_MODE = false; // Set true para probar sin backend // --- Componentes UI --- const Header = () => (

Probador Virtual IA

Sube tus fotos y visualiza el resultado en segundos

); const Dropzone = ({ label, icon, onFile, preview }) => { const inputRef = useRef(null); const handleFile = (e) => { const file = e.target.files[0]; if (file) onFile(file); }; return (
{label}
inputRef.current.click()} className={` border-2 border-dashed rounded-xl h-48 flex flex-col items-center justify-center cursor-pointer transition-all duration-200 relative overflow-hidden group ${preview ? 'border-indigo-500 bg-indigo-50' : 'border-slate-300 hover:border-indigo-400 hover:bg-slate-50 bg-white'} `} > {preview ? ( Preview ) : (
{icon}

Click para subir

)}
); }; const RatioSelect = ({ value, onChange }) => (
); const ResultCard = ({ item, onDelete }) => { const [isHovered, setIsHovered] = useState(false); // Fallback híbrido de descarga (Logic Copied from V1.9) const handleDownload = async () => { const url = item.url || item.urlimagen; const filename = `tryon_${item.id}.png`; try { const response = await fetch(url); const blob = await response.blob(); const blobUrl = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = blobUrl; link.download = filename; document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(blobUrl); } catch (e) { console.warn("Direct download failed, using proxy", e); const downloadBase = API_URL.substring(0, API_URL.lastIndexOf('/')); window.location.href = `${downloadBase}/download_image.php?url=${encodeURIComponent(url)}`; } }; return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > Resultado {/* Overlay */}
{new Date(item.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
); }; // --- Main App --- const App = () => { // State const [personFile, setPersonFile] = useState(null); const [clothFile, setClothFile] = useState(null); const [ratio, setRatio] = useState('1:1'); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [history, setHistory] = useState([]); // Load History on Mount useEffect(() => { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { try { const parsed = JSON.parse(saved); if (Array.isArray(parsed)) setHistory(parsed); } catch (e) { console.error("History load error", e); } } }, []); // Save History on Change useEffect(() => { localStorage.setItem(STORAGE_KEY, JSON.stringify(history)); }, [history]); // --- B2B Contextual Loader --- const [isContextMode, setIsContextMode] = useState(false); useEffect(() => { const container = document.getElementById('tryon-widget-container-react'); const contextUrl = container?.getAttribute('data-product-image'); if (contextUrl) { setIsContextMode(true); setLoading(true); // Show loading while fetching context image // Fetch the image and convert to File to mimic user upload fetch(contextUrl) .then(res => res.blob()) .then(blob => { const file = new File([blob], "product_context.jpg", { type: blob.type }); setClothFile(file); // Also define a preview property on the file for the Dropzone to show it (if we were showing it) // But usually Dropzone takes the file and creates objectURL. // We can just rely on normal Dropzone behavior or custom UI. }) .catch(err => console.error("Error loading context product:", err)) .finally(() => setLoading(false)); } }, []); const handleClearHistory = () => { if (confirm('¿Seguro que quieres borrar todo el historial?')) { setHistory([]); } }; const handleDeleteItem = (id) => { if (confirm('¿Eliminar esta imagen?')) { setHistory(prev => prev.filter(item => item.id !== id)); } }; const handleGenerate = async () => { if (!personFile || !clothFile) { setError("Por favor sube ambas imágenes"); return; } setError(null); setLoading(true); const formData = new FormData(); formData.append('action', 'tryon'); formData.append('api_key', 'TEST-KEY-123'); // Debería venir de config formData.append('user_email', 'react_tester@example.com'); formData.append('prefijo_tabla', 'react_beta'); formData.append('image_ratio', ratio); formData.append('num_images', '1'); formData.append('imagen_modelo', personFile); formData.append('imagen_accesorio', clothFile); try { if (MOCK_MODE) { // Simulation await new Promise(r => setTimeout(r, 2000)); const mockItem = { id: Date.now().toString(), url: 'https://via.placeholder.com/600x800', timestamp: Date.now() }; setHistory(prev => [mockItem, ...prev]); } else { // Real API const response = await fetch(API_URL, { method: 'POST', headers: { 'X-Api-Key': 'TEST-KEY-123' }, body: formData }); if (!response.ok) throw new Error("Error en el servidor"); const result = await response.json(); const imageUrl = result.url || result.urlimagen || (Array.isArray(result) ? result[0].urlimagen : null); if (imageUrl) { const newItem = { id: Date.now().toString(), url: imageUrl, timestamp: Date.now() }; setHistory(prev => [newItem, ...prev]); } else { throw new Error("No se recibió imagen válida"); } } } catch (err) { setError(err.message || "Error desconocido"); } finally { setLoading(false); } }; return (
{/* Context Mode: Show Product Card instead of Dropzone */} {isContextMode ? (
PRODUCTO DE TIENDA
{clothFile ? ( Producto ) : (
Cargando producto...
)}

Prenda lista

) : ( )}
{error && (
{error}
)}
{/* Results Section */} {history.length > 0 && (

Resultados {history.length}

{history.length > 0 && ( )}
{history.map(item => ( ))}
)}
); }; // Render // Render const initWidget = () => { const container = document.getElementById('tryon-widget-container-react') || document.getElementById('root'); if (container) { const root = ReactDOM.createRoot(container); root.render(); } else { console.error("TryOn Widget: Target container not found!"); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initWidget); } else { initWidget(); }