import React, { useState, useCallback, useRef, useEffect } from 'react'; import { HiExclamationTriangle, HiEye } from 'react-icons/hi2'; import Typography from '../../../ui/Typography'; import { useBlockTesterStore } from '../../../../stores/blockTesterStore'; import { useConfigStore } from '../../../../stores/configStore'; import { AttributeSchema } from '../../../../types/block-tester.types'; import { cn } from '../../../../lib/utils'; import PreviewControls from './PreviewControls'; import * as Handlebars from 'handlebars'; import { Logger } from '@hashgraphonline/standards-sdk'; interface BlockPreviewProps { className?: string; } const logger = new Logger({ module: 'BlockPreviewDirect' }); const BlockPreviewDirect: React.FC = ({ className }) => { const { currentBlock, template, attributes, actions: _actions, previewMode, addError } = useBlockTesterStore(); const { config } = useConfigStore(); const isDarkMode = config?.advanced?.theme === 'dark'; const [renderedContent, setRenderedContent] = useState(''); const [isLoading, setIsLoading] = useState(false); const [_lastRefresh, __setLastRefresh] = useState(Date.now()); const contentRef = useRef(null); const scriptsExecutedRef = useRef(false); const getViewportDimensions = (mode: string) => { switch (mode) { case 'mobile': return { width: 375, height: 667 }; case 'tablet': return { width: 768, height: 1024 }; case 'desktop': default: return { width: 1200, height: 800 }; } }; const processTemplate = useCallback((templateStr: string, attributeValues: Record) => { try { const template = Handlebars.compile(templateStr); const context = { content: 'Sample content', ...attributeValues }; const rendered = template(context); return rendered; } catch (error: unknown) { logger.error('Handlebars template processing error:', error); throw new Error(`Template processing failed: ${error instanceof Error ? error.message : String(error)}`); } }, []); const generatePreviewContent = useCallback(async () => { if (!currentBlock || !template) { setRenderedContent(''); return; } try { setIsLoading(true); const attributeValues = Object.entries(attributes).reduce((acc, [key, attr]) => { const attrData = attr as { schema?: AttributeSchema; value?: unknown; defaultValue?: unknown }; acc[key] = attrData.value || attrData.defaultValue || ''; return acc; }, {} as Record); const processedContent = processTemplate(template, attributeValues); setRenderedContent(processedContent); scriptsExecutedRef.current = false; } catch (error: unknown) { logger.error('Preview generation error:', error); addError({ type: 'preview', source: 'preview', message: `Preview generation failed: ${error instanceof Error ? error.message : String(error)}` }); setRenderedContent(`

Preview Error

${error instanceof Error ? error.message : String(error)}

`); } finally { setIsLoading(false); } }, [currentBlock, template, attributes, isDarkMode, processTemplate, addError]); const debounce = (func: (...args: unknown[]) => void, wait: number) => { let timeout: NodeJS.Timeout; return function executedFunction(...args: unknown[]) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }; const debouncedGenerate = useCallback( debounce(generatePreviewContent, 300), [generatePreviewContent] ); useEffect(() => { debouncedGenerate(); }, [template, attributes, currentBlock, previewMode, isDarkMode, debouncedGenerate]); useEffect(() => { if (renderedContent && contentRef.current && !scriptsExecutedRef.current) { logger.info('Executing scripts in block preview'); const tempDiv = document.createElement('div'); tempDiv.innerHTML = renderedContent; const scripts = tempDiv.querySelectorAll('script'); logger.info(`Found ${scripts.length} script tags in template`); scripts.forEach((script, index) => { const newScript = document.createElement('script'); Array.from(script.attributes).forEach((attr) => { newScript.setAttribute(attr.name, attr.value); }); try { const scriptContent = script.textContent || ''; const wrappedScript = ` (function() { 'use strict'; try { ${scriptContent} } catch (error) { logger.error('Script execution error in block preview:', error); } })(); `; newScript.textContent = wrappedScript; contentRef.current?.appendChild(newScript); logger.info(`Script ${index + 1} executed successfully`); setTimeout(() => { newScript.remove(); }, 0); } catch (error) { logger.error(`Failed to execute script ${index + 1}:`, error); } }); scriptsExecutedRef.current = true; } }, [renderedContent]); const handleRefresh = () => { __setLastRefresh(Date.now()); generatePreviewContent(); }; const handleOpenInNewWindow = () => { if (renderedContent) { const fullHTML = ` Block Preview - ${currentBlock?.name || 'Untitled'}