diff --git a/db/migrations/006_add_form_fields.sql b/db/migrations/006_add_form_fields.sql index 5bfd597..f6aefbb 100644 --- a/db/migrations/006_add_form_fields.sql +++ b/db/migrations/006_add_form_fields.sql @@ -1,4 +1 @@ -ALTER TABLE `attendees` -CHANGE `name` `first_name` VARCHAR(255), -ADD `last_name` VARCHAR(255) NULL AFTER `first_name`, -ADD `how_did_you_hear` VARCHAR(255) NULL; +ALTER TABLE `attendees` ADD `consented` TINYINT(1) NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/db/migrations/007_add_consented_column.sql b/db/migrations/007_add_consented_column.sql new file mode 100644 index 0000000..f6aefbb --- /dev/null +++ b/db/migrations/007_add_consented_column.sql @@ -0,0 +1 @@ +ALTER TABLE `attendees` ADD `consented` TINYINT(1) NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/db/migrations/008_rename_column.sql b/db/migrations/008_rename_column.sql new file mode 100644 index 0000000..a56afac --- /dev/null +++ b/db/migrations/008_rename_column.sql @@ -0,0 +1 @@ +ALTER TABLE attendees CHANGE COLUMN registered_at created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP; \ No newline at end of file diff --git a/login.php b/login.php index 6fe1559..9cbbc86 100644 --- a/login.php +++ b/login.php @@ -11,7 +11,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['email'])) { $password = isset($_POST['password']) ? $_POST['password'] : ''; // Admin Login - if ($email === 'admin' && $password === 'password') { + if ($email === 'admin@gmail.com' && $password === 'admin') { $_SESSION['user'] = 'admin'; header('Location: admin.php'); exit; diff --git a/register.php b/register.php index 56ed02d..8602cc3 100644 --- a/register.php +++ b/register.php @@ -2,39 +2,30 @@ 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) { +// Helper function to fetch webinar details +function get_webinar_details($id) { + if (empty($id)) { + return null; + } try { - $stmt = $pdo->prepare("SELECT title, description, starts_at, ends_at FROM webinars WHERE id = ?"); - $stmt->execute([$webinar_id]); - $webinar = $stmt->fetch(PDO::FETCH_ASSOC); + $stmt = db()->prepare("SELECT id, title, description, scheduled_at, presenter FROM webinars WHERE id = ?"); + $stmt->execute([$id]); + return $stmt->fetch(PDO::FETCH_ASSOC); } catch (PDOException $e) { - // Log error, but don't show to user + error_log("Database error fetching webinar ID $id: " . $e->getMessage()); + return null; } } -// --- FORM SUBMISSION (POST REQUEST) --- +// --- AJAX FORM SUBMISSION (POST REQUEST) --- if ($_SERVER["REQUEST_METHOD"] == "POST") { header('Content-Type: application/json'); + $response = []; // --- DATA CAPTURE --- - $webinar_id = filter_input(INPUT_POST, 'webinar_id', FILTER_VALIDATE_INT); - $webinar = null; - if ($webinar_id) { - try { - $stmt = $pdo->prepare("SELECT title, description, starts_at, ends_at FROM webinars WHERE id = ?"); - $stmt->execute([$webinar_id]); - $webinar = $stmt->fetch(PDO::FETCH_ASSOC); - } catch (PDOException $e) { - // Log error, but don't show to user - } - } - + $webinar_id = filter_input(INPUT_POST, 'webinar_id', FILTER_VALIDATE_INT) ?: filter_input(INPUT_GET, 'webinar_id', FILTER_VALIDATE_INT) ?: 1; + $webinar = get_webinar_details($webinar_id); + $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); @@ -54,73 +45,67 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") { $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 (!$webinar) { - $response['error'] = 'Webinar not found.'; - echo json_encode($response); - exit; - } + $response = ['success' => false, 'error' => 'Webinar not found. Tried to find webinar with ID: ' . $webinar_id]; + } elseif (!$first_name || !$last_name || !$email) { + $response = ['success' => false, 'error' => 'Please fill out all required fields.']; + } elseif ($password !== $confirm_password) { + $response = ['success' => false, 'error' => 'Passwords do not match.']; + } else { + try { + $stmt = db()->prepare("SELECT id FROM attendees WHERE webinar_id = ? AND email = ?"); + $stmt->execute([$webinar_id, $email]); + if ($stmt->fetch()) { + $response = ['success' => false, 'error' => 'You are already registered for this webinar.']; + } else { + $password_hash = password_hash($password, PASSWORD_DEFAULT); + $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]); + + $webinar_date_obj = new DateTime($webinar['scheduled_at']); + $subject = "Confirmation: You're Registered for " . $webinar['title']; + $body_html = "
Thanks for registering for our webinar: {$webinar['title']}.
It will take place on " . $webinar_date_obj->format('l, F j, Y \a\t g:i A T') . ".
You can now log in to your dashboard to see the details.
"; + MailService::sendMail($email, $subject, $body_html); - if ($password !== $confirm_password) { - $response['error'] = 'Passwords do not match.'; - echo json_encode($response); - exit; - } + // --- PREPARE SUCCESS RESPONSE --- + $webinar_date = new DateTime($webinar['scheduled_at'], new DateTimeZone('UTC')); + $start_time_utc = $webinar_date->format('Ymd H is Z'); + $webinar_date->add(new DateInterval('PT1H')); // Assume 1 hour duration + $end_time_utc = $webinar_date->format('Ymd H is Z'); - $password_hash = password_hash($password, PASSWORD_DEFAULT); + $google_link = 'https://www.google.com/calendar/render?action=TEMPLATE&text=' . urlencode($webinar['title']) . '&dates=' . $start_time_utc . '/' . $end_time_utc . '&details=' . urlencode($webinar['description']) . '&ctz=UTC'; + + $ics_content = implode("\r\n", [ + 'BEGIN:VCALENDAR', 'VERSION:2.0', 'BEGIN:VEVENT', + 'URL:' . 'http://' . $_SERVER['HTTP_HOST'], + 'DTSTART:' . $start_time_utc, 'DTEND:' . $end_time_utc, + 'SUMMARY:' . $webinar['title'], 'DESCRIPTION:' . $webinar['description'], + 'END:VEVENT', 'END:VCALENDAR' + ]); + $outlook_link = 'data:text/calendar;charset=utf-8,' . rawurlencode($ics_content); - 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; + $response = [ + 'success' => true, + 'webinar_title' => $webinar['title'], + 'google_link' => $google_link, + 'outlook_link' => $outlook_link + ]; + } + } catch (Exception $e) { + error_log("Registration error: " . $e->getMessage()); + $response = ['success' => false, 'error' => 'An unexpected error occurred. Please try again.']; } - - // 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['starts_at']); - $subject = "Confirmation: You're Registered for " . $webinar['title']; - - $body_html = "Thanks for registering for our webinar: {$webinar['title']}.
" - . "It will take place on " . $webinar_date->format('l, F j, Y \a\t g:i A T') . ".
" - . "You can now log in to your dashboard to see the details.
"; - - MailService::sendMail($email, $subject, $body_html); - - $response['success'] = true; - $response['webinar_title'] = $webinar['title']; - $response['webinar_date_utc'] = $webinar['starts_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) --- +// --- RENDER PAGE (Initial GET Request) --- +$webinar_id = filter_input(INPUT_GET, 'webinar_id', FILTER_VALIDATE_INT) ?: 1; +$webinar = get_webinar_details($webinar_id); + if (!$webinar) { http_response_code(404); echo "Webinar not found."; @@ -143,18 +128,24 @@ if (!$webinar) { .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; } + + .right-pane .card { background-color: #2d3748; border-radius: 0.5rem; padding: 2rem; border: 1px solid #4a5568; } + .right-pane 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"], input[type="password"] { 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; } .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; text-align: center; } - .error-message { background-color: #c53030; padding: 1rem; border-radius: 0.375rem; } - .calendar-buttons a { 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; } + .submit-btn:disabled { background-color: #a0aec0; cursor: not-allowed; } + + .error-message { background-color: #c53030; color: #fff; padding: 1rem; border-radius: 0.375rem; text-align: center; margin-bottom: 1.5rem; } + + .success-message { text-align: center; } + .success-message h1 { color: #f6e05e; font-size: 2rem; margin-top: 0; } + .success-message p { color: #cbd5e0; font-size: 1.1rem; line-height: 1.6; } + .calendar-buttons a { display: inline-block; background-color: #4a5568; color: #e2e8f0; padding: 0.75rem 1.5rem; border-radius: 0.375rem; text-decoration: none; margin: 1rem 0.5rem 0; font-weight: bold; transition: background-color 0.2s; } + .calendar-buttons a:hover { background-color: #5a6578; } + @media (max-width: 768px) { .container { grid-template-columns: 1fr; } } @@ -176,8 +167,9 @@ if (!$webinar) {