diff --git a/admin.php b/admin.php
new file mode 100644
index 0000000..87d4fdc
--- /dev/null
+++ b/admin.php
@@ -0,0 +1,117 @@
+query('SELECT a.id, w.title AS webinar_title, a.first_name, a.email, a.consented, a.created_at, a.timezone, a.utm_source, a.utm_medium, a.utm_campaign, a.referrer, a.gclid, a.fbclid FROM attendees a JOIN webinars w ON a.webinar_id = w.id ORDER BY a.created_at DESC');
+ $attendees = $stmt->fetchAll(PDO::FETCH_ASSOC);
+} catch (PDOException $e) {
+ die("Could not connect to the database: " . $e->getMessage());
+}
+
+?>
+
+
+
+
+
+ Admin Board
+
+
+
+
+
+
Logout
+
Webinar Attendees
+
+
+
+
+ | ID |
+ Webinar |
+ Name |
+ Email |
+ Consented |
+ Registered At |
+ Timezone |
+ UTM Source |
+ UTM Medium |
+ UTM Campaign |
+ Referrer |
+ GCLID |
+ FBCLID |
+
+
+
+
+
+ | No attendees yet. |
+
+
+
+
+ | = htmlspecialchars($attendee['id']) ?> |
+ = htmlspecialchars($attendee['webinar_title']) ?> |
+ = htmlspecialchars($attendee['first_name']) ?> |
+ = htmlspecialchars($attendee['email']) ?> |
+ = $attendee['consented'] ? 'Yes' : 'No' ?> |
+ = htmlspecialchars($attendee['created_at']) ?> |
+ = htmlspecialchars($attendee['timezone']) ?> |
+ = htmlspecialchars($attendee['utm_source']) ?> |
+ = htmlspecialchars($attendee['utm_medium']) ?> |
+ = htmlspecialchars($attendee['utm_campaign']) ?> |
+ = htmlspecialchars($attendee['referrer']) ?> |
+ = htmlspecialchars($attendee['gclid']) ?> |
+ = htmlspecialchars($attendee['fbclid']) ?> |
+
+
+
+
+
+
+
+
+
diff --git a/api/pexels.php b/api/pexels.php
new file mode 100644
index 0000000..9cc0c60
--- /dev/null
+++ b/api/pexels.php
@@ -0,0 +1,29 @@
+ 'assets/images/pexels/'.$p['id'].'.jpg',
+ 'photographer' => $p['photographer'] ?? 'Unknown',
+ 'photographer_url' => $p['photographer_url'] ?? '',
+ ];
+ } else {
+ // Fallback: Picsum
+ $out[] = [
+ 'src' => 'https://picsum.photos/600',
+ 'photographer' => 'Random Picsum',
+ 'photographer_url' => 'https://picsum.photos/'
+ ];
+ }
+ }
+ echo json_encode($out);
+ ?>
\ No newline at end of file
diff --git a/assets/images/pexels/22601971.jpg b/assets/images/pexels/22601971.jpg
new file mode 100644
index 0000000..7f67267
Binary files /dev/null and b/assets/images/pexels/22601971.jpg differ
diff --git a/assets/images/pexels/34238049.jpg b/assets/images/pexels/34238049.jpg
new file mode 100644
index 0000000..dec0503
Binary files /dev/null and b/assets/images/pexels/34238049.jpg differ
diff --git a/assets/images/pexels/34285016.jpg b/assets/images/pexels/34285016.jpg
new file mode 100644
index 0000000..8448f03
Binary files /dev/null and b/assets/images/pexels/34285016.jpg differ
diff --git a/assets/pasted-20251016-160256-cf9071d4.jpg b/assets/pasted-20251016-160256-cf9071d4.jpg
new file mode 100644
index 0000000..05da89c
Binary files /dev/null and b/assets/pasted-20251016-160256-cf9071d4.jpg differ
diff --git a/assets/pasted-20251016-161033-a327c220.png b/assets/pasted-20251016-161033-a327c220.png
new file mode 100644
index 0000000..57d7074
Binary files /dev/null and b/assets/pasted-20251016-161033-a327c220.png differ
diff --git a/assets/vm-shot-2025-10-16T16-02-18-334Z.jpg b/assets/vm-shot-2025-10-16T16-02-18-334Z.jpg
new file mode 100644
index 0000000..05da89c
Binary files /dev/null and b/assets/vm-shot-2025-10-16T16-02-18-334Z.jpg differ
diff --git a/dashboard.php b/dashboard.php
new file mode 100644
index 0000000..9e87d2e
--- /dev/null
+++ b/dashboard.php
@@ -0,0 +1,126 @@
+prepare("SELECT * FROM attendees WHERE id = ?");
+ $stmt->execute([$user_id]);
+ $attendee = $stmt->fetch();
+
+ if ($attendee) {
+ // Fetch webinar details
+ $stmt = db()->prepare("SELECT * FROM webinars WHERE id = ?");
+ $stmt->execute([$attendee['webinar_id']]);
+ $webinar = $stmt->fetch();
+ } else {
+ $error = 'Could not find your registration details.';
+ }
+} catch (PDOException $e) {
+ $error = 'Database error. Please try again later.';
+}
+
+?>
+
+
+
+
+
+ Your Webinar Dashboard
+
+
+
+
+
+
Your Dashboard
+
+
= htmlspecialchars($error) ?>
+
+
Hello, = htmlspecialchars($attendee['first_name']) ?>!
+
You are registered for the following webinar:
+
= htmlspecialchars($webinar['title']) ?>
+
+ format('l, F j, Y \a\t g:i A T');
+ ?>
+
+
Join Webinar
+
+
Could not find your registration details.
+
+
+
+
+
+
diff --git a/db/migrate.php b/db/migrate.php
index b922e8f..31962db 100644
--- a/db/migrate.php
+++ b/db/migrate.php
@@ -1,26 +1,49 @@
-
PDO::ERRMODE_EXCEPTION,
]);
$pdo->exec('CREATE DATABASE IF NOT EXISTS '.DB_NAME);
- echo "Database created or already exists." . PHP_EOL;
// Now connect to the specific database
$pdo = db();
- $migrations = glob(__DIR__ . '/migrations/*.sql');
- sort($migrations);
- foreach ($migrations as $migration) {
- $sql = file_get_contents($migration);
- $pdo->exec($sql);
- echo "Executed migration: $migration" . PHP_EOL;
+ // 1. Create migrations table if it doesn't exist
+ $pdo->exec('CREATE TABLE IF NOT EXISTS migrations (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ migration VARCHAR(255) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )');
+
+ // 2. Get all migration files
+ $migration_files = glob(__DIR__ . '/migrations/*.sql');
+ sort($migration_files);
+
+ // 3. Get already executed migrations
+ $executed_migrations_stmt = $pdo->query('SELECT migration FROM migrations');
+ $executed_migrations = $executed_migrations_stmt->fetchAll(PDO::FETCH_COLUMN);
+
+ foreach ($migration_files as $file) {
+ $migration_name = basename($file);
+
+ // 4. If migration has not been run, execute it
+ if (!in_array($migration_name, $executed_migrations)) {
+ $sql = file_get_contents($file);
+ $pdo->exec($sql);
+
+ // 5. Record the migration
+ $stmt = $pdo->prepare('INSERT INTO migrations (migration) VALUES (?)');
+ $stmt->execute([$migration_name]);
+
+ echo "Executed migration: $migration_name" . PHP_EOL;
+ }
}
+ echo "All migrations have been run." . PHP_EOL;
+
} catch (PDOException $e) {
die("Database migration failed: " . $e->getMessage());
-}
+}
\ No newline at end of file
diff --git a/db/migrations/004_add_tracking_to_attendees.sql b/db/migrations/004_add_tracking_to_attendees.sql
new file mode 100644
index 0000000..d054cc2
--- /dev/null
+++ b/db/migrations/004_add_tracking_to_attendees.sql
@@ -0,0 +1,10 @@
+ALTER TABLE attendees
+ADD COLUMN timezone VARCHAR(255) DEFAULT NULL,
+ADD COLUMN utm_source VARCHAR(255) DEFAULT NULL,
+ADD COLUMN utm_medium VARCHAR(255) DEFAULT NULL,
+ADD COLUMN utm_campaign VARCHAR(255) DEFAULT NULL,
+ADD COLUMN utm_term VARCHAR(255) DEFAULT NULL,
+ADD COLUMN utm_content VARCHAR(255) DEFAULT NULL,
+ADD COLUMN referrer VARCHAR(255) DEFAULT NULL,
+ADD COLUMN gclid VARCHAR(255) DEFAULT NULL,
+ADD COLUMN fbclid VARCHAR(255) DEFAULT NULL;
diff --git a/db/migrations/005_add_password_to_attendees.sql b/db/migrations/005_add_password_to_attendees.sql
new file mode 100644
index 0000000..4ac011a
--- /dev/null
+++ b/db/migrations/005_add_password_to_attendees.sql
@@ -0,0 +1 @@
+ALTER TABLE `attendees` ADD `password` VARCHAR(255) NOT NULL;
\ No newline at end of file
diff --git a/includes/pexels.php b/includes/pexels.php
new file mode 100644
index 0000000..c2b95ff
--- /dev/null
+++ b/includes/pexels.php
@@ -0,0 +1,26 @@
+ 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18';
+ }
+ function pexels_get($url) {
+ $ch = curl_init();
+ curl_setopt_array($ch, [
+ CURLOPT_URL => $url,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ],
+ CURLOPT_TIMEOUT => 15,
+ ]);
+ $resp = curl_exec($ch);
+ $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+ if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true);
+ return null;
+ }
+ function download_to($srcUrl, $destPath) {
+ $data = file_get_contents($srcUrl);
+ if ($data === false) return false;
+ if (!is_dir(dirname($destPath))) mkdir(dirname($destPath), 0775, true);
+ return file_put_contents($destPath, $data) !== false;
+ }
+ ?>
\ No newline at end of file
diff --git a/index.php b/index.php
index 30caa1e..7ae8f1b 100644
--- a/index.php
+++ b/index.php
@@ -1,9 +1,27 @@
+prepare("SELECT * FROM webinars WHERE scheduled_at > NOW() ORDER BY scheduled_at ASC LIMIT 1");
+ $stmt->execute();
+ $webinar = $stmt->fetch();
+} catch (PDOException $e) {
+ // Silently fail for now
+}
+
+$webinar_id = $webinar ? $webinar['id'] : 1; // Fallback to 1 if no webinar is found
+$webinar_title = $webinar ? $webinar['title'] : 'Professional Vibe-Coding Webinar';
+$webinar_date_str = $webinar ? (new DateTime($webinar['scheduled_at']))->format('l, F j \\ • \\ At g.i A T') : 'Monday, November 3 • At 6.00 PM PST';
+
+?>
- Professional Vibe-Coding Webinar
+ = htmlspecialchars($webinar_title) ?>
+
+
+
+
Welcome, = htmlspecialchars($attendee['name']) ?>!
+
You are now joining the webinar: = htmlspecialchars($webinar['title']) ?>
+
The webinar is scheduled for: = (new DateTime($webinar['scheduled_at']))->format('l, F j, Y \a\t g:i A T') ?>
+
+
+
diff --git a/login.php b/login.php
new file mode 100644
index 0000000..6fe1559
--- /dev/null
+++ b/login.php
@@ -0,0 +1,199 @@
+prepare("SELECT * FROM attendees WHERE email = ?");
+ $stmt->execute([$email]);
+ $attendee = $stmt->fetch();
+
+ if ($attendee && password_verify($password, $attendee['password'])) {
+ $_SESSION['user_id'] = $attendee['id'];
+ header('Location: dashboard.php');
+ exit;
+ } else {
+ $error = 'Invalid email or password. Would you like to register for the webinar?';
+ }
+ } catch (PDOException $e) {
+ error_log($e->getMessage());
+ $error = 'A database error occurred. Please try again later.';
+ }
+}
+?>
+
+
+
+
+
+ Login - Webinar Platform
+
+
+
+
+
+
WebinarPlatform
+
+
Welcome Back
+
Login to access your dashboard
+
+
= $error ?>
+
= $success ?>
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/register.php b/register.php
index ddf5093..13bc79c 100644
--- a/register.php
+++ b/register.php
@@ -1,191 +1,306 @@
prepare('SELECT id, title, scheduled_at FROM webinars WHERE id = ?');
+ $stmt = db()->prepare("SELECT * FROM webinars WHERE id = ?");
$stmt->execute([$webinar_id]);
- $webinar = $stmt->fetch(PDO::FETCH_ASSOC);
+ $webinar = $stmt->fetch();
} catch (PDOException $e) {
- error_log("Webinar fetch error: " . $e->getMessage());
- // Don't expose error details to user
+ // Log error, but don't show to user
}
}
-// Handle form submission
-if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- $name = trim($_POST['name'] ?? '');
- $email = filter_var(trim($_POST['email'] ?? ''), FILTER_VALIDATE_EMAIL);
- $submitted_webinar_id = filter_input(INPUT_POST, 'webinar_id', FILTER_VALIDATE_INT);
+// --- 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);
+ $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 (!$name || !$email || !$submitted_webinar_id) {
- $feedback = ['type' => 'error', 'message' => 'Please fill in all fields with valid information.'];
- } else {
- try {
- $stmt = $pdo->prepare('INSERT INTO attendees (webinar_id, name, email) VALUES (?, ?, ?)');
- $stmt->execute([$submitted_webinar_id, $name, $email]);
- $feedback = ['type' => 'success', 'message' => 'Thank you for registering! A confirmation has been sent to your email.'];
- // In a real app, you would trigger an email here.
- } catch (PDOException $e) {
- error_log("Registration error: " . $e->getMessage());
- if ($e->errorInfo[1] == 1062) { // Duplicate entry
- $feedback = ['type' => 'error', 'message' => 'This email address has already been registered for this webinar.'];
- } else {
- $feedback = ['type' => 'error', 'message' => 'An error occurred during registration. Please try again.'];
- }
+
+ if (!$email || !$consent || !$webinar) {
+ $response['error'] = 'Please provide a valid email and 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, name, email, 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, $email, $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 = "You're in!
"
+ . "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['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;
+}
?>
-
+
-
-
- Register for Webinar
-
-
-
-
+
+
+ Register for = htmlspecialchars($webinar['title']) ?>
+
-
-
+
+
\ No newline at end of file