From 392dc73382fdd8f1f0eab8c94d9f2cfafe20425e Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 28 Feb 2026 15:38:54 +0000 Subject: [PATCH] v3 --- dashboard.php | 163 +++++++++------ db/migrations/02_onboarding_fields.sql | 15 ++ founder_onboarding.php | 274 +++++++++++++++++++++---- investor_onboarding.php | 27 ++- login.php | 23 ++- register.php | 58 +++++- verify.php | 52 +++++ 7 files changed, 494 insertions(+), 118 deletions(-) create mode 100644 db/migrations/02_onboarding_fields.sql create mode 100644 verify.php diff --git a/dashboard.php b/dashboard.php index 68fccf7..2d3b75e 100644 --- a/dashboard.php +++ b/dashboard.php @@ -11,13 +11,22 @@ $stmt = db()->prepare("SELECT * FROM users WHERE id = ?"); $stmt->execute([$_SESSION['user_id']]); $user = $stmt->fetch(); -// Check if profile is complete (e.g., bio or interests) -if (empty($user['bio']) && empty($user['interests'])) { - if ($user['role'] === 'investor') { - header("Location: investor_onboarding.php"); - } else { - header("Location: founder_onboarding.php"); - } +if (!$user) { + session_destroy(); + header("Location: login.php"); + exit; +} + +// Security: Check if verified +if ($user['verified'] == 0) { + session_destroy(); + header("Location: login.php?error=not_verified"); + exit; +} + +// Check if onboarding is complete +if ($user['role'] === 'founder' && $user['onboarding_completed'] == 0) { + header("Location: founder_onboarding.php"); exit; } @@ -36,6 +45,10 @@ if ($user['role'] === 'founder') { $stmt->execute([$_SESSION['user_id']]); $myInvestments = $stmt->fetchAll(); } + +function number_get_formatted($num) { + return number_format((float)$num, 0, '.', ','); +} ?> @@ -64,42 +77,45 @@ if ($user['role'] === 'founder') { Notifications
- () - Log Out + () + Log Out
-
-

Welcome, !

-

Here is your startup ecosystem overview.

+
+

Welcome, !

+

Manage your projects and network from one place.

-
-

My Startups

- + List Startup +
+

My Ventures

+ + Launch Round
-
- -

You haven't listed any startups yet.

- Start Funding Round +
+ +

Ready to share your vision with the world?

+ Start Your First Round
-
+
-
-
• Raising £
+
+
+ + Target: £ +
-
£ raised
-
of £
+
£
+
Raised so far
@@ -108,28 +124,30 @@ if ($user['role'] === 'founder') {
-
-

My Portfolio

- Explore Startups +
+

Portfolio Overview

+ Find New Deals
-
- -

You haven't backed any student projects yet.

- Discover Startups +
+ +

Browse the next generation of student-led innovation.

+ Start Investing
-
+
-
-
Invested on
+
+
Committed on
-
£
-
+
£
+
+ +
@@ -139,46 +157,75 @@ if ($user['role'] === 'founder') {
-

Latest Network Activity

-

Discover the latest student innovations and trends.

-
-

No new activity in your network. Follow founders or startups to see updates.

+

Insights & Activity

+
+

Coming soon: Real-time insights from your network and matching suggestions based on your profile.

-

Your Profile

-
-
+
+

My Profile

+ Edit +
+
+
-
-
+
+
'
-
- +
+
- Edit Profile + + +
+ + + +
+
-
-

Networking

-

Find the right people to build the future with.

- Find Partners +
+

Gatsby Pro

+

Get advanced analytics and direct intros to top-tier VC scouts.

+
- + - \ No newline at end of file + diff --git a/db/migrations/02_onboarding_fields.sql b/db/migrations/02_onboarding_fields.sql new file mode 100644 index 0000000..1e5d54e --- /dev/null +++ b/db/migrations/02_onboarding_fields.sql @@ -0,0 +1,15 @@ +-- Add detailed founder onboarding fields to users table +ALTER TABLE users +ADD COLUMN degree_program VARCHAR(255) AFTER university, +ADD COLUMN country VARCHAR(100) AFTER graduation_year, +ADD COLUMN skills TEXT AFTER interests, +ADD COLUMN years_experience INT DEFAULT 0, +ADD COLUMN previous_startup_exp TINYINT(1) DEFAULT 0, +ADD COLUMN previous_startup_desc TEXT, +ADD COLUMN startup_industries TEXT, +ADD COLUMN preferred_stage ENUM('Idea', 'MVP', 'Early traction', 'Scaling'), +ADD COLUMN commitment_level ENUM('part-time', 'full-time'), +ADD COLUMN risk_tolerance ENUM('low', 'medium', 'high'), +ADD COLUMN equity_expectations TEXT, +ADD COLUMN preferred_co_founder_skills TEXT, +ADD COLUMN onboarding_completed TINYINT(1) DEFAULT 0; diff --git a/founder_onboarding.php b/founder_onboarding.php index 587ca42..522098d 100644 --- a/founder_onboarding.php +++ b/founder_onboarding.php @@ -7,18 +7,70 @@ if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'founder') { require_once __DIR__ . '/db/config.php'; +// Check if already completed +$stmt = db()->prepare("SELECT onboarding_completed, full_name, university, graduation_year FROM users WHERE id = ?"); +$stmt->execute([$_SESSION['user_id']]); +$user = $stmt->fetch(); + +if ($user['onboarding_completed']) { + header("Location: dashboard.php"); + exit; +} + $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $degree_program = trim($_POST['degree_program'] ?? ''); + $country = trim($_POST['country'] ?? ''); + $skills = isset($_POST['skills']) ? implode(',', $_POST['skills']) : ''; + $years_experience = (int)($_POST['years_experience'] ?? 0); + $previous_startup_exp = isset($_POST['previous_startup_exp']) ? 1 : 0; + $previous_startup_desc = trim($_POST['previous_startup_desc'] ?? ''); + $startup_industries = isset($_POST['startup_industries']) ? implode(',', $_POST['startup_industries']) : ''; + $preferred_stage = $_POST['preferred_stage'] ?? 'Idea'; + $commitment_level = $_POST['commitment_level'] ?? 'part-time'; + $risk_tolerance = $_POST['risk_tolerance'] ?? 'medium'; + $equity_expectations = trim($_POST['equity_expectations'] ?? ''); + $preferred_co_founder_skills = isset($_POST['preferred_co_founder_skills']) ? implode(',', $_POST['preferred_co_founder_skills']) : ''; $bio = trim($_POST['bio'] ?? ''); - $interests = isset($_POST['interests']) ? implode(',', $_POST['interests']) : ''; - - if (empty($bio) || empty($interests)) { - $error = "Please fill in all required fields."; + + if (empty($degree_program) || empty($country) || empty($skills) || empty($bio)) { + $error = "Please fill in all mandatory fields."; } else { - $stmt = db()->prepare("UPDATE users SET bio = ?, interests = ? WHERE id = ?"); + $stmt = db()->prepare("UPDATE users SET + degree_program = ?, + country = ?, + skills = ?, + years_experience = ?, + previous_startup_exp = ?, + previous_startup_desc = ?, + startup_industries = ?, + preferred_stage = ?, + commitment_level = ?, + risk_tolerance = ?, + equity_expectations = ?, + preferred_co_founder_skills = ?, + bio = ?, + onboarding_completed = 1 + WHERE id = ?"); + try { - $stmt->execute([$bio, $interests, $_SESSION['user_id']]); + $stmt->execute([ + $degree_program, + $country, + $skills, + $years_experience, + $previous_startup_exp, + $previous_startup_desc, + $startup_industries, + $preferred_stage, + $commitment_level, + $risk_tolerance, + $equity_expectations, + $preferred_co_founder_skills, + $bio, + $_SESSION['user_id'] + ]); header("Location: dashboard.php"); exit; } catch (PDOException $e) { @@ -28,7 +80,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby'; -$skills_options = ['Frontend Development', 'Backend Development', 'Mobile App Development', 'UI/UX Design', 'Digital Marketing', 'Sales & Business Dev', 'Data Science', 'Operations', 'Finance', 'Legal']; + +$all_skills = ['Technical (Full-stack)', 'Technical (AI/ML)', 'Technical (Mobile)', 'Product Management', 'UI/UX Design', 'Marketing & Growth', 'Sales & Biz Dev', 'Finance', 'Operations', 'Legal']; +$all_industries = ['AI & Machine Learning', 'Fintech', 'SaaS', 'Climate Tech', 'Health Tech', 'Marketplaces', 'E-commerce', 'EdTech', 'Web3 & Crypto', 'Hardware']; ?> @@ -39,12 +93,53 @@ $skills_options = ['Frontend Development', 'Backend Development', 'Mobile App De + -
-

Create Your Founder Profile

-

Let people know what you're building and what skills you have.

+
+ +

Welcome,

+

Tell us about your background and interests to help us find the best matches.

+ +
+
+
+
+
+
@@ -52,37 +147,146 @@ $skills_options = ['Frontend Development', 'Backend Development', 'Mobile App De
-
-
- - -
- -
- -
- - - + + +
+

1. Basic Information

+
+ + +
+
+ + +
+
+
- + +
+

2. Professional Information

+
+ +
+ + + +
+
+
+ + +
+
+ +
+ +
+ + +
+
+ + +
+

3. Startup Interests

+
+ +
+ + + +
+
+
+ + +
+
+ + +
+
+ + +
+

4. Founder Preferences

+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + + +
+
+
+ + +
+
+ + +
+
- + + document.getElementById('prevExp').addEventListener('change', function() { + document.getElementById('descGroup').style.display = this.checked ? 'block' : 'none'; + }); + - + \ No newline at end of file diff --git a/investor_onboarding.php b/investor_onboarding.php index 64d994b..3babeaa 100644 --- a/investor_onboarding.php +++ b/investor_onboarding.php @@ -7,6 +7,16 @@ if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'investor') { require_once __DIR__ . '/db/config.php'; +// Check if already completed +$stmt = db()->prepare("SELECT onboarding_completed FROM users WHERE id = ?"); +$stmt->execute([$_SESSION['user_id']]); +$user = $stmt->fetch(); + +if ($user['onboarding_completed']) { + header("Location: dashboard.php"); + exit; +} + $error = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { @@ -17,7 +27,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (empty($bio) || empty($interests) || empty($investment_appetite)) { $error = "Please fill in all required fields."; } else { - $stmt = db()->prepare("UPDATE users SET bio = ?, interests = ?, investment_appetite = ? WHERE id = ?"); + $stmt = db()->prepare("UPDATE users SET bio = ?, interests = ?, investment_appetite = ?, onboarding_completed = 1 WHERE id = ?"); try { $stmt->execute([$bio, $interests, $investment_appetite, $_SESSION['user_id']]); header("Location: dashboard.php"); @@ -44,6 +54,7 @@ $interests_options = ['Tech', 'Sustainability', 'Healthcare', 'Fintech', 'Educat
+

Create Your Investor Profile

Tell us about your investment preferences.

@@ -55,12 +66,12 @@ $interests_options = ['Tech', 'Sustainability', 'Healthcare', 'Fintech', 'Educat
- - + +
- +
- - + +
- +
@@ -91,4 +102,4 @@ $interests_options = ['Tech', 'Sustainability', 'Healthcare', 'Fintech', 'Educat - + \ No newline at end of file diff --git a/login.php b/login.php index 9c637db..9410b1b 100644 --- a/login.php +++ b/login.php @@ -16,12 +16,21 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $user = $stmt->fetch(); if ($user && password_verify($password, $user['password'])) { - $_SESSION['user_id'] = $user['id']; - $_SESSION['role'] = $user['role']; - $_SESSION['full_name'] = $user['full_name']; - - header("Location: dashboard.php"); - exit; + if ($user['verified'] == 0) { + $error = "Your account is not verified. Please check your email for the verification link."; + } else { + $_SESSION['user_id'] = $user['id']; + $_SESSION['role'] = $user['role']; + $_SESSION['full_name'] = $user['full_name']; + + // Check if onboarding is completed + if ($user['role'] === 'founder' && $user['onboarding_completed'] == 0) { + header("Location: founder_onboarding.php"); + } else { + header("Location: dashboard.php"); + } + exit; + } } else { $error = "Invalid email or password."; } @@ -68,4 +77,4 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
- + \ No newline at end of file diff --git a/register.php b/register.php index e368d00..e673ea1 100644 --- a/register.php +++ b/register.php @@ -5,6 +5,23 @@ require_once __DIR__ . '/mail/MailService.php'; $error = ''; $success = ''; +function isUniversityEmail($email) { + $parts = explode('@', $email); + if (count($parts) !== 2) return false; + $domain = strtolower($parts[1]); + + // Whitelist for university domains + $university_suffixes = ['.edu', '.ac.uk', '.edu.cn', '.edu.au', '.edu.in', '.edu.pk', '.edu.br', '.ac.jp', '.ac.kr', '.edu.za', '.ac.il', '.edu.mx', '.edu.ar', '.edu.co', '.edu.ph', '.edu.my', '.edu.sg']; + + foreach ($university_suffixes as $suffix) { + if (str_ends_with($domain, $suffix)) { + return true; + } + } + + return false; +} + if ($_SERVER['REQUEST_METHOD'] === 'POST') { $full_name = trim($_POST['full_name'] ?? ''); $email = trim($_POST['email'] ?? ''); @@ -18,6 +35,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $error = "All fields are required."; } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $error = "Invalid email format."; + } elseif ($role === 'founder' && !isUniversityEmail($email)) { + $error = "Founders must use a valid university email address (e.g. .edu, .ac.uk)."; } elseif ($graduation_year < 1900 || $graduation_year > 2100) { $error = "Invalid graduation year."; } else { @@ -32,14 +51,26 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $hashed_password = password_hash($password, PASSWORD_DEFAULT); // Insert user - $stmt = db()->prepare("INSERT INTO users (full_name, email, password, role, university, graduation_year, verification_code) VALUES (?, ?, ?, ?, ?, ?, ?)"); + $stmt = db()->prepare("INSERT INTO users (full_name, email, password, role, university, graduation_year, verification_code, verified) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); try { - $stmt->execute([$full_name, $email, $hashed_password, $role, $university, $graduation_year, $verification_code]); - $success = "Registration successful! Please check your email to verify your account."; + // Investors are verified by default as they don't need student verification + $is_verified = ($role === 'investor') ? 1 : 0; + $stmt->execute([$full_name, $email, $hashed_password, $role, $university, $graduation_year, $verification_code, $is_verified]); - // Send verification email - // MailService::sendMail($email, "Verify your account", "Your verification code is: $verification_code", "Your verification code is: $verification_code"); - // For now, we'll just show the success message. + if ($role === 'founder') { + $success = "Registration successful! A verification link has been sent to $email. Please verify your account before logging in."; + + // Send verification email + $baseUrl = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST']; + $verifyUrl = "$baseUrl/verify.php?code=$verification_code"; + $subject = "Verify your " . PLATFORM_NAME . " account"; + $html = "

Welcome to " . PLATFORM_NAME . "!

Please click the link below to verify your student status:

$verifyUrl

"; + $text = "Welcome to " . PLATFORM_NAME . "!\n\nPlease visit the following URL to verify your account:\n$verifyUrl"; + + MailService::sendMail($email, $subject, $html, $text); + } else { + $success = "Registration successful! You can now log in to your investor account."; + } } catch (PDOException $e) { $error = "Database error: " . $e->getMessage(); } @@ -86,7 +117,7 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
- Only university/graduate emails accepted. + Only university/graduate emails (.edu, etc.) accepted for founders.
@@ -106,13 +137,13 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
+ + - + \ No newline at end of file diff --git a/verify.php b/verify.php new file mode 100644 index 0000000..eb823cb --- /dev/null +++ b/verify.php @@ -0,0 +1,52 @@ +prepare("SELECT id FROM users WHERE verification_code = ? AND verified = 0"); + $stmt->execute([$code]); + $user = $stmt->fetch(); + + if ($user) { + $update = db()->prepare("UPDATE users SET verified = 1, verification_code = NULL WHERE id = ?"); + if ($update->execute([$user['id']])) { + $message = "Email verified successfully! You can now log in."; + $status = 'success'; + } else { + $message = "Something went wrong. Please try again later."; + } + } else { + $message = "Invalid or expired verification link."; + } +} else { + $message = "No verification code provided."; +} + +$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby'; +?> + + + + + + Email Verification — <?= htmlspecialchars($platformName) ?> + + + + + +
+ + +

+

+ + Go to Log In +
+ + +