Spaces:
Sleeping
Sleeping
| namespace SoftEdge; | |
| /** | |
| * React Loader class for integrating React components with PHP | |
| */ | |
| class ReactLoader | |
| { | |
| private string $buildPath; | |
| private string $publicPath; | |
| private array $manifest = []; | |
| public function __construct() | |
| { | |
| $this->buildPath = __DIR__ . '/../dist'; | |
| $this->publicPath = '/dist'; | |
| // Load manifest if it exists | |
| $this->loadManifest(); | |
| } | |
| /** | |
| * Load webpack manifest for asset management | |
| */ | |
| private function loadManifest(): void | |
| { | |
| $manifestPath = $this->buildPath . '/static/js/manifest.json'; | |
| if (file_exists($manifestPath)) { | |
| $manifest = json_decode(file_get_contents($manifestPath), true); | |
| $this->manifest = $manifest ?: []; | |
| } | |
| } | |
| /** | |
| * Check if React build exists | |
| */ | |
| public function isBuilt(): bool | |
| { | |
| return file_exists($this->buildPath . '/static/js/bundle.js') && | |
| file_exists($this->buildPath . '/static/css/main.css'); | |
| } | |
| /** | |
| * Get JavaScript bundle URL | |
| */ | |
| public function getJsBundle(): string | |
| { | |
| if (isset($this->manifest['main.js'])) { | |
| return $this->publicPath . '/' . $this->manifest['main.js']; | |
| } | |
| return $this->publicPath . '/static/js/bundle.js'; | |
| } | |
| /** | |
| * Get CSS bundle URL | |
| */ | |
| public function getCssBundle(): string | |
| { | |
| if (isset($this->manifest['main.css'])) { | |
| return $this->publicPath . '/' . $this->manifest['main.css']; | |
| } | |
| return $this->publicPath . '/static/css/main.css'; | |
| } | |
| /** | |
| * Render React root element | |
| */ | |
| public function renderRoot(string $elementId = 'react-app', array $props = []): string | |
| { | |
| $propsJson = json_encode($props, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); | |
| return "<div id=\"{$elementId}\" data-react-props=\"{$propsJson}\"></div>"; | |
| } | |
| /** | |
| * Render React scripts | |
| */ | |
| public function renderScripts(): string | |
| { | |
| if (!$this->isBuilt()) { | |
| return $this->renderFallbackScripts(); | |
| } | |
| $jsUrl = $this->getJsBundle(); | |
| $cssUrl = $this->getCssBundle(); | |
| $scripts = []; | |
| // CSS | |
| if (file_exists($this->buildPath . str_replace($this->publicPath, '', $cssUrl))) { | |
| $scripts[] = "<link rel=\"stylesheet\" href=\"{$cssUrl}\">"; | |
| } | |
| // JavaScript | |
| $scripts[] = "<script src=\"{$jsUrl}\"></script>"; | |
| return implode("\n", $scripts); | |
| } | |
| /** | |
| * Render fallback scripts when React is not built | |
| */ | |
| private function renderFallbackScripts(): string | |
| { | |
| return "<!-- React not built - run 'npm run build' to enable React components -->"; | |
| } | |
| /** | |
| * Initialize React app with props | |
| */ | |
| public function initApp(string $elementId = 'react-app', array $props = []): string | |
| { | |
| $propsJson = json_encode($props, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); | |
| $script = <<<JS | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const element = document.getElementById('{$elementId}'); | |
| if (element && window.React && window.ReactDOM) { | |
| const props = {$propsJson}; | |
| // React app will be initialized here | |
| console.log('React app initialized with props:', props); | |
| } | |
| }); | |
| </script> | |
| JS; | |
| return $script; | |
| } | |
| /** | |
| * Get React component HTML | |
| */ | |
| public function getComponentHtml(string $componentName, array $props = []): string | |
| { | |
| if (!$this->isBuilt()) { | |
| return $this->getFallbackHtml($componentName, $props); | |
| } | |
| // In a real implementation, this would render the component server-side | |
| // For now, return a placeholder that will be hydrated by React | |
| $propsJson = json_encode($props, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); | |
| return "<div data-react-component=\"{$componentName}\" data-props=\"{$propsJson}\">Loading...</div>"; | |
| } | |
| /** | |
| * Get fallback HTML when React is not available | |
| */ | |
| private function getFallbackHtml(string $componentName, array $props = []): string | |
| { | |
| switch ($componentName) { | |
| case 'App': | |
| return $this->getAppFallbackHtml($props); | |
| case 'Navigation': | |
| return $this->getNavigationFallbackHtml($props); | |
| case 'ContactForm': | |
| return $this->getContactFormFallbackHtml($props); | |
| default: | |
| return "<div class=\"react-fallback\">Component: {$componentName}</div>"; | |
| } | |
| } | |
| /** | |
| * Get app fallback HTML | |
| */ | |
| private function getAppFallbackHtml(array $props = []): string | |
| { | |
| return <<<HTML | |
| <div class="react-app-fallback"> | |
| <div class="react-container"> | |
| <div class="react-header"> | |
| <h3>🚀 SoftEdge Corporation - React Integration</h3> | |
| <p>Componentes React não disponíveis. Execute 'npm run build' para ativar.</p> | |
| </div> | |
| <div class="react-content"> | |
| <p>Para ativar a aplicação React completa:</p> | |
| <code>npm install && npm run build</code> | |
| </div> | |
| </div> | |
| </div> | |
| HTML; | |
| } | |
| /** | |
| * Get navigation fallback HTML | |
| */ | |
| private function getNavigationFallbackHtml(array $props = []): string | |
| { | |
| $currentSection = $props['currentSection'] ?? 'home'; | |
| $sections = [ | |
| ['id' => 'home', 'label' => 'Início', 'icon' => '🏠'], | |
| ['id' => 'services', 'label' => 'Serviços', 'icon' => '⚙️'], | |
| ['id' => 'projects', 'label' => 'Projetos', 'icon' => '📁'], | |
| ['id' => 'about', 'label' => 'Sobre', 'icon' => '👥'], | |
| ['id' => 'contact', 'label' => 'Contato', 'icon' => '📧'] | |
| ]; | |
| $navItems = ''; | |
| foreach ($sections as $section) { | |
| $active = $currentSection === $section['id'] ? 'active' : ''; | |
| $navItems .= "<button class=\"nav-item {$active}\">{$section['icon']} {$section['label']}</button>"; | |
| } | |
| return "<nav class=\"react-nav\">{$navItems}</nav>"; | |
| } | |
| /** | |
| * Get contact form fallback HTML | |
| */ | |
| private function getContactFormFallbackHtml(array $props = []): string | |
| { | |
| return <<<HTML | |
| <form class="contact-form" method="POST" action="/api.php?r=contact"> | |
| <div class="form-group"> | |
| <label for="nome">Nome</label> | |
| <input type="text" id="nome" name="nome" required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="email">Email</label> | |
| <input type="email" id="email" name="email" required> | |
| </div> | |
| <div class="form-group"> | |
| <label for="mensagem">Mensagem</label> | |
| <textarea id="mensagem" name="mensagem" rows="5" required></textarea> | |
| </div> | |
| <button type="submit" class="submit-btn">Enviar Mensagem</button> | |
| </form> | |
| HTML; | |
| } | |
| /** | |
| * Check if we should use fallback mode | |
| */ | |
| public function shouldUseFallback(): bool | |
| { | |
| return !$this->isBuilt() || isset($_GET['react_fallback']); | |
| } | |
| /** | |
| * Get build status information | |
| */ | |
| public function getBuildStatus(): array | |
| { | |
| return [ | |
| 'is_built' => $this->isBuilt(), | |
| 'build_path' => $this->buildPath, | |
| 'public_path' => $this->publicPath, | |
| 'has_manifest' => !empty($this->manifest), | |
| 'manifest_count' => count($this->manifest), | |
| ]; | |
| } | |
| } | |