Files
roi-theme/Public/CtaPost/Infrastructure/Ui/CtaPostRenderer.php
FrankZamora ffe6ea8e65 feat(visibility): añadir opción "Ocultar para usuarios logueados" (Plan 99.16)
- Crear UserVisibilityHelper centralizado en Shared/Infrastructure/Services
- Añadir campo hide_for_logged_in en schemas de 4 componentes
- Integrar validación en Renderers: TopBar, LetsTalk, CTASidebar, CTAPost
- Añadir checkbox UI en FormBuilders de los 4 componentes
- Refactorizar adsense-placement.php para usar el helper centralizado
- Deprecar función roi_should_hide_for_logged_in() (backwards compatible)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 18:28:53 -06:00

192 lines
6.5 KiB
PHP

<?php
declare(strict_types=1);
namespace ROITheme\Public\CtaPost\Infrastructure\Ui;
use ROITheme\Shared\Domain\Contracts\RendererInterface;
use ROITheme\Shared\Domain\Contracts\CSSGeneratorInterface;
use ROITheme\Shared\Domain\Entities\Component;
use ROITheme\Shared\Infrastructure\Services\PageVisibilityHelper;
use ROITheme\Shared\Infrastructure\Services\UserVisibilityHelper;
/**
* CtaPostRenderer - Renderiza CTA promocional debajo del contenido
*
* RESPONSABILIDAD: Generar HTML y CSS del componente CTA Post
*
* CARACTERISTICAS:
* - Gradiente configurable
* - Layout responsive (2 columnas en desktop)
* - Boton CTA con icono
* - Estilos 100% desde BD via CSSGenerator
*
* @package ROITheme\Public\CtaPost\Infrastructure\Ui
*/
final class CtaPostRenderer implements RendererInterface
{
private const COMPONENT_NAME = 'cta-post';
public function __construct(
private CSSGeneratorInterface $cssGenerator
) {}
public function render(Component $component): string
{
$data = $component->getData();
if (!$this->isEnabled($data)) {
return '';
}
if (!PageVisibilityHelper::shouldShow(self::COMPONENT_NAME)) {
return '';
}
// Validar visibilidad por usuario logueado
if (!UserVisibilityHelper::shouldShowForUser($data['visibility'] ?? [])) {
return '';
}
$css = $this->generateCSS($data);
$html = $this->buildHTML($data);
return sprintf("<style>%s</style>\n%s", $css, $html);
}
public function supports(string $componentType): bool
{
return $componentType === self::COMPONENT_NAME;
}
private function isEnabled(array $data): bool
{
$value = $data['visibility']['is_enabled'] ?? false;
return $value === true || $value === '1' || $value === 1;
}
private function generateCSS(array $data): string
{
$colors = $data['colors'] ?? [];
$effects = $data['visual_effects'] ?? [];
$spacing = $data['spacing'] ?? [];
$visibility = $data['visibility'] ?? [];
$cssRules = [];
// Container values
$gradientStart = $colors['gradient_start'] ?? '#FF8600';
$gradientEnd = $colors['gradient_end'] ?? '#FFB800';
$gradientAngle = $effects['gradient_angle'] ?? '135deg';
$borderRadius = $effects['border_radius'] ?? '12px';
$boxShadow = $effects['box_shadow'] ?? '0 8px 24px rgba(255, 133, 0, 0.3)';
$containerPadding = $spacing['container_padding'] ?? '2rem';
// Button values
$buttonBgColor = $colors['button_bg_color'] ?? '#FF8600';
$buttonTextColor = $colors['button_text_color'] ?? '#ffffff';
$buttonHoverBgColor = $colors['button_hover_bg'] ?? '#e67a00';
$buttonBorderRadius = $effects['button_border_radius'] ?? '8px';
// Container - gradient background with box-shadow and border-radius
$cssRules[] = $this->cssGenerator->generate('.cta-post-container', [
'background' => "linear-gradient({$gradientAngle}, {$gradientStart} 0%, {$gradientEnd} 100%)",
'box-shadow' => $boxShadow,
'border-radius' => $borderRadius,
'padding' => $containerPadding,
]);
// Button styles (matching template .cta-button) - Using !important to override Bootstrap btn-light
$cssRules[] = ".cta-post-container .cta-button {
background-color: {$buttonBgColor} !important;
color: {$buttonTextColor} !important;
font-weight: 600;
padding: 0.75rem 2rem;
border: none !important;
border-radius: {$buttonBorderRadius};
transition: all 0.3s ease;
text-decoration: none;
display: inline-block;
}";
// Button hover state
$cssRules[] = ".cta-post-container .cta-button:hover {
background-color: {$buttonHoverBgColor};
color: {$buttonTextColor};
}";
// Responsive: button full width on mobile
$cssRules[] = "@media (max-width: 768px) {
.cta-post-container .cta-button {
width: 100%;
margin-top: 1rem;
}
}";
// Responsive visibility
$showOnDesktop = $visibility['show_on_desktop'] ?? true;
$showOnDesktop = $showOnDesktop === true || $showOnDesktop === '1' || $showOnDesktop === 1;
$showOnMobile = $visibility['show_on_mobile'] ?? true;
$showOnMobile = $showOnMobile === true || $showOnMobile === '1' || $showOnMobile === 1;
if (!$showOnMobile) {
$cssRules[] = "@media (max-width: 991.98px) {
.cta-post-container { display: none !important; }
}";
}
if (!$showOnDesktop) {
$cssRules[] = "@media (min-width: 992px) {
.cta-post-container { display: none !important; }
}";
}
return implode("\n", $cssRules);
}
private function buildHTML(array $data): string
{
$content = $data['content'] ?? [];
$title = $content['title'] ?? 'Accede a 200,000+ Análisis de Precios Unitarios';
$description = $content['description'] ?? '';
$buttonText = $content['button_text'] ?? 'Ver Catálogo Completo';
$buttonUrl = $content['button_url'] ?? '#';
$buttonIcon = $content['button_icon'] ?? 'bi-arrow-right';
$html = '<div class="my-5 cta-post-container">';
$html .= ' <div class="row align-items-center">';
// Left column - Content
$html .= ' <div class="col-md-8">';
$html .= sprintf(
' <h3 class="h4 fw-bold text-white mb-2">%s</h3>',
esc_html($title)
);
if (!empty($description)) {
$html .= sprintf(
' <p class="text-white mb-md-0">%s</p>',
esc_html($description)
);
}
$html .= ' </div>';
// Right column - Button
$html .= ' <div class="col-md-4 text-md-end mt-3 mt-md-0">';
$html .= sprintf(
' <a href="%s" class="cta-button">%s',
esc_url($buttonUrl),
esc_html($buttonText)
);
if (!empty($buttonIcon)) {
$html .= sprintf(' <i class="bi %s ms-2"></i>', esc_attr($buttonIcon));
}
$html .= '</a>';
$html .= ' </div>';
$html .= ' </div>';
$html .= '</div>';
return $html;
}
}