321 lines
16 KiB
PHP
321 lines
16 KiB
PHP
<?php
|
||
require_once 'db/config.php';
|
||
require_once 'mail/MailService.php';
|
||
|
||
// --- CONFIGURATION ---
|
||
$webinar_id = filter_input(INPUT_GET, 'webinar_id', FILTER_VALIDATE_INT);
|
||
$response = [];
|
||
|
||
// --- WEBINAR DETAILS ---
|
||
$webinar = null;
|
||
if ($webinar_id) {
|
||
try {
|
||
$stmt = db()->prepare("SELECT * FROM webinars WHERE id = ?");
|
||
$stmt->execute([$webinar_id]);
|
||
$webinar = $stmt->fetch();
|
||
} catch (PDOException $e) {
|
||
// Log error, but don't show to user
|
||
}
|
||
}
|
||
|
||
// --- FORM SUBMISSION (POST REQUEST) ---
|
||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||
header('Content-Type: application/json');
|
||
|
||
// --- DATA CAPTURE ---
|
||
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
|
||
$first_name = filter_input(INPUT_POST, 'first_name', FILTER_SANITIZE_STRING);
|
||
$last_name = filter_input(INPUT_POST, 'last_name', FILTER_SANITIZE_STRING);
|
||
$company = filter_input(INPUT_POST, 'company', FILTER_SANITIZE_STRING);
|
||
$how_did_you_hear = filter_input(INPUT_POST, 'how_did_you_hear', FILTER_SANITIZE_STRING);
|
||
$password = filter_input(INPUT_POST, 'password', FILTER_UNSAFE_RAW);
|
||
$confirm_password = filter_input(INPUT_POST, 'confirm_password', FILTER_UNSAFE_RAW);
|
||
$consent = filter_input(INPUT_POST, 'consent', FILTER_VALIDATE_BOOLEAN);
|
||
$timezone = filter_input(INPUT_POST, 'timezone', FILTER_SANITIZE_STRING);
|
||
|
||
// Tracking data
|
||
$utm_source = filter_input(INPUT_POST, 'utm_source', FILTER_SANITIZE_STRING);
|
||
$utm_medium = filter_input(INPUT_POST, 'utm_medium', FILTER_SANITIZE_STRING);
|
||
$utm_campaign = filter_input(INPUT_POST, 'utm_campaign', FILTER_SANITIZE_STRING);
|
||
$utm_term = filter_input(INPUT_POST, 'utm_term', FILTER_SANITIZE_STRING);
|
||
$utm_content = filter_input(INPUT_POST, 'utm_content', FILTER_SANITIZE_STRING);
|
||
$referrer = filter_input(INPUT_POST, 'referrer', FILTER_SANITIZE_STRING);
|
||
$gclid = filter_input(INPUT_POST, 'gclid', FILTER_SANITIZE_STRING);
|
||
$fbclid = filter_input(INPUT_POST, 'fbclid', FILTER_SANITIZE_STRING);
|
||
|
||
|
||
if (!$first_name || !$last_name || !$email) {
|
||
$response['error'] = 'Please fill out all required fields.';
|
||
echo json_encode($response);
|
||
exit;
|
||
}
|
||
|
||
if (!$consent || !$webinar) {
|
||
$response['error'] = 'Please agree to the terms.';
|
||
echo json_encode($response);
|
||
exit;
|
||
}
|
||
|
||
if ($password !== $confirm_password) {
|
||
$response['error'] = 'Passwords do not match.';
|
||
echo json_encode($response);
|
||
exit;
|
||
}
|
||
|
||
$password_hash = password_hash($password, PASSWORD_DEFAULT);
|
||
|
||
try {
|
||
// Check for duplicates
|
||
$stmt = db()->prepare("SELECT id FROM attendees WHERE webinar_id = ? AND email = ?");
|
||
$stmt->execute([$webinar_id, $email]);
|
||
if ($stmt->fetch()) {
|
||
$response['error'] = 'You are already registered for this webinar.';
|
||
echo json_encode($response);
|
||
exit;
|
||
}
|
||
|
||
// Insert attendee
|
||
$sql = "INSERT INTO attendees (webinar_id, first_name, last_name, email, company, how_did_you_hear, password, timezone, utm_source, utm_medium, utm_campaign, utm_term, utm_content, referrer, gclid, fbclid)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||
$stmt = db()->prepare($sql);
|
||
$stmt->execute([$webinar_id, $first_name, $last_name, $email, $company, $how_did_you_hear, $password_hash, $timezone, $utm_source, $utm_medium, $utm_campaign, $utm_term, $utm_content, $referrer, $gclid, $fbclid]);
|
||
$attendee_id = db()->lastInsertId();
|
||
|
||
// --- SEND CONFIRMATION EMAIL ---
|
||
$webinar_date = new DateTime($webinar['scheduled_at']);
|
||
$subject = "Confirmation: You're Registered for " . $webinar['title'];
|
||
|
||
$body_html = "<h1>You're in!</h1>"
|
||
. "<p>Thanks for registering for our webinar: <strong>{$webinar['title']}</strong>.</p>"
|
||
. "<p>It will take place on <strong>" . $webinar_date->format('l, F j, Y \a\t g:i A T') . "</strong>.</p>"
|
||
. "<p>You can now log in to your dashboard to see the details.</p>";
|
||
|
||
MailService::sendMail($email, $subject, $body_html);
|
||
|
||
$response['success'] = true;
|
||
$response['webinar_title'] = $webinar['title'];
|
||
$response['webinar_date_utc'] = $webinar['scheduled_at'];
|
||
|
||
|
||
} catch (PDOException $e) {
|
||
// Log error
|
||
$response['error'] = 'A database error occurred. Please try again later.';
|
||
} catch (Exception $e) {
|
||
// Log error
|
||
$response['error'] = 'An error occurred: ' . $e->getMessage();
|
||
}
|
||
|
||
echo json_encode($response);
|
||
exit;
|
||
}
|
||
|
||
// --- RENDER PAGE (GET REQUEST) ---
|
||
if (!$webinar) {
|
||
http_response_code(404);
|
||
echo "Webinar not found.";
|
||
exit;
|
||
}
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Register for <?= htmlspecialchars($webinar['title']) ?></title>
|
||
<style>
|
||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background-color: #1a202c; color: #e2e8f0; margin: 0; padding: 2rem; }
|
||
.container { max-width: 900px; margin: auto; display: grid; grid-template-columns: 1fr 1fr; gap: 4rem; align-items: start; }
|
||
.left-pane h1 { font-size: 2.5rem; color: #f6e05e; margin-bottom: 1rem; }
|
||
.left-pane .date-time { font-size: 1.25rem; font-weight: bold; margin-bottom: 1.5rem; }
|
||
.left-pane .value-prop { font-size: 1.1rem; color: #a0aec0; line-height: 1.6; }
|
||
.speakers { margin-top: 2rem; }
|
||
.speakers h3 { font-size: 1.2rem; color: #cbd5e0; margin-bottom: 1rem; }
|
||
.speaker { display: flex; align-items: center; margin-bottom: 1rem; }
|
||
.speaker img { width: 50px; height: 50px; border-radius: 50%; margin-right: 1rem; background-color: #4a5568; }
|
||
.form-card { background-color: #2d3748; border-radius: 0.5rem; padding: 2rem; border: 1px solid #4a5568; }
|
||
.form-card h2 { margin-top: 0; font-size: 1.5rem; color: #f6e05e; text-align: center; }
|
||
.form-group { margin-bottom: 1.5rem; }
|
||
label { display: block; margin-bottom: 0.5rem; font-weight: bold; }
|
||
input[type="email"], input[type="text"] { width: 100%; padding: 0.75rem; background-color: #1a202c; border: 1px solid #4a5568; border-radius: 0.375rem; color: #e2e8f0; font-size: 1rem; box-sizing: border-box; }
|
||
.consent-group { display: flex; align-items: start; gap: 0.75rem; }
|
||
.consent-group label { font-weight: normal; font-size: 0.9rem; color: #a0aec0; }
|
||
.microcopy { font-size: 0.8rem; color: #718096; margin-top: 0.5rem; }
|
||
.submit-btn { display: block; width: 100%; background-color: #f6e05e; color: #1a202c; padding: 0.85rem; border: none; border-radius: 0.375rem; font-weight: bold; font-size: 1.125rem; cursor: pointer; transition: background-color 0.2s; }
|
||
.submit-btn:hover { background-color: #f6d32d; }
|
||
.submit-btn:disabled { background-color: #4a5568; cursor: not-allowed; }
|
||
#form-result { margin-top: 1.5rem; text-align: center; }
|
||
.success-message { background-color: #2d3748; border: 1px solid #4a5568; padding: 2rem; border-radius: 0.5rem; }
|
||
.error-message { background-color: #c53030; padding: 1rem; border-radius: 0.375rem; }
|
||
.calendar-buttons a, .copy-link-btn { display: inline-block; background-color: #4a5568; color: #e2e8f0; padding: 0.75rem 1.5rem; border-radius: 0.375rem; text-decoration: none; margin: 0.5rem; font-weight: bold; }
|
||
@media (max-width: 768px) { .container { grid-template-columns: 1fr; } }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<header style="padding: 1rem;">
|
||
<a href="index.php" style="color: #1a202c; text-decoration: none; background-color: #f6e05e; padding: 0.75rem 1.5rem; border-radius: 0.375rem; font-weight: bold; font-size: 1.125rem;">Back to Home</a>
|
||
</header>
|
||
<div class="container">
|
||
<div class="left-pane">
|
||
<h1><?= htmlspecialchars($webinar['title']) ?></h1>
|
||
<div class="date-time" id="local-date-time">Loading date...</div>
|
||
<p class="value-prop"><?= htmlspecialchars($webinar['description']) ?></p>
|
||
<div class="speakers">
|
||
<h3>Speakers</h3>
|
||
<div class="speaker"><img src="assets/images/pexels/22601971.jpg" alt="Philip Daineka"> <span>Philip Daineka</span></div>
|
||
<div class="speaker"><img src="assets/images/pexels/34285016.jpg" alt="Alex Rubanau"> <span>Alex Rubanau</span></div>
|
||
<div class="speaker"><img src="assets/images/pexels/34238049.jpg" alt="Alexey Vertel"> <span>Alexey Vertel</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="right-pane">
|
||
<div id="registration-form-container">
|
||
<form id="registration-form" class="form-card" method="POST">
|
||
<h2>Register & Get Calendar Invite</h2>
|
||
<div class="form-group">
|
||
<label for="email">Email (required)</label>
|
||
<input type="email" id="email" name="email" required>
|
||
<p class="microcopy">We’ll send the join link & calendar invite.</p>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="first_name">First name (optional)</label>
|
||
<input type="text" id="first_name" name="first_name">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="password">Password</label>
|
||
<input type="password" id="password" name="password" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="confirm_password">Confirm Password</label>
|
||
<input type="password" id="confirm_password" name="confirm_password" required>
|
||
</div>
|
||
<div class="form-group consent-group">
|
||
<input type="checkbox" id="consent" name="consent" required>
|
||
<label for="consent">I agree to receive info about this webinar.</label>
|
||
</div>
|
||
<p class="microcopy" style="margin-top:-1rem; margin-bottom: 1.5rem;">No spam. Unsubscribe anytime.</p>
|
||
|
||
<input type="hidden" name="timezone" id="timezone">
|
||
<input type="hidden" name="utm_source" id="utm_source">
|
||
<input type="hidden" name="utm_medium" id="utm_medium">
|
||
<input type="hidden" name="utm_campaign" id="utm_campaign">
|
||
<input type="hidden" name="utm_term" id="utm_term">
|
||
<input type="hidden" name="utm_content" id="utm_content">
|
||
<input type="hidden" name="referrer" id="referrer">
|
||
<input type="hidden" name="gclid" id="gclid">
|
||
<input type="hidden" name="fbclid" id="fbclid">
|
||
|
||
<button type="submit" class="submit-btn" id="submit-button">Register Now</button>
|
||
</form>
|
||
</div>
|
||
<div id="form-result"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// --- TIMEZONE & DATE LOCALIZATION ---
|
||
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||
document.getElementById('timezone').value = timezone;
|
||
|
||
const webinarDateUTC = '<?= $webinar["scheduled_at"] ?>';
|
||
const localDate = new Date(webinarDateUTC + 'Z'); // 'Z' for UTC
|
||
|
||
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' };
|
||
document.getElementById('local-date-time').textContent = localDate.toLocaleDateString(undefined, options);
|
||
|
||
// --- TRACKING PARAMS ---
|
||
const urlParams = new URLSearchParams(window.location.search);
|
||
['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gclid', 'fbclid'].forEach(param => {
|
||
if (urlParams.has(param)) {
|
||
document.getElementById(param).value = urlParams.get(param);
|
||
}
|
||
});
|
||
document.getElementById('referrer').value = document.referrer;
|
||
|
||
|
||
// --- AJAX FORM SUBMISSION ---
|
||
const form = document.getElementById('registration-form');
|
||
const formContainer = document.getElementById('registration-form-container');
|
||
const formResult = document.getElementById('form-result');
|
||
const submitButton = document.getElementById('submit-button');
|
||
|
||
form.addEventListener('submit', function(e) {
|
||
e.preventDefault();
|
||
submitButton.disabled = true;
|
||
submitButton.textContent = 'Processing...';
|
||
|
||
const formData = new FormData(form);
|
||
fetch(window.location.href, {
|
||
method: 'POST',
|
||
body: formData
|
||
})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
formContainer.style.display = 'none';
|
||
const webinarTitle = encodeURIComponent(data.webinar_title);
|
||
const webinarDate = new Date(data.webinar_date_utc + 'Z');
|
||
|
||
// Correctly format dates for UTC (YYYYMMDDTHHMMSSZ)
|
||
const formatUTCDate = (date) => {
|
||
return date.toISOString().replace(/\.\d{3}Z$/, 'Z').replace(/[-:]/g, '');
|
||
};
|
||
|
||
const startTime = formatUTCDate(webinarDate);
|
||
const endTime = formatUTCDate(new Date(webinarDate.getTime() + (60 * 60 * 1000)));
|
||
|
||
const googleLink = `https://www.google.com/calendar/render?action=TEMPLATE&text=${webinarTitle}&dates=${startTime}/${endTime}&details=Join+the+webinar!&ctz=UTC`;
|
||
|
||
const icsContent = [
|
||
'BEGIN:VCALENDAR',
|
||
'VERSION:2.0',
|
||
'BEGIN:VEVENT',
|
||
`URL:${window.location.href}`,
|
||
`DTSTART:${startTime}`,
|
||
`DTEND:${endTime}`,
|
||
`SUMMARY:${data.webinar_title}`,
|
||
'DESCRIPTION:Join the webinar!',
|
||
'END:VEVENT',
|
||
'END:VCALENDAR'
|
||
].join('\n');
|
||
const outlookLink = `data:text/calendar;charset=utf-8,${encodeURIComponent(icsContent)}`;
|
||
|
||
formResult.innerHTML = `
|
||
<div class="success-message">
|
||
<h3 style="color: #f6e05e; font-size: 1.75rem;">You’re in for ${data.webinar_title}!</h3>
|
||
<p style="color: #cbd5e0; font-size: 1.1rem;">Check your email for your confirmation. You can now log in to see the details.</p>
|
||
<div class="calendar-buttons">
|
||
<a href="${googleLink}" target="_blank">Add to Google Calendar</a>
|
||
<a href="${outlookLink}" download="webinar.ics">Add to Outlook (ICS)</a>
|
||
</div>
|
||
</div>
|
||
`;
|
||
} else {
|
||
formResult.innerHTML = `<div class="error-message">${data.error}</div>`;
|
||
submitButton.disabled = false;
|
||
submitButton.textContent = 'Register Now';
|
||
}
|
||
})
|
||
.catch(error => {
|
||
formResult.innerHTML = `<div class="error-message">An unexpected error occurred.</div>`;
|
||
submitButton.disabled = false;
|
||
submitButton.textContent = 'Register Now';
|
||
});
|
||
});
|
||
|
||
// --- COPY LINK ---
|
||
formResult.addEventListener('click', function(e) {
|
||
if (e.target.classList.contains('copy-link-btn')) {
|
||
e.preventDefault();
|
||
const link = e.target.dataset.link;
|
||
navigator.clipboard.writeText(link).then(() => {
|
||
e.target.textContent = 'Copied!';
|
||
setTimeout(() => {
|
||
e.target.textContent = 'Copy Join Link';
|
||
}, 2000);
|
||
});
|
||
}
|
||
});
|
||
|
||
</script>
|
||
</body>
|
||
</html>
|