Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4716313903 | ||
|
|
6adecbd6fa | ||
|
|
7642b9a18a | ||
|
|
adfd01d74b | ||
|
|
0053cb8830 | ||
|
|
d2d6703960 | ||
|
|
3f9d35d276 | ||
|
|
4f94d39ce7 | ||
|
|
3575e4a095 | ||
|
|
ec96458978 | ||
|
|
ad1e95fee1 | ||
|
|
f604e9edbf | ||
|
|
6d5011aef2 | ||
|
|
cab62424f8 | ||
|
|
173d4d77a5 | ||
|
|
378fa008c6 | ||
|
|
fb4133a854 | ||
|
|
113fd9f5f9 | ||
|
|
d9f48ce404 | ||
|
|
98fedc4d56 | ||
|
|
48562f356c | ||
|
|
871eb7711b | ||
|
|
7d6eb1b1e4 | ||
|
|
665b2a0b0c | ||
|
|
142cd9134d | ||
|
|
86b73d7d46 | ||
|
|
ce4cf48902 | ||
|
|
409309595e | ||
|
|
620c82043f | ||
|
|
5e486a2b26 | ||
|
|
77ab52bc7f | ||
|
|
6171608c3c | ||
|
|
eb6f8a216e | ||
|
|
93e195d19b | ||
|
|
017ad41531 | ||
|
|
a7855afce8 | ||
|
|
d3e6f9d8d1 | ||
|
|
9624830ffb | ||
|
|
66df8a0207 | ||
|
|
096a24971d | ||
|
|
d9eba63b0d | ||
|
|
03c203ff92 | ||
|
|
306361e5fb | ||
|
|
a67fbbdaf5 | ||
|
|
ffcaed889a | ||
|
|
3abb7cc4ae | ||
|
|
c312777c3a | ||
|
|
241cf7f5b9 | ||
|
|
c0f0a02ee2 | ||
|
|
9f71e36542 | ||
|
|
fc3fe3f0a0 | ||
|
|
e904e15720 | ||
|
|
57704d3ff0 | ||
|
|
d515f936b1 | ||
|
|
7fc6180066 | ||
|
|
ffc61a8ab0 | ||
|
|
0ddffbfe31 | ||
|
|
00a4b21825 | ||
|
|
3b76e4ec5b | ||
|
|
eedf246822 | ||
|
|
9141a82a52 | ||
|
|
2f6215ae8e | ||
|
|
844a54704c | ||
|
|
392dc73382 | ||
|
|
21f3fc7eab |
13
api/chat.php
13
api/chat.php
@ -3,6 +3,9 @@ header('Content-Type: application/json');
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
||||
|
||||
session_start();
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$message = $input['message'] ?? '';
|
||||
|
||||
@ -42,12 +45,12 @@ try {
|
||||
if (!empty($response['success'])) {
|
||||
$aiReply = LocalAIApi::extractText($response);
|
||||
|
||||
// 4. Save to Database
|
||||
// 4. Save to Database (ai_chats table)
|
||||
try {
|
||||
$stmt = db()->prepare("INSERT INTO messages (user_message, ai_response) VALUES (?, ?)");
|
||||
$stmt->execute([$message, $aiReply]);
|
||||
$stmt = db()->prepare("INSERT INTO ai_chats (user_id, user_message, ai_response) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$user_id, $message, $aiReply]);
|
||||
} catch (Exception $e) {
|
||||
error_log("DB Save Error: " . $e->getMessage());
|
||||
error_log("AI DB Save Error: " . $e->getMessage());
|
||||
// Continue even if save fails, so the user still gets a reply
|
||||
}
|
||||
|
||||
@ -61,4 +64,4 @@ try {
|
||||
} catch (Exception $e) {
|
||||
error_log("Chat Error: " . $e->getMessage());
|
||||
echo json_encode(['reply' => "An internal error occurred."]);
|
||||
}
|
||||
}
|
||||
54
api/follow_startup.php
Normal file
54
api/follow_startup.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) {
|
||||
echo json_encode(['success' => false, 'error' => 'Not logged in']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$startup_id = $_POST['startup_id'] ?? null;
|
||||
|
||||
if (!$startup_id) {
|
||||
echo json_encode(['success' => false, 'error' => 'Startup ID is required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
// Check if already following
|
||||
$stmt = db()->prepare("SELECT 1 FROM startup_followers WHERE startup_id = ? AND user_id = ?");
|
||||
$stmt->execute([$startup_id, $user_id]);
|
||||
$is_following = (bool)$stmt->fetch();
|
||||
|
||||
if (!$is_following) {
|
||||
// Follow
|
||||
$stmt = db()->prepare("INSERT IGNORE INTO startup_followers (startup_id, user_id) VALUES (?, ?)");
|
||||
$stmt->execute([$startup_id, $user_id]);
|
||||
$action_result = 'followed';
|
||||
} else {
|
||||
// Unfollow
|
||||
$stmt = db()->prepare("DELETE FROM startup_followers WHERE startup_id = ? AND user_id = ?");
|
||||
$stmt->execute([$startup_id, $user_id]);
|
||||
$action_result = 'unfollowed';
|
||||
}
|
||||
|
||||
// Update denormalized count
|
||||
$stmt = db()->prepare("UPDATE startups SET followers_count = (SELECT COUNT(*) FROM startup_followers WHERE startup_id = ?) WHERE id = ?");
|
||||
$stmt->execute([$startup_id, $startup_id]);
|
||||
|
||||
// Get new count
|
||||
$stmt = db()->prepare("SELECT followers_count FROM startups WHERE id = ?");
|
||||
$stmt->execute([$startup_id]);
|
||||
$new_count = $stmt->fetchColumn();
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'action' => $action_result,
|
||||
'new_count' => (int)$new_count,
|
||||
'followers_count' => (int)$new_count // redundancy for both frontend versions
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
61
api/wallet_transaction.php
Normal file
61
api/wallet_transaction.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$action = $_POST['action'] ?? '';
|
||||
$amount = (float)($_POST['amount'] ?? 0);
|
||||
|
||||
if ($amount <= 0) {
|
||||
echo json_encode(['success' => false, 'error' => 'Please enter a valid amount greater than zero.']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
db()->beginTransaction();
|
||||
|
||||
// Fetch current balance
|
||||
$stmt = db()->prepare("SELECT balance FROM users WHERE id = ? FOR UPDATE");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user) {
|
||||
throw new Exception("User account not found.");
|
||||
}
|
||||
|
||||
$current_balance = (float)$user['balance'];
|
||||
|
||||
if ($action === 'add') {
|
||||
$new_balance = $current_balance + $amount;
|
||||
$stmt = db()->prepare("UPDATE users SET balance = ? WHERE id = ?");
|
||||
$stmt->execute([$new_balance, $user_id]);
|
||||
|
||||
db()->commit();
|
||||
echo json_encode(['success' => true, 'new_balance' => $new_balance]);
|
||||
} elseif ($action === 'withdraw') {
|
||||
if ($current_balance < $amount) {
|
||||
throw new Exception("Insufficient funds. Your current balance is £" . number_format($current_balance, 2) . ".");
|
||||
}
|
||||
|
||||
$new_balance = $current_balance - $amount;
|
||||
$stmt = db()->prepare("UPDATE users SET balance = ? WHERE id = ?");
|
||||
$stmt->execute([$new_balance, $user_id]);
|
||||
|
||||
db()->commit();
|
||||
echo json_encode(['success' => true, 'new_balance' => $new_balance]);
|
||||
} else {
|
||||
throw new Exception("Invalid wallet action requested.");
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
if (db()->inTransaction()) {
|
||||
db()->rollBack();
|
||||
}
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@ -1,302 +1,372 @@
|
||||
body {
|
||||
background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
|
||||
background-size: 400% 400%;
|
||||
animation: gradient 15s ease infinite;
|
||||
color: #212529;
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
:root {
|
||||
--bg-color: #0D0D0D;
|
||||
--surface-color: #1A1A1A;
|
||||
--elevated-color: #242424;
|
||||
--accent-primary: #00C853;
|
||||
--accent-secondary: #00E676;
|
||||
--text-primary: #FFFFFF;
|
||||
--text-secondary: #A0A0A0;
|
||||
--text-disabled: #555555;
|
||||
--success-color: #00C853;
|
||||
--error-color: #FF4444;
|
||||
--warning-color: #FFB300;
|
||||
--info-color: #2979FF;
|
||||
--border-color: #2A2A2A;
|
||||
--card-bg: #1A1A1A;
|
||||
--shadow-soft: 0 4px 20px rgba(0, 0, 0, 0.5);
|
||||
/* For compatibility */
|
||||
--accent-color: var(--accent-primary);
|
||||
--accent-blue: var(--accent-secondary);
|
||||
--gradient-primary: var(--accent-primary); /* Flat color now */
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-primary);
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
||||
line-height: 1.6;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
padding: 15px 0;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
background: var(--bg-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.logo-text {
|
||||
font-size: 24px;
|
||||
font-weight: 800;
|
||||
color: var(--text-primary);
|
||||
letter-spacing: -0.5px;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
position: relative;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.nav-links a:hover, .nav-links a.active {
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.nav-links a.active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
background: var(--accent-primary);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px 28px;
|
||||
border-radius: 999px !important; /* Fully rounded as per rules */
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--accent-primary) !important;
|
||||
color: #000000 !important; /* Black text on primary fill */
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--accent-secondary) !important;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: var(--surface-color);
|
||||
color: var(--text-primary);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: var(--elevated-color);
|
||||
border-color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* Hero Section */
|
||||
.hero {
|
||||
padding: 120px 0;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 72px;
|
||||
font-weight: 900;
|
||||
margin-bottom: 24px;
|
||||
letter-spacing: -2.5px;
|
||||
line-height: 1.1;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.hero h1 span {
|
||||
color: var(--accent-primary) !important;
|
||||
background: none !important;
|
||||
-webkit-text-fill-color: initial !important;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
font-size: 22px;
|
||||
color: var(--text-secondary);
|
||||
max-width: 750px;
|
||||
margin: 0 auto 48px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.hero-bg, .hero-blob {
|
||||
display: none !important; /* Remove gradients and blobs */
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
background: var(--card-bg) !important;
|
||||
border: 1px solid var(--border-color) !important;
|
||||
padding: 40px;
|
||||
border-radius: 12px !important;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: var(--shadow-soft) !important;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: var(--accent-primary) !important;
|
||||
}
|
||||
|
||||
/* Features grid */
|
||||
.features {
|
||||
padding: 80px 0;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 30px;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
font-size: 32px;
|
||||
color: var(--accent-primary);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
/* How It Works Section */
|
||||
.how-it-works {
|
||||
background: var(--surface-color) !important;
|
||||
padding: 100px 40px;
|
||||
border-radius: 16px !important;
|
||||
margin-bottom: 100px;
|
||||
border: 1px solid var(--border-color) !important;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.how-it-works h2 {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.how-it-works h2 span {
|
||||
color: var(--accent-primary) !important;
|
||||
}
|
||||
|
||||
.steps {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 40px;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
display: block;
|
||||
color: var(--accent-primary);
|
||||
font-weight: 900;
|
||||
font-size: 64px;
|
||||
line-height: 1;
|
||||
margin-bottom: 16px;
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
/* Status colors */
|
||||
.text-success { color: var(--success-color) !important; }
|
||||
.text-danger { color: var(--error-color) !important; }
|
||||
.text-warning { color: var(--warning-color) !important; }
|
||||
.text-info { color: var(--info-color) !important; }
|
||||
|
||||
/* Swipe Buttons (Discovery) */
|
||||
.action-btn {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes gradient {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 85vh;
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
|
||||
backdrop-filter: blur(15px);
|
||||
-webkit-backdrop-filter: blur(15px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-header {
|
||||
padding: 1.5rem;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
/* Custom Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.message {
|
||||
max-width: 85%;
|
||||
padding: 0.85rem 1.1rem;
|
||||
border-radius: 16px;
|
||||
line-height: 1.5;
|
||||
font-size: 0.95rem;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.05);
|
||||
animation: fadeIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20px) scale(0.95); }
|
||||
to { opacity: 1; transform: translateY(0) scale(1); }
|
||||
}
|
||||
|
||||
.message.visitor {
|
||||
align-self: flex-end;
|
||||
background: linear-gradient(135deg, #212529 0%, #343a40 100%);
|
||||
color: #fff;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
.message.bot {
|
||||
align-self: flex-start;
|
||||
background: #ffffff;
|
||||
color: #212529;
|
||||
border-bottom-left-radius: 4px;
|
||||
}
|
||||
|
||||
.chat-input-area {
|
||||
padding: 1.25rem;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.chat-input-area form {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.chat-input-area input {
|
||||
flex: 1;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 12px;
|
||||
padding: 0.75rem 1rem;
|
||||
outline: none;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.chat-input-area input:focus {
|
||||
border-color: #23a6d5;
|
||||
box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.2);
|
||||
}
|
||||
|
||||
.chat-input-area button {
|
||||
background: #212529;
|
||||
color: #fff;
|
||||
border: none;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 12px;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--elevated-color);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.chat-input-area button:hover {
|
||||
background: #000;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
||||
.btn-dislike {
|
||||
color: var(--error-color);
|
||||
}
|
||||
|
||||
/* Background Animations */
|
||||
.bg-animations {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 0;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.blob {
|
||||
position: absolute;
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
filter: blur(80px);
|
||||
animation: move 20s infinite alternate cubic-bezier(0.45, 0, 0.55, 1);
|
||||
}
|
||||
|
||||
.blob-1 {
|
||||
top: -10%;
|
||||
left: -10%;
|
||||
background: rgba(238, 119, 82, 0.4);
|
||||
}
|
||||
|
||||
.blob-2 {
|
||||
bottom: -10%;
|
||||
right: -10%;
|
||||
background: rgba(35, 166, 213, 0.4);
|
||||
animation-delay: -7s;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.blob-3 {
|
||||
top: 40%;
|
||||
left: 30%;
|
||||
background: rgba(231, 60, 126, 0.3);
|
||||
animation-delay: -14s;
|
||||
width: 450px;
|
||||
height: 450px;
|
||||
}
|
||||
|
||||
@keyframes move {
|
||||
0% { transform: translate(0, 0) rotate(0deg) scale(1); }
|
||||
33% { transform: translate(150px, 100px) rotate(120deg) scale(1.1); }
|
||||
66% { transform: translate(-50px, 200px) rotate(240deg) scale(0.9); }
|
||||
100% { transform: translate(0, 0) rotate(360deg) scale(1); }
|
||||
}
|
||||
|
||||
.admin-link {
|
||||
font-size: 14px;
|
||||
.btn-dislike:hover {
|
||||
background: var(--error-color);
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 0.5rem 1rem;
|
||||
border-color: var(--error-color);
|
||||
}
|
||||
|
||||
.btn-like {
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
|
||||
.btn-like:hover {
|
||||
background: var(--accent-primary);
|
||||
color: #000;
|
||||
border-color: var(--accent-primary);
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
input, textarea, select {
|
||||
background: var(--elevated-color) !important;
|
||||
border: 1px solid var(--border-color) !important;
|
||||
color: var(--text-primary) !important;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.admin-link:hover {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Admin Styles */
|
||||
.admin-container {
|
||||
max-width: 900px;
|
||||
margin: 3rem auto;
|
||||
padding: 2.5rem;
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
border-radius: 24px;
|
||||
box-shadow: 0 20px 50px rgba(0,0,0,0.15);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.admin-container h1 {
|
||||
margin-top: 0;
|
||||
color: #212529;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0 8px;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 1rem;
|
||||
color: #6c757d;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.table td {
|
||||
background: #fff;
|
||||
padding: 1rem;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.table tr td:first-child { border-radius: 12px 0 0 12px; }
|
||||
.table tr td:last-child { border-radius: 0 12px 12px 0; }
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
transition: all 0.3s ease;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
outline: none;
|
||||
border-color: #23a6d5;
|
||||
box-shadow: 0 0 0 3px rgba(35, 166, 213, 0.1);
|
||||
width: 100%;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
input:focus, textarea:focus, select:focus {
|
||||
border-color: var(--accent-primary) !important;
|
||||
}
|
||||
|
||||
label {
|
||||
color: var(--text-secondary);
|
||||
font-size: 14px;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Modals */
|
||||
.modal-content {
|
||||
background-color: var(--elevated-color) !important;
|
||||
border: 1px solid var(--border-color) !important;
|
||||
box-shadow: 0 25px 60px rgba(0,0,0,0.8) !important;
|
||||
border-radius: 16px !important;
|
||||
}
|
||||
|
||||
/* Trending Pill */
|
||||
.trending-pill {
|
||||
background: var(--warning-color) !important;
|
||||
color: #000 !important;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 3px;
|
||||
margin-left: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Dashboard candidate cards */
|
||||
.candidate-card {
|
||||
background: var(--elevated-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.candidate-card:hover {
|
||||
border-color: var(--accent-primary);
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
padding: 80px 0 40px;
|
||||
background: var(--bg-color);
|
||||
border-top: 1px solid var(--border-color);
|
||||
margin-top: 120px;
|
||||
text-align: center;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.footer-links {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.footer-links a:hover {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.hero h1 {
|
||||
font-size: 48px;
|
||||
}
|
||||
.hero p {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
1
assets/docs/cvs/placeholder.pdf
Normal file
1
assets/docs/cvs/placeholder.pdf
Normal file
@ -0,0 +1 @@
|
||||
%PDF-1.4 Placeholder CV
|
||||
BIN
assets/docs/financials/doc_balance_sheets_1772313254.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772313254.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772313586.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772313586.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772313672.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772313672.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772313778.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772313778.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772314253.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772314253.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772314468.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772314468.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772314558.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772314558.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772314825.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772314825.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772319574.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772319574.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_balance_sheets_1772359761.xlsx
Normal file
BIN
assets/docs/financials/doc_balance_sheets_1772359761.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772313254.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772313254.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772313586.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772313586.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772313672.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772313672.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772313778.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772313778.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772314253.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772314253.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772314468.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772314468.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772314558.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772314558.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772314825.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772314825.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772319574.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772319574.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_cash_flow_statements_1772359761.xlsx
Normal file
BIN
assets/docs/financials/doc_cash_flow_statements_1772359761.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772313254.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772313254.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772313586.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772313586.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772313672.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772313672.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772313778.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772313778.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772314253.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772314253.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772314468.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772314468.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772314558.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772314558.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772314825.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772314825.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772319574.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772319574.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_gross_margin_1772359761.xlsx
Normal file
BIN
assets/docs/financials/doc_gross_margin_1772359761.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772313254.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772313254.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772313586.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772313586.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772313672.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772313672.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772313778.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772313778.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772314253.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772314253.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772314468.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772314468.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772314558.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772314558.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772314825.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772314825.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772319574.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772319574.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_income_statements_1772359761.xlsx
Normal file
BIN
assets/docs/financials/doc_income_statements_1772359761.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772313254.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772313254.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772313586.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772313586.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772313672.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772313672.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772313778.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772313778.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772314253.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772314253.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772314468.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772314468.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772314558.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772314558.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772314825.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772314825.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772319574.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772319574.xlsx
Normal file
Binary file not shown.
BIN
assets/docs/financials/doc_revenue_breakdown_1772359761.xlsx
Normal file
BIN
assets/docs/financials/doc_revenue_breakdown_1772359761.xlsx
Normal file
Binary file not shown.
1
assets/docs/financials/placeholder.pdf
Normal file
1
assets/docs/financials/placeholder.pdf
Normal file
@ -0,0 +1 @@
|
||||
Placeholder for financial document
|
||||
21
assets/images/logo.svg
Normal file
21
assets/images/logo.svg
Normal file
@ -0,0 +1,21 @@
|
||||
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- Gatsby: High-End Minimalist 'G' -->
|
||||
<defs>
|
||||
<filter id="neon-glow" x="-20%" y="-20%" width="140%" height="140%">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="2.5" />
|
||||
<feOffset dx="0" dy="0" result="offsetblur" />
|
||||
<feFlood flood-color="#00C853" flood-opacity="0.8" />
|
||||
<feComposite in2="offsetblur" operator="in" />
|
||||
<feMerge>
|
||||
<feMergeNode />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- The main 'G' frame -->
|
||||
<path d="M78 35C73 22 61 15 48 15C29 15 15 30 15 50C15 70 29 85 48 85C67 85 82 72 82 52H48" stroke="#00C853" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" filter="url(#neon-glow)" />
|
||||
|
||||
<!-- Center Dot -->
|
||||
<circle cx="48" cy="52" r="5" fill="#FFFFFF" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 890 B |
BIN
assets/vm-shot-2026-02-28T23-21-58-644Z.jpg
Normal file
BIN
assets/vm-shot-2026-02-28T23-21-58-644Z.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
387
create_startup.php
Normal file
387
create_startup.php
Normal file
@ -0,0 +1,387 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once 'ai/LocalAIApi.php';
|
||||
|
||||
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'founder') {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$countries = require_once 'includes/countries.php';
|
||||
|
||||
$success = '';
|
||||
$error = '';
|
||||
|
||||
$startupId = $_GET['id'] ?? null;
|
||||
$existingStartup = null;
|
||||
|
||||
if ($startupId) {
|
||||
$stmt = db()->prepare("SELECT * FROM startups WHERE id = ? AND founder_id = ?");
|
||||
$stmt->execute([$startupId, $_SESSION['user_id']]);
|
||||
$existingStartup = $stmt->fetch();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$name = $_POST['name'] ?? '';
|
||||
$description = $_POST['description'] ?? '';
|
||||
$legal_name = $_POST['legal_name'] ?? '';
|
||||
$country = $_POST['country'] ?? '';
|
||||
$industry = $_POST['industry'] ?? '';
|
||||
$sub_industry = $_POST['sub_industry'] ?? '';
|
||||
$business_model = $_POST['business_model'] ?? '';
|
||||
$product_service = $_POST['product_service'] ?? '';
|
||||
$operational_stage = $_POST['operational_stage'] ?? '';
|
||||
|
||||
$cofounder_equity_pct = $_POST['cofounder_equity_pct'] ?? 0.0;
|
||||
$cofounder_equity_type = $_POST['cofounder_equity_type'] ?? '';
|
||||
$cofounder_responsibilities = $_POST['cofounder_responsibilities'] ?? '';
|
||||
$repayment_term = (int)($_POST["repayment_term"] ?? 12);
|
||||
$desired_cofounder_experience = $_POST['desired_cofounder_experience'] ?? '';
|
||||
$cofounder_commitment = $_POST['cofounder_commitment'] ?? '';
|
||||
$other_partnership_details = $_POST['other_partnership_details'] ?? '';
|
||||
|
||||
$current_cash_balance = $_POST['current_cash_balance'] ?? 0.0;
|
||||
$burn_rate = $_POST['burn_rate'] ?? 0.0;
|
||||
$founder_return_rate = isset($_POST['founder_return_rate']) && $_POST['founder_return_rate'] !== '' ? (float)$_POST['founder_return_rate'] : null;
|
||||
|
||||
$doc_fields = [
|
||||
'doc_income_statements',
|
||||
'doc_balance_sheets',
|
||||
'doc_cash_flow_statements',
|
||||
'doc_revenue_breakdown',
|
||||
'doc_gross_margin'
|
||||
];
|
||||
|
||||
$uploaded_paths = [];
|
||||
foreach ($doc_fields as $field) {
|
||||
$uploaded_paths[$field] = $existingStartup[$field] ?? null;
|
||||
if (isset($_FILES[$field]) && $_FILES[$field]['error'] === UPLOAD_ERR_OK) {
|
||||
$ext = pathinfo($_FILES[$field]['name'], PATHINFO_EXTENSION);
|
||||
$new_name = $field . '_' . time() . '.' . $ext;
|
||||
$upload_dir = 'assets/docs/financials/';
|
||||
if (!is_dir($upload_dir)) mkdir($upload_dir, 0775, true);
|
||||
$upload_path = $upload_dir . $new_name;
|
||||
if (move_uploaded_file($_FILES[$field]['tmp_name'], $upload_path)) {
|
||||
$uploaded_paths[$field] = $upload_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
if (empty($name) || empty($description) || empty($legal_name) || empty($country) || empty($industry) || empty($business_model) || empty($product_service) || empty($operational_stage)) {
|
||||
$error = "Please fill in all mandatory company information fields, including the short pitch.";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
db()->beginTransaction();
|
||||
try {
|
||||
// Compute AI Recommended Return Rate
|
||||
$recommended_return_rate = $existingStartup['recommended_return_rate'] ?? 0.0;
|
||||
$recommended_return_reasoning = $existingStartup['recommended_return_reasoning'] ?? '';
|
||||
|
||||
$doc_list = [];
|
||||
foreach ($uploaded_paths as $key => $path) {
|
||||
if ($path) {
|
||||
$label = str_replace(['doc_', '_'], ['', ' '], $key);
|
||||
$doc_list[] = ucwords($label);
|
||||
}
|
||||
}
|
||||
$docs_str = !empty($doc_list) ? implode(", ", $doc_list) : "None";
|
||||
|
||||
// AI Prompt
|
||||
$prompt = "As a financial analyst, calculate a recommended annual dividend yield (interest percentage) based on this startup profile:
|
||||
Name: {$name}
|
||||
Short Pitch: {$description}
|
||||
Industry: {$industry}/{$sub_industry}
|
||||
Business Model: {$business_model}
|
||||
Product: {$product_service}
|
||||
Stage: {$operational_stage}
|
||||
Cash Balance: £{$current_cash_balance}
|
||||
Burn Rate: £{$burn_rate}
|
||||
Documents provided: {$docs_str}
|
||||
|
||||
Based on the financial documents provided and the company's stage/industry, please provide:
|
||||
1. A recommended return rate (percentage).
|
||||
2. A brief reasoning (2-3 sentences) on how you arrived at this figure, explicitly mentioning how the provided documents influenced your decision.
|
||||
|
||||
Respond ONLY with a JSON object: {\"recommended_rate\": X.X, \"reasoning\": \"...\"}";
|
||||
|
||||
$aiResponse = LocalAIApi::createResponse([
|
||||
'input' => [
|
||||
['role' => 'system', 'content' => 'You are a financial analyst. Return JSON only.'],
|
||||
['role' => 'user', 'content' => $prompt],
|
||||
],
|
||||
]);
|
||||
|
||||
if (!empty($aiResponse['success'])) {
|
||||
$decoded = LocalAIApi::decodeJsonFromResponse($aiResponse);
|
||||
$recommended_return_rate = (float)($decoded['recommended_rate'] ?? 5.0);
|
||||
$recommended_return_reasoning = (string)($decoded['reasoning'] ?? 'Based on industry standards and provided financials.');
|
||||
}
|
||||
|
||||
if ($existingStartup) {
|
||||
$stmt = db()->prepare("UPDATE startups SET
|
||||
name = ?, description = ?, legal_name = ?, country = ?, industry = ?, sub_industry = ?, business_model = ?, product_service = ?, operational_stage = ?,
|
||||
cofounder_equity_pct = ?, cofounder_equity_type = ?, cofounder_responsibilities = ?, desired_cofounder_experience = ?, cofounder_commitment = ?, other_partnership_details = ?,
|
||||
current_cash_balance = ?, burn_rate = ?,
|
||||
doc_income_statements = ?, doc_balance_sheets = ?, doc_cash_flow_statements = ?, doc_revenue_breakdown = ?, doc_gross_margin = ?,
|
||||
recommended_return_rate = ?, recommended_return_reasoning = ?, founder_return_rate = ?, repayment_term = ?
|
||||
WHERE id = ? AND founder_id = ?");
|
||||
|
||||
$stmt->execute([
|
||||
$name, $description, $legal_name, $country, $industry, $sub_industry, $business_model, $product_service, $operational_stage,
|
||||
$cofounder_equity_pct, $cofounder_equity_type, $cofounder_responsibilities, $desired_cofounder_experience, $cofounder_commitment, $other_partnership_details,
|
||||
$current_cash_balance, $burn_rate,
|
||||
$uploaded_paths['doc_income_statements'], $uploaded_paths['doc_balance_sheets'], $uploaded_paths['doc_cash_flow_statements'],
|
||||
$uploaded_paths['doc_revenue_breakdown'], $uploaded_paths['doc_gross_margin'],
|
||||
$recommended_return_rate, $recommended_return_reasoning, $founder_return_rate, $repayment_term,
|
||||
$existingStartup['id'], $_SESSION['user_id']
|
||||
]);
|
||||
$final_id = $existingStartup['id'];
|
||||
} else {
|
||||
$stmt = db()->prepare("INSERT INTO startups (
|
||||
name, description, legal_name, country, industry, sub_industry, business_model, product_service, operational_stage,
|
||||
cofounder_equity_pct, cofounder_equity_type, cofounder_responsibilities, desired_cofounder_experience, cofounder_commitment, other_partnership_details,
|
||||
current_cash_balance, burn_rate,
|
||||
doc_income_statements, doc_balance_sheets, doc_cash_flow_statements, doc_revenue_breakdown, doc_gross_margin,
|
||||
founder_id, recommended_return_rate, recommended_return_reasoning, founder_return_rate, repayment_term, status
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'private')");
|
||||
|
||||
$stmt->execute([
|
||||
$name, $description, $legal_name, $country, $industry, $sub_industry, $business_model, $product_service, $operational_stage,
|
||||
$cofounder_equity_pct, $cofounder_equity_type, $cofounder_responsibilities, $desired_cofounder_experience, $cofounder_commitment, $other_partnership_details,
|
||||
$current_cash_balance, $burn_rate,
|
||||
$uploaded_paths['doc_income_statements'], $uploaded_paths['doc_balance_sheets'], $uploaded_paths['doc_cash_flow_statements'],
|
||||
$uploaded_paths['doc_revenue_breakdown'], $uploaded_paths['doc_gross_margin'],
|
||||
$_SESSION['user_id'], $recommended_return_rate, $recommended_return_reasoning, $founder_return_rate, $repayment_term
|
||||
]);
|
||||
$final_id = db()->lastInsertId();
|
||||
}
|
||||
|
||||
db()->commit();
|
||||
$success = "Startup profile saved successfully! Recommended return rate: " . number_format($recommended_return_rate, 2) . "%" ;
|
||||
|
||||
// Refresh local data
|
||||
$stmt = db()->prepare("SELECT * FROM startups WHERE id = ?");
|
||||
$stmt->execute([$final_id]);
|
||||
$existingStartup = $stmt->fetch();
|
||||
|
||||
} catch (Exception $e) {
|
||||
db()->rollBack();
|
||||
$error = "Database error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><?= $existingStartup ? 'Edit' : 'Create' ?> Startup Profile | Venture Capitalist</title>
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
</head>
|
||||
<body style="background: var(--bg-color); color: #fff;">
|
||||
|
||||
<div class="container" style="padding: 40px 20px;">
|
||||
<div style="max-width: 800px; margin: 0 auto;">
|
||||
<h1 style="font-weight: 900; font-size: 32px; margin-bottom: 30px;"><?= $existingStartup ? 'Edit' : 'Create' ?> Startup Profile</h1>
|
||||
<a href="startups.php" style="display: inline-block; margin-bottom: 20px; color: #aaa; text-decoration: none; font-size: 14px;"><i class="fas fa-arrow-left"></i> Back to Startups</a>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div style="background: rgba(255, 59, 48, 0.1); color: #ff3b30; padding: 15px; border-radius: 12px; border: 1px solid #ff3b30; margin-bottom: 25px;">
|
||||
<i class="fas fa-exclamation-circle"></i> <?= $error ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div style="background: rgba(48, 209, 88, 0.1); color: #30d158; padding: 15px; border-radius: 12px; border: 1px solid #30d158; margin-bottom: 25px;">
|
||||
<i class="fas fa-check-circle"></i> <?= $success ?>
|
||||
<?php if (!$startupId): ?>
|
||||
<div style="margin-top: 15px;">
|
||||
<a href="start_funding_round.php?id=<?= $final_id ?>" class="btn btn-primary" style="display: inline-block;">Launch Funding Round Now</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<!-- Basic Info -->
|
||||
<section style="background: var(--card-bg); padding: 30px; border-radius: 20px; border: 1px solid var(--border-color); margin-bottom: 30px;">
|
||||
<h2 style="font-size: 20px; margin-bottom: 20px;"><i class="fas fa-info-circle" style="color: var(--accent-color);"></i> Company Information</h2>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Startup Name *</label>
|
||||
<input type="text" name="name" value="<?= htmlspecialchars($existingStartup['name'] ?? '') ?>" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Legal Entity Name *</label>
|
||||
<input type="text" name="legal_name" value="<?= htmlspecialchars($existingStartup['legal_name'] ?? '') ?>" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Country of Incorporation *</label>
|
||||
<select name="country" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
<option value="">Select Country</option>
|
||||
<?php foreach ($countries as $c): ?>
|
||||
<option value="<?= $c ?>" <?= ($existingStartup['country'] ?? '') === $c ? 'selected' : '' ?>><?= $c ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Industry *</label>
|
||||
<select name="industry" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
<option value="FinTech" <?= ($existingStartup['industry'] ?? '') === 'FinTech' ? 'selected' : '' ?>>FinTech</option>
|
||||
<option value="SaaS" <?= ($existingStartup['industry'] ?? '') === 'SaaS' ? 'selected' : '' ?>>SaaS</option>
|
||||
<option value="HealthTech" <?= ($existingStartup['industry'] ?? '') === 'HealthTech' ? 'selected' : '' ?>>HealthTech</option>
|
||||
<option value="E-commerce" <?= ($existingStartup['industry'] ?? '') === 'E-commerce' ? 'selected' : '' ?>>E-commerce</option>
|
||||
<option value="AI/ML" <?= ($existingStartup['industry'] ?? '') === 'AI/ML' ? 'selected' : '' ?>>AI/ML</option>
|
||||
<option value="CleanTech" <?= ($existingStartup['industry'] ?? '') === 'CleanTech' ? 'selected' : '' ?>>CleanTech</option>
|
||||
<option value="EdTech" <?= ($existingStartup['industry'] ?? '') === 'EdTech' ? 'selected' : '' ?>>EdTech</option>
|
||||
<option value="PropTech" <?= ($existingStartup['industry'] ?? '') === 'PropTech' ? 'selected' : '' ?>>PropTech</option>
|
||||
<option value="Other" <?= ($existingStartup['industry'] ?? '') === 'Other' ? 'selected' : '' ?>>Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Sub-Industry</label>
|
||||
<input type="text" name="sub_industry" value="<?= htmlspecialchars($existingStartup['sub_industry'] ?? '') ?>" placeholder="e.g. Payments, CRM, Bioinformatics" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Operational Stage *</label>
|
||||
<select name="operational_stage" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
<option value="Idea/Prototype" <?= ($existingStartup['operational_stage'] ?? '') === 'Idea/Prototype' ? 'selected' : '' ?>>Idea/Prototype</option>
|
||||
<option value="MVP/Early Traction" <?= ($existingStartup['operational_stage'] ?? '') === 'MVP/Early Traction' ? 'selected' : '' ?>>MVP/Early Traction</option>
|
||||
<option value="Growth/Scaling" <?= ($existingStartup['operational_stage'] ?? '') === 'Growth/Scaling' ? 'selected' : '' ?>>Growth/Scaling</option>
|
||||
<option value="Mature" <?= ($existingStartup['operational_stage'] ?? '') === 'Mature' ? 'selected' : '' ?>>Mature</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Short Description / Elevator Pitch *</label>
|
||||
<input type="text" name="description" value="<?= htmlspecialchars($existingStartup['description'] ?? '') ?>" required placeholder="A catchy one-sentence pitch (max 150 chars)" maxlength="255" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Business Model *</label>
|
||||
<textarea name="business_model" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff; height: 100px;" placeholder="e.g. B2B Subscription, Marketplace, Freemium..."><?= htmlspecialchars($existingStartup['business_model'] ?? '') ?></textarea>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Product/Service Overview *</label>
|
||||
<textarea name="product_service" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff; height: 100px;" placeholder="Describe what your startup actually does..."><?= htmlspecialchars($existingStartup['product_service'] ?? '') ?></textarea>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Financials -->
|
||||
<section style="background: var(--card-bg); padding: 30px; border-radius: 20px; border: 1px solid var(--border-color); margin-bottom: 30px;">
|
||||
<h2 style="font-size: 20px; margin-bottom: 20px;"><i class="fas fa-chart-line" style="color: var(--accent-color);"></i> Financial Overview</h2>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Current Cash Balance (£)</label>
|
||||
<input type="number" step="0.01" name="current_cash_balance" value="<?= htmlspecialchars($existingStartup['current_cash_balance'] ?? 0) ?>" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Monthly Burn Rate (£)</label>
|
||||
<input type="number" step="0.01" name="burn_rate" value="<?= htmlspecialchars($existingStartup['burn_rate'] ?? 0) ?>" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px; border-top: 1px solid #333; padding-top: 20px;">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 700;">Repayment Term (Months)</label>
|
||||
<input type="number" name="repayment_term" value="<?= htmlspecialchars($existingStartup["repayment_term"] ?? "12") ?>" min="1" max="60" required style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid var(--accent-color); color: #fff; font-size: 16px; font-weight: 700;">
|
||||
<small style="color: #aaa; display: block; margin-top: 8px;">The duration over which you will repay the investment plus interest.</small>
|
||||
</div>
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 700;">Proposed Investor Return (%)</label>
|
||||
<input type="number" step="0.1" name="founder_return_rate" value="<?= htmlspecialchars($existingStartup['founder_return_rate'] ?? '') ?>" placeholder="e.g. 8.5" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid var(--accent-color); color: #fff; font-size: 16px; font-weight: 700;">
|
||||
<small style="color: #aaa; display: block; margin-top: 8px;">Your proposed annual dividend yield. The platform also computes a recommendation based on your financials.</small>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 30px;">
|
||||
<h3 style="font-size: 16px; margin-bottom: 15px; color: #fff;">Upload Financial Documents (PDF/Images)</h3>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
|
||||
<?php
|
||||
$doc_labels = [
|
||||
'doc_income_statements' => 'Income Statements',
|
||||
'doc_balance_sheets' => 'Balance Sheets',
|
||||
'doc_cash_flow_statements' => 'Cash Flow Statements',
|
||||
'doc_revenue_breakdown' => 'Revenue Breakdown',
|
||||
'doc_gross_margin' => 'Gross Margin Analysis'
|
||||
];
|
||||
foreach ($doc_labels as $field => $label):
|
||||
?>
|
||||
<div style="background: #222; padding: 15px; border-radius: 12px; border: 1px solid #333;">
|
||||
<label style="display: block; margin-bottom: 8px; font-size: 14px; color: #aaa;"><?= $label ?></label>
|
||||
<input type="file" name="<?= $field ?>" style="width: 100%; color: #888; font-size: 12px;">
|
||||
<?php if (!empty($existingStartup[$field])):
|
||||
?>
|
||||
<div style="margin-top: 8px; font-size: 12px; color: var(--accent-color);">
|
||||
<i class="fas fa-file-alt"></i> Already uploaded
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Partnership & Co-founder Info -->
|
||||
<section style="background: var(--card-bg); padding: 30px; border-radius: 20px; border: 1px solid var(--border-color); margin-bottom: 30px;">
|
||||
<h2 style="font-size: 20px; margin-bottom: 20px;"><i class="fas fa-handshake" style="color: var(--accent-color);"></i> Partnership & Co-founder Info</h2>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Co-founder Equity (%)</label>
|
||||
<input type="number" step="0.1" name="cofounder_equity_pct" value="<?= htmlspecialchars($existingStartup['cofounder_equity_pct'] ?? 0) ?>" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Equity Type</label>
|
||||
<select name="cofounder_equity_type" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
<option value="Ordinary" <?= ($existingStartup['cofounder_equity_type'] ?? '') === 'Ordinary' ? 'selected' : '' ?>>Ordinary Shares</option>
|
||||
<option value="Restricted" <?= ($existingStartup['cofounder_equity_type'] ?? '') === 'Restricted' ? 'selected' : '' ?>>Restricted Stock</option>
|
||||
<option value="Phantom" <?= ($existingStartup['cofounder_equity_type'] ?? '') === 'Phantom' ? 'selected' : '' ?>>Phantom Equity</option>
|
||||
<option value="Options" <?= ($existingStartup['cofounder_equity_type'] ?? '') === 'Options' ? 'selected' : '' ?>>Stock Options</option>
|
||||
<option value="Other" <?= ($existingStartup['cofounder_equity_type'] ?? '') === 'Other' ? 'selected' : '' ?>>Other</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Co-founder Responsibilities</label>
|
||||
<textarea name="cofounder_responsibilities" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff; height: 80px;" placeholder="What will the co-founder be responsible for?"><?= htmlspecialchars($existingStartup['cofounder_responsibilities'] ?? '') ?></textarea>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px;">
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Desired Co-founder Experience</label>
|
||||
<textarea name="desired_cofounder_experience" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff; height: 80px;" placeholder="What background should they have?"><?= htmlspecialchars($existingStartup['desired_cofounder_experience'] ?? '') ?></textarea>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 20px;">
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Commitment Required</label>
|
||||
<select name="cofounder_commitment" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
<option value="Full-time" <?= ($existingStartup['cofounder_commitment'] ?? '') === 'Full-time' ? 'selected' : '' ?>>Full-time</option>
|
||||
<option value="Part-time" <?= ($existingStartup['cofounder_commitment'] ?? '') === 'Part-time' ? 'selected' : '' ?>>Part-time</option>
|
||||
<option value="Flexible" <?= ($existingStartup['cofounder_commitment'] ?? '') === 'Flexible' ? 'selected' : '' ?>>Flexible</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label style="display: block; margin-bottom: 8px; color: #aaa;">Other Partnership Details</label>
|
||||
<input type="text" name="other_partnership_details" value="<?= htmlspecialchars($existingStartup['other_partnership_details'] ?? '') ?>" style="width: 100%; padding: 12px; border-radius: 8px; background: #222; border: 1px solid #333; color: #fff;">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%; padding: 16px; border-radius: 12px; font-weight: 700; font-size: 18px;">
|
||||
Save & Compute AI Recommendation
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
509
dashboard.php
Normal file
509
dashboard.php
Normal file
@ -0,0 +1,509 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
require_once __DIR__ . "/sync_funding.php";
|
||||
syncRepayments();
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user) {
|
||||
session_destroy();
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($user['verified'] == 0) {
|
||||
session_destroy();
|
||||
header("Location: login.php?error=not_verified");
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($user['role'] === 'founder' && $user['onboarding_completed'] == 0) {
|
||||
header("Location: founder_onboarding.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
$trendingIds = [];
|
||||
$stmt = db()->prepare("
|
||||
SELECT s.id
|
||||
FROM startups s
|
||||
LEFT JOIN startup_followers sf ON s.id = sf.startup_id
|
||||
GROUP BY s.id
|
||||
ORDER BY COUNT(sf.id) DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$stmt->execute();
|
||||
$topFollowed = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$trendingIds = array_merge($trendingIds, $topFollowed);
|
||||
|
||||
$stmt = db()->prepare("
|
||||
SELECT id
|
||||
FROM startups
|
||||
ORDER BY funding_raised DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$stmt->execute();
|
||||
$topFunded = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$trendingIds = array_unique(array_merge($trendingIds, $topFunded));
|
||||
|
||||
$myStartups = [];
|
||||
$myInvestments = [];
|
||||
$repaymentSummary = [
|
||||
'total_raised' => 0,
|
||||
'total_obligation' => 0,
|
||||
'monthly_outgoing' => 0,
|
||||
'active_investors' => 0,
|
||||
'next_payment_date' => null
|
||||
];
|
||||
|
||||
if ($user['role'] === 'founder') {
|
||||
$stmt = db()->prepare("
|
||||
SELECT s.*, fr.funding_goal as active_goal, fr.funding_raised as active_raised, fr.status as round_status, fr.id as round_id
|
||||
FROM startups s
|
||||
LEFT JOIN funding_rounds fr ON s.id = fr.startup_id AND fr.status = 'Active'
|
||||
WHERE s.founder_id = ?
|
||||
ORDER BY s.created_at DESC
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$myStartups = $stmt->fetchAll();
|
||||
|
||||
// Repayment Summary Calculation
|
||||
$stmt = db()->prepare("
|
||||
SELECT
|
||||
SUM(CASE WHEN i.status IN ('approved', 'completed') THEN i.amount ELSE 0 END) as total_raised,
|
||||
SUM(CASE WHEN i.status IN ('approved', 'completed') THEN i.total_return ELSE 0 END) as total_obligation,
|
||||
SUM(CASE WHEN i.status = 'approved' THEN i.monthly_dividend ELSE 0 END) as monthly_outgoing,
|
||||
COUNT(DISTINCT CASE WHEN i.status = 'approved' THEN i.investor_id END) as active_investors,
|
||||
MIN(CASE WHEN i.status = 'approved' THEN i.next_payment_date END) as next_payment_date
|
||||
FROM investments i
|
||||
JOIN startups s ON i.startup_id = s.id
|
||||
WHERE s.founder_id = ?
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$repaymentSummary = $stmt->fetch();
|
||||
} else {
|
||||
$stmt = db()->prepare("SELECT i.*, s.name as startup_name FROM investments i JOIN startups s ON i.startup_id = s.id WHERE i.investor_id = ? ORDER BY i.created_at DESC");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$myInvestments = $stmt->fetchAll();
|
||||
}
|
||||
|
||||
function number_get_formatted($num) {
|
||||
return number_format((float)$num, 0, '.', ',');
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Dashboard — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.profile-link-card {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: transform 0.2s;
|
||||
display: block;
|
||||
}
|
||||
.profile-link-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.9);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
.repayment-stat-card {
|
||||
background: rgba(255,255,255,0.03);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
text-align: left;
|
||||
}
|
||||
.repayment-stat-label {
|
||||
font-size: 11px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 700;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.repayment-stat-value {
|
||||
font-size: 20px;
|
||||
font-weight: 900;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<a href="startups.php">My Startups</a>
|
||||
<a href="partners.php">Find Partners</a>
|
||||
<?php else: ?>
|
||||
<a href="funding_rounds.php">Founding Rounds</a>
|
||||
<a href="portfolio.php">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<?php endif; ?>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<div onclick="openWalletModal('add')" style="cursor: pointer; display: flex; align-items: center; gap: 8px; padding: 6px 14px; background: var(--surface-color); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<i class="fas fa-wallet" style="color: var(--accent-primary); font-size: 14px;"></i>
|
||||
<span id="header-wallet-balance" style="font-size: 14px; font-weight: 800; color: #fff;">£<?= number_format($user['balance'], 2) ?></span>
|
||||
</div>
|
||||
|
||||
<a href="notifications.php" style="color: var(--text-secondary); position: relative; font-size: 18px;">
|
||||
<i class="fas fa-bell"></i>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 6px 14px; background: var(--surface-color); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<div style="width: 24px; height: 24px; background: var(--accent-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #000; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container" style="padding-top: 60px; padding-bottom: 80px;">
|
||||
<div style="margin-bottom: 60px;">
|
||||
<div class="match-score-pill" style="margin-bottom: 24px; color: var(--accent-primary); font-weight: 700; font-size: 14px; text-transform: uppercase; letter-spacing: 1px;">
|
||||
<i class="fas fa-rocket"></i> Launchpad Active
|
||||
</div>
|
||||
<h1 style="font-size: 56px; font-weight: 900; letter-spacing: -2px; line-height: 1.1;">Welcome back, <span style="color: var(--accent-primary);"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?>.</span></h1>
|
||||
<p style="color: var(--text-secondary); font-size: 20px; margin-top: 10px;">Your command center for the next big thing.</p>
|
||||
</div>
|
||||
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<!-- Founder Repayment Dashboard -->
|
||||
<div class="card" style="margin-bottom: 40px; padding: 35px; border: 1px solid var(--accent-primary)33; background: linear-gradient(145deg, rgba(0, 242, 255, 0.05), transparent);">
|
||||
<h3 style="margin-bottom: 25px; font-size: 22px; font-weight: 800;"><i class="fas fa-chart-pie" style="color: var(--accent-primary); margin-right: 10px;"></i> Funding & Repayment Overview</h3>
|
||||
<div style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 15px;">
|
||||
<div class="repayment-stat-card">
|
||||
<div class="repayment-stat-label">Total Raised</div>
|
||||
<div class="repayment-stat-value">£<?= number_format($repaymentSummary['total_raised'] ?? 0, 0) ?></div>
|
||||
</div>
|
||||
<div class="repayment-stat-card">
|
||||
<div class="repayment-stat-label">Total Obligation</div>
|
||||
<div class="repayment-stat-value" style="color: var(--error-color);">£<?= number_format($repaymentSummary['total_obligation'] ?? 0, 0) ?></div>
|
||||
</div>
|
||||
<div class="repayment-stat-card">
|
||||
<div class="repayment-stat-label">Monthly Outgoing</div>
|
||||
<div class="repayment-stat-value" style="color: var(--warning-color);">£<?= number_format($repaymentSummary['monthly_outgoing'] ?? 0, 0) ?></div>
|
||||
</div>
|
||||
<div class="repayment-stat-card">
|
||||
<div class="repayment-stat-label">Active Investors</div>
|
||||
<div class="repayment-stat-value"><?= $repaymentSummary['active_investors'] ?? 0 ?></div>
|
||||
</div>
|
||||
<div class="repayment-stat-card">
|
||||
<div class="repayment-stat-label">Next Due Date</div>
|
||||
<div class="repayment-stat-value" style="font-size: 16px;"><?= $repaymentSummary['next_payment_date'] ? date('M d, Y', strtotime($repaymentSummary['next_payment_date'])) : 'None' ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 40px;">
|
||||
<div>
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<div class="card" style="margin-bottom: 40px; padding: 35px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;">
|
||||
<h3 style="margin: 0; font-size: 24px; font-weight: 800;">My Ventures</h3>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<a href="create_startup.php" class="btn btn-primary" style="padding: 12px 24px; font-size: 13px;">+ Launch Startup</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (empty($myStartups)): ?>
|
||||
<div style="text-align: center; padding: 60px 0; background: var(--elevated-color); border-radius: 16px; border: 1px dashed var(--border-color);">
|
||||
<div class="card-icon" style="margin: 0 auto 20px;"><i class="fas fa-rocket"></i></div>
|
||||
<p style="color: var(--text-secondary); margin-bottom: 25px; font-size: 18px;">Ready to share your vision with the world?</p>
|
||||
<a href="create_startup.php" class="btn btn-primary">Start Your First Round</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div style="display: grid; grid-template-columns: 1fr; gap: 20px;">
|
||||
<?php foreach ($myStartups as $startup):
|
||||
$goal = $startup['active_goal'] ?? $startup['funding_target'];
|
||||
$raised = $startup['active_raised'] ?? $startup['funding_raised'];
|
||||
$isTrending = in_array($startup['id'], $trendingIds);
|
||||
?>
|
||||
<div class="candidate-card" style="padding: 25px; display: flex; justify-content: space-between; align-items: center; cursor: pointer;" onclick="window.location.href='startup_details.php?id=<?= $startup['id'] ?>'">
|
||||
<div style="display: flex; align-items: center; gap: 20px;">
|
||||
<div style="width: 60px; height: 60px; background: var(--accent-primary); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; color: #000; font-weight: 800;">
|
||||
<?= substr($startup['name'], 0, 1) ?>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight: 800; font-size: 20px; margin-bottom: 6px;">
|
||||
<?= htmlspecialchars($startup['name']) ?>
|
||||
<?php if ($isTrending): ?>
|
||||
<span class="trending-pill"><i class="fas fa-fire"></i> Trending</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div style="font-size: 14px; color: var(--text-secondary); display: flex; align-items: center; gap: 12px;">
|
||||
<span style="padding: 4px 10px; background: var(--surface-color); color: var(--accent-primary); border-radius: 6px; font-weight: 700; font-size: 11px; letter-spacing: 0.5px; border: 1px solid var(--border-color);">
|
||||
<?= strtoupper($startup['round_status'] ?? 'Draft') ?>
|
||||
</span>
|
||||
<span style="opacity: 0.7;">Target: £<?= number_get_formatted($goal) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; gap: 20px; align-items: center;">
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 22px; font-weight: 900; color: #fff;">£<?= number_get_formatted($raised) ?></div>
|
||||
<div style="font-size: 13px; color: var(--text-secondary); opacity: 0.6;">Funds Raised</div>
|
||||
</div>
|
||||
<?php if ($startup['round_status'] === 'Active'): ?>
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<button onclick="event.stopPropagation(); updateRound(<?= $startup['round_id'] ?>, 'Closed')" class="btn" style="padding: 8px 14px; font-size: 11px; background: var(--success-color); color: #000;">Finish</button>
|
||||
<button onclick="event.stopPropagation(); updateRound(<?= $startup['round_id'] ?>, 'Cancelled')" class="btn" style="padding: 8px 14px; font-size: 11px; background: var(--error-color); color: #fff;">Cancel</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="card" style="margin-bottom: 40px; padding: 35px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;">
|
||||
<h3 style="margin: 0; font-size: 24px; font-weight: 800;">Portfolio Overview</h3>
|
||||
<a href="funding_rounds.php" class="btn btn-primary" style="padding: 12px 24px; font-size: 13px;">Find New Deals</a>
|
||||
</div>
|
||||
|
||||
<?php if (empty($myInvestments)): ?>
|
||||
<div style="text-align: center; padding: 60px 0; background: var(--elevated-color); border-radius: 16px; border: 1px dashed var(--border-color);">
|
||||
<div class="card-icon" style="margin: 0 auto 20px;"><i class="fas fa-chart-line"></i></div>
|
||||
<p style="color: var(--text-secondary); margin-bottom: 25px; font-size: 18px;">Start backing the next generation of founders.</p>
|
||||
<a href="funding_rounds.php" class="btn btn-primary">Start Investing</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div style="display: grid; grid-template-columns: 1fr; gap: 20px;">
|
||||
<?php foreach ($myInvestments as $inv): ?>
|
||||
<div class="candidate-card" style="padding: 25px; display: flex; justify-content: space-between; align-items: center; cursor: pointer;" onclick="window.location.href='startup_details.php?id=<?= $inv['startup_id'] ?>'">
|
||||
<div style="display: flex; align-items: center; gap: 20px;">
|
||||
<div style="width: 60px; height: 60px; background: var(--surface-color); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; border: 1px solid var(--border-color);">
|
||||
<i class="fas fa-building" style="opacity: 0.5;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight: 800; font-size: 20px; margin-bottom: 6px;"><?= htmlspecialchars($inv['startup_name']) ?></div>
|
||||
<div style="font-size: 14px; color: var(--text-secondary);">Committed on <?= date('M d, Y', strtotime($inv['created_at'])) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 22px; font-weight: 900; color: var(--accent-primary);">£<?= number_get_formatted($inv['amount']) ?></div>
|
||||
<div style="font-size: 13px; font-weight: 800; color: <?= $inv['status'] === 'approved' ? 'var(--success-color)' : ($inv['status'] === 'rejected' ? 'var(--error-color)' : 'var(--warning-color)') ?>; letter-spacing: 1px;">
|
||||
<?= strtoupper($inv['status']) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="card" style="padding: 40px; text-align: center; border-style: dashed;">
|
||||
<h3 style="font-size: 22px; font-weight: 800; margin-bottom: 10px;">Ecosystem Activity</h3>
|
||||
<p style="color: var(--text-secondary); font-size: 16px;">Insights from your network and trending matches will appear here.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- Money Pot Section -->
|
||||
<div class="card" style="margin-bottom: 30px; padding: 30px; background: var(--elevated-color);">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px;">
|
||||
<h3 style="margin: 0; font-size: 18px; font-weight: 800; color: var(--accent-primary);">My Money Pot</h3>
|
||||
<i class="fas fa-wallet" style="color: var(--accent-primary); opacity: 0.5;"></i>
|
||||
</div>
|
||||
<div style="margin-bottom: 32px;">
|
||||
<span style="font-size: 12px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; font-weight: 700;">Available Balance</span>
|
||||
<div id="wallet-balance" style="font-size: 40px; font-weight: 900; color: #fff; margin-top: 5px; letter-spacing: -1px;">£<?= number_format($user['balance'], 2) ?></div>
|
||||
</div>
|
||||
<div style="display: grid; grid-template-columns: 1fr; gap: 12px;">
|
||||
<button onclick="openWalletModal('add')" class="btn btn-primary" style="padding: 14px; font-size: 13px;">
|
||||
<i class="fas fa-plus-circle" style="margin-right: 8px;"></i> Add Funds
|
||||
</button>
|
||||
<button onclick="openWalletModal('withdraw')" class="btn btn-secondary" style="padding: 14px; font-size: 13px;">
|
||||
<i class="fas fa-minus-circle" style="margin-right: 8px;"></i> Withdraw
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-bottom: 30px; padding: 30px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px;">
|
||||
<h3 style="margin: 0; font-size: 20px; font-weight: 800;">My Profile</h3>
|
||||
<a href="edit_profile.php" style="color: var(--accent-primary); font-size: 13px; font-weight: 700; text-decoration: none; padding: 6px 14px; background: var(--surface-color); border-radius: 50px; border: 1px solid var(--border-color);">Edit</a>
|
||||
</div>
|
||||
<a href="profile.php?id=<?= $user['id'] ?>" class="profile-link-card">
|
||||
<div style="display: flex; align-items: center; gap: 20px; margin-bottom: 25px;">
|
||||
<div style="width: 80px; height: 80px; background: var(--accent-primary); border-radius: 16px; display: flex; align-items: center; justify-content: center; font-size: 32px; color: #000; font-weight: 900;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight: 900; font-size: 22px; letter-spacing: -0.5px;"><?= htmlspecialchars($user['full_name']) ?></div>
|
||||
<div style="font-size: 14px; color: var(--accent-primary); font-weight: 700; opacity: 0.8;"><?= htmlspecialchars($user['university']) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div style="margin-bottom: 25px; font-size: 15px; line-height: 1.6; color: var(--text-secondary);">
|
||||
<?= htmlspecialchars($user['bio'] ?: 'No bio provided yet.') ?>
|
||||
</div>
|
||||
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 10px;">
|
||||
<?php
|
||||
$skills = explode(',', $user['skills'] ?? '');
|
||||
foreach (array_slice($skills, 0, 3) as $skill): if(empty(trim($skill))) continue; ?>
|
||||
<span style="font-size: 11px; padding: 6px 14px; background: var(--surface-color); border-radius: 50px; border: 1px solid var(--border-color); font-weight: 600; color: var(--text-secondary);"><?= htmlspecialchars(trim($skill)) ?></span>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="card" style="background: var(--accent-primary); color: #000; border: none; margin-bottom: 30px; padding: 30px;">
|
||||
<h3 style="color: #000; margin-bottom: 12px; font-size: 22px; font-weight: 800;"><?= $user['role'] === 'founder' ? 'Find Your Team' : 'Discover Talent' ?></h3>
|
||||
<p style="font-size: 15px; opacity: 0.8; margin-bottom: 25px; font-weight: 500;">
|
||||
<?= $user['role'] === 'founder' ? 'Start swiping to find co-founders with complementary skills.' : 'Explore the most promising student startups today.' ?>
|
||||
</p>
|
||||
<a href="<?= $user['role'] === 'founder' ? 'partners.php' : 'discover.php' ?>" class="btn" style="width: 100%; background: #000; color: var(--accent-primary); font-weight: 800; text-align: center;">
|
||||
<?= $user['role'] === 'founder' ? 'Launch Matching' : 'Go to Discovery Hub' ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Wallet Modal -->
|
||||
<div id="wallet-modal" class="modal">
|
||||
<div class="modal-content" style="width: 100%; max-width: 420px; margin: 10% auto;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;">
|
||||
<h2 id="modal-title" style="margin: 0; font-size: 24px; font-weight: 900; color: #fff;">Add Funds</h2>
|
||||
<button onclick="closeWalletModal()" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 20px;"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<form id="wallet-form">
|
||||
<input type="hidden" id="wallet-action" name="action" value="add">
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 12px; font-size: 12px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; font-weight: 700;">Amount (£)</label>
|
||||
<input type="number" id="wallet-amount" name="amount" min="1" step="0.01" required placeholder="0.00"
|
||||
style="width: 100%; padding: 18px; background: var(--bg-color); border: 1px solid var(--border-color); border-radius: 12px; color: #fff; font-size: 24px; font-weight: 800;">
|
||||
</div>
|
||||
<button type="submit" id="wallet-submit-btn" class="btn btn-primary" style="width: 100%; padding: 18px; font-size: 16px;">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function openWalletModal(action) {
|
||||
const modal = document.getElementById('wallet-modal');
|
||||
const title = document.getElementById('modal-title');
|
||||
const actionInput = document.getElementById('wallet-action');
|
||||
const submitBtn = document.getElementById('wallet-submit-btn');
|
||||
|
||||
actionInput.value = action;
|
||||
if (action === 'add') {
|
||||
title.innerText = 'Add Funds';
|
||||
submitBtn.innerText = 'Confirm Deposit';
|
||||
submitBtn.className = 'btn btn-primary';
|
||||
} else {
|
||||
title.innerText = 'Withdraw Funds';
|
||||
submitBtn.innerText = 'Confirm Withdrawal';
|
||||
submitBtn.className = 'btn btn-secondary';
|
||||
}
|
||||
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
|
||||
function closeWalletModal() {
|
||||
document.getElementById('wallet-modal').style.display = 'none';
|
||||
}
|
||||
|
||||
document.getElementById('wallet-form').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(this);
|
||||
|
||||
fetch('api/wallet_transaction.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const formattedBalance = '£' + parseFloat(data.new_balance).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
if (document.getElementById('wallet-balance')) {
|
||||
document.getElementById('wallet-balance').innerText = formattedBalance;
|
||||
}
|
||||
if (document.getElementById('header-wallet-balance')) {
|
||||
document.getElementById('header-wallet-balance').innerText = formattedBalance;
|
||||
}
|
||||
closeWalletModal();
|
||||
alert(formData.get('action') === 'add' ? 'Funds added successfully!' : 'Withdrawal successful!');
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An unexpected error occurred.');
|
||||
});
|
||||
});
|
||||
|
||||
function updateRound(roundId, status) {
|
||||
if (confirm('Are you sure you want to ' + status.toLowerCase() + ' this funding round?')) {
|
||||
const formData = new FormData();
|
||||
formData.append('round_id', roundId);
|
||||
formData.append('status', status);
|
||||
|
||||
fetch('update_round_status.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('wallet-modal');
|
||||
if (event.target == modal) {
|
||||
closeWalletModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,17 +1,22 @@
|
||||
<?php
|
||||
// Generated by setup_mariadb_project.sh — edit as needed.
|
||||
// Database configuration
|
||||
define('DB_HOST', '127.0.0.1');
|
||||
define('DB_NAME', 'app_38384');
|
||||
define('DB_USER', 'app_38384');
|
||||
define('DB_PASS', '5561099f-23a3-43d8-b1a2-54739c50721b');
|
||||
define('DB_NAME', 'app_38873');
|
||||
define('DB_USER', 'app_38873');
|
||||
define('DB_PASS', 'd2654632-5c87-4757-a602-36b9781cab66');
|
||||
define('PLATFORM_NAME', 'Gatsby');
|
||||
|
||||
function db() {
|
||||
static $pdo;
|
||||
if (!$pdo) {
|
||||
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]);
|
||||
try {
|
||||
$pdo = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8mb4', DB_USER, DB_PASS, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
die("Connection failed: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
58
db/migrations/01_initial_schema.sql
Normal file
58
db/migrations/01_initial_schema.sql
Normal file
@ -0,0 +1,58 @@
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
full_name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
role ENUM('founder', 'investor') NOT NULL,
|
||||
university VARCHAR(255),
|
||||
graduation_year INT,
|
||||
bio TEXT,
|
||||
interests TEXT, -- Store as JSON or comma-separated tags
|
||||
investment_appetite VARCHAR(255),
|
||||
verified TINYINT(1) DEFAULT 0,
|
||||
verification_code VARCHAR(100),
|
||||
profile_photo VARCHAR(255),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS startups (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
founder_id INT NOT NULL,
|
||||
funding_target DECIMAL(15, 2),
|
||||
funding_raised DECIMAL(15, 2) DEFAULT 0.00,
|
||||
status ENUM('public', 'private') DEFAULT 'public',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (founder_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS investments (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
investor_id INT NOT NULL,
|
||||
startup_id INT NOT NULL,
|
||||
amount DECIMAL(15, 2) NOT NULL,
|
||||
status ENUM('pending', 'approved', 'rejected') DEFAULT 'pending',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (investor_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (startup_id) REFERENCES startups(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
sender_id INT NOT NULL,
|
||||
receiver_id INT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (receiver_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
is_read TINYINT(1) DEFAULT 0,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
15
db/migrations/02_onboarding_fields.sql
Normal file
15
db/migrations/02_onboarding_fields.sql
Normal file
@ -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;
|
||||
26
db/migrations/03_founder_matching.sql
Normal file
26
db/migrations/03_founder_matching.sql
Normal file
@ -0,0 +1,26 @@
|
||||
-- Migration: Founder Matching and Additional Fields
|
||||
CREATE TABLE IF NOT EXISTS swipes (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
swiper_id INT NOT NULL,
|
||||
swiped_id INT NOT NULL,
|
||||
direction ENUM('like', 'dislike') NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (swiper_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (swiped_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY unique_swipe (swiper_id, swiped_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS matches (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user1_id INT NOT NULL,
|
||||
user2_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user1_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user2_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY unique_match (user1_id, user2_id)
|
||||
);
|
||||
|
||||
-- Add missing onboarding fields
|
||||
ALTER TABLE users
|
||||
ADD COLUMN preferred_working_style ENUM('remote', 'in-person', 'hybrid') AFTER risk_tolerance,
|
||||
ADD COLUMN availability VARCHAR(255) AFTER preferred_working_style;
|
||||
30
db/migrations/04_funding_rounds.sql
Normal file
30
db/migrations/04_funding_rounds.sql
Normal file
@ -0,0 +1,30 @@
|
||||
-- Migration: Independent Funding Rounds and Pot System
|
||||
|
||||
-- 1. Create funding_rounds table
|
||||
CREATE TABLE IF NOT EXISTS funding_rounds (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
startup_id INT NOT NULL,
|
||||
funding_goal DECIMAL(15, 2) NOT NULL,
|
||||
funding_raised DECIMAL(15, 2) DEFAULT 0.00,
|
||||
status ENUM('Active', 'Closed', 'Cancelled') DEFAULT 'Active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (startup_id) REFERENCES startups(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
-- 2. Modify investments table to link to funding_rounds
|
||||
ALTER TABLE investments ADD COLUMN funding_round_id INT AFTER startup_id;
|
||||
ALTER TABLE investments ADD FOREIGN KEY (funding_round_id) REFERENCES funding_rounds(id) ON DELETE CASCADE;
|
||||
|
||||
-- 3. Update startups table to allow NULL founder_id (for deleted accounts)
|
||||
ALTER TABLE startups DROP FOREIGN KEY startups_ibfk_1;
|
||||
ALTER TABLE startups MODIFY founder_id INT NULL;
|
||||
ALTER TABLE startups ADD CONSTRAINT startups_founder_fk FOREIGN KEY (founder_id) REFERENCES users(id) ON DELETE SET NULL;
|
||||
|
||||
-- 4. Seed initial funding rounds from existing startup data if any
|
||||
INSERT INTO funding_rounds (startup_id, funding_goal, funding_raised, status, created_at)
|
||||
SELECT id, funding_target, funding_raised, 'Active', created_at FROM startups;
|
||||
|
||||
-- 5. Link existing investments to the newly created rounds
|
||||
UPDATE investments i
|
||||
JOIN funding_rounds fr ON i.startup_id = fr.startup_id
|
||||
SET i.funding_round_id = fr.id;
|
||||
2
db/migrations/05_investment_refund_status.sql
Normal file
2
db/migrations/05_investment_refund_status.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- Migration: Add Refunded status to investments
|
||||
ALTER TABLE investments MODIFY COLUMN status ENUM('pending', 'approved', 'rejected', 'Refunded') DEFAULT 'pending';
|
||||
11
db/migrations/06_startup_updates.sql
Normal file
11
db/migrations/06_startup_updates.sql
Normal file
@ -0,0 +1,11 @@
|
||||
-- Migration: Add startup_updates table for founder progress reports
|
||||
CREATE TABLE IF NOT EXISTS startup_updates (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
startup_id INT NOT NULL,
|
||||
founder_id INT NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (startup_id) REFERENCES startups(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (founder_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
10
db/migrations/07_startup_followers.sql
Normal file
10
db/migrations/07_startup_followers.sql
Normal file
@ -0,0 +1,10 @@
|
||||
-- Migration: Add startup_followers table
|
||||
CREATE TABLE IF NOT EXISTS startup_followers (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
startup_id INT NOT NULL,
|
||||
user_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_follow (startup_id, user_id),
|
||||
FOREIGN KEY (startup_id) REFERENCES startups(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
5
db/migrations/08_message_requests.sql
Normal file
5
db/migrations/08_message_requests.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- Migration: Add status and startup_id to messages
|
||||
ALTER TABLE messages
|
||||
ADD COLUMN status ENUM('pending', 'accepted', 'rejected') DEFAULT 'accepted' AFTER content,
|
||||
ADD COLUMN startup_id INT NULL AFTER status,
|
||||
ADD CONSTRAINT fk_messages_startup FOREIGN KEY (startup_id) REFERENCES startups(id) ON DELETE SET NULL;
|
||||
13
db/migrations/09_unmatch_and_block.sql
Normal file
13
db/migrations/09_unmatch_and_block.sql
Normal file
@ -0,0 +1,13 @@
|
||||
-- Migration: Unmatch and Block Features
|
||||
CREATE TABLE IF NOT EXISTS blocked_users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
blocker_id INT NOT NULL,
|
||||
blocked_id INT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (blocker_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (blocked_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY unique_block (blocker_id, blocked_id)
|
||||
);
|
||||
|
||||
-- Add status to matches to allow unmatching without deleting history
|
||||
ALTER TABLE matches ADD COLUMN status ENUM('active', 'unmatched') DEFAULT 'active';
|
||||
7
db/migrations/10_add_missing_startup_fields.sql
Normal file
7
db/migrations/10_add_missing_startup_fields.sql
Normal file
@ -0,0 +1,7 @@
|
||||
-- Migration: Add missing fields to startups table for Discovery Hub and Details page
|
||||
ALTER TABLE startups
|
||||
ADD COLUMN industry VARCHAR(100) AFTER description,
|
||||
ADD COLUMN followers_count INT DEFAULT 0 AFTER status;
|
||||
|
||||
-- Initialize followers_count from existing startup_followers table
|
||||
UPDATE startups s SET followers_count = (SELECT COUNT(*) FROM startup_followers WHERE startup_id = s.id);
|
||||
6
db/migrations/11_startup_financials.sql
Normal file
6
db/migrations/11_startup_financials.sql
Normal file
@ -0,0 +1,6 @@
|
||||
-- Migration: Add financial and return rate fields to startups table
|
||||
ALTER TABLE startups
|
||||
ADD COLUMN equity_structure TEXT AFTER description,
|
||||
ADD COLUMN financial_doc_path VARCHAR(255) AFTER industry,
|
||||
ADD COLUMN recommended_return_rate DECIMAL(5, 2) AFTER followers_count,
|
||||
ADD COLUMN founder_return_rate DECIMAL(5, 2) AFTER recommended_return_rate;
|
||||
24
db/migrations/12_detailed_startup_profile.sql
Normal file
24
db/migrations/12_detailed_startup_profile.sql
Normal file
@ -0,0 +1,24 @@
|
||||
-- Migration: Add detailed startup profile fields
|
||||
ALTER TABLE startups
|
||||
ADD COLUMN legal_name VARCHAR(255) AFTER name,
|
||||
ADD COLUMN country VARCHAR(100) AFTER legal_name,
|
||||
ADD COLUMN sub_industry VARCHAR(100) AFTER industry,
|
||||
ADD COLUMN business_model TEXT AFTER sub_industry,
|
||||
ADD COLUMN product_service TEXT AFTER business_model,
|
||||
ADD COLUMN operational_stage VARCHAR(100) AFTER product_service,
|
||||
ADD COLUMN total_shares BIGINT AFTER operational_stage,
|
||||
ADD COLUMN share_classes TEXT AFTER total_shares,
|
||||
ADD COLUMN founder_ownership TEXT AFTER share_classes,
|
||||
ADD COLUMN investor_ownership TEXT AFTER founder_ownership,
|
||||
ADD COLUMN esop_percentage DECIMAL(5,2) AFTER investor_ownership,
|
||||
ADD COLUMN convertible_instruments TEXT AFTER esop_percentage,
|
||||
ADD COLUMN current_cash_balance DECIMAL(15,2) AFTER convertible_instruments,
|
||||
ADD COLUMN outstanding_debt TEXT AFTER current_cash_balance,
|
||||
ADD COLUMN accounts_receivable_payable TEXT AFTER outstanding_debt,
|
||||
ADD COLUMN burn_rate DECIMAL(15,2) AFTER accounts_receivable_payable,
|
||||
ADD COLUMN doc_income_statements VARCHAR(255) AFTER financial_doc_path,
|
||||
ADD COLUMN doc_balance_sheets VARCHAR(255) AFTER doc_income_statements,
|
||||
ADD COLUMN doc_cash_flow_statements VARCHAR(255) AFTER doc_balance_sheets,
|
||||
ADD COLUMN doc_revenue_breakdown VARCHAR(255) AFTER doc_cash_flow_statements,
|
||||
ADD COLUMN doc_gross_margin VARCHAR(255) AFTER doc_revenue_breakdown,
|
||||
ADD COLUMN doc_opex_breakdown VARCHAR(255) AFTER doc_gross_margin;
|
||||
24
db/migrations/13_repurpose_equity_fields.sql
Normal file
24
db/migrations/13_repurpose_equity_fields.sql
Normal file
@ -0,0 +1,24 @@
|
||||
-- Migration: Repurpose equity fields for co-founder matching
|
||||
ALTER TABLE startups
|
||||
RENAME COLUMN total_shares TO cofounder_equity_pct;
|
||||
|
||||
ALTER TABLE startups
|
||||
MODIFY COLUMN cofounder_equity_pct VARCHAR(255); -- Change to string to allow ranges or descriptions
|
||||
|
||||
ALTER TABLE startups
|
||||
RENAME COLUMN share_classes TO cofounder_equity_type;
|
||||
|
||||
ALTER TABLE startups
|
||||
RENAME COLUMN founder_ownership TO cofounder_responsibilities;
|
||||
|
||||
ALTER TABLE startups
|
||||
RENAME COLUMN investor_ownership TO desired_cofounder_experience;
|
||||
|
||||
ALTER TABLE startups
|
||||
RENAME COLUMN esop_percentage TO cofounder_commitment;
|
||||
|
||||
ALTER TABLE startups
|
||||
MODIFY COLUMN cofounder_commitment VARCHAR(255);
|
||||
|
||||
ALTER TABLE startups
|
||||
RENAME COLUMN convertible_instruments TO other_partnership_details;
|
||||
9
db/migrations/14_ai_chats_table.sql
Normal file
9
db/migrations/14_ai_chats_table.sql
Normal file
@ -0,0 +1,9 @@
|
||||
-- Migration: Create ai_chats table for AI assistant
|
||||
CREATE TABLE IF NOT EXISTS ai_chats (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NULL,
|
||||
user_message TEXT NOT NULL,
|
||||
ai_response TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
|
||||
);
|
||||
14
db/migrations/15_faqs_table.sql
Normal file
14
db/migrations/15_faqs_table.sql
Normal file
@ -0,0 +1,14 @@
|
||||
-- Migration: Create faqs table for AI assistant knowledge base
|
||||
CREATE TABLE IF NOT EXISTS faqs (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
keywords TEXT NOT NULL,
|
||||
answer TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Seed some initial FAQs
|
||||
INSERT INTO faqs (keywords, answer) VALUES
|
||||
('What is Gatsby?', 'Gatsby is an exclusive student-led startup network for university students and graduates to connect, hire talent, and raise capital.'),
|
||||
('How can I raise money?', 'Startups can launch a funding round from their dashboard. Investors can browse startups and invest in verified ventures.'),
|
||||
('Who can join Gatsby?', 'Any student or graduate with a valid university email address can join and become a founder or investor.'),
|
||||
('What is the minimum investment?', 'The minimum investment is set by the founder of each startup round, but is typically around £100 for micro-investments.');
|
||||
3
db/migrations/16_recommended_return_reasoning.sql
Normal file
3
db/migrations/16_recommended_return_reasoning.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- Migration: Add recommended return reasoning to startups
|
||||
ALTER TABLE startups
|
||||
ADD COLUMN recommended_return_reasoning TEXT AFTER recommended_return_rate;
|
||||
2
db/migrations/17_add_equity_pct_to_investments.sql
Normal file
2
db/migrations/17_add_equity_pct_to_investments.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- Migration: Add equity_pct to investments table
|
||||
ALTER TABLE investments ADD COLUMN equity_pct DECIMAL(5, 2) DEFAULT 0.00 AFTER amount;
|
||||
3
db/migrations/18_add_cv_and_country_to_users.sql
Normal file
3
db/migrations/18_add_cv_and_country_to_users.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- Add CV and Country fields to users table
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS cv_url VARCHAR(255) DEFAULT NULL;
|
||||
ALTER TABLE users ADD COLUMN IF NOT EXISTS country VARCHAR(100) DEFAULT NULL;
|
||||
2
db/migrations/19_add_balance_to_users.sql
Normal file
2
db/migrations/19_add_balance_to_users.sql
Normal file
@ -0,0 +1,2 @@
|
||||
-- Add balance to users table
|
||||
ALTER TABLE users ADD COLUMN balance DECIMAL(15, 2) DEFAULT 0.00;
|
||||
16
db/migrations/20_repayment_system.sql
Normal file
16
db/migrations/20_repayment_system.sql
Normal file
@ -0,0 +1,16 @@
|
||||
-- Migration: Repayment and Dividend System
|
||||
|
||||
-- 1. Add repayment_term to startups table
|
||||
ALTER TABLE startups ADD COLUMN repayment_term INT DEFAULT 12 AFTER founder_return_rate;
|
||||
|
||||
-- 2. Update investments table with locked terms and payment tracking
|
||||
ALTER TABLE investments
|
||||
ADD COLUMN interest_rate DECIMAL(5, 2) AFTER amount,
|
||||
ADD COLUMN repayment_term INT AFTER interest_rate,
|
||||
ADD COLUMN total_return DECIMAL(15, 2) AFTER repayment_term,
|
||||
ADD COLUMN monthly_dividend DECIMAL(15, 2) AFTER total_return,
|
||||
ADD COLUMN paid_amount DECIMAL(15, 2) DEFAULT 0.00 AFTER monthly_dividend,
|
||||
ADD COLUMN next_payment_date DATE AFTER paid_amount;
|
||||
|
||||
-- 3. Update status enum in investments table
|
||||
ALTER TABLE investments MODIFY COLUMN status ENUM('pending', 'approved', 'rejected', 'completed') DEFAULT 'pending';
|
||||
311
discover.php
Normal file
311
discover.php
Normal file
@ -0,0 +1,311 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) { header('Location: login.php'); exit; }
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!$user) { header('Location: login.php'); exit; }
|
||||
|
||||
$user_role = $user['role'];
|
||||
if ($user_role === 'founder') {
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
// Get user's followed startups
|
||||
$stmt = db()->prepare("SELECT startup_id FROM startup_followers WHERE user_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$followedStartups = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
// Leaderboard: Most Followed
|
||||
$stmt = db()->query("
|
||||
SELECT s.*, u.full_name as founder_name
|
||||
FROM startups s
|
||||
JOIN users u ON s.founder_id = u.id
|
||||
ORDER BY s.followers_count DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$mostFollowed = $stmt->fetchAll();
|
||||
|
||||
// Leaderboard: Most Funded (Total funding raised)
|
||||
$stmt = db()->query("
|
||||
SELECT s.id, s.name, u.full_name as founder_name, s.funding_raised as funded_amount
|
||||
FROM startups s
|
||||
JOIN users u ON s.founder_id = u.id
|
||||
ORDER BY s.funding_raised DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$mostFunded = $stmt->fetchAll();
|
||||
|
||||
// General Browse - ONLY Founding Rounds (Active)
|
||||
$q = $_GET['q'] ?? '';
|
||||
$where = "fr.status = 'Active'";
|
||||
$params = [];
|
||||
if ($q) {
|
||||
$where .= " AND (s.name LIKE ? OR s.description LIKE ? OR s.industry LIKE ?)";
|
||||
$params[] = "%$q%";
|
||||
$params[] = "%$q%";
|
||||
$params[] = "%$q%";
|
||||
}
|
||||
|
||||
$stmt = db()->prepare("
|
||||
SELECT s.*, u.full_name as founder_name, fr.funding_goal as active_goal, fr.funding_raised as active_raised
|
||||
FROM funding_rounds fr
|
||||
JOIN startups s ON fr.startup_id = s.id
|
||||
JOIN users u ON s.founder_id = u.id
|
||||
WHERE $where
|
||||
ORDER BY fr.created_at DESC
|
||||
LIMIT 12
|
||||
");
|
||||
$stmt->execute($params);
|
||||
$browseStartups = $stmt->fetchAll();
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Discovery Hub — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.hub-header { padding: 60px 0 40px; text-align: center; }
|
||||
.hub-header h1 { font-size: 56px; font-weight: 900; margin-bottom: 12px; color: var(--text-primary); }
|
||||
.hub-header p { color: var(--text-secondary); font-size: 20px; }
|
||||
.leaderboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 60px; }
|
||||
@media (max-width: 900px) { .leaderboard-grid { grid-template-columns: 1fr; } }
|
||||
.lb-card { background: var(--surface-color); border: 1px solid var(--border-color); border-radius: 16px; padding: 30px; }
|
||||
.lb-title { display: flex; align-items: center; gap: 12px; margin-bottom: 25px; font-size: 20px; font-weight: 800; color: var(--text-primary); }
|
||||
.lb-item { display: flex; align-items: center; gap: 15px; padding: 15px; background: var(--elevated-color); border-radius: 12px; border: 1px solid var(--border-color); margin-bottom: 12px; transition: all 0.3s; text-decoration: none; color: inherit; position: relative; }
|
||||
.lb-item:hover { transform: translateX(8px); border-color: var(--accent-primary); }
|
||||
.lb-rank { width: 32px; height: 32px; background: var(--bg-color); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-weight: 800; color: var(--accent-primary); font-size: 14px; border: 1px solid var(--border-color); }
|
||||
.rank-1 { background: var(--warning-color); color: #000; border-color: var(--warning-color); }
|
||||
.rank-2 { background: var(--text-secondary); color: #000; border-color: var(--text-secondary); }
|
||||
.rank-3 { background: #cd7f32; color: #000; border-color: #cd7f32; }
|
||||
.startup-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 25px; }
|
||||
|
||||
.follow-btn {
|
||||
background: var(--surface-color);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--text-primary);
|
||||
padding: 8px 16px;
|
||||
border-radius: 50px;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
z-index: 2;
|
||||
}
|
||||
.follow-btn:hover {
|
||||
border-color: var(--accent-primary);
|
||||
color: var(--accent-primary);
|
||||
}
|
||||
.follow-btn.active {
|
||||
background: var(--accent-primary);
|
||||
color: #000;
|
||||
border-color: var(--accent-primary);
|
||||
}
|
||||
.follow-btn i { font-size: 14px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<a href="funding_rounds.php">Founding Rounds</a>
|
||||
<a href="portfolio.php">Portfolio</a>
|
||||
<a href="discover.php" class="active">Discovery Hub</a>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<a href="notifications.php" style="color: var(--text-secondary); position: relative; font-size: 18px;">
|
||||
<i class="fas fa-bell"></i>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 6px 14px; background: var(--surface-color); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<div style="width: 24px; height: 24px; background: var(--accent-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #000; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<div class="hub-header">
|
||||
<h1>Discovery <span style="color: var(--accent-primary);">Hub.</span></h1>
|
||||
<p>Explore the best student-led innovation across the network.</p>
|
||||
</div>
|
||||
|
||||
<div class="leaderboard-grid">
|
||||
<div class="lb-card">
|
||||
<div class="lb-title"><i class="fas fa-heart" style="color: var(--error-color);"></i> Top Followed</div>
|
||||
<?php foreach ($mostFollowed as $i => $s):
|
||||
$isFollowing = in_array($s['id'], $followedStartups);
|
||||
?>
|
||||
<div class="lb-item-wrapper" style="position: relative; margin-bottom: 12px;">
|
||||
<a href="startup_details.php?id=<?= $s['id'] ?>" class="lb-item" style="margin-bottom: 0;">
|
||||
<div class="lb-rank rank-<?= $i+1 ?>"><?= $i+1 ?></div>
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 700; color: var(--text-primary);"><?= htmlspecialchars($s['name']) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);">by <?= htmlspecialchars($s['founder_name']) ?></div>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<div style="font-weight: 800; color: var(--accent-primary); min-width: 40px; text-align: right;" id="follower-count-<?= $s['id'] ?>"><?= number_format($s['followers_count']) ?></div>
|
||||
</div>
|
||||
</a>
|
||||
<button class="follow-btn <?= $isFollowing ? 'active' : '' ?>"
|
||||
data-id="<?= $s['id'] ?>"
|
||||
data-action="<?= $isFollowing ? 'unfollow' : 'follow' ?>"
|
||||
style="position: absolute; right: 80px; top: 50%; transform: translateY(-50%);">
|
||||
<i class="<?= $isFollowing ? 'fas' : 'far' ?> fa-heart"></i>
|
||||
<?= $isFollowing ? 'Following' : 'Follow' ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="lb-card">
|
||||
<div class="lb-title"><i class="fas fa-rocket" style="color: var(--accent-primary);"></i> Most Funded</div>
|
||||
<?php foreach ($mostFunded as $i => $s): ?>
|
||||
<a href="startup_details.php?id=<?= $s['id'] ?>" class="lb-item">
|
||||
<div class="lb-rank rank-<?= $i+1 ?>"><?= $i+1 ?></div>
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 700; color: var(--text-primary);"><?= htmlspecialchars($s['name']) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);">by <?= htmlspecialchars($s['founder_name']) ?></div>
|
||||
</div>
|
||||
<div style="font-weight: 800; color: var(--success-color);">£<?= number_format($s['funded_amount']) ?></div>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 40px; text-align: center;">
|
||||
<h2 style="margin-bottom: 25px; color: var(--text-primary);">Founding Rounds</h2>
|
||||
<form method="GET" style="display: flex; gap: 10px; max-width: 600px; margin: 0 auto;">
|
||||
<input type="text" name="q" value="<?= htmlspecialchars($q) ?>" placeholder="Search founding rounds..." class="form-control" style="flex: 1;">
|
||||
<button type="submit" class="btn btn-primary">Filter</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="startup-grid">
|
||||
<?php foreach ($browseStartups as $s):
|
||||
$isFollowing = in_array($s['id'], $followedStartups);
|
||||
?>
|
||||
<div class="card" onclick="location.href='startup_details.php?id=<?= $s['id'] ?>'" style="cursor: pointer; position: relative;">
|
||||
<div style="display: flex; gap: 20px; align-items: center; margin-bottom: 20px;">
|
||||
<div style="width: 50px; height: 50px; background: var(--accent-primary); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 900; color: #000;">
|
||||
<?= substr($s['name'], 0, 1) ?>
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 800; font-size: 18px; color: var(--text-primary);"><?= htmlspecialchars($s['name']) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);">by <?= htmlspecialchars($s['founder_name']) ?></div>
|
||||
</div>
|
||||
<button class="follow-btn <?= $isFollowing ? 'active' : '' ?>"
|
||||
data-id="<?= $s['id'] ?>"
|
||||
data-action="<?= $isFollowing ? 'unfollow' : 'follow' ?>"
|
||||
onclick="event.stopPropagation();">
|
||||
<i class="<?= $isFollowing ? 'fas' : 'far' ?> fa-heart"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); font-size: 13px; margin-bottom: 20px; line-height: 1.5; height: 39px; overflow: hidden;">
|
||||
<?= htmlspecialchars(substr($s['description'], 0, 100)) ?>...
|
||||
</p>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px;">
|
||||
<div style="background: rgba(255,255,255,0.03); padding: 8px; border-radius: 8px; border: 1px solid var(--border-color); text-align: center;">
|
||||
<div style="font-size: 9px; color: var(--text-secondary); text-transform: uppercase;">Rate</div>
|
||||
<div style="font-size: 13px; font-weight: 800; color: var(--accent-primary);"><?= number_format($s['founder_return_rate'] ?? 0, 1) ?>%</div>
|
||||
</div>
|
||||
<div style="background: rgba(255,255,255,0.03); padding: 8px; border-radius: 8px; border: 1px solid var(--border-color); text-align: center;">
|
||||
<div style="font-size: 9px; color: var(--text-secondary); text-transform: uppercase;">Term</div>
|
||||
<div style="font-size: 13px; font-weight: 800; color: #fff;"><?= $s['repayment_term'] ?? 12 ?> Mo</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; border-top: 1px solid var(--border-color); padding-top: 15px;">
|
||||
<span style="font-size: 11px; font-weight: 700; color: var(--text-secondary); text-transform: uppercase;"><?= htmlspecialchars($s['industry']) ?></span>
|
||||
<span style="font-weight: 900; color: var(--text-primary);">£<?= number_format($s['active_raised']) ?> Raised</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer style="margin-top: 80px; padding: 60px 0; border-top: 1px solid var(--border-color);">
|
||||
<div class="container" style="text-align: center;">
|
||||
<div class="logo-container" style="justify-content: center; margin-bottom: 25px;">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img" style="width: 30px; height: 30px;">
|
||||
<span class="logo-text" style="font-size: 20px;"><?= htmlspecialchars($platformName) ?></span>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">© <?= date('Y') ?> <?= htmlspecialchars($platformName) ?>. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll('.follow-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const startupId = this.dataset.id;
|
||||
const action = this.dataset.action;
|
||||
const formData = new FormData();
|
||||
formData.append('startup_id', startupId);
|
||||
formData.append('action', action);
|
||||
|
||||
fetch('api/follow_startup.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Update all buttons for this startup
|
||||
document.querySelectorAll(`.follow-btn[data-id="${startupId}"]`).forEach(b => {
|
||||
if (action === 'follow') {
|
||||
b.classList.add('active');
|
||||
b.dataset.action = 'unfollow';
|
||||
b.querySelector('i').className = 'fas fa-heart';
|
||||
if (b.innerText.trim() !== '') {
|
||||
b.innerHTML = '<i class="fas fa-heart"></i> Following';
|
||||
}
|
||||
} else {
|
||||
b.classList.remove('active');
|
||||
b.dataset.action = 'follow';
|
||||
b.querySelector('i').className = 'far fa-heart';
|
||||
if (b.innerText.trim() !== '') {
|
||||
b.innerHTML = '<i class="far fa-heart"></i> Follow';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Update follower count if exists
|
||||
const countDisplay = document.getElementById(`follower-count-${startupId}`);
|
||||
if (countDisplay) {
|
||||
countDisplay.innerText = data.new_count.toLocaleString();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
224
edit_profile.php
Normal file
224
edit_profile.php
Normal file
@ -0,0 +1,224 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) { header('Location: login.php'); exit; }
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!$user) { header('Location: login.php'); exit; }
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// Centralized country list
|
||||
$countries = require 'includes/countries.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['action']) && $_POST['action'] === 'update_profile') {
|
||||
$full_name = trim($_POST['full_name']);
|
||||
$bio = trim($_POST['bio']);
|
||||
$university = trim($_POST['university']);
|
||||
$degree_program = trim($_POST['degree_program']);
|
||||
$skills = trim($_POST['skills']);
|
||||
$startup_industries = trim($_POST['startup_industries']);
|
||||
$country = $_POST['country'] ?? '';
|
||||
|
||||
$cv_url = $user['cv_url'];
|
||||
|
||||
// Handle CV Upload
|
||||
if (isset($_FILES['cv_file']) && $_FILES['cv_file']['error'] === UPLOAD_ERR_OK) {
|
||||
$file_tmp = $_FILES['cv_file']['tmp_name'];
|
||||
$file_name = $_FILES['cv_file']['name'];
|
||||
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
|
||||
$allowed_exts = ['pdf', 'doc', 'docx'];
|
||||
|
||||
if (in_array($file_ext, $allowed_exts)) {
|
||||
$upload_dir = 'assets/docs/cvs/';
|
||||
if (!is_dir($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
$new_file_name = 'cv_' . $user_id . '_' . time() . '.' . $file_ext;
|
||||
$target_path = $upload_dir . $new_file_name;
|
||||
|
||||
if (move_uploaded_file($file_tmp, $target_path)) {
|
||||
$cv_url = $target_path;
|
||||
} else {
|
||||
$error = "Failed to upload CV.";
|
||||
}
|
||||
} else {
|
||||
$error = "Invalid CV file type. Only PDF, DOC, and DOCX are allowed.";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
if ($full_name) {
|
||||
$stmt = db()->prepare("UPDATE users SET full_name = ?, bio = ?, university = ?, degree_program = ?, skills = ?, startup_industries = ?, country = ?, cv_url = ? WHERE id = ?");
|
||||
$stmt->execute([$full_name, $bio, $university, $degree_program, $skills, $startup_industries, $country, $cv_url, $user_id]);
|
||||
$success = "Profile updated successfully!";
|
||||
// Refresh user data
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
} else {
|
||||
$error = "Full name is required.";
|
||||
}
|
||||
}
|
||||
} elseif (isset($_POST['action']) && $_POST['action'] === 'delete_account') {
|
||||
try {
|
||||
db()->beginTransaction();
|
||||
db()->prepare("DELETE FROM startup_followers WHERE user_id = ?")->execute([$user_id]);
|
||||
db()->prepare("DELETE FROM matches WHERE user1_id = ? OR user2_id = ?")->execute([$user_id, $user_id]);
|
||||
db()->prepare("DELETE FROM swipes WHERE swiper_id = ? OR swiped_id = ?")->execute([$user_id, $user_id]);
|
||||
db()->prepare("DELETE FROM notifications WHERE user_id = ?")->execute([$user_id]);
|
||||
db()->prepare("DELETE FROM users WHERE id = ?")->execute([$user_id]);
|
||||
db()->commit();
|
||||
session_destroy();
|
||||
header("Location: login.php?msg=account_deleted");
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
db()->rollBack();
|
||||
$error = "Account deletion failed: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Edit Profile — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<a href="startups.php">My Startups</a>
|
||||
<a href="partners.php">Find Partners</a>
|
||||
<?php else: ?>
|
||||
<a href="funding_rounds.php">Founding Rounds</a>
|
||||
<a href="portfolio.php">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<?php endif; ?>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<a href="notifications.php" style="color: var(--text-secondary); position: relative; font-size: 18px;">
|
||||
<i class="fas fa-bell"></i>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 5px 12px; background: rgba(255,255,255,0.05); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<div style="width: 24px; height: 24px; background: var(--gradient-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px; border-radius: 10px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container" style="padding-top: 50px; padding-bottom: 80px;">
|
||||
<div style="max-width: 600px; margin: 0 auto;">
|
||||
<h1>Edit Profile</h1>
|
||||
<a href="dashboard.php" style="display: inline-block; margin-bottom: 20px; color: #aaa; text-decoration: none; font-size: 14px;"><i class="fas fa-arrow-left"></i> Back to Dashboard</a>
|
||||
<p style="color: var(--text-secondary); margin-bottom: 40px;">Manage your public presence in the <?= htmlspecialchars($platformName) ?> community.</p>
|
||||
|
||||
<?php if ($error): ?><div class="alert alert-danger" style="margin-bottom: 30px;"><?= htmlspecialchars($error) ?></div><?php endif; ?>
|
||||
<?php if ($success): ?><div class="alert alert-success" style="margin-bottom: 30px;"><?= htmlspecialchars($success) ?></div><?php endif; ?>
|
||||
|
||||
<div class="card">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<input type="hidden" name="action" value="update_profile">
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label>Full Name</label>
|
||||
<input type="text" name="full_name" class="form-control" value="<?= htmlspecialchars($user['full_name']) ?>" required style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label>Bio</label>
|
||||
<textarea name="bio" class="form-control" rows="4" style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);"><?= htmlspecialchars($user['bio']) ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label>Country</label>
|
||||
<select name="country" class="form-control" style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
||||
<option value="">Select a country...</option>
|
||||
<?php foreach ($countries as $c): ?>
|
||||
<option value="<?= htmlspecialchars($c) ?>" <?= ($user['country'] === $c) ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($c) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label>University</label>
|
||||
<input type="text" name="university" class="form-control" value="<?= htmlspecialchars($user['university']) ?>" style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label>Degree Program</label>
|
||||
<input type="text" name="degree_program" class="form-control" value="<?= htmlspecialchars($user['degree_program']) ?>" style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label>Skills (comma separated)</label>
|
||||
<input type="text" name="skills" class="form-control" value="<?= htmlspecialchars($user['skills']) ?>" style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
||||
</div>
|
||||
<div class="form-group" style="margin-bottom: 20px;">
|
||||
<label>Industries of Interest (comma separated)</label>
|
||||
<input type="text" name="startup_industries" class="form-control" value="<?= htmlspecialchars($user['startup_industries']) ?>" style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
||||
</div>
|
||||
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<div class="form-group" style="margin-bottom: 30px;">
|
||||
<label>Upload CV (PDF, DOC, DOCX)</label>
|
||||
<?php if ($user['cv_url']): ?>
|
||||
<div style="margin-bottom: 10px; font-size: 14px;">
|
||||
<a href="<?= htmlspecialchars($user['cv_url']) ?>" target="_blank" style="color: var(--accent-color);"><i class="fas fa-file-alt"></i> Current CV</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<input type="file" name="cv_file" class="form-control" style="background: var(--surface-color); color: #fff; border: 1px solid var(--border-color); padding: 10px;">
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%;">Save Changes</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top: 40px; border-color: rgba(255, 77, 77, 0.2);">
|
||||
<h3 style="color: #ff4d4d;">Danger Zone</h3>
|
||||
<p style="color: var(--text-secondary); font-size: 14px; margin-bottom: 25px;">Deleting your account is permanent. All your data, startups, and matches will be removed.</p>
|
||||
<form method="POST" onsubmit="return confirm('Are you absolutely sure you want to delete your account? This cannot be undone.');">
|
||||
<input type="hidden" name="action" value="delete_account">
|
||||
<button type="submit" class="btn btn-secondary" style="color: #ff4d4d; border-color: rgba(255, 77, 77, 0.2);">Delete My Account</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer style="margin-top: 80px; padding: 60px 0; border-top: 1px solid var(--border-color); background: rgba(0,0,0,0.2);">
|
||||
<div class="container" style="text-align: center;">
|
||||
<div class="logo-container" style="justify-content: center; margin-bottom: 25px;">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img" style="width: 30px; height: 30px;">
|
||||
<span class="logo-text" style="font-size: 20px;"><?= htmlspecialchars($platformName) ?></span>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">© <?= date('Y') ?> <?= htmlspecialchars($platformName) ?>. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
321
founder_onboarding.php
Normal file
321
founder_onboarding.php
Normal file
@ -0,0 +1,321 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'founder') {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
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 = '';
|
||||
$countries = require 'includes/countries.php';
|
||||
|
||||
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';
|
||||
$preferred_working_style = $_POST['preferred_working_style'] ?? 'hybrid';
|
||||
$availability = trim($_POST['availability'] ?? '');
|
||||
$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'] ?? '');
|
||||
|
||||
if (empty($degree_program) || empty($country) || empty($skills) || empty($bio)) {
|
||||
$error = "Please fill in all mandatory fields.";
|
||||
} else {
|
||||
$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 = ?,
|
||||
preferred_working_style = ?,
|
||||
availability = ?,
|
||||
equity_expectations = ?,
|
||||
preferred_co_founder_skills = ?,
|
||||
bio = ?,
|
||||
onboarding_completed = 1
|
||||
WHERE id = ?");
|
||||
|
||||
try {
|
||||
$stmt->execute([
|
||||
$degree_program,
|
||||
$country,
|
||||
$skills,
|
||||
$years_experience,
|
||||
$previous_startup_exp,
|
||||
$previous_startup_desc,
|
||||
$startup_industries,
|
||||
$preferred_stage,
|
||||
$commitment_level,
|
||||
$risk_tolerance,
|
||||
$preferred_working_style,
|
||||
$availability,
|
||||
$equity_expectations,
|
||||
$preferred_co_founder_skills,
|
||||
$bio,
|
||||
$_SESSION['user_id']
|
||||
]);
|
||||
header("Location: dashboard.php");
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
$error = "Database error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
$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'];
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Founder Onboarding — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.step { display: none; }
|
||||
.step.active { display: block; }
|
||||
.skill-checkbox, .industry-checkbox { display: none; }
|
||||
.tag-label {
|
||||
display: inline-block;
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 30px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.skill-checkbox:checked + .tag-label, .industry-checkbox:checked + .tag-label {
|
||||
background: var(--gradient-primary);
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
.form-group { margin-bottom: 20px; }
|
||||
label { display: block; margin-bottom: 8px; font-weight: 500; font-size: 14px; }
|
||||
input[type="text"], input[type="number"], select, textarea {
|
||||
width: 100%; padding: 12px; border-radius: 12px; background: var(--surface-color); border: 1px solid var(--border-color); color: #fff;
|
||||
}
|
||||
.step-indicator {
|
||||
display: flex; justify-content: space-between; margin-bottom: 30px;
|
||||
}
|
||||
.step-dot {
|
||||
width: 10px; height: 10px; border-radius: 50%; background: var(--border-color);
|
||||
}
|
||||
.step-dot.active { background: var(--accent-blue); }
|
||||
</style>
|
||||
</head>
|
||||
<body style="display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 40px 20px;">
|
||||
|
||||
<div class="card" style="width: 100%; max-width: 700px;">
|
||||
<div class="logo" style="text-align: center; margin-bottom: 20px;"><?= htmlspecialchars($platformName) ?></div>
|
||||
<h2 style="margin-bottom: 10px; text-align: center;">Partner Questionnaire</h2>
|
||||
<p style="text-align: center; color: var(--text-secondary); margin-bottom: 30px;">Tell us about your background to help us find the best co-founder matches.</p>
|
||||
|
||||
<div class="step-indicator">
|
||||
<div class="step-dot active" id="dot-1"></div>
|
||||
<div class="step-dot" id="dot-2"></div>
|
||||
<div class="step-dot" id="dot-3"></div>
|
||||
<div class="step-dot" id="dot-4"></div>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div style="background: rgba(255, 0, 0, 0.1); border: 1px solid rgba(255, 0, 0, 0.3); color: #ff5555; padding: 12px; border-radius: 8px; margin-bottom: 20px;">
|
||||
<?= htmlspecialchars($error) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" id="onboardingForm">
|
||||
<!-- Step 1: Basic Information -->
|
||||
<div class="step active" id="step-1">
|
||||
<h3 style="margin-bottom: 20px;">1. Basic Information</h3>
|
||||
<div class="form-group">
|
||||
<label>Degree Program</label>
|
||||
<input type="text" name="degree_program" placeholder="e.g. Computer Science, MBA" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Country of Residence</label>
|
||||
<select name="country" required>
|
||||
<option value="">Select a country...</option>
|
||||
<?php foreach ($countries as $c): ?>
|
||||
<option value="<?= htmlspecialchars($c) ?>"><?= htmlspecialchars($c) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: flex-end; margin-top: 30px;">
|
||||
<button type="button" class="btn btn-primary" onclick="nextStep(2)">Next: Professional Info</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Professional Information -->
|
||||
<div class="step" id="step-2">
|
||||
<h3 style="margin-bottom: 20px;">2. Professional Information</h3>
|
||||
<div class="form-group">
|
||||
<label>What are your core skills?</label>
|
||||
<div style="display: flex; flex-wrap: wrap;">
|
||||
<?php foreach ($all_skills as $skill): ?>
|
||||
<label>
|
||||
<input type="checkbox" name="skills[]" value="<?= $skill ?>" class="skill-checkbox">
|
||||
<span class="tag-label"><?= $skill ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Years of Professional Experience</label>
|
||||
<input type="number" name="years_experience" value="0" min="0">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="checkbox" name="previous_startup_exp" style="margin-right: 10px;" id="prevExp">
|
||||
Have you founded or worked in a startup before?
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group" id="descGroup" style="display: none;">
|
||||
<label>Briefly describe your previous experience</label>
|
||||
<textarea name="previous_startup_desc" placeholder="Role, company, outcome..."></textarea>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 30px;">
|
||||
<button type="button" class="btn" style="border: 1px solid var(--border-color);" onclick="nextStep(1)">Back</button>
|
||||
<button type="button" class="btn btn-primary" onclick="nextStep(3)">Next: Startup Interests</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Startup Interests -->
|
||||
<div class="step" id="step-3">
|
||||
<h3 style="margin-bottom: 20px;">3. Startup Interests</h3>
|
||||
<div class="form-group">
|
||||
<label>Industries of interest</label>
|
||||
<div style="display: flex; flex-wrap: wrap;">
|
||||
<?php foreach ($all_industries as $industry): ?>
|
||||
<label>
|
||||
<input type="checkbox" name="startup_industries[]" value="<?= $industry ?>" class="industry-checkbox">
|
||||
<span class="tag-label"><?= $industry ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Preferred startup stage</label>
|
||||
<select name="preferred_stage">
|
||||
<option value="Idea">Idea</option>
|
||||
<option value="MVP">MVP</option>
|
||||
<option value="Early traction">Early traction</option>
|
||||
<option value="Scaling">Scaling</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 30px;">
|
||||
<button type="button" class="btn" style="border: 1px solid var(--border-color);" onclick="nextStep(2)">Back</button>
|
||||
<button type="button" class="btn btn-primary" onclick="nextStep(4)">Next: Founder Preferences</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 4: Founder Preferences -->
|
||||
<div class="step" id="step-4">
|
||||
<h3 style="margin-bottom: 20px;">4. Founder Preferences</h3>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div class="form-group">
|
||||
<label>Commitment level</label>
|
||||
<select name="commitment_level">
|
||||
<option value="part-time">Part-time</option>
|
||||
<option value="full-time">Full-time</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Risk tolerance</label>
|
||||
<select name="risk_tolerance">
|
||||
<option value="low">Low</option>
|
||||
<option value="medium">Medium</option>
|
||||
<option value="high">High</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div class="form-group">
|
||||
<label>Working Style</label>
|
||||
<select name="preferred_working_style">
|
||||
<option value="hybrid">Hybrid</option>
|
||||
<option value="remote">Remote</option>
|
||||
<option value="in-person">In-person</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Availability</label>
|
||||
<input type="text" name="availability" placeholder="e.g. Weeknights & Weekends">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Equity expectations</label>
|
||||
<input type="text" name="equity_expectations" placeholder="e.g. 50/50, negotiable">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Preferred co-founder skills</label>
|
||||
<div style="display: flex; flex-wrap: wrap;">
|
||||
<?php foreach ($all_skills as $skill): ?>
|
||||
<label>
|
||||
<input type="checkbox" name="preferred_co_founder_skills[]" value="<?= $skill ?>" class="skill-checkbox">
|
||||
<span class="tag-label"><?= $skill ?></span>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Your Personal Bio / Mission</label>
|
||||
<textarea name="bio" required maxlength="500" placeholder="A short blurb about who you are and what drives you." style="height: 100px;"></textarea>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 30px;">
|
||||
<button type="button" class="btn" style="border: 1px solid var(--border-color);" onclick="nextStep(3)">Back</button>
|
||||
<button type="submit" class="btn btn-primary">Complete Questionnaire</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function nextStep(step) {
|
||||
document.querySelectorAll('.step').forEach(s => s.classList.remove('active'));
|
||||
document.getElementById('step-' + step).classList.add('active');
|
||||
|
||||
document.querySelectorAll('.step-dot').forEach(d => d.classList.remove('active'));
|
||||
for (let i = 1; i <= step; i++) {
|
||||
document.getElementById('dot-' + i).classList.add('active');
|
||||
}
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
document.getElementById('prevExp').addEventListener('change', function() {
|
||||
document.getElementById('descGroup').style.display = this.checked ? 'block' : 'none';
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
140
funding_rounds.php
Normal file
140
funding_rounds.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) { header('Location: login.php'); exit; }
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!$user) { header('Location: login.php'); exit; }
|
||||
|
||||
if ($user['role'] !== 'investor') {
|
||||
header('Location: dashboard.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
// Fetch ONLY active funding rounds
|
||||
$stmt = db()->prepare("
|
||||
SELECT s.*, fr.id as round_id, fr.funding_goal as active_goal, fr.funding_raised as active_raised, fr.status as round_status, u.full_name as founder_name
|
||||
FROM funding_rounds fr
|
||||
JOIN startups s ON fr.startup_id = s.id
|
||||
LEFT JOIN users u ON s.founder_id = u.id
|
||||
WHERE fr.status = 'Active'
|
||||
ORDER BY fr.created_at DESC
|
||||
");
|
||||
$stmt->execute();
|
||||
$activeRounds = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Founding Rounds — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<a href="funding_rounds.php" class="active">Founding Rounds</a>
|
||||
<a href="portfolio.php">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 6px 14px; background: var(--surface-color); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<div style="width: 24px; height: 24px; background: var(--accent-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #000; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container" style="padding-top: 50px; padding-bottom: 50px;">
|
||||
<div style="margin-bottom: 40px;">
|
||||
<h1 style="font-size: 48px; font-weight: 900; color: var(--text-primary);">Active Founding <span style="color: var(--accent-primary);">Rounds.</span></h1>
|
||||
<p style="color: var(--text-secondary); font-size: 18px;">Direct access to the most promising student startups seeking capital right now.</p>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: 25px;">
|
||||
<?php if (empty($activeRounds)): ?>
|
||||
<div class="card" style="grid-column: 1 / -1; text-align: center; padding: 80px 20px;">
|
||||
<i class="fas fa-coins" style="font-size: 64px; color: var(--accent-primary); opacity: 0.2; margin-bottom: 30px;"></i>
|
||||
<h3>No active rounds at the moment</h3>
|
||||
<p style="color: var(--text-secondary);">Check back soon for new opportunities.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($activeRounds as $round):
|
||||
$goal = $round['active_goal'];
|
||||
$raised = $round['active_raised'];
|
||||
$progress = ($raised > 0 && ($raised / ($goal ?: 1)) * 100 < 1) ? 1 : round(($raised / ($goal ?: 1)) * 100);
|
||||
?>
|
||||
<div class="card" style="position: relative; padding: 35px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 20px;">
|
||||
<div>
|
||||
<div style="font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--accent-primary); font-weight: 800; margin-bottom: 5px;"><?= htmlspecialchars($round['industry']) ?></div>
|
||||
<h3 style="margin: 0; font-size: 22px; font-weight: 800;"><?= htmlspecialchars($round['name']) ?></h3>
|
||||
<div style="font-size: 13px; color: var(--text-secondary); margin-top: 4px;">by <?= htmlspecialchars($round['founder_name']) ?></div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 11px; color: var(--text-secondary); text-transform: uppercase;">Goal</div>
|
||||
<div style="font-size: 18px; font-weight: 900; color: var(--text-primary);">£<?= number_format($goal) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 12px; font-weight: 700; display: flex; justify-content: space-between; font-size: 14px;">
|
||||
<span style="color: var(--accent-primary);">£<?= number_format($raised) ?> Secured</span>
|
||||
<span style="color: var(--text-secondary);"><?= $progress ?>%</span>
|
||||
</div>
|
||||
<div style="width: 100%; height: 8px; background: var(--bg-color); border-radius: 100px; overflow: hidden; margin-bottom: 25px; border: 1px solid var(--border-color);">
|
||||
<div style="width: <?= min(100, $progress) ?>%; height: 100%; background: var(--accent-primary);"></div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-bottom: 30px;">
|
||||
<div style="background: var(--bg-color); padding: 12px; border-radius: 12px; border: 1px solid var(--border-color);">
|
||||
<div style="font-size: 10px; color: var(--text-secondary); text-transform: uppercase; margin-bottom: 4px;">Return Rate</div>
|
||||
<div style="font-weight: 800; color: var(--accent-primary);"><?= number_format($round['founder_return_rate'] ?? 0, 1) ?>%</div>
|
||||
</div>
|
||||
<div style="background: var(--bg-color); padding: 12px; border-radius: 12px; border: 1px solid var(--border-color);">
|
||||
<div style="font-size: 10px; color: var(--text-secondary); text-transform: uppercase; margin-bottom: 4px;">Term</div>
|
||||
<div style="font-weight: 800; color: #fff;"><?= $round['repayment_term'] ?? 12 ?> Months</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 12px;">
|
||||
<a href="startup_details.php?id=<?= $round['id'] ?>" class="btn btn-secondary" style="flex: 1; text-align: center; padding: 14px; font-size: 13px;">View Profile</a>
|
||||
<a href="invest.php?id=<?= $round['id'] ?>" class="btn btn-primary" style="flex: 1.2; text-align: center; padding: 14px; font-size: 13px;">Invest Now</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer style="margin-top: 80px; padding: 60px 0; border-top: 1px solid var(--border-color);">
|
||||
<div class="container" style="text-align: center;">
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">© <?= date('Y') ?> <?= htmlspecialchars($platformName) ?> Capitalist Platform. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
99
generate_activity.php
Normal file
99
generate_activity.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
function generateActivity($pdo) {
|
||||
echo "Starting to generate matches, swipes, and notifications...\n";
|
||||
|
||||
$stmt = $pdo->query("SELECT id, role, full_name FROM users WHERE role IN ('founder', 'investor')");
|
||||
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$founders = array_values(array_filter($users, fn($u) => $u['role'] === 'founder'));
|
||||
$investors = array_values(array_filter($users, fn($u) => $u['role'] === 'investor'));
|
||||
|
||||
if (count($founders) < 2 || count($investors) < 2) {
|
||||
echo "Not enough users found. Please run seed_data.php first.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
echo "Found " . count($founders) . " founders and " . count($investors) . " investors.\n";
|
||||
|
||||
$swipeStmt = $pdo->prepare("INSERT IGNORE INTO swipes (swiper_id, swiped_id, direction, created_at) VALUES (?, ?, ?, NOW())");
|
||||
$matchStmt = $pdo->prepare("INSERT IGNORE INTO matches (user1_id, user2_id, status, created_at) VALUES (?, ?, 'active', NOW())");
|
||||
$msgStmt = $pdo->prepare("INSERT INTO messages (sender_id, receiver_id, content, created_at) VALUES (?, ?, ?, NOW())");
|
||||
$notifStmt = $pdo->prepare("INSERT INTO notifications (user_id, content, created_at) VALUES (?, ?, NOW())");
|
||||
|
||||
// 1. Investor-Founder matches
|
||||
foreach ($investors as $investor) {
|
||||
$numSwipes = rand(3, 5);
|
||||
$founderKeys = array_rand($founders, min($numSwipes, count($founders)));
|
||||
$targetIndices = is_array($founderKeys) ? $founderKeys : [$founderKeys];
|
||||
|
||||
foreach ($targetIndices as $founderIdx) {
|
||||
$founder = $founders[$founderIdx];
|
||||
|
||||
// Investor likes founder
|
||||
$swipeStmt->execute([$investor['id'], $founder['id'], 'like']);
|
||||
|
||||
// 40% chance founder likes back
|
||||
if (rand(1, 10) <= 4) {
|
||||
$swipeStmt->execute([$founder['id'], $investor['id'], 'like']);
|
||||
|
||||
$u1 = min($investor['id'], $founder['id']);
|
||||
$u2 = max($investor['id'], $founder['id']);
|
||||
$matchStmt->execute([$u1, $u2]);
|
||||
|
||||
// Notifications
|
||||
$notifStmt->execute([$investor['id'], "You have a new match with {$founder['full_name']}!"]);
|
||||
$notifStmt->execute([$founder['id'], "You have a new match with {$investor['full_name']}!"]);
|
||||
|
||||
// Message
|
||||
$msgStmt->execute([
|
||||
$investor['id'],
|
||||
$founder['id'],
|
||||
"Hi {$founder['full_name']}! I'm impressed by your startup's mission. Let's talk!"
|
||||
]);
|
||||
echo "Match: {$investor['full_name']} <-> {$founder['full_name']}\n";
|
||||
} else {
|
||||
echo "Swipe: {$investor['full_name']} liked {$founder['full_name']}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Founder-Founder matches
|
||||
foreach ($founders as $index => $founder) {
|
||||
$otherFounders = $founders;
|
||||
unset($otherFounders[$index]);
|
||||
$otherFounders = array_values($otherFounders);
|
||||
|
||||
$numSwipes = rand(1, 2);
|
||||
$otherKeys = array_rand($otherFounders, min($numSwipes, count($otherFounders)));
|
||||
$targetIndices = is_array($otherKeys) ? $otherKeys : [$otherKeys];
|
||||
|
||||
foreach ($targetIndices as $idx) {
|
||||
$other = $otherFounders[$idx];
|
||||
$swipeStmt->execute([$founder['id'], $other['id'], 'like']);
|
||||
|
||||
// 30% chance they match
|
||||
if (rand(1, 10) <= 3) {
|
||||
$swipeStmt->execute([$other['id'], $founder['id'], 'like']);
|
||||
$u1 = min($founder['id'], $other['id']);
|
||||
$u2 = max($founder['id'], $other['id']);
|
||||
$matchStmt->execute([$u1, $u2]);
|
||||
|
||||
$notifStmt->execute([$founder['id'], "New co-founder match with {$other['full_name']}!"]);
|
||||
$notifStmt->execute([$other['id'], "New co-founder match with {$founder['full_name']}!"]);
|
||||
|
||||
echo "Co-founder Match: {$founder['full_name']} <-> {$other['full_name']}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "Finished generating initial activity.\n";
|
||||
}
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
generateActivity($pdo);
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
133
generate_startup_content.php
Normal file
133
generate_startup_content.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
function generate_startup_updates() {
|
||||
$db = db();
|
||||
|
||||
// Fetch all startups and their founders
|
||||
$stmt = $db->query("SELECT s.id as startup_id, s.name as startup_name, s.founder_id, u.full_name as founder_name
|
||||
FROM startups s
|
||||
JOIN users u ON s.founder_id = u.id");
|
||||
$startups = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$update_templates = [
|
||||
"Product Milestone" => [
|
||||
"We've just hit our first 1,000 active users!",
|
||||
"Major update: Version 2.0 is now live with enhanced AI features.",
|
||||
"Our Beta testing phase is officially complete, and the feedback has been incredible.",
|
||||
"Excited to announce our new partnership with a leading industry provider."
|
||||
],
|
||||
"Funding Update" => [
|
||||
"We've reached 50% of our funding goal! Huge thanks to our early supporters.",
|
||||
"New institutional investor joined our seed round today.",
|
||||
"Only $50k left to close our current funding round. Don't miss out!",
|
||||
"We are extending our round due to high demand from strategic partners."
|
||||
],
|
||||
"Team & Growth" => [
|
||||
"Welcoming our new CTO, who brings 10+ years of experience in the sector.",
|
||||
"We've just moved into our new office space to accommodate our growing team.",
|
||||
"Hiring alert: We are looking for talented developers and marketing specialists.",
|
||||
"Our team just won the 'Most Innovative Startup' award at the local tech summit!"
|
||||
]
|
||||
];
|
||||
|
||||
foreach ($startups as $startup) {
|
||||
$num_updates = rand(2, 3);
|
||||
for ($i = 0; $i < $num_updates; $i++) {
|
||||
$category = array_rand($update_templates);
|
||||
$title = $category . ": " . $startup['startup_name'] . " Progress";
|
||||
$content = $update_templates[$category][array_rand($update_templates[$category])];
|
||||
|
||||
$stmt = $db->prepare("INSERT INTO startup_updates (startup_id, founder_id, title, content, created_at)
|
||||
VALUES (:sid, :fid, :title, :content, :created)");
|
||||
// Randomize creation date over the last 30 days
|
||||
$days_ago = rand(1, 30);
|
||||
$created_at = date('Y-m-d H:i:s', strtotime("-$days_ago days"));
|
||||
|
||||
$stmt->execute([
|
||||
'sid' => $startup['startup_id'],
|
||||
'fid' => $startup['founder_id'],
|
||||
'title' => $title,
|
||||
'content' => $content,
|
||||
'created' => $created_at
|
||||
]);
|
||||
}
|
||||
echo "Generated updates for " . $startup['startup_name'] . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
function simulate_funding_progress() {
|
||||
$db = db();
|
||||
|
||||
// Fetch all active funding rounds
|
||||
$stmt = $db->query("SELECT fr.id as round_id, fr.startup_id, fr.funding_goal, fr.funding_raised
|
||||
FROM funding_rounds fr
|
||||
WHERE fr.status = 'Active'");
|
||||
$rounds = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Fetch all investors
|
||||
$stmt = $db->query("SELECT id FROM users WHERE role = 'investor'");
|
||||
$investors = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
if (empty($investors)) return;
|
||||
|
||||
foreach ($rounds as $round) {
|
||||
// Decide how many investments to simulate for this round
|
||||
$num_investments = rand(1, 4);
|
||||
$total_new_raised = 0;
|
||||
|
||||
for ($i = 0; $i < $num_investments; $i++) {
|
||||
$investor_id = $investors[array_rand($investors)];
|
||||
|
||||
// Random investment amount between $5,000 and $50,000
|
||||
$amount = rand(5, 50) * 1000;
|
||||
|
||||
// Don't exceed the goal significantly
|
||||
if ($round['funding_raised'] + $total_new_raised + $amount > $round['funding_goal'] * 1.1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$status = 'approved'; // 80% chance of being approved
|
||||
|
||||
$stmt = $db->prepare("INSERT INTO investments (investor_id, startup_id, funding_round_id, amount, status, created_at)
|
||||
VALUES (:iid, :sid, :frid, :amount, :status, :created)");
|
||||
|
||||
$days_ago = rand(1, 15);
|
||||
$created_at = date('Y-m-d H:i:s', strtotime("-$days_ago days"));
|
||||
|
||||
$stmt->execute([
|
||||
'iid' => $investor_id,
|
||||
'sid' => $round['startup_id'],
|
||||
'frid' => $round['round_id'],
|
||||
'amount' => $amount,
|
||||
'status' => $status,
|
||||
'created' => $created_at
|
||||
]);
|
||||
|
||||
if ($status === 'approved') {
|
||||
$total_new_raised += $amount;
|
||||
}
|
||||
}
|
||||
|
||||
// Update funding_raised in both tables
|
||||
if ($total_new_raised > 0) {
|
||||
$stmt = $db->prepare("UPDATE funding_rounds SET funding_raised = funding_raised + :amount WHERE id = :id");
|
||||
$stmt->execute(['amount' => $total_new_raised, 'id' => $round['round_id']]);
|
||||
|
||||
$stmt = $db->prepare("UPDATE startups SET funding_raised = funding_raised + :amount WHERE id = :id");
|
||||
$stmt->execute(['amount' => $total_new_raised, 'id' => $round['startup_id']]);
|
||||
}
|
||||
|
||||
echo "Simulated " . $num_investments . " investments for startup ID " . $round['startup_id'] . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
echo "Starting startup content generation...\n";
|
||||
generate_startup_updates();
|
||||
echo "Starting funding simulation...\n";
|
||||
simulate_funding_progress();
|
||||
echo "Success!\n";
|
||||
} catch (Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
}
|
||||
28
includes/countries.php
Normal file
28
includes/countries.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
// Comprehensive list of countries for dropdowns
|
||||
return [
|
||||
"Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua and Barbuda", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan",
|
||||
"Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
|
||||
"Cabo Verde", "Cambodia", "Cameroon", "Canada", "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo (Congo-Brazzaville)", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czechia (Czech Republic)",
|
||||
"Denmark", "Djibouti", "Dominica", "Dominican Republic",
|
||||
"Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Eswatini", "Ethiopia",
|
||||
"Fiji", "Finland", "France",
|
||||
"Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana",
|
||||
"Haiti", "Holy See", "Honduras", "Hungary",
|
||||
"Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Ivory Coast",
|
||||
"Jamaica", "Japan", "Jordan",
|
||||
"Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan",
|
||||
"Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
|
||||
"Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar (formerly Burma)",
|
||||
"Namibia", "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger", "Nigeria", "North Korea", "North Macedonia", "Norway",
|
||||
"Oman",
|
||||
"Pakistan", "Palau", "Palestine State", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal",
|
||||
"Qatar",
|
||||
"Romania", "Russia", "Rwanda",
|
||||
"Saint Kitts and Nevis", "Saint Lucia", "Saint Vincent and the Grenades", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Korea", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Sweden", "Switzerland", "Syria",
|
||||
"Tajikistan", "Tanzania", "Thailand", "Timor-Leste", "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu",
|
||||
"Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States of America", "Uruguay", "Uzbekistan",
|
||||
"Vanuatu", "Venezuela", "Vietnam",
|
||||
"Yemen",
|
||||
"Zambia", "Zimbabwe"
|
||||
];
|
||||
120
index.php
120
index.php
@ -1,14 +1,15 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Modern AI-ready Chat Assistant';
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Exclusive startup networking and micro-investment platform for students and graduates.';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Chat Assistant</title>
|
||||
<title><?= htmlspecialchars($platformName) ?> — Connect. Fund. Build.</title>
|
||||
<?php if ($projectDescription): ?>
|
||||
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>">
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>">
|
||||
@ -18,35 +19,102 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="bg-animations">
|
||||
<div class="blob blob-1"></div>
|
||||
<div class="blob blob-2"></div>
|
||||
<div class="blob blob-3"></div>
|
||||
</div>
|
||||
<div class="main-wrapper">
|
||||
<div class="chat-container">
|
||||
<div class="chat-header">
|
||||
<span>Chat Assistant</span>
|
||||
<a href="admin.php" class="admin-link">Admin</a>
|
||||
</div>
|
||||
<div class="chat-messages" id="chat-messages">
|
||||
<div class="message bot">
|
||||
Hello! I'm your assistant. How can I help you today?
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-input-area">
|
||||
<form id="chat-form">
|
||||
<input type="text" id="chat-input" placeholder="Type your message..." autocomplete="off">
|
||||
<button type="submit">Send</button>
|
||||
</form>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="index.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<a href="#how-it-works">How it works</a>
|
||||
<a href="#features">Features</a>
|
||||
<a href="login.php">Log In</a>
|
||||
</nav>
|
||||
<div style="display: flex; gap: 12px;">
|
||||
<a href="register.php" class="btn btn-primary">Join Now</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section class="hero">
|
||||
<div class="container">
|
||||
<div class="match-score-pill" style="margin-bottom: 30px; background: var(--surface-color); color: var(--accent-primary); border: 1px solid var(--border-color); padding: 8px 16px; border-radius: 999px; display: inline-flex; align-items: center; gap: 8px; font-weight: 700; font-size: 14px;">
|
||||
<i class="fas fa-sparkles"></i> The University Startup Network
|
||||
</div>
|
||||
<h1>The smarter way to <br><span>Connect & Scale.</span></h1>
|
||||
<p>Connect with co-founders, hire early talent, and raise micro-investments from a verified community of university students and graduates.</p>
|
||||
<div style="display: flex; gap: 20px; justify-content: center;">
|
||||
<a href="register.php" class="btn btn-primary" style="padding: 16px 32px; font-size: 18px;">Start Your Journey</a>
|
||||
<a href="#how-it-works" class="btn btn-secondary" style="padding: 16px 32px; font-size: 18px;">See How It Works</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="features" class="container">
|
||||
<div class="features">
|
||||
<div class="card">
|
||||
<div class="card-icon"><i class="fas fa-user-shield"></i></div>
|
||||
<h3 style="font-size: 24px; font-weight: 800; margin-bottom: 15px;">Verified Exclusivity</h3>
|
||||
<p style="color: var(--text-secondary);">Exclusive access for verified university students and recent graduates. We ensure a high-trust environment for serious builders.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon"><i class="fas fa-people-arrows"></i></div>
|
||||
<h3 style="font-size: 24px; font-weight: 800; margin-bottom: 15px;">Intelligent Matching</h3>
|
||||
<p style="color: var(--text-secondary);">Find your ideal co-founder based on complementary skills, shared vision, and cultural fit using our advanced discovery engine.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon"><i class="fas fa-chart-line"></i></div>
|
||||
<h3 style="font-size: 24px; font-weight: 800; margin-bottom: 15px;">Peer Micro-Funding</h3>
|
||||
<p style="color: var(--text-secondary);">Raise early-stage capital from your peers. Startups can list rounds while investors build diversified portfolios of student talent.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="how-it-works" class="how-it-works container">
|
||||
<h2 style="font-size: 48px; font-weight: 900; margin-bottom: 60px;">Your path from idea to <span>IPO.</span></h2>
|
||||
<div class="steps">
|
||||
<div class="step">
|
||||
<span class="step-number">01</span>
|
||||
<h4 style="font-size: 28px; font-weight: 800; margin-bottom: 10px;">Verify & Profile</h4>
|
||||
<p style="color: var(--text-secondary); font-size: 18px;">Sign up with your .edu or university email to join the elite circle of student founders.</p>
|
||||
</div>
|
||||
<div class="step">
|
||||
<span class="step-number">02</span>
|
||||
<h4 style="font-size: 28px; font-weight: 800; margin-bottom: 10px;">Swipe & Match</h4>
|
||||
<p style="color: var(--text-secondary); font-size: 18px;">Discover partners or startups. Swipe right on potential co-founders or investment opportunities.</p>
|
||||
</div>
|
||||
<div class="step">
|
||||
<span class="step-number">03</span>
|
||||
<h4 style="font-size: 28px; font-weight: 800; margin-bottom: 10px;">Build & Fund</h4>
|
||||
<p style="color: var(--text-secondary); font-size: 18px;">Incorporate, launch your funding round, and scale with the support of the whole community.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="logo-container" style="justify-content: center; margin-bottom: 40px;">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" style="width: 48px; height: 48px;">
|
||||
<span class="logo-text" style="font-size: 32px;"><?= htmlspecialchars($platformName) ?></span>
|
||||
</div>
|
||||
<div class="footer-links">
|
||||
<a href="#">About Us</a>
|
||||
<a href="#">Terms of Service</a>
|
||||
<a href="#">Privacy Policy</a>
|
||||
<a href="#">Contact Support</a>
|
||||
</div>
|
||||
<p style="margin-top: 40px; font-size: 14px; color: var(--text-disabled);">© <?= date('Y') ?> <?= htmlspecialchars($platformName) ?>. All rights reserved.</p>
|
||||
<p style="font-size: 12px; margin-top: 10px; color: var(--text-disabled);">Built for the next generation of entrepreneurs.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
</body>
|
||||
</html>
|
||||
181
invest.php
Normal file
181
invest.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'investor') {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$startupId = $_GET['id'] ?? null;
|
||||
if (!$startupId) {
|
||||
header('Location: startups.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = db()->prepare("
|
||||
SELECT s.*, fr.id as round_id, fr.funding_goal, fr.funding_raised, fr.status as round_status, s.founder_id as founder_id
|
||||
FROM startups s
|
||||
LEFT JOIN funding_rounds fr ON s.id = fr.startup_id AND fr.status = 'Active'
|
||||
WHERE s.id = ?
|
||||
");
|
||||
$stmt->execute([$startupId]);
|
||||
$startup = $stmt->fetch();
|
||||
|
||||
if (!$startup) {
|
||||
die("Startup not found.");
|
||||
}
|
||||
|
||||
if ($startup['round_status'] !== 'Active') {
|
||||
die("This startup does not have an active funding round.");
|
||||
}
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// Get investor's current balance
|
||||
$stmt = db()->prepare("SELECT balance FROM users WHERE id = ?");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$investor_balance = (float)$stmt->fetchColumn();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$amount = (float)($_POST['amount'] ?? 0);
|
||||
$investor_id = $_SESSION['user_id'];
|
||||
$remaining = $startup['funding_goal'] - $startup['funding_raised'];
|
||||
|
||||
if ($amount < 50) {
|
||||
$error = "Minimum investment is £50.";
|
||||
} elseif ($amount > $investor_balance) {
|
||||
$error = "Insufficient funds in your money pot. Please add funds first.";
|
||||
} elseif ($amount > $remaining) {
|
||||
$error = "You cannot invest more than the remaining goal (£" . number_format($remaining, 2) . ").";
|
||||
} else {
|
||||
db()->beginTransaction();
|
||||
try {
|
||||
// Repayment & Dividend Logic
|
||||
$interest_rate = (float)($startup['founder_return_rate'] ?? 0);
|
||||
$repayment_term = (int)($startup['repayment_term'] ?? 12);
|
||||
if ($repayment_term <= 0) $repayment_term = 12;
|
||||
|
||||
$total_return = $amount + ($amount * ($interest_rate / 100));
|
||||
$monthly_dividend = $total_return / $repayment_term;
|
||||
|
||||
// First payment is one month after investment date
|
||||
$next_payment_date = date('Y-m-d', strtotime('+1 month'));
|
||||
|
||||
// 1. Create investment record
|
||||
$equity_pct = 0.00; // Mock logic for equity
|
||||
|
||||
$stmt = db()->prepare("INSERT INTO investments (
|
||||
startup_id, investor_id, funding_round_id, amount, interest_rate, repayment_term, total_return, monthly_dividend, next_payment_date, equity_pct, status
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'approved')");
|
||||
$stmt->execute([
|
||||
$startupId, $investor_id, $startup['round_id'], $amount,
|
||||
$interest_rate, $repayment_term, $total_return, $monthly_dividend, $next_payment_date,
|
||||
$equity_pct
|
||||
]);
|
||||
|
||||
// 2. Update funding_rounds raised amount
|
||||
$stmt = db()->prepare("UPDATE funding_rounds SET funding_raised = funding_raised + ? WHERE id = ?");
|
||||
$stmt->execute([$amount, $startup['round_id']]);
|
||||
|
||||
// 3. Update startup total raised
|
||||
$stmt = db()->prepare("UPDATE startups SET funding_raised = funding_raised + ? WHERE id = ?");
|
||||
$stmt->execute([$amount, $startupId]);
|
||||
|
||||
// 4. TRANSFER MONEY: Investor pot -> Founder pot
|
||||
// Deduct from investor
|
||||
$stmt = db()->prepare("UPDATE users SET balance = balance - ? WHERE id = ?");
|
||||
$stmt->execute([$amount, $investor_id]);
|
||||
|
||||
// Add to founder
|
||||
$stmt = db()->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
|
||||
$stmt->execute([$amount, $startup['founder_id']]);
|
||||
|
||||
db()->commit();
|
||||
$success = "Investment of £" . number_format($amount, 2) . " confirmed successfully! Repayment schedule: £" . number_format($monthly_dividend, 2) . "/month for $repayment_term months.";
|
||||
header("refresh:3;url=portfolio.php");
|
||||
} catch (Exception $e) {
|
||||
db()->rollBack();
|
||||
$error = "Error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Invest in <?= htmlspecialchars($startup['name']) ?> | <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?= time() ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
</head>
|
||||
<body style="background: #000; color: #fff; padding: 60px 20px;">
|
||||
|
||||
<div class="container" style="max-width: 600px; margin: 0 auto;">
|
||||
<div class="card" style="padding: 40px; background: #1a1a1a; border-radius: 24px; border: 1px solid rgba(255,255,255,0.1);">
|
||||
<h1 style="font-size: 32px; font-weight: 900; margin-bottom: 10px;">Back <?= htmlspecialchars($startup['name']) ?></h1>
|
||||
<p style="color: #999; margin-bottom: 30px;">
|
||||
You are participating in the active funding round for this startup.
|
||||
</p>
|
||||
|
||||
<!-- Wallet Info -->
|
||||
<div style="background: rgba(0, 242, 255, 0.05); padding: 15px; border-radius: 12px; border: 1px solid rgba(0, 242, 255, 0.2); margin-bottom: 25px; display: flex; align-items: center; justify-content: space-between;">
|
||||
<div>
|
||||
<span style="font-size: 12px; color: #999; text-transform: uppercase;">Your Wallet Balance</span>
|
||||
<div style="font-size: 18px; font-weight: 900; color: var(--accent-blue);">£<?= number_format($investor_balance, 2) ?></div>
|
||||
</div>
|
||||
<a href="dashboard.php" style="font-size: 12px; color: var(--accent-blue); text-decoration: none; font-weight: 600;">Add Funds <i class="fas fa-plus"></i></a>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div style="background: rgba(255, 0, 0, 0.1); border: 1px solid rgba(255, 0, 0, 0.3); color: #ff5555; padding: 15px; border-radius: 12px; margin-bottom: 25px;">
|
||||
<?= htmlspecialchars($error) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div style="background: rgba(0, 242, 255, 0.1); border: 1px solid var(--accent-blue); color: var(--accent-blue); padding: 15px; border-radius: 12px; margin-bottom: 25px;">
|
||||
<?= htmlspecialchars($success) ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div style="background: rgba(255,255,255,0.03); padding: 25px; border-radius: 16px; border: 1px solid rgba(255,255,255,0.05); margin-bottom: 30px;">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 15px;">
|
||||
<span style="color: #999;">Interest Rate</span>
|
||||
<span style="font-weight: 700; color: #fff;"><?= number_format($startup['founder_return_rate'] ?? 0, 1) ?>%</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 15px;">
|
||||
<span style="color: #999;">Repayment Term</span>
|
||||
<span style="font-weight: 700; color: #fff;"><?= htmlspecialchars($startup['repayment_term'] ?? 12) ?> Months</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; padding-top: 15px; border-top: 1px solid rgba(255,255,255,0.05);">
|
||||
<span style="color: #999;">Remaining Allocation</span>
|
||||
<?php $remaining = $startup['funding_goal'] - $startup['funding_raised']; ?>
|
||||
<span style="font-weight: 900; color: var(--accent-blue);">£<?= number_format(max(0, $remaining), 2) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="POST">
|
||||
<div style="margin-bottom: 30px;">
|
||||
<label style="display: block; margin-bottom: 10px; font-weight: 600; color: #999; text-transform: uppercase; font-size: 12px; letter-spacing: 1px;">Investment Amount (£)</label>
|
||||
<input type="number" name="amount" min="50" step="0.01" required placeholder="Min £50..."
|
||||
style="width: 100%; padding: 20px; background: #000; border: 1px solid rgba(255,255,255,0.1); border-radius: 16px; color: #fff; font-size: 24px; font-weight: 900;">
|
||||
<p style="margin-top: 10px; font-size: 13px; color: #777;">The minimum investment is £50. Terms are locked upon confirmation.</p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%; padding: 20px; font-size: 18px; font-weight: 800; border-radius: 16px; background: var(--accent-blue); color: #000; border: none; cursor: pointer;">
|
||||
Confirm Investment <i class="fas fa-rocket" style="margin-left: 10px;"></i>
|
||||
</button>
|
||||
<a href="startup_details.php?id=<?= $startupId ?>" style="display: block; text-align: center; margin-top: 20px; color: #999; text-decoration: none; font-size: 14px;">Back to Startup Profile</a>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
117
investor_onboarding.php
Normal file
117
investor_onboarding.php
Normal file
@ -0,0 +1,117 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'investor') {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
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 = '';
|
||||
$countries = require 'includes/countries.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$bio = trim($_POST['bio'] ?? '');
|
||||
$interests = isset($_POST['interests']) ? implode(',', $_POST['interests']) : '';
|
||||
$investment_appetite = trim($_POST['investment_appetite'] ?? '');
|
||||
$country = $_POST['country'] ?? '';
|
||||
|
||||
if (empty($bio) || empty($interests) || empty($investment_appetite) || empty($country)) {
|
||||
$error = "Please fill in all required fields.";
|
||||
} else {
|
||||
$stmt = db()->prepare("UPDATE users SET bio = ?, interests = ?, investment_appetite = ?, country = ?, onboarding_completed = 1 WHERE id = ?");
|
||||
try {
|
||||
$stmt->execute([$bio, $interests, $investment_appetite, $country, $_SESSION['user_id']]);
|
||||
header("Location: dashboard.php");
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
$error = "Database error: " . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
$interests_options = ['Tech', 'Sustainability', 'Healthcare', 'Fintech', 'Education', 'Consumer', 'Social Impact', 'AI', 'SaaS', 'E-commerce'];
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Investor Onboarding — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body style="display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 40px 20px;">
|
||||
|
||||
<div class="card" style="width: 100%; max-width: 600px;">
|
||||
<div class="logo" style="text-align: center; margin-bottom: 20px;"><?= htmlspecialchars($platformName) ?></div>
|
||||
<h2 style="margin-bottom: 10px;">Create Your Investor Profile</h2>
|
||||
<p style="color: var(--text-secondary); margin-bottom: 30px;">Tell us about your investment preferences.</p>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div style="background: rgba(255, 0, 0, 0.1); border: 1px solid rgba(255, 0, 0, 0.3); color: #ff5555; padding: 12px; border-radius: 8px; margin-bottom: 20px;">
|
||||
<?= htmlspecialchars($error) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-size: 14px; font-weight: 500;">Investment Bio (Max 250 characters)</label>
|
||||
<textarea name="bio" required maxlength="250" style="width: 100%; padding: 12px; border-radius: 12px; background: var(--surface-color); border: 1px solid var(--border-color); color: #fff; height: 120px; resize: none;" placeholder="E.g. Angel investor focused on climate tech and early-stage SaaS..."></textarea>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-size: 14px; font-weight: 500;">Country of Residence</label>
|
||||
<select name="country" required style="width: 100%; padding: 12px; border-radius: 12px; background: var(--surface-color); border: 1px solid var(--border-color); color: #fff;">
|
||||
<option value="">Select a country...</option>
|
||||
<?php foreach ($countries as $c): ?>
|
||||
<option value="<?= htmlspecialchars($c) ?>"><?= htmlspecialchars($c) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-size: 14px; font-weight: 500;">Industries of Interest</label>
|
||||
<div style="display: flex; flex-wrap: wrap; gap: 10px;">
|
||||
<?php foreach ($interests_options as $option): ?>
|
||||
<label style="cursor: pointer;">
|
||||
<input type="checkbox" name="interests[]" value="<?= $option ?>" style="display: none;" class="interest-checkbox">
|
||||
<div class="interest-tag" style="padding: 8px 16px; border: 1px solid var(--border-color); border-radius: 30px; font-size: 14px; transition: all 0.2s;">
|
||||
<?= $option ?>
|
||||
</div>
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 30px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-size: 14px; font-weight: 500;">Investment Appetite (Avg. check size)</label>
|
||||
<input type="text" name="investment_appetite" required style="width: 100%; padding: 12px; border-radius: 12px; background: var(--surface-color); border: 1px solid var(--border-color); color: #fff;" placeholder="e.g. £500 - £5,000 per startup">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%; padding: 15px;">Complete Investor Profile</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.interest-checkbox:checked + .interest-tag {
|
||||
background: var(--gradient-primary);
|
||||
border-color: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
92
login.php
Normal file
92
login.php
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
session_start();
|
||||
|
||||
// Redirect if already logged in
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
header("Location: dashboard.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
if (empty($email) || empty($password)) {
|
||||
$error = "Email and password are required.";
|
||||
} else {
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE email = ?");
|
||||
$stmt->execute([$email]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
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.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Log In — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body style="display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 20px; background: var(--bg-color);">
|
||||
|
||||
<div class="card" style="width: 100%; max-width: 400px; padding: 40px;">
|
||||
<div style="text-align: center; margin-bottom: 40px;">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="Logo" style="width: 64px; height: 64px; margin-bottom: 16px;">
|
||||
<div class="logo-text" style="font-size: 28px; justify-content: center;"><?= htmlspecialchars($platformName) ?></div>
|
||||
</div>
|
||||
|
||||
<h2 style="margin-bottom: 8px; text-align: center; font-size: 24px; font-weight: 800;">Welcome Back</h2>
|
||||
<p style="text-align: center; color: var(--text-secondary); margin-bottom: 32px; font-size: 14px;">Log in to access your startup network.</p>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div style="background: rgba(255, 68, 68, 0.1); border: 1px solid var(--error-color); color: var(--error-color); padding: 12px; border-radius: 8px; margin-bottom: 24px; font-size: 14px; text-align: center; font-weight: 600;">
|
||||
<?= htmlspecialchars($error) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label>Email Address</label>
|
||||
<input type="email" name="email" required placeholder="name@university.edu">
|
||||
</div>
|
||||
<div style="margin-bottom: 32px;">
|
||||
<label>Password</label>
|
||||
<input type="password" name="password" required placeholder="••••••••">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%; padding: 16px;">Log In</button>
|
||||
<p style="text-align: center; margin-top: 24px; color: var(--text-secondary); font-size: 14px;">
|
||||
Don't have an account? <a href="register.php" style="color: var(--accent-primary); font-weight: 700;">Sign Up</a>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
5
logout.php
Normal file
5
logout.php
Normal file
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_destroy();
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
293
messages.php
Normal file
293
messages.php
Normal file
@ -0,0 +1,293 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) { header('Location: login.php'); exit; }
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!$user) { header('Location: login.php'); exit; }
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
// Action: Accept message request
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'accept' && isset($_POST['sender_id'])) {
|
||||
$sender_id = (int)$_POST['sender_id'];
|
||||
$stmt = db()->prepare("UPDATE messages SET status = 'accepted' WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
||||
$stmt->execute([$sender_id, $user_id]);
|
||||
header("Location: messages.php?chat_with=" . $sender_id);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch Blocked Users
|
||||
$stmt = db()->prepare("SELECT blocked_id FROM blocked_users WHERE blocker_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$blocked_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$stmt = db()->prepare("SELECT blocker_id FROM blocked_users WHERE blocked_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$blocked_by_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$all_blocked = array_unique(array_merge($blocked_ids, $blocked_by_ids));
|
||||
$placeholders = empty($all_blocked) ? "0" : implode(',', array_fill(0, count($all_blocked), '?'));
|
||||
|
||||
// Fetch Matches for Founders (active only, not blocked)
|
||||
$matches = [];
|
||||
if ($user['role'] === 'founder') {
|
||||
$sql = "
|
||||
SELECT u.full_name as match_name,
|
||||
u.id as match_id,
|
||||
u.university,
|
||||
u.degree_program
|
||||
FROM matches m
|
||||
JOIN users u ON (m.user1_id = u.id OR m.user2_id = u.id)
|
||||
WHERE (m.user1_id = ? OR m.user2_id = ?)
|
||||
AND u.id != ?
|
||||
AND m.status = 'active'
|
||||
AND u.id NOT IN ($placeholders)
|
||||
";
|
||||
$stmt = db()->prepare($sql);
|
||||
$params = array_merge([$user_id, $user_id, $user_id], $all_blocked ?: []);
|
||||
$stmt->execute($params);
|
||||
$matches = $stmt->fetchAll();
|
||||
}
|
||||
|
||||
// Fetch Conversations (accepted or pending, excluding blocked)
|
||||
$sql = "
|
||||
SELECT DISTINCT u.id as other_user_id, u.full_name as other_user_name, u.role as other_role
|
||||
FROM messages m
|
||||
JOIN users u ON (m.sender_id = u.id OR m.receiver_id = u.id)
|
||||
WHERE ((m.sender_id = ? OR m.receiver_id = ?) AND u.id != ?)
|
||||
AND m.status != 'rejected'
|
||||
AND u.id NOT IN ($placeholders)
|
||||
";
|
||||
$stmt = db()->prepare($sql);
|
||||
$params = array_merge([$user_id, $user_id, $user_id], $all_blocked ?: []);
|
||||
$stmt->execute($params);
|
||||
$conversations = $stmt->fetchAll();
|
||||
|
||||
$active_chat_id = isset($_GET['chat_with']) ? (int)$_GET['chat_with'] : null;
|
||||
$active_chat_user = null;
|
||||
$chat_messages = [];
|
||||
$can_reply = true;
|
||||
$needs_acceptance = false;
|
||||
$is_currently_matched = false;
|
||||
|
||||
if ($active_chat_id) {
|
||||
if (in_array($active_chat_id, $all_blocked)) { header("Location: messages.php"); exit; }
|
||||
$stmt = db()->prepare("SELECT id, full_name, role FROM users WHERE id = ?");
|
||||
$stmt->execute([$active_chat_id]);
|
||||
$active_chat_user = $stmt->fetch();
|
||||
if ($active_chat_user) {
|
||||
$stmt = db()->prepare("SELECT * FROM messages WHERE ((sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?)) AND status != 'rejected' ORDER BY created_at ASC");
|
||||
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||
$chat_messages = $stmt->fetchAll();
|
||||
|
||||
$stmt = db()->prepare("SELECT 1 FROM messages WHERE ((sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?)) AND status = 'accepted'");
|
||||
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||
$has_accepted = (bool)$stmt->fetchColumn();
|
||||
|
||||
$stmt = db()->prepare("SELECT 1 FROM matches WHERE ((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND status = 'active'");
|
||||
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||
$is_currently_matched = (bool)$stmt->fetchColumn();
|
||||
|
||||
$stmt = db()->prepare("SELECT 1 FROM messages WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
||||
$stmt->execute([$active_chat_id, $user_id]);
|
||||
if (!$has_accepted && !$is_currently_matched && (bool)$stmt->fetchColumn()) {
|
||||
$can_reply = false;
|
||||
$needs_acceptance = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active_chat_id && $can_reply) {
|
||||
$content = trim($_POST['content']);
|
||||
if (!empty($content)) {
|
||||
$status = ($is_currently_matched || (isset($has_accepted) && $has_accepted)) ? 'accepted' : 'pending';
|
||||
$stmt = db()->prepare("INSERT INTO messages (sender_id, receiver_id, content, status) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$user_id, $active_chat_id, $content, $status]);
|
||||
header("Location: messages.php?chat_with=" . $active_chat_id);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Messages — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.profile-avatar-link {
|
||||
text-decoration: none;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.profile-avatar-link:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<a href="startups.php">My Startups</a>
|
||||
<a href="partners.php">Find Partners</a>
|
||||
<?php else: ?>
|
||||
<a href="funding_rounds.php">Founding Rounds</a>
|
||||
<a href="portfolio.php">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<?php endif; ?>
|
||||
<a href="messages.php" class="active">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<a href="notifications.php" style="color: var(--text-secondary); position: relative; font-size: 18px;">
|
||||
<i class="fas fa-bell"></i>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 5px 12px; background: rgba(255,255,255,0.05); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<a href="profile.php?id=<?= $user['id'] ?>" style="text-decoration: none; display: flex; align-items: center; gap: 10px;">
|
||||
<div style="width: 24px; height: 24px; background: var(--gradient-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600; color: #fff;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</a>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px; border-radius: 10px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container" style="padding-top: 30px; padding-bottom: 50px; height: calc(100vh - 100px); display: flex; gap: 30px;">
|
||||
<div style="width: 350px; flex-shrink: 0; background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 24px; display: flex; flex-direction: column; overflow: hidden;">
|
||||
<div style="padding: 25px; border-bottom: 1px solid var(--border-color);">
|
||||
<h2 style="margin: 0; font-size: 24px;">Inbox</h2>
|
||||
</div>
|
||||
|
||||
<?php if ($user['role'] === 'founder' && !empty($matches)): ?>
|
||||
<div style="padding: 15px 25px; font-size: 12px; text-transform: uppercase; letter-spacing: 1px; color: var(--text-secondary); font-weight: 700;">New Matches</div>
|
||||
<div style="padding: 0 15px 15px; display: flex; gap: 10px; overflow-x: auto; scrollbar-width: none;">
|
||||
<?php foreach ($matches as $match): ?>
|
||||
<a href="messages.php?chat_with=<?= $match['match_id'] ?>" style="flex-shrink: 0; width: 60px; height: 60px; background: var(--surface-color); border: 1px solid var(--accent-blue); border-radius: 18px; display: flex; align-items: center; justify-content: center; font-size: 20px; font-weight: 800; color: #fff; text-decoration: none;">
|
||||
<?= substr($match['match_name'], 0, 1) ?>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div style="flex: 1; overflow-y: auto; padding: 10px;">
|
||||
<?php if (empty($conversations)): ?>
|
||||
<div style="text-align: center; padding: 40px 20px; color: var(--text-secondary);">
|
||||
<i class="fas fa-comments" style="font-size: 32px; opacity: 0.2; margin-bottom: 15px;"></i>
|
||||
<p style="font-size: 14px;">No active conversations yet.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($conversations as $conv): ?>
|
||||
<div style="display: flex; align-items: center; gap: 5px; margin-bottom: 5px;">
|
||||
<a href="messages.php?chat_with=<?= $conv['other_user_id'] ?>" style="display: flex; align-items: center; gap: 15px; padding: 15px; border-radius: 16px; text-decoration: none; color: inherit; transition: background 0.2s; flex: 1; <?= $active_chat_id == $conv['other_user_id'] ? 'background: rgba(255,255,255,0.06); border: 1px solid var(--border-color);' : '' ?>">
|
||||
<div style="width: 48px; height: 48px; border-radius: 14px; background: var(--surface-color); display: flex; align-items: center; justify-content: center; font-weight: 800; border: 1px solid var(--border-color);">
|
||||
<?= substr($conv['other_user_name'], 0, 1) ?>
|
||||
</div>
|
||||
<div style="flex: 1; overflow: hidden;">
|
||||
<div style="font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"><?= htmlspecialchars($conv['other_user_name']) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);"><?= ucfirst($conv['other_role']) ?></div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="profile.php?id=<?= $conv['other_user_id'] ?>" title="View Profile" style="padding: 10px; color: var(--text-secondary);"><i class="fas fa-user-circle"></i></a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 24px; display: flex; flex-direction: column; overflow: hidden; position: relative;">
|
||||
<?php if (!$active_chat_user): ?>
|
||||
<div style="flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--text-secondary); text-align: center; padding: 40px;">
|
||||
<div style="width: 100px; height: 100px; background: var(--surface-color); border-radius: 30px; display: flex; align-items: center; justify-content: center; font-size: 40px; margin-bottom: 30px; border: 1px solid var(--border-color);">
|
||||
<i class="fas fa-paper-plane" style="opacity: 0.1;"></i>
|
||||
</div>
|
||||
<h3>Your Conversations</h3>
|
||||
<p style="max-width: 300px;">Select a person from the sidebar to start chatting or view your match history.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div style="padding: 20px 30px; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; background: rgba(255,255,255,0.02);">
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<a href="profile.php?id=<?= $active_chat_user['id'] ?>" class="profile-avatar-link">
|
||||
<div style="width: 40px; height: 40px; border-radius: 12px; background: var(--surface-color); display: flex; align-items: center; justify-content: center; font-weight: 800; border: 1px solid var(--border-color);">
|
||||
<?= substr($active_chat_user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
</a>
|
||||
<div>
|
||||
<a href="profile.php?id=<?= $active_chat_user['id'] ?>" style="text-decoration: none; color: inherit;"><div style="font-weight: 700;"><?= htmlspecialchars($active_chat_user['full_name']) ?></div></a>
|
||||
<div style="font-size: 12px; color: var(--accent-blue); font-weight: 600;">Online</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="profile.php?id=<?= $active_chat_user['id'] ?>" class="btn btn-outline" style="padding: 8px 16px; font-size: 12px;">View Profile</a>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; overflow-y: auto; padding: 30px; display: flex; flex-direction: column; gap: 15px;" id="chat-scroller">
|
||||
<?php if (empty($chat_messages)): ?>
|
||||
<div style="text-align: center; padding: 40px; color: var(--text-secondary);">
|
||||
<p style="font-size: 14px; font-style: italic;">No messages yet. Say hi!</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($chat_messages as $msg):
|
||||
$is_me = ($msg['sender_id'] == $user_id);
|
||||
?>
|
||||
<div style="display: flex; justify-content: <?= $is_me ? 'flex-end' : 'flex-start' ?>;">
|
||||
<div style="max-width: 70%; padding: 14px 20px; border-radius: 20px; font-size: 15px; line-height: 1.5; <?= $is_me ? 'background: var(--gradient-primary); color: #fff; border-bottom-right-radius: 4px;' : 'background: var(--surface-color); border: 1px solid var(--border-color); border-bottom-left-radius: 4px;' ?>">
|
||||
<?= nl2br(htmlspecialchars($msg['content'])) ?>
|
||||
<div style="font-size: 10px; margin-top: 8px; opacity: 0.6; text-align: right;">
|
||||
<?= date('H:i', strtotime($msg['created_at'])) ?>
|
||||
<?php if ($msg['status'] === 'pending' && $is_me): ?>
|
||||
<i class="fas fa-clock" title="Pending acceptance" style="margin-left: 5px;"></i>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($needs_acceptance): ?>
|
||||
<div style="padding: 20px 30px; background: rgba(0, 242, 255, 0.05); border-top: 1px solid var(--border-color); text-align: center;">
|
||||
<p style="font-size: 14px; margin-bottom: 15px;">Accept this message request to reply.</p>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="accept">
|
||||
<input type="hidden" name="sender_id" value="<?= $active_chat_id ?>">
|
||||
<button type="submit" class="btn btn-primary">Accept & Reply</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div style="padding: 25px 30px; border-top: 1px solid var(--border-color);">
|
||||
<form method="POST" style="display: flex; gap: 15px;">
|
||||
<input type="text" name="content" placeholder="Type your message..." style="flex: 1; background: var(--surface-color); border: 1px solid var(--border-color); color: #fff; padding: 15px 20px; border-radius: 15px;" required autocomplete="off">
|
||||
<button type="submit" class="btn btn-primary" style="width: 50px; height: 50px; border-radius: 15px; padding: 0; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="fas fa-paper-plane"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const scroller = document.getElementById('chat-scroller');
|
||||
if (scroller) scroller.scrollTop = scroller.scrollHeight;
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
132
notifications.php
Normal file
132
notifications.php
Normal file
@ -0,0 +1,132 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) { header('Location: login.php'); exit; }
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!$user) { header('Location: login.php'); exit; }
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
if (isset($_POST['mark_read'])) {
|
||||
$stmt = db()->prepare("UPDATE notifications SET is_read = 1 WHERE user_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
}
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM notifications WHERE user_id = ? ORDER BY created_at DESC");
|
||||
$stmt->execute([$user_id]);
|
||||
$notifications = $stmt->fetchAll();
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Notifications — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<a href="startups.php">My Startups</a>
|
||||
<a href="partners.php">Find Partners</a>
|
||||
<?php else: ?>
|
||||
<a href="funding_rounds.php">Founding Rounds</a>
|
||||
<a href="portfolio.php">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<?php endif; ?>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<a href="notifications.php" style="color: #fff; position: relative; font-size: 18px;">
|
||||
<i class="fas fa-bell"></i>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 5px 12px; background: rgba(255,255,255,0.05); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<div style="width: 24px; height: 24px; background: var(--gradient-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px; border-radius: 10px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container" style="padding-top: 50px; padding-bottom: 80px;">
|
||||
<div class="hero-bg">
|
||||
<div class="hero-blob" style="top: 10%; right: -10%;"></div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 40px;">
|
||||
<div>
|
||||
<h1>Activity Center</h1>
|
||||
<p style="color: var(--text-secondary);">Stay updated with your latest matches and investments.</p>
|
||||
</div>
|
||||
<?php if (!empty($notifications)): ?>
|
||||
<form method="POST">
|
||||
<button type="submit" name="mark_read" class="btn btn-outline" style="font-size: 13px; border-radius: 50px;">Mark all as read</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="card" style="padding: 0; overflow: hidden; border-color: var(--border-color);">
|
||||
<?php if (empty($notifications)): ?>
|
||||
<div style="text-align: center; padding: 100px 20px;">
|
||||
<div style="width: 100px; height: 100px; background: var(--surface-color); border-radius: 30px; display: inline-flex; align-items: center; justify-content: center; font-size: 40px; margin-bottom: 30px; border: 1px solid var(--border-color);">
|
||||
<i class="fas fa-bell-slash" style="opacity: 0.1; color: var(--accent-blue);"></i>
|
||||
</div>
|
||||
<h3>All quiet for now</h3>
|
||||
<p style="color: var(--text-secondary); max-width: 300px; margin: 0 auto 30px;">We'll notify you when you get a new match or investment.</p>
|
||||
<a href="discover.php" class="btn btn-primary">Browse Ecosystem</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<?php foreach ($notifications as $n): ?>
|
||||
<div style="padding: 25px 30px; border-bottom: 1px solid var(--border-color); display: flex; align-items: flex-start; gap: 20px; transition: all 0.2s; <?= $n['is_read'] ? 'opacity: 0.5;' : 'background: rgba(0, 242, 255, 0.04);' ?>">
|
||||
<div style="width: 48px; height: 48px; border-radius: 14px; background: <?= $n['is_read'] ? 'var(--surface-color)' : 'var(--gradient-primary)' ?>; display: flex; align-items: center; justify-content: center; color: #fff; flex-shrink: 0; font-size: 18px;">
|
||||
<i class="fas <?= strpos($n['content'], 'match') !== false ? 'fa-heart' : (strpos($n['content'], 'invest') !== false ? 'fa-coins' : 'fa-bolt') ?>"></i>
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<div style="margin: 0; font-size: 16px; color: #fff; font-weight: <?= $n['is_read'] ? '500' : '700' ?>; line-height: 1.4;">
|
||||
<?= htmlspecialchars($n['content']) ?>
|
||||
</div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary); margin-top: 10px; display: flex; align-items: center; gap: 6px;">
|
||||
<i class="fas fa-clock" style="font-size: 10px;"></i>
|
||||
<?= date('M d, Y • H:i', strtotime($n['created_at'])) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer style="margin-top: 80px; padding: 60px 0; border-top: 1px solid var(--border-color); background: rgba(0,0,0,0.2);">
|
||||
<div class="container" style="text-align: center;">
|
||||
<div class="logo-container" style="justify-content: center; margin-bottom: 25px;">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img" style="width: 30px; height: 30px;">
|
||||
<span class="logo-text" style="font-size: 20px;"><?= htmlspecialchars($platformName) ?></span>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">© <?= date('Y') ?> <?= htmlspecialchars($platformName) ?>. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
299
partners.php
Normal file
299
partners.php
Normal file
@ -0,0 +1,299 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) { header('Location: login.php'); exit; }
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!$user) { header('Location: login.php'); exit; }
|
||||
|
||||
$current_user_id = $user_id;
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
// Blocked users logic
|
||||
$stmt = db()->prepare("SELECT blocked_id FROM blocked_users WHERE blocker_id = ?");
|
||||
$stmt->execute([$current_user_id]);
|
||||
$blocked_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$stmt = db()->prepare("SELECT blocker_id FROM blocked_users WHERE blocked_id = ?");
|
||||
$stmt->execute([$current_user_id]);
|
||||
$blocked_by_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
$all_blocked = array_unique(array_merge($blocked_ids, $blocked_by_ids));
|
||||
$placeholders = empty($all_blocked) ? "0" : implode(',', array_fill(0, count($all_blocked), '?'));
|
||||
|
||||
function calculateMatchScore($me, $them) {
|
||||
$score = 0;
|
||||
$mySkills = array_map('trim', explode(',', strtolower($me['skills'] ?? '')));
|
||||
$theirSkills = array_map('trim', explode(',', strtolower($them['skills'] ?? '')));
|
||||
$myPreferred = array_map('trim', explode(',', strtolower($me['preferred_co_founder_skills'] ?? '')));
|
||||
$theirPreferred = array_map('trim', explode(',', strtolower($them['preferred_co_founder_skills'] ?? '')));
|
||||
$myIndustries = array_map('trim', explode(',', strtolower($me['startup_industries'] ?? '')));
|
||||
$theirIndustries = array_map('trim', explode(',', strtolower($them['startup_industries'] ?? '')));
|
||||
|
||||
$skillMatches = array_intersect($theirSkills, $myPreferred);
|
||||
$score += count($skillMatches) * 5;
|
||||
$industryMatches = array_intersect($myIndustries, $theirIndustries);
|
||||
$score += count($industryMatches) * 3;
|
||||
if (!empty($me['university']) && $me['university'] === $them['university']) { $score += 5; }
|
||||
return ['total' => $score, 'skillMatches' => array_values($skillMatches), 'industryMatches' => array_values($industryMatches)];
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'swipe') {
|
||||
header('Content-Type: application/json');
|
||||
$swiped_id = (int)$_POST['swiped_id'];
|
||||
$direction = $_POST['direction'];
|
||||
if ($swiped_id > 0 && in_array($direction, ['like', 'dislike'])) {
|
||||
$stmt = db()->prepare("INSERT IGNORE INTO swipes (swiper_id, swiped_id, direction) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$current_user_id, $swiped_id, $direction]);
|
||||
$isMatch = false;
|
||||
if ($direction === 'like') {
|
||||
$stmt = db()->prepare("SELECT id FROM swipes WHERE swiper_id = ? AND swiped_id = ? AND direction = 'like'");
|
||||
$stmt->execute([$swiped_id, $current_user_id]);
|
||||
if ($stmt->fetch()) {
|
||||
$isMatch = true;
|
||||
$u1 = min($current_user_id, $swiped_id);
|
||||
$u2 = max($current_user_id, $swiped_id);
|
||||
$stmt = db()->prepare("INSERT INTO matches (user1_id, user2_id, status) VALUES (?, ?, 'active') ON DUPLICATE KEY UPDATE status = 'active'");
|
||||
$stmt->execute([$u1, $u2]);
|
||||
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||
$stmt->execute([$swiped_id, "You have a new match! Start a conversation now."]);
|
||||
$stmt->execute([$current_user_id, "You have a new match! Start a conversation now."]);
|
||||
}
|
||||
}
|
||||
echo json_encode(['status' => 'success', 'match' => $isMatch]);
|
||||
exit;
|
||||
}
|
||||
echo json_encode(['status' => 'error']);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch active matches
|
||||
$sql = "SELECT u.*, m.created_at as matched_at FROM matches m JOIN users u ON (m.user1_id = u.id OR m.user2_id = u.id) WHERE (m.user1_id = ? OR m.user2_id = ?) AND u.id != ? AND m.status = 'active' AND u.id NOT IN ($placeholders) ORDER BY m.created_at DESC";
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute(array_merge([$current_user_id, $current_user_id, $current_user_id], $all_blocked ?: []));
|
||||
$matches = $stmt->fetchAll();
|
||||
|
||||
// Fetch swipe candidates
|
||||
$sql = "SELECT * FROM users WHERE role = 'founder' AND id != ? AND onboarding_completed = 1 AND id NOT IN (SELECT swiped_id FROM swipes WHERE swiper_id = ?) AND id NOT IN ($placeholders) LIMIT 50";
|
||||
$stmt = db()->prepare($sql);
|
||||
$stmt->execute(array_merge([$current_user_id, $current_user_id], $all_blocked ?: []));
|
||||
$allCandidates = $stmt->fetchAll();
|
||||
|
||||
foreach ($allCandidates as &$c) { $c['match_data'] = calculateMatchScore($user, $c); $c['score'] = $c['match_data']['total']; }
|
||||
usort($allCandidates, function($a, $b) { return $b['score'] <=> $a['score']; });
|
||||
$swipeCandidates = array_slice($allCandidates, 0, 10);
|
||||
|
||||
// Fetch partners for Browse
|
||||
$search = $_GET['q'] ?? '';
|
||||
$where = "role = 'founder' AND id != ? AND onboarding_completed = 1 AND id NOT IN (SELECT swiped_id FROM swipes WHERE swiper_id = ?) AND id NOT IN ($placeholders)";
|
||||
$params = array_merge([$current_user_id, $current_user_id], $all_blocked ?: []);
|
||||
if ($search) { $where .= " AND (full_name LIKE ? OR skills LIKE ? OR university LIKE ? OR startup_industries LIKE ?)"; $params[] = "%$search%"; $params[] = "%$search%"; $params[] = "%$search%"; $params[] = "%$search%"; }
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE $where LIMIT 40");
|
||||
$stmt->execute($params);
|
||||
$browseCandidates = $stmt->fetchAll();
|
||||
foreach ($browseCandidates as &$c) { $c['match_data'] = calculateMatchScore($user, $c); $c['score'] = $c['match_data']['total']; }
|
||||
if (!$search) { usort($browseCandidates, function($a, $b) { return $b['score'] <=> $a['score']; }); }
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Find Partners — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.match-avatar {
|
||||
width: 85px;
|
||||
height: 85px;
|
||||
border-radius: 12px;
|
||||
background: var(--surface-color);
|
||||
border: 2px solid var(--accent-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 30px;
|
||||
font-weight: 800;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 12px;
|
||||
box-shadow: var(--shadow-soft);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.match-avatar img {
|
||||
width: 100%; height: 100%; object-fit: cover;
|
||||
}
|
||||
.tab-btn.active {
|
||||
background: var(--accent-primary) !important;
|
||||
color: #000 !important;
|
||||
border-color: var(--accent-primary) !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<?php if ($user['role'] === 'founder'): ?>
|
||||
<a href="startups.php">My Startups</a>
|
||||
<a href="partners.php" class="active">Find Partners</a>
|
||||
<?php else: ?>
|
||||
<a href="funding_rounds.php">Founding Rounds</a>
|
||||
<a href="portfolio.php">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<?php endif; ?>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<a href="notifications.php" style="color: var(--text-secondary); position: relative; font-size: 18px;">
|
||||
<i class="fas fa-bell"></i>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 6px 14px; background: var(--surface-color); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<div style="width: 24px; height: 24px; background: var(--accent-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #000; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container">
|
||||
<div class="page-header" style="padding: 60px 0 40px; text-align: center;">
|
||||
<h1 style="font-size: 56px; font-weight: 900; color: var(--text-primary);">Meet Your <span style="color: var(--accent-primary);">Team.</span></h1>
|
||||
<p style="color: var(--text-secondary); font-size: 20px;">Connect with high-potential founders and engineers in the university ecosystem.</p>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($matches)): ?>
|
||||
<section class="matches-section" style="margin-bottom: 60px;">
|
||||
<h3 style="margin-bottom: 24px; font-size: 14px; font-weight: 800; color: var(--accent-primary); text-transform: uppercase; letter-spacing: 1.5px; display: flex; align-items: center; gap: 12px;">
|
||||
<i class="fas fa-fire"></i> Active Connections
|
||||
</h3>
|
||||
<div class="matches-scroller" style="display: flex; gap: 24px; overflow-x: auto; padding: 20px 5px; scrollbar-width: none;">
|
||||
<?php foreach ($matches as $match): ?>
|
||||
<div class="match-card" onclick="location.href='messages.php?chat_with=<?= $match['id'] ?>'" style="flex: 0 0 85px; text-align: center; cursor: pointer;">
|
||||
<div class="match-avatar">
|
||||
<?php if ($match['profile_photo']): ?><img src="<?= htmlspecialchars($match['profile_photo']) ?>"><?php else: ?><?= substr($match['full_name'], 0, 1) ?><?php endif; ?>
|
||||
</div>
|
||||
<div class="match-name" style="font-size: 13px; font-weight: 700; color: var(--text-primary);"><?= htmlspecialchars(explode(' ', $match['full_name'])[0]) ?></div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="tabs" style="display: flex; justify-content: center; gap: 20px; margin-bottom: 50px;">
|
||||
<button class="tab-btn active" id="tab-swipe" onclick="setTab('swipe')" style="padding: 14px 28px; border-radius: 999px; background: var(--surface-color); border: 1px solid var(--border-color); color: var(--text-secondary); font-weight: 700; cursor: pointer; transition: all 0.4s; font-size: 13px; text-transform: uppercase;">
|
||||
<i class="fas fa-layer-group"></i> Swipe Engine
|
||||
</button>
|
||||
<button class="tab-btn" id="tab-browse" onclick="setTab('browse')" style="padding: 14px 28px; border-radius: 999px; background: var(--surface-color); border: 1px solid var(--border-color); color: var(--text-secondary); font-weight: 700; cursor: pointer; transition: all 0.4s; font-size: 13px; text-transform: uppercase;">
|
||||
<i class="fas fa-list-ul"></i> Directory
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="swipe-view" class="swipe-container" style="display: flex; flex-direction: column; align-items: center; padding: 20px 0;">
|
||||
<div class="card-stack" id="card-stack" style="position: relative; width: 100%; max-width: 440px; height: 600px; perspective: 1000px;">
|
||||
<?php if (empty($swipeCandidates)): ?>
|
||||
<div style="text-align: center; color: var(--text-secondary); padding: 120px 40px; background: var(--surface-color); border-radius: 24px; border: 1px dashed var(--border-color); width: 100%;">
|
||||
<h3>The well is dry!</h3>
|
||||
<p>Check back tomorrow for more visionaries.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach (array_reverse($swipeCandidates) as $c): ?>
|
||||
<div class="swipe-card" data-id="<?= $c['id'] ?>" style="position: absolute; width: 100%; height: 100%; background: var(--surface-color); border: 1px solid var(--border-color); border-radius: 24px; overflow: hidden; box-shadow: var(--shadow-soft); transition: transform 0.6s cubic-bezier(0.23, 1, 0.32, 1), opacity 0.6s ease; cursor: grab; display: flex; flex-direction: column;">
|
||||
<div class="card-header-img" style="height: 320px; background: var(--elevated-color); display: flex; align-items: center; justify-content: center; font-size: 120px; color: rgba(255,255,255,0.05); position: relative;">
|
||||
<?php if ($c['score'] >= 10): ?><div class="match-badge" style="position: absolute; top: 25px; right: 25px; background: var(--accent-primary); padding: 8px 16px; border-radius: 50px; color: #000; font-weight: 800; font-size: 12px; display: flex; align-items: center; gap: 8px; z-index: 10; text-transform: uppercase;"><i class="fas fa-bolt"></i> <?= $c['score'] ?>% Match</div><?php endif; ?>
|
||||
<?php if ($c['profile_photo']): ?><img src="<?= htmlspecialchars($c['profile_photo']) ?>" style="width: 100%; height: 100%; object-fit: cover;"><?php else: ?><i class="fas fa-user-astronaut"></i><?php endif; ?>
|
||||
</div>
|
||||
<div class="card-details" style="padding: 30px; flex-grow: 1; display: flex; flex-direction: column;">
|
||||
<div class="card-title" style="font-size: 28px; font-weight: 900; margin-bottom: 6px;"><?= htmlspecialchars($c['full_name']) ?></div>
|
||||
<div class="card-subtitle" style="font-size: 15px; color: var(--accent-primary); font-weight: 700; margin-bottom: 18px;"><i class="fas fa-university"></i> <?= htmlspecialchars($c['university']) ?></div>
|
||||
<p class="card-bio" style="font-size: 16px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 20px;"><?= htmlspecialchars($c['bio'] ?: 'Building the next generation of startup infrastructure.') ?></p>
|
||||
<div class="card-tags" style="display: flex; flex-wrap: wrap; gap: 10px;">
|
||||
<?php foreach (array_slice(explode(',', $c['skills']), 0, 4) as $skill): if(empty(trim($skill))) continue; ?><span class="card-tag" style="font-size: 11px; padding: 6px 14px; background: var(--bg-color); border-radius: 50px; border: 1px solid var(--border-color); font-weight: 600; color: var(--text-secondary);"><?= htmlspecialchars(trim($skill)) ?></span><?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if (!empty($swipeCandidates)): ?>
|
||||
<div class="swipe-actions" style="margin-top: 40px; display: flex; gap: 30px;">
|
||||
<button class="action-btn btn-dislike" onclick="handleSwipe('dislike')"><i class="fas fa-times"></i></button>
|
||||
<button class="action-btn btn-like" onclick="handleSwipe('like')" style="width: 80px; height: 80px; font-size: 32px;"><i class="fas fa-heart"></i></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div id="browse-view" style="display: none;">
|
||||
<div style="margin-bottom: 40px;">
|
||||
<form method="GET" style="display: flex; gap: 15px; max-width: 700px; margin: 0 auto;">
|
||||
<input type="text" name="q" value="<?= htmlspecialchars($search) ?>" placeholder="Search by skill, university..." class="form-control" style="flex: 1;">
|
||||
<button type="submit" class="btn btn-primary">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="browse-container" style="display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 30px;">
|
||||
<?php foreach ($browseCandidates as $c): ?>
|
||||
<div class="card" onclick="location.href='messages.php?chat_with=<?= $c['id'] ?>'" style="cursor: pointer; position: relative;">
|
||||
<?php if ($c['score'] >= 10): ?><div style="position: absolute; top: 20px; right: 20px; font-size: 11px; font-weight: 800; color: var(--accent-primary); text-transform: uppercase;"><i class="fas fa-bolt"></i> <?= $c['score'] ?>%</div><?php endif; ?>
|
||||
<div style="display: flex; gap: 15px; align-items: center; margin-bottom: 20px;">
|
||||
<div style="width: 50px; height: 50px; border-radius: 8px; background: var(--accent-primary); display: flex; align-items: center; justify-content: center; font-weight: 900; color: #000;"><?= substr($c['full_name'], 0, 1) ?></div>
|
||||
<div><div style="font-weight: 800; color: var(--text-primary);"><?= htmlspecialchars($c['full_name']) ?></div><div style="font-size: 12px; color: var(--text-secondary);"><?= htmlspecialchars($c['university']) ?></div></div>
|
||||
</div>
|
||||
<p style="font-size: 14px; color: var(--text-secondary); height: 40px; overflow: hidden;"><?= htmlspecialchars($c['bio'] ?: 'Building the future.') ?></p>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div id="match-modal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.95); z-index: 2000; display: none; align-items: center; justify-content: center; backdrop-filter: blur(10px);">
|
||||
<div style="text-align: center;">
|
||||
<h1 style="font-size: 80px; font-weight: 950; color: var(--accent-primary); margin-bottom: 30px;">It's a Match!</h1>
|
||||
<p style="font-size: 24px; color: #fff; margin-bottom: 40px;">You and this founder are ready to build together.</p>
|
||||
<button class="btn btn-primary" onclick="location.href='messages.php'" style="padding: 16px 32px; font-size: 18px;">Start Conversation</button>
|
||||
<button class="btn btn-secondary" style="margin-left: 15px; padding: 16px 32px; font-size: 18px;" onclick="document.getElementById('match-modal').style.display='none'">Keep Swiping</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function setTab(tab) {
|
||||
document.getElementById('swipe-view').style.display = tab === 'swipe' ? 'flex' : 'none';
|
||||
document.getElementById('browse-view').style.display = tab === 'browse' ? 'block' : 'none';
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
document.getElementById('tab-' + tab).classList.add('active');
|
||||
}
|
||||
function handleSwipe(direction) {
|
||||
const stack = document.getElementById('card-stack');
|
||||
const card = stack.querySelector('.swipe-card:last-child');
|
||||
if (!card) return;
|
||||
const swiped_id = card.dataset.id;
|
||||
card.style.transform = `translateX(${direction === 'like' ? '1000px' : '-1000px'}) rotate(${direction === 'like' ? '30deg' : '-30deg'})`;
|
||||
card.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
card.remove();
|
||||
fetch('partners.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `action=swipe&swiped_id=${swiped_id}&direction=${direction}`
|
||||
}).then(r => r.json()).then(data => {
|
||||
if (data.match) { document.getElementById('match-modal').style.display = 'flex'; }
|
||||
});
|
||||
}, 300);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
327
portfolio.php
Normal file
327
portfolio.php
Normal file
@ -0,0 +1,327 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
require_once __DIR__ . "/sync_funding.php";
|
||||
syncRepayments();
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
if (!$user_id) { header('Location: login.php'); exit; }
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
if (!$user) { header('Location: login.php'); exit; }
|
||||
|
||||
if ($user['role'] !== 'investor') { header('Location: dashboard.php'); exit; }
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
$stmt = db()->prepare("
|
||||
SELECT i.*, s.name as startup_name, s.description as startup_desc
|
||||
FROM investments i
|
||||
JOIN startups s ON i.startup_id = s.id
|
||||
WHERE i.investor_id = ?
|
||||
ORDER BY i.created_at DESC
|
||||
");
|
||||
$stmt->execute([$user_id]);
|
||||
$myInvestments = $stmt->fetchAll();
|
||||
|
||||
$totalInvested = 0;
|
||||
foreach ($myInvestments as $inv) {
|
||||
if ($inv['status'] === 'approved' || $inv['status'] === 'completed') {
|
||||
$totalInvested += $inv['amount'];
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Investment Portfolio — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.repayment-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 15px;
|
||||
margin-top: 20px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
.repayment-item {
|
||||
text-align: left;
|
||||
}
|
||||
.repayment-label {
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 700;
|
||||
letter-spacing: 1px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.repayment-value {
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
color: #fff;
|
||||
}
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 2000;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.85);
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.modal-content {
|
||||
background-color: #1a1a24;
|
||||
margin: 10% auto;
|
||||
padding: 40px;
|
||||
border: 1px solid var(--border-color);
|
||||
width: 420px;
|
||||
border-radius: 32px;
|
||||
box-shadow: 0 25px 60px rgba(0,0,0,0.7);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<a href="funding_rounds.php">Founding Rounds</a>
|
||||
<a href="portfolio.php" class="active">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<div onclick="openWalletModal('add')" style="cursor: pointer; display: flex; align-items: center; gap: 8px; padding: 5px 12px; background: rgba(0, 242, 255, 0.1); border-radius: 50px; border: 1px solid rgba(0, 242, 255, 0.2);">
|
||||
<i class="fas fa-wallet" style="color: var(--accent-blue); font-size: 12px;"></i>
|
||||
<span id="header-wallet-balance" style="font-size: 13px; font-weight: 800; color: #fff;">£<?= number_format($user['balance'], 2) ?></span>
|
||||
</div>
|
||||
<a href="notifications.php" style="color: var(--text-secondary); position: relative; font-size: 18px;">
|
||||
<i class="fas fa-bell"></i>
|
||||
</a>
|
||||
<div style="display: flex; align-items: center; gap: 10px; padding: 5px 12px; background: rgba(255,255,255,0.05); border-radius: 50px; border: 1px solid var(--border-color);">
|
||||
<div style="width: 24px; height: 24px; background: var(--gradient-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; color: #fff; font-weight: 800;">
|
||||
<?= substr($user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<span style="font-size: 13px; font-weight: 600;"><?= htmlspecialchars(explode(' ', $user['full_name'])[0]) ?></span>
|
||||
</div>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px; border-radius: 10px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container" style="padding-top: 50px; padding-bottom: 50px;">
|
||||
<div class="hero-bg">
|
||||
<div class="hero-blob" style="top: 10%; right: -10%;"></div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 40px;">
|
||||
<div>
|
||||
<h1>Investment Portfolio</h1>
|
||||
<p style="color: var(--text-secondary);">Manage your stakes and track your repayments.</p>
|
||||
</div>
|
||||
<div class="card" style="padding: 20px 30px; display: flex; align-items: center; gap: 30px; border: 1px solid var(--border-color); background: var(--card-bg);">
|
||||
<div>
|
||||
<div style="font-size: 10px; text-transform: uppercase; color: var(--text-secondary); font-weight: 700; letter-spacing: 1px; margin-bottom: 5px;">Total Principal</div>
|
||||
<div style="font-size: 28px; font-weight: 900; color: var(--accent-blue);">£<?= number_format($totalInvested, 0) ?></div>
|
||||
</div>
|
||||
<div style="width: 1px; height: 40px; background: var(--border-color);"></div>
|
||||
<div>
|
||||
<div style="font-size: 10px; text-transform: uppercase; color: var(--text-secondary); font-weight: 700; letter-spacing: 1px; margin-bottom: 5px;">Startups</div>
|
||||
<div style="font-size: 28px; font-weight: 900; color: #fff;"><?= count($myInvestments) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr; gap: 25px;">
|
||||
<?php if (empty($myInvestments)): ?>
|
||||
<div class="card" style="text-align: center; padding: 80px 20px; border: 1px dashed var(--border-color);">
|
||||
<i class="fas fa-chart-line" style="font-size: 64px; color: var(--accent-blue); opacity: 0.2; margin-bottom: 30px;"></i>
|
||||
<h3>No investments yet</h3>
|
||||
<p style="color: var(--text-secondary);">Start your journey by backing the next generation of founders.</p>
|
||||
<a href="discover.php" class="btn btn-primary" style="margin-top: 25px;">Go to Discovery Hub</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($myInvestments as $inv):
|
||||
$interest = $inv['interest_rate'] ?? 0;
|
||||
$totalReturn = $inv['total_return'] ?? ($inv['amount'] * (1 + $interest / 100));
|
||||
$monthlyDiv = $inv['monthly_dividend'] ?? ($totalReturn / ($inv['repayment_term'] ?: 12));
|
||||
$paid = $inv['paid_amount'] ?? 0;
|
||||
$remainingAmount = $totalReturn - $paid;
|
||||
$paymentsRemaining = $monthlyDiv > 0 ? ceil($remainingAmount / $monthlyDiv) : 0;
|
||||
$status = ($inv['status'] === 'completed') ? 'Completed' : 'Active';
|
||||
$statusColor = ($inv['status'] === 'completed') ? '#4cd964' : '#00f2ff';
|
||||
if ($inv['status'] === 'pending') {
|
||||
$status = 'Pending';
|
||||
$statusColor = '#ffcc00';
|
||||
} elseif ($inv['status'] === 'rejected') {
|
||||
$status = 'Rejected';
|
||||
$statusColor = '#ff3b30';
|
||||
}
|
||||
?>
|
||||
<div class="card" style="padding: 30px; transition: all 0.3s; position: relative; overflow: hidden;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 25px;">
|
||||
<div style="display: flex; align-items: center; gap: 20px;">
|
||||
<div style="width: 50px; height: 50px; background: var(--gradient-primary); border-radius: 14px; display: flex; align-items: center; justify-content: center; font-size: 20px; color: #fff; font-weight: 800;">
|
||||
<?= substr($inv['startup_name'], 0, 1) ?>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="margin: 0; font-size: 20px; font-weight: 800;"><?= htmlspecialchars($inv['startup_name']) ?></h3>
|
||||
<div style="font-size: 12px; color: var(--text-secondary); margin-top: 4px;">
|
||||
Invested on <?= date('M d, Y', strtotime($inv['created_at'])) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 10px; text-transform: uppercase; color: var(--text-secondary); font-weight: 700; letter-spacing: 1px; margin-bottom: 5px;">Status</div>
|
||||
<div style="font-size: 12px; font-weight: 900; color: <?= $statusColor ?>; background: rgba(255,255,255,0.05); padding: 4px 12px; border-radius: 20px; border: 1px solid <?= $statusColor ?>33;">
|
||||
<?= strtoupper($status) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; background: rgba(255,255,255,0.02); padding: 20px; border-radius: 16px; border: 1px solid rgba(255,255,255,0.05);">
|
||||
<div>
|
||||
<div class="repayment-label">Invested</div>
|
||||
<div class="repayment-value">£<?= number_format($inv['amount'], 2) ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="repayment-label">Interest Rate</div>
|
||||
<div class="repayment-value"><?= number_format($interest, 1) ?>%</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="repayment-label">Total Return</div>
|
||||
<div class="repayment-value" style="color: var(--accent-blue);">£<?= number_format($totalReturn, 2) ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="repayment-label">Monthly Div</div>
|
||||
<div class="repayment-value" style="color: #4cd964;">£<?= number_format($monthlyDiv, 2) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="repayment-grid">
|
||||
<div class="repayment-item">
|
||||
<div class="repayment-label">Term</div>
|
||||
<div class="repayment-value"><?= $inv['repayment_term'] ?? 12 ?> Months</div>
|
||||
</div>
|
||||
<div class="repayment-item">
|
||||
<div class="repayment-label">Remaining Payouts</div>
|
||||
<div class="repayment-value"><?= $paymentsRemaining ?></div>
|
||||
</div>
|
||||
<div class="repayment-item">
|
||||
<div class="repayment-label">Next Payment</div>
|
||||
<div class="repayment-value"><?= $inv['next_payment_date'] ? date('M d, Y', strtotime($inv['next_payment_date'])) : 'N/A' ?></div>
|
||||
</div>
|
||||
<div class="repayment-item" style="text-align: right;">
|
||||
<a href="startup_details.php?id=<?= $inv['startup_id'] ?>" style="color: var(--accent-blue); text-decoration: none; font-size: 13px; font-weight: 700;">View Profile <i class="fas fa-chevron-right" style="font-size: 10px; margin-left: 5px;"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Wallet Modal -->
|
||||
<div id="wallet-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;">
|
||||
<h2 id="modal-title" style="margin: 0; font-size: 24px; font-weight: 900; color: #fff;">Add Funds</h2>
|
||||
<button onclick="closeWalletModal()" style="background: none; border: none; color: #999; cursor: pointer; font-size: 20px;"><i class="fas fa-times"></i></button>
|
||||
</div>
|
||||
<form id="wallet-form">
|
||||
<input type="hidden" id="wallet-action" name="action" value="add">
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 10px; font-size: 12px; color: #999; text-transform: uppercase; letter-spacing: 1px; font-weight: 700;">Amount (£)</label>
|
||||
<input type="number" id="wallet-amount" name="amount" min="1" step="0.01" required placeholder="0.00"
|
||||
style="width: 100%; padding: 18px; background: #000; border: 1px solid rgba(255,255,255,0.1); border-radius: 16px; color: #fff; font-size: 24px; font-weight: 800;">
|
||||
</div>
|
||||
<button type="submit" id="wallet-submit-btn" class="btn btn-primary" style="width: 100%; padding: 18px; font-size: 16px; font-weight: 800; border-radius: 16px; background: var(--accent-blue); color: #000;">Confirm</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer style="margin-top: 80px; padding: 60px 0; border-top: 1px solid var(--border-color); background: rgba(0,0,0,0.2);">
|
||||
<div class="container" style="text-align: center;">
|
||||
<div class="logo-container" style="justify-content: center; margin-bottom: 25px;">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img" style="width: 30px; height: 30px;">
|
||||
<span class="logo-text" style="font-size: 20px;"><?= htmlspecialchars($platformName) ?></span>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">© <?= date('Y') ?> <?= htmlspecialchars($platformName) ?>. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
function openWalletModal(action) {
|
||||
const modal = document.getElementById('wallet-modal');
|
||||
const title = document.getElementById('modal-title');
|
||||
const actionInput = document.getElementById('wallet-action');
|
||||
const submitBtn = document.getElementById('wallet-submit-btn');
|
||||
|
||||
actionInput.value = action;
|
||||
if (action === 'add') {
|
||||
title.innerText = 'Add Funds';
|
||||
submitBtn.innerText = 'Confirm Deposit';
|
||||
submitBtn.style.background = 'var(--accent-blue)';
|
||||
} else {
|
||||
title.innerText = 'Withdraw Funds';
|
||||
submitBtn.innerText = 'Confirm Withdrawal';
|
||||
submitBtn.style.background = '#fff';
|
||||
}
|
||||
|
||||
modal.style.display = 'block';
|
||||
}
|
||||
|
||||
function closeWalletModal() {
|
||||
document.getElementById('wallet-modal').style.display = 'none';
|
||||
}
|
||||
|
||||
document.getElementById('wallet-form').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(this);
|
||||
|
||||
fetch('api/wallet_transaction.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const formattedBalance = '£' + parseFloat(data.new_balance).toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
document.getElementById('header-wallet-balance').innerText = formattedBalance;
|
||||
closeWalletModal();
|
||||
alert(formData.get('action') === 'add' ? 'Funds added successfully!' : 'Withdrawal successful!');
|
||||
} else {
|
||||
alert('Error: ' + data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('An unexpected error occurred.');
|
||||
});
|
||||
});
|
||||
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('wallet-modal');
|
||||
if (event.target == modal) {
|
||||
closeWalletModal();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
215
profile.php
Normal file
215
profile.php
Normal file
@ -0,0 +1,215 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$current_user_id = $_SESSION['user_id'];
|
||||
$target_user_id = $_GET['id'] ?? $current_user_id;
|
||||
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$stmt->execute([$target_user_id]);
|
||||
$target_user = $stmt->fetch();
|
||||
|
||||
if (!$target_user) {
|
||||
die("User not found.");
|
||||
}
|
||||
|
||||
$is_own_profile = ($current_user_id == $target_user_id);
|
||||
|
||||
$stmt_current = db()->prepare("SELECT role FROM users WHERE id = ?");
|
||||
$stmt_current->execute([$current_user_id]);
|
||||
$current_user = $stmt_current->fetch();
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
// Fetch target user's startups if they are a founder
|
||||
$startups = [];
|
||||
if ($target_user['role'] === 'founder') {
|
||||
$stmt = db()->prepare("SELECT * FROM startups WHERE founder_id = ? ORDER BY created_at DESC");
|
||||
$stmt->execute([$target_user_id]);
|
||||
$startups = $stmt->fetchAll();
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title><?= htmlspecialchars($target_user['full_name']) ?> | Profile</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
.profile-card {
|
||||
background: var(--surface-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 32px;
|
||||
padding: 50px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.stat-box {
|
||||
background: rgba(255,255,255,0.03);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 20px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
.tag {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
background: rgba(255,255,255,0.05);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 50px;
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
margin: 0 8px 8px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body style="background: #000; color: #fff;">
|
||||
|
||||
<header>
|
||||
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
||||
<a href="dashboard.php" class="logo-container">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="<?= htmlspecialchars($platformName) ?> Logo" class="logo-img">
|
||||
<span class="logo-text"><?= htmlspecialchars($platformName) ?></span>
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<a href="dashboard.php">Dashboard</a>
|
||||
<a href="messages.php">Messages</a>
|
||||
</nav>
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<?php if ($is_own_profile): ?>
|
||||
<a href="edit_profile.php" class="btn btn-secondary" style="font-size: 12px; border-radius: 10px;">Edit Profile</a>
|
||||
<?php endif; ?>
|
||||
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px; border-radius: 10px;">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="container" style="padding: 80px 20px;">
|
||||
<div style="max-width: 1000px; margin: 0 auto;">
|
||||
|
||||
<div class="profile-card">
|
||||
<div style="display: flex; align-items: center; gap: 40px; margin-bottom: 40px;">
|
||||
<div style="width: 140px; height: 140px; background: var(--gradient-primary); border-radius: 40px; display: flex; align-items: center; justify-content: center; font-size: 60px; color: #fff; font-weight: 900; box-shadow: 0 20px 40px rgba(0, 122, 255, 0.2);">
|
||||
<?= substr($target_user['full_name'], 0, 1) ?>
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<div style="display: flex; align-items: center; gap: 15px; margin-bottom: 10px;">
|
||||
<h1 style="font-size: 40px; font-weight: 900; margin: 0; letter-spacing: -1px;"><?= htmlspecialchars($target_user['full_name']) ?></h1>
|
||||
<span style="background: rgba(0, 242, 255, 0.1); color: var(--accent-blue); padding: 6px 14px; border-radius: 100px; font-size: 12px; font-weight: 800; letter-spacing: 1px; text-transform: uppercase;">
|
||||
<?= htmlspecialchars($target_user['role']) ?>
|
||||
</span>
|
||||
</div>
|
||||
<div style="color: var(--text-secondary); font-size: 18px; margin-bottom: 20px;">
|
||||
<i class="fas fa-university"></i> <?= htmlspecialchars($target_user['university']) ?> • <?= htmlspecialchars($target_user['degree_program']) ?>
|
||||
</div>
|
||||
<div style="display: flex; gap: 15px;">
|
||||
<?php if (!$is_own_profile): ?>
|
||||
<a href="messages.php?chat_with=<?= $target_user['id'] ?>" class="btn btn-primary" style="padding: 12px 24px; font-size: 14px;">
|
||||
<i class="far fa-comment-dots"></i> Message
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($target_user['role'] === 'founder' && $target_user['cv_url']): ?>
|
||||
<a href="<?= htmlspecialchars($target_user['cv_url']) ?>" target="_blank" class="btn btn-secondary" style="padding: 12px 24px; font-size: 14px; border-color: var(--border-color);">
|
||||
<i class="fas fa-file-pdf"></i> Download CV
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="grid-template-columns: 1fr 2fr; display: grid; gap: 50px;">
|
||||
<div>
|
||||
<h3 style="font-size: 18px; font-weight: 800; margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;">About</h3>
|
||||
<p style="color: var(--text-secondary); line-height: 1.6; font-size: 15px; margin-bottom: 30px;">
|
||||
<?= nl2br(htmlspecialchars($target_user['bio'] ?: 'No bio provided.')) ?>
|
||||
</p>
|
||||
|
||||
<h3 style="font-size: 18px; font-weight: 800; margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;">Details</h3>
|
||||
<div style="display: flex; flex-direction: column; gap: 15px;">
|
||||
<div>
|
||||
<div style="font-size: 11px; text-transform: uppercase; color: var(--text-secondary); margin-bottom: 4px;">Location</div>
|
||||
<div style="font-weight: 600;"><i class="fas fa-globe-americas" style="margin-right: 5px; opacity: 0.6;"></i> <?= htmlspecialchars($target_user['country'] ?: 'Not specified') ?></div>
|
||||
</div>
|
||||
<?php if($target_user['role'] === 'founder'): ?>
|
||||
<div>
|
||||
<div style="font-size: 11px; text-transform: uppercase; color: var(--text-secondary); margin-bottom: 4px;">Commitment</div>
|
||||
<div style="font-weight: 600;"><?= ucfirst(htmlspecialchars($target_user['commitment_level'] ?: 'Not specified')) ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<?php if($target_user['role'] === 'founder'): ?>
|
||||
<h3 style="font-size: 18px; font-weight: 800; margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;">Skills & Expertise</h3>
|
||||
<div style="margin-bottom: 40px;">
|
||||
<?php
|
||||
$skills = explode(',', $target_user['skills'] ?? '');
|
||||
foreach ($skills as $skill): if(empty(trim($skill))) continue; ?>
|
||||
<span class="tag"><?= htmlspecialchars(trim($skill)) ?></span>
|
||||
<?php endforeach; if(empty(trim($target_user['skills'] ?? ''))) echo '<p style="color: var(--text-secondary);">No skills listed.</p>';
|
||||
?>
|
||||
</div>
|
||||
|
||||
<h3 style="font-size: 18px; font-weight: 800; margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;">Ventures</h3>
|
||||
<div style="display: grid; gap: 15px;">
|
||||
<?php foreach ($startups as $startup): ?>
|
||||
<a href="startup_details.php?id=<?= $startup['id'] ?>" style="display: flex; align-items: center; justify-content: space-between; padding: 20px; background: rgba(255,255,255,0.03); border-radius: 18px; border: 1px solid var(--border-color); text-decoration: none; color: inherit;">
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<div style="width: 45px; height: 45px; border-radius: 12px; background: var(--gradient-primary); display: flex; align-items: center; justify-content: center; font-weight: 800;">
|
||||
<?= substr($startup['name'], 0, 1) ?>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight: 700;"><?= htmlspecialchars($startup['name']) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);"><?= htmlspecialchars($startup['industry']) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<i class="fas fa-chevron-right" style="color: var(--text-secondary); font-size: 12px;"></i>
|
||||
</a>
|
||||
<?php endforeach; if(empty($startups)) echo '<p style="color: var(--text-secondary);">No startups listed.</p>'; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<h3 style="font-size: 18px; font-weight: 800; margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;">Investment Profile</h3>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 40px;">
|
||||
<div class="stat-box">
|
||||
<div style="font-size: 11px; text-transform: uppercase; color: var(--text-secondary); margin-bottom: 10px;">Appetite</div>
|
||||
<div style="font-size: 18px; font-weight: 800; color: var(--accent-blue);"><?= htmlspecialchars($target_user['investment_appetite'] ?: 'N/A') ?></div>
|
||||
</div>
|
||||
<div class="stat-box">
|
||||
<div style="font-size: 11px; text-transform: uppercase; color: var(--text-secondary); margin-bottom: 10px;">Risk Tolerance</div>
|
||||
<div style="font-size: 18px; font-weight: 800; color: #fff;"><?= ucfirst(htmlspecialchars($target_user['risk_tolerance'] ?: 'N/A')) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 style="font-size: 18px; font-weight: 800; margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 10px;">Interests</h3>
|
||||
<div style="margin-bottom: 40px;">
|
||||
<?php
|
||||
$interests = explode(',', $target_user['interests'] ?? '');
|
||||
foreach ($interests as $interest): if(empty(trim($interest))) continue; ?>
|
||||
<span class="tag"><?= htmlspecialchars(trim($interest)) ?></span>
|
||||
<?php endforeach; if(empty(trim($target_user['interests'] ?? ''))) echo '<p style="color: var(--text-secondary);">No interests listed.</p>';
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer style="padding: 60px 0; border-top: 1px solid var(--border-color); margin-top: 100px; text-align: center;">
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">© <?= date('Y') ?> Gatsby Capitalist Platform. All rights reserved.</p>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
192
register.php
Normal file
192
register.php
Normal file
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
session_start();
|
||||
|
||||
// Redirect if already logged in
|
||||
if (isset($_SESSION['user_id'])) {
|
||||
header("Location: dashboard.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$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'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
$role = $_POST['role'] ?? '';
|
||||
$university = trim($_POST['university'] ?? '');
|
||||
$graduation_year = (int)($_POST['graduation_year'] ?? 0);
|
||||
|
||||
// Simple validation
|
||||
if (empty($full_name) || empty($email) || empty($password) || empty($role) || empty($university) || empty($graduation_year)) {
|
||||
$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 {
|
||||
// Check if email already exists
|
||||
$stmt = db()->prepare("SELECT id FROM users WHERE email = ?");
|
||||
$stmt->execute([$email]);
|
||||
if ($stmt->fetch()) {
|
||||
$error = "Email already registered.";
|
||||
} else {
|
||||
// Generate verification code
|
||||
$verification_code = bin2hex(random_bytes(16));
|
||||
$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, verified) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
try {
|
||||
// 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]);
|
||||
|
||||
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 = "<h1>Welcome to " . PLATFORM_NAME . "!</h1><p>Please click the link below to verify your student status:</p><p><a href='$verifyUrl'>$verifyUrl</a></p>";
|
||||
$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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Sign Up — <?= htmlspecialchars($platformName) ?></title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body style="display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 20px; background: var(--bg-color);">
|
||||
|
||||
<div class="card" style="width: 100%; max-width: 500px; padding: 40px;">
|
||||
<div style="text-align: center; margin-bottom: 40px;">
|
||||
<img src="assets/images/logo.svg?v=<?php echo time(); ?>" alt="Logo" style="width: 64px; height: 64px; margin-bottom: 16px;">
|
||||
<div class="logo-text" style="font-size: 28px; justify-content: center;"><?= htmlspecialchars($platformName) ?></div>
|
||||
</div>
|
||||
|
||||
<h2 style="margin-bottom: 8px; text-align: center; font-size: 24px; font-weight: 800;">Join the Exclusive Network</h2>
|
||||
<p style="text-align: center; color: var(--text-secondary); margin-bottom: 32px; font-size: 14px;">Verify your student or graduate status to get started.</p>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div style="background: rgba(255, 68, 68, 0.1); border: 1px solid var(--error-color); color: var(--error-color); padding: 12px; border-radius: 8px; margin-bottom: 24px; text-align: center; font-weight: 600;">
|
||||
<?= htmlspecialchars($error) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div style="background: rgba(0, 200, 83, 0.1); border: 1px solid var(--success-color); color: var(--success-color); padding: 12px; border-radius: 8px; margin-bottom: 24px; text-align: center; font-weight: 600;">
|
||||
<?= htmlspecialchars($success) ?>
|
||||
</div>
|
||||
<p style="text-align: center;"><a href="login.php" class="btn btn-primary" style="width: 100%; padding: 16px;">Go to Log In</a></p>
|
||||
<?php else: ?>
|
||||
<form method="POST">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label>Full Name</label>
|
||||
<input type="text" name="full_name" required placeholder="John Doe">
|
||||
</div>
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label>University Email</label>
|
||||
<input type="email" name="email" required placeholder="you@university.ac.uk">
|
||||
<span id="founder-hint" style="font-size: 12px; color: var(--text-secondary); margin-top: 6px; display: block;">Only university/graduate emails accepted for founders.</span>
|
||||
</div>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px;">
|
||||
<div>
|
||||
<label>University</label>
|
||||
<input type="text" name="university" required placeholder="Oxford">
|
||||
</div>
|
||||
<div>
|
||||
<label>Grad Year</label>
|
||||
<input type="number" name="graduation_year" required placeholder="2026">
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label>Password</label>
|
||||
<input type="password" name="password" required placeholder="••••••••">
|
||||
</div>
|
||||
<div style="margin-bottom: 32px;">
|
||||
<label>I want to be a:</label>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
|
||||
<label style="display: block; cursor: pointer;">
|
||||
<input type="radio" name="role" value="founder" required style="display: none;" class="role-radio" onchange="toggleHint()">
|
||||
<div class="role-box" style="padding: 15px; border: 1px solid var(--border-color); border-radius: 12px; text-align: center; transition: all 0.2s; font-weight: 700; color: var(--text-secondary);">
|
||||
Founder
|
||||
</div>
|
||||
</label>
|
||||
<label style="display: block; cursor: pointer;">
|
||||
<input type="radio" name="role" value="investor" required style="display: none;" class="role-radio" onchange="toggleHint()">
|
||||
<div class="role-box" style="padding: 15px; border: 1px solid var(--border-color); border-radius: 12px; text-align: center; transition: all 0.2s; font-weight: 700; color: var(--text-secondary);">
|
||||
Investor
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" style="width: 100%; padding: 16px;">Create Account</button>
|
||||
<p style="text-align: center; margin-top: 24px; color: var(--text-secondary); font-size: 14px;">
|
||||
Already have an account? <a href="login.php" style="color: var(--accent-primary); font-weight: 700;">Log In</a>
|
||||
</p>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleHint() {
|
||||
const selectedRole = document.querySelector('input[name="role"]:checked');
|
||||
if (selectedRole) {
|
||||
const isFounder = selectedRole.value === 'founder';
|
||||
document.getElementById('founder-hint').style.display = isFounder ? 'block' : 'none';
|
||||
}
|
||||
}
|
||||
toggleHint();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.role-radio:checked + .role-box {
|
||||
background: var(--accent-primary) !important;
|
||||
border-color: var(--accent-primary) !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
269
seed_data.php
Normal file
269
seed_data.php
Normal file
@ -0,0 +1,269 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
$db = db();
|
||||
|
||||
function hash_pass($p) {
|
||||
return password_hash($p, PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
// Clear existing data to avoid conflicts during re-seed
|
||||
$db->exec("SET FOREIGN_KEY_CHECKS = 0");
|
||||
$tables = [
|
||||
'ai_chats',
|
||||
'blocked_users',
|
||||
'faqs',
|
||||
'funding_rounds',
|
||||
'investments',
|
||||
'matches',
|
||||
'messages',
|
||||
'notifications',
|
||||
'startup_followers',
|
||||
'startup_updates',
|
||||
'startups',
|
||||
'swipes',
|
||||
'users'
|
||||
];
|
||||
foreach ($tables as $table) {
|
||||
$db->exec("TRUNCATE TABLE $table");
|
||||
}
|
||||
$db->exec("SET FOREIGN_KEY_CHECKS = 1");
|
||||
|
||||
$founders = [
|
||||
[
|
||||
'full_name' => 'Alex Chen',
|
||||
'email' => 'alex.chen@founder.io',
|
||||
'role' => 'founder',
|
||||
'university' => 'Stanford University',
|
||||
'graduation_year' => 2018,
|
||||
'bio' => 'Former software engineer at Google with a passion for logistics and AI.',
|
||||
'interests' => 'AI, Logistics, E-commerce',
|
||||
'country' => 'United States of America',
|
||||
'cv_url' => 'assets/docs/cvs/placeholder.pdf',
|
||||
'skills' => 'Python, TensorFlow, Cloud Architecture',
|
||||
'years_experience' => 5,
|
||||
'previous_startup_exp' => 1,
|
||||
'startup_name' => 'LogiAI',
|
||||
'legal_name' => 'LogiAI Systems Inc.',
|
||||
'startup_desc' => 'AI-powered predictive analytics for global supply chain optimization.',
|
||||
'industry' => 'AI & Robotics',
|
||||
'sub_industry' => 'Logistics Tech',
|
||||
'business_model' => 'B2B SaaS subscription model based on shipment volume.',
|
||||
'product_service' => 'Predictive analytics dashboard and API for freight forwarders.',
|
||||
'operational_stage' => 'Revenue-generating',
|
||||
'cofounder_equity_pct' => '10-15%',
|
||||
'cofounder_equity_type' => 'Options',
|
||||
'cofounder_responsibilities' => 'Oversee hardware integrations and edge computing strategy.',
|
||||
'desired_cofounder_experience' => 'Hardware engineering, IoT systems.',
|
||||
'cofounder_commitment' => 'Full-time',
|
||||
'other_partnership_details' => 'Preference for candidates with previous exit experience.',
|
||||
'current_cash_balance' => 450000.00,
|
||||
'burn_rate' => 25000.00,
|
||||
'outstanding_debt' => '£50k Convertible Note',
|
||||
'accounts_receivable_payable' => '£80k / £20k',
|
||||
'funding_target' => 500000.00,
|
||||
'recommended_return_rate' => 7.5,
|
||||
'founder_return_rate' => 8.0
|
||||
],
|
||||
[
|
||||
'full_name' => 'Sarah Jenkins',
|
||||
'email' => 'sarah.j@sea-pack.com',
|
||||
'role' => 'founder',
|
||||
'university' => 'Oxford University',
|
||||
'graduation_year' => 2015,
|
||||
'bio' => 'Marine biologist turned entrepreneur.',
|
||||
'interests' => 'Sustainability, Marine Biology',
|
||||
'country' => 'United Kingdom',
|
||||
'cv_url' => 'assets/docs/cvs/placeholder.pdf',
|
||||
'skills' => 'Biochemistry, Product Development',
|
||||
'years_experience' => 8,
|
||||
'previous_startup_exp' => 0,
|
||||
'startup_name' => 'SeaPack',
|
||||
'legal_name' => 'SeaPack Solutions Ltd',
|
||||
'startup_desc' => 'Biodegradable packaging solutions derived from cultivated seaweed.',
|
||||
'industry' => 'Clean Energy',
|
||||
'sub_industry' => 'Sustainable Packaging',
|
||||
'business_model' => 'Direct-to-manufacturer wholesale of raw biopolymer sheets.',
|
||||
'product_service' => 'Seaweed-based alternative to plastic shrink wrap.',
|
||||
'operational_stage' => 'MVP',
|
||||
'cofounder_equity_pct' => '20%',
|
||||
'cofounder_equity_type' => 'Common Shares',
|
||||
'cofounder_responsibilities' => 'Lead sales and business development efforts globally.',
|
||||
'desired_cofounder_experience' => 'FMCG sales, supply chain networking.',
|
||||
'cofounder_commitment' => 'Full-time',
|
||||
'other_partnership_details' => 'Seeking someone with strong ties to major retail brands.',
|
||||
'current_cash_balance' => 85000.00,
|
||||
'burn_rate' => 8000.00,
|
||||
'outstanding_debt' => 'None',
|
||||
'accounts_receivable_payable' => '£5k / £2k',
|
||||
'funding_target' => 250000.00,
|
||||
'recommended_return_rate' => 12.0,
|
||||
'founder_return_rate' => 10.5
|
||||
],
|
||||
[
|
||||
'full_name' => 'Marco Rossi',
|
||||
'email' => 'm.rossi@finflow.it',
|
||||
'role' => 'founder',
|
||||
'university' => 'Bocconi University',
|
||||
'graduation_year' => 2012,
|
||||
'bio' => 'Finance veteran with 10 years in investment banking.',
|
||||
'interests' => 'Fintech, Banking, Blockchain',
|
||||
'country' => 'Italy',
|
||||
'cv_url' => 'assets/docs/cvs/placeholder.pdf',
|
||||
'skills' => 'Financial Modeling, Compliance',
|
||||
'years_experience' => 12,
|
||||
'previous_startup_exp' => 1,
|
||||
'startup_name' => 'FinFlow',
|
||||
'legal_name' => 'FinFlow Payments S.p.A.',
|
||||
'startup_desc' => 'Unified payment orchestration for SMEs operating across European borders.',
|
||||
'industry' => 'Fintech',
|
||||
'sub_industry' => 'Cross-border Payments',
|
||||
'business_model' => 'Transaction fee (0.5%) on cross-border settlements.',
|
||||
'product_service' => 'API-first payment gateway for multi-currency invoicing.',
|
||||
'operational_stage' => 'Scaling',
|
||||
'cofounder_equity_pct' => '5-8%',
|
||||
'cofounder_equity_type' => 'Founder Shares',
|
||||
'cofounder_responsibilities' => 'Chief Technology Officer - manage engineering team and security.',
|
||||
'desired_cofounder_experience' => 'Scalable backend systems, FinTech compliance.',
|
||||
'cofounder_commitment' => 'Full-time',
|
||||
'other_partnership_details' => 'Must be based in or willing to relocate to Milan.',
|
||||
'current_cash_balance' => 1200000.00,
|
||||
'burn_rate' => 95000.00,
|
||||
'outstanding_debt' => '£200k Venture Debt',
|
||||
'accounts_receivable_payable' => '£400k / £150k',
|
||||
'funding_target' => 1200000.00,
|
||||
'recommended_return_rate' => 5.5,
|
||||
'founder_return_rate' => 6.0
|
||||
]
|
||||
];
|
||||
|
||||
$investors = [
|
||||
[
|
||||
'full_name' => 'Sofia Moretti',
|
||||
'email' => 'sofia@moretti-capital.com',
|
||||
'role' => 'investor',
|
||||
'bio' => 'Managing Partner at Moretti Capital.',
|
||||
'interests' => 'Renewables, Sustainability',
|
||||
'investment_appetite' => '$100k - $500k',
|
||||
'country' => 'Italy'
|
||||
],
|
||||
[
|
||||
'full_name' => 'Robert Sterling',
|
||||
'email' => 'robert@sterling-ventures.com',
|
||||
'role' => 'investor',
|
||||
'bio' => 'Angel investor with a background in SaaS.',
|
||||
'interests' => 'SaaS, B2B',
|
||||
'investment_appetite' => '$50k - $250k',
|
||||
'country' => 'United States of America'
|
||||
]
|
||||
];
|
||||
|
||||
$stmt_user = $db->prepare("INSERT INTO users (full_name, email, password, role, university, graduation_year, bio, interests, country, cv_url, skills, years_experience, previous_startup_exp, investment_appetite, verified, onboarding_completed)
|
||||
VALUES (:full_name, :email, :password, :role, :university, :graduation_year, :bio, :interests, :country, :cv_url, :skills, :years_experience, :previous_startup_exp, :investment_appetite, 1, 1)");
|
||||
|
||||
$stmt_startup = $db->prepare("INSERT INTO startups (
|
||||
name, description, founder_id, funding_target, status,
|
||||
legal_name, country, industry, sub_industry, business_model, product_service, operational_stage,
|
||||
cofounder_equity_pct, cofounder_equity_type, cofounder_responsibilities, desired_cofounder_experience, cofounder_commitment, other_partnership_details,
|
||||
current_cash_balance, burn_rate, outstanding_debt, accounts_receivable_payable,
|
||||
doc_income_statements, doc_balance_sheets, doc_cash_flow_statements, doc_revenue_breakdown, doc_gross_margin, doc_opex_breakdown,
|
||||
recommended_return_rate, founder_return_rate
|
||||
) VALUES (
|
||||
:name, :description, :founder_id, :funding_target, 'public',
|
||||
:legal_name, :country, :industry, :sub_industry, :business_model, :product_service, :operational_stage,
|
||||
:cofounder_equity_pct, :cofounder_equity_type, :cofounder_responsibilities, :desired_cofounder_experience, :cofounder_commitment, :other_partnership_details,
|
||||
:current_cash_balance, :burn_rate, :outstanding_debt, :accounts_receivable_payable,
|
||||
'assets/docs/financials/placeholder.pdf', 'assets/docs/financials/placeholder.pdf', 'assets/docs/financials/placeholder.pdf', 'assets/docs/financials/placeholder.pdf', 'assets/docs/financials/placeholder.pdf', 'assets/docs/financials/placeholder.pdf',
|
||||
:recommended_return_rate, :founder_return_rate)");
|
||||
|
||||
$stmt_round = $db->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (:startup_id, :funding_goal, 'Active')");
|
||||
|
||||
// Create CV directory if not exists
|
||||
if (!is_dir('assets/docs/cvs/')) {
|
||||
mkdir('assets/docs/cvs/', 0777, true);
|
||||
}
|
||||
// Create placeholder CV if not exists
|
||||
if (!file_exists('assets/docs/cvs/placeholder.pdf')) {
|
||||
file_put_contents('assets/docs/cvs/placeholder.pdf', '%PDF-1.4 Placeholder CV');
|
||||
}
|
||||
|
||||
echo "Seeding founders...\n";
|
||||
foreach ($founders as $f) {
|
||||
$stmt_user->execute([
|
||||
':full_name' => $f['full_name'],
|
||||
':email' => $f['email'],
|
||||
':password' => hash_pass('password123'),
|
||||
':role' => $f['role'],
|
||||
':university' => $f['university'],
|
||||
':graduation_year' => $f['graduation_year'],
|
||||
':bio' => $f['bio'],
|
||||
':interests' => $f['interests'],
|
||||
':country' => $f['country'],
|
||||
':cv_url' => $f['cv_url'] ?? NULL,
|
||||
':skills' => $f['skills'],
|
||||
':years_experience' => $f['years_experience'],
|
||||
':previous_startup_exp' => $f['previous_startup_exp'],
|
||||
':investment_appetite' => NULL
|
||||
]);
|
||||
|
||||
$founder_id = $db->lastInsertId();
|
||||
if ($founder_id) {
|
||||
$stmt_startup->execute([
|
||||
':name' => $f['startup_name'],
|
||||
':description' => $f['startup_desc'],
|
||||
':founder_id' => $founder_id,
|
||||
':funding_target' => $f['funding_target'],
|
||||
':legal_name' => $f['legal_name'],
|
||||
':country' => $f['country'],
|
||||
':industry' => $f['industry'],
|
||||
':sub_industry' => $f['sub_industry'],
|
||||
':business_model' => $f['business_model'],
|
||||
':product_service' => $f['product_service'],
|
||||
':operational_stage' => $f['operational_stage'],
|
||||
':cofounder_equity_pct' => $f['cofounder_equity_pct'],
|
||||
':cofounder_equity_type' => $f['cofounder_equity_type'],
|
||||
':cofounder_responsibilities' => $f['cofounder_responsibilities'],
|
||||
':desired_cofounder_experience' => $f['desired_cofounder_experience'],
|
||||
':cofounder_commitment' => $f['cofounder_commitment'],
|
||||
':other_partnership_details' => $f['other_partnership_details'],
|
||||
':current_cash_balance' => $f['current_cash_balance'],
|
||||
':burn_rate' => $f['burn_rate'],
|
||||
':outstanding_debt' => $f['outstanding_debt'],
|
||||
':accounts_receivable_payable' => $f['accounts_receivable_payable'],
|
||||
':recommended_return_rate' => $f['recommended_return_rate'],
|
||||
':founder_return_rate' => $f['founder_return_rate']
|
||||
]);
|
||||
|
||||
$startup_id = $db->lastInsertId();
|
||||
$stmt_round->execute([
|
||||
':startup_id' => $startup_id,
|
||||
':funding_goal' => $f['funding_target']
|
||||
]);
|
||||
echo "Created founder {" . $f['full_name'] . "} and startup {" . $f['startup_name'] . "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "Seeding investors...\n";
|
||||
foreach ($investors as $i) {
|
||||
$stmt_user->execute([
|
||||
':full_name' => $i['full_name'],
|
||||
':email' => $i['email'],
|
||||
':password' => hash_pass('password123'),
|
||||
':role' => $i['role'],
|
||||
':university' => NULL,
|
||||
':graduation_year' => NULL,
|
||||
':bio' => $i['bio'],
|
||||
':interests' => $i['interests'],
|
||||
':country' => $i['country'],
|
||||
':cv_url' => NULL,
|
||||
':skills' => NULL,
|
||||
':years_experience' => 0,
|
||||
':previous_startup_exp' => 0,
|
||||
':investment_appetite' => $i['investment_appetite']
|
||||
]);
|
||||
if ($db->lastInsertId()) {
|
||||
echo "Created investor {" . $i['full_name'] . "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "Done!\n";
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user