This commit is contained in:
andre committed 2026-06-12 21:20:23 +01:00
1 parent e68d357177
commit 3e3382df57
65 files changed
+1836 -42

No files matched your search

+237
View File
@@ -0,0 +1,237 @@
<?php
// ── Event landing page ──────────────────────────────────────────────────────
// Branded, time-limited landing page reached at /evento/<slug> (see .htaccess).
// Visible to the public only while the event is live (db_events_active rule);
// logged-in staff may preview drafts/scheduled/expired events. Carries an
// optional lead-capture form that stores submissions in event_leads.
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/functions.php';
// Resolve any SSO session up front (mirrors _open.php) so the is_staff() preview
// gate below sees a logged-in admin. _open.php's later call then no-ops.
if (empty($_SESSION['user_id']) && identity_is_federated()) {
sso_resolve_session($pdo);
}
$slug = preg_replace('/[^a-z0-9\-]/', '', strtolower((string) ($_GET['slug'] ?? '')));
$event = $slug !== '' ? db_events_get_by_slug($pdo, $slug) : null;
// Gate: live for everyone, otherwise only staff (preview).
$can_view = $event && (events_is_live($event) || is_staff());
// ── Lead form submission (PRG) ──────────────────────────────────────────────
$lead_errors = [];
if ($can_view && $_SERVER['REQUEST_METHOD'] === 'POST') {
csrf_check();
$back = base_url('evento/' . rawurlencode($event['slug']));
// Honeypot: a filled "website" field means a bot — silently accept & drop.
if (trim((string) ($_POST['website'] ?? '')) !== '') {
header('Location: ' . $back . '?ok=1#inscricao');
exit;
}
// The exact wording the visitor consents to — stored for GDPR evidence.
$consent_text = 'Autorizo o contacto e o tratamento dos meus dados para efeitos desta inscrição, nos termos da Política de Privacidade.';
$lead = [
'name' => trim((string) ($_POST['lead_name'] ?? '')),
'email' => trim((string) ($_POST['lead_email'] ?? '')),
'phone' => trim((string) ($_POST['lead_phone'] ?? '')),
'message' => trim((string) ($_POST['lead_message'] ?? '')),
'consent' => !empty($_POST['lead_consent']) ? 1 : 0,
'consent_text' => $consent_text,
// First hop of X-Forwarded-For (behind the id.andmore.pt proxy), else peer.
'ip' => trim(explode(',', (string) ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? ''))[0]) ?: ($_SERVER['REMOTE_ADDR'] ?? ''),
'user_agent' => (string) ($_SERVER['HTTP_USER_AGENT'] ?? ''),
];
if ($lead['name'] === '') $lead_errors[] = 'Indica o teu nome.';
if ($lead['email'] === '' && $lead['phone'] === '') $lead_errors[] = 'Indica um email ou um telefone para te podermos contactar.';
if ($lead['email'] !== '' && !filter_var($lead['email'], FILTER_VALIDATE_EMAIL)) $lead_errors[] = 'O email indicado não é válido.';
if (!$lead['consent']) $lead_errors[] = 'É necessário aceitar o tratamento dos dados para enviar a inscrição.';
if (!$lead_errors) {
db_event_lead_create($pdo, (int) $event['e_id'], $lead);
header('Location: ' . $back . '?ok=1#inscricao');
exit;
}
// fall through and re-render with $lead_errors + the submitted $lead values
$lead_old = $lead;
}
// ── Not found / not visible ─────────────────────────────────────────────────
if (!$can_view) {
http_response_code(404);
$current_uri_2 = '';
require __DIR__ . '/_open.php';
?>
<section class="event-notfound" style="padding:160px 0 90px;text-align:center;">
<div class="container">
<h1 style="font-size:2.4rem;">Evento não encontrado</h1>
<p class="text-muted">Este evento pode já ter terminado ou o link estar incorreto.</p>
<a href="<?= base_url('/') ?>" class="site-btn mt-3">Voltar ao início</a>
</div>
</section>
<?php
echo view('footer');
return;
}
// ── Visible: render the landing page ────────────────────────────────────────
$is_preview = !events_is_live($event);
$hero_url = $event['hero_image'] !== '' ? base_url('uploads/events/' . rawurlencode($event['hero_image'])) : '';
$accent = $event['cor'] !== '' ? $event['cor'] : '#C2D500';
// Human date line for the event window.
$date_line = '';
if (!empty($event['event_starts_at'])) {
$date_line = format_date_pt((string) $event['event_starts_at']);
if (!empty($event['event_ends_at'])
&& substr((string) $event['event_ends_at'], 0, 10) !== substr((string) $event['event_starts_at'], 0, 10)) {
$date_line .= ' – ' . format_date_pt((string) $event['event_ends_at']);
}
}
// CTA target: explicit URL, else the on-page form (when shown), else contacts.
$cta_label = trim((string) $event['cta_label']);
$cta_href = trim((string) $event['cta_url']);
if ($cta_href === '') {
$cta_href = ((int) $event['show_lead_form'] === 1) ? '#inscricao' : base_url('home/contactos');
}
// ── SEO ─────────────────────────────────────────────────────────────────────
// include.php / seo.php honour these globals when set before _open.php runs.
$event_url = base_url('evento/' . rawurlencode($event['slug']));
$seo_desc = $event['summary'] !== ''
? $event['summary']
: trim(mb_substr(strip_tags((string) ($event['subtitle'] ?: $event['description'])), 0, 200));
$current_uri_2 = 'evento';
$GLOBALS['_page_meta_override'] = [
($event['title'] !== '' ? $event['title'] : 'Evento') . ' | FitMe 3070',
$seo_desc,
];
$GLOBALS['_canonical_override'] = $event_url;
$GLOBALS['_og_type_override'] = 'article';
if ($hero_url !== '') $GLOBALS['_og_image_override'] = $hero_url;
// Event structured data (schema.org/Event) for rich link previews / search.
$info = site_info($pdo);
$ld_event = [
'@context' => 'https://schema.org',
'@type' => 'Event',
'name' => $event['title'],
'description' => $seo_desc !== '' ? $seo_desc : $event['title'],
'url' => $event_url,
'eventStatus' => 'https://schema.org/EventScheduled',
'eventAttendanceMode' => 'https://schema.org/OfflineEventAttendanceMode',
];
if ($hero_url !== '') $ld_event['image'] = [$hero_url];
if (!empty($event['event_starts_at'])) $ld_event['startDate'] = str_replace(' ', 'T', (string) $event['event_starts_at']);
if (!empty($event['event_ends_at'])) $ld_event['endDate'] = str_replace(' ', 'T', (string) $event['event_ends_at']);
$ld_event['location'] = $event['location'] !== ''
? ['@type' => 'Place', 'name' => $event['location']]
: ['@type' => 'Place',
'name' => ($info['name'] ?? '') !== '' ? $info['name'] : 'FitMe 3070',
'address' => $info['adress'] ?? ''];
$ld_event['organizer'] = [
'@type' => 'Organization',
'name' => ($info['name'] ?? '') !== '' ? $info['name'] : 'FitMe 3070',
'url' => base_url(),
];
$GLOBALS['_jsonld_extra'] = $ld_event;
require __DIR__ . '/_open.php';
?>
<?php if ($is_preview): ?>
<div class="event-preview-bar">Pré-visualização — este evento não está visível ao público (<?= htmlspecialchars(events_status($event)) ?>).</div>
<?php endif; ?>
<section class="event-hero set-bg<?= $hero_url ? '' : ' event-hero--plain' ?>"
<?= $hero_url ? 'style="background-image:url(\'' . htmlspecialchars($hero_url, ENT_QUOTES) . '\')"' : '' ?>>
<div class="event-hero-overlay"></div>
<div class="container">
<div class="event-hero-inner">
<span class="event-hero-eyebrow" style="color:<?= htmlspecialchars($accent, ENT_QUOTES) ?>">Evento</span>
<h1><?= htmlspecialchars($event['title']) ?></h1>
<?php if ($event['subtitle'] !== ''): ?><p class="event-hero-sub"><?= htmlspecialchars($event['subtitle']) ?></p><?php endif; ?>
<ul class="event-hero-meta">
<?php if ($date_line !== ''): ?><li><i class="fas fa-calendar-alt"></i> <?= htmlspecialchars($date_line) ?></li><?php endif; ?>
<?php if ($event['location'] !== ''): ?><li><i class="fas fa-map-marker-alt"></i> <?= htmlspecialchars($event['location']) ?></li><?php endif; ?>
</ul>
<?php if ($cta_label !== ''): ?>
<a href="<?= htmlspecialchars($cta_href, ENT_QUOTES) ?>" class="site-btn event-hero-cta"
style="background:<?= htmlspecialchars($accent, ENT_QUOTES) ?>"
<?= ($cta_href[0] ?? '') === '#' ? 'data-scroll' : '' ?>><?= htmlspecialchars($cta_label) ?></a>
<?php endif; ?>
</div>
</div>
</section>
<?php if (trim((string) $event['description']) !== ''): ?>
<section class="event-body">
<div class="container">
<div class="row justify-content-md-center">
<div class="col-lg-8">
<?php /* description is admin-authored HTML — sanitised allowlist HTML */ ?>
<?= clean_richtext($event['description']) ?>
</div>
</div>
</div>
</section>
<?php endif; ?>
<?php if ((int) $event['show_lead_form'] === 1): ?>
<section class="event-leadform" id="inscricao">
<div class="container">
<div class="row justify-content-md-center">
<div class="col-lg-7">
<div class="section-title text-center deco">
<span class="section-eyebrow">Participa</span>
<h2>Inscreve-te</h2>
<p class="section-subtitle">Deixa os teus dados e entramos em contacto.</p>
</div>
<?php if (isset($_GET['ok'])): ?>
<div class="event-alert event-alert--ok">Inscrição enviada com sucesso. Obrigado!</div>
<?php endif; ?>
<?php foreach ($lead_errors as $e): ?>
<div class="event-alert event-alert--err"><?= htmlspecialchars($e) ?></div>
<?php endforeach; ?>
<form method="POST" action="<?= base_url('evento/' . rawurlencode($event['slug'])) ?>#inscricao" class="event-form">
<?= csrf_field() ?>
<!-- honeypot: must stay empty -->
<input type="text" name="website" tabindex="-1" autocomplete="off" class="event-hp" aria-hidden="true">
<div class="event-form-grid">
<div class="event-field">
<label>Nome *</label>
<input type="text" name="lead_name" required maxlength="150" value="<?= htmlspecialchars($lead_old['name'] ?? '') ?>">
</div>
<div class="event-field">
<label>Telefone</label>
<input type="tel" name="lead_phone" maxlength="40" value="<?= htmlspecialchars($lead_old['phone'] ?? '') ?>">
</div>
<div class="event-field event-field--full">
<label>Email</label>
<input type="email" name="lead_email" maxlength="190" value="<?= htmlspecialchars($lead_old['email'] ?? '') ?>">
</div>
<div class="event-field event-field--full">
<label>Mensagem</label>
<textarea name="lead_message" rows="3" maxlength="1000"><?= htmlspecialchars($lead_old['message'] ?? '') ?></textarea>
</div>
</div>
<label class="event-consent">
<input type="checkbox" name="lead_consent" value="1" required <?= !empty($lead_old['consent']) ? 'checked' : '' ?>>
<span>Autorizo o contacto e o tratamento dos meus dados para esta inscrição, nos termos da <a href="<?= base_url('home/privacidade') ?>" target="_blank" rel="noopener">Política de Privacidade</a>.</span>
</label>
<div class="text-center mt-3">
<button type="submit" class="site-btn" style="background:<?= htmlspecialchars($accent, ENT_QUOTES) ?>">Enviar inscrição</button>
</div>
</form>
</div>
</div>
</div>
</section>
<?php endif; ?>
<?php
echo view('footer');