320 lines
18 KiB
PHP
320 lines
18 KiB
PHP
<?php
|
|
session_start();
|
|
if (!isset($_SESSION['user_id'])) {
|
|
header("Location: login.php");
|
|
exit;
|
|
}
|
|
|
|
require_once __DIR__ . '/db/config.php';
|
|
|
|
$startup_id = (int)($_GET['id'] ?? 0);
|
|
if (!$startup_id) {
|
|
header("Location: startups.php");
|
|
exit;
|
|
}
|
|
|
|
// Fetch startup details (handle missing founder due to account deletion)
|
|
$stmt = db()->prepare("SELECT s.*, u.full_name as founder_name, u.university as founder_uni, u.graduation_year FROM startups s LEFT JOIN users u ON s.founder_id = u.id WHERE s.id = ?");
|
|
$stmt->execute([$startup_id]);
|
|
$startup = $stmt->fetch();
|
|
|
|
if (!$startup) {
|
|
header("Location: startups.php");
|
|
exit;
|
|
}
|
|
|
|
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
|
|
$stmt->execute([$_SESSION['user_id']]);
|
|
$user = $stmt->fetch();
|
|
|
|
// Fetch active funding round
|
|
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE startup_id = ? AND status = 'Active' LIMIT 1");
|
|
$stmt->execute([$startup_id]);
|
|
$activeRound = $stmt->fetch();
|
|
|
|
// Fetch round history
|
|
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE startup_id = ? ORDER BY created_at DESC");
|
|
$stmt->execute([$startup_id]);
|
|
$rounds = $stmt->fetchAll();
|
|
|
|
$error = '';
|
|
$success = '';
|
|
|
|
// Handle Round Controls (Founder Only)
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $startup['founder_id'] == $_SESSION['user_id']) {
|
|
$action = $_POST['action'];
|
|
$round_id = (int)($_POST['round_id'] ?? 0);
|
|
|
|
if ($action === 'finish_round_early' && $activeRound && $activeRound['id'] == $round_id) {
|
|
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Closed' WHERE id = ?");
|
|
$stmt->execute([$round_id]);
|
|
$success = "Funding round finished early. No new investments allowed.";
|
|
$activeRound = null; // Refresh for UI
|
|
} elseif ($action === 'cancel_round' && $activeRound && $activeRound['id'] == $round_id) {
|
|
db()->beginTransaction();
|
|
try {
|
|
// 1. Cancel round
|
|
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Cancelled' WHERE id = ?");
|
|
$stmt->execute([$round_id]);
|
|
|
|
// 2. Refund all investors for this round
|
|
$stmt = db()->prepare("SELECT * FROM investments WHERE funding_round_id = ? AND status = 'approved'");
|
|
$stmt->execute([$round_id]);
|
|
$investmentsToRefund = $stmt->fetchAll();
|
|
|
|
foreach ($investmentsToRefund as $inv) {
|
|
// Mark investment as refunded
|
|
$upd = db()->prepare("UPDATE investments SET status = 'Refunded' WHERE id = ?");
|
|
$upd->execute([$inv['id']]);
|
|
|
|
// Notify investor
|
|
$notif = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
|
$notif->execute([$inv['investor_id'], "The funding round for " . $startup['name'] . " has been cancelled. Your investment of £" . number_format($inv['amount']) . " has been refunded."]);
|
|
}
|
|
|
|
db()->commit();
|
|
$success = "Funding round cancelled and investors refunded.";
|
|
$activeRound = null; // Refresh for UI
|
|
} catch (Exception $e) {
|
|
db()->rollBack();
|
|
$error = "Cancellation failed: " . $e->getMessage();
|
|
}
|
|
} elseif ($action === 'start_new_round') {
|
|
$newTarget = (float)($_POST['new_target'] ?? 0);
|
|
if ($newTarget < 50) {
|
|
$error = "Minimum target for a new round is £50.";
|
|
} elseif ($activeRound) {
|
|
$error = "An active round already exists.";
|
|
} else {
|
|
$stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')");
|
|
$stmt->execute([$startup_id, $newTarget]);
|
|
$success = "New funding round launched!";
|
|
// Refresh active round
|
|
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE startup_id = ? AND status = 'Active' LIMIT 1");
|
|
$stmt->execute([$startup_id]);
|
|
$activeRound = $stmt->fetch();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle Investment (Investor Only)
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'invest') {
|
|
if ($user['role'] !== 'investor') {
|
|
$error = "Founders cannot make investments.";
|
|
} elseif (!$activeRound) {
|
|
$error = "There is no active funding round for this startup.";
|
|
} else {
|
|
$amount = (float)($_POST['amount'] ?? 0);
|
|
if ($amount < 50) {
|
|
$error = "Minimum investment is £50.";
|
|
} else {
|
|
db()->beginTransaction();
|
|
try {
|
|
// Use funding_round_id for the investment
|
|
$stmt = db()->prepare("INSERT INTO investments (investor_id, startup_id, funding_round_id, amount, status) VALUES (?, ?, ?, ?, 'approved')");
|
|
$stmt->execute([$_SESSION['user_id'], $startup_id, $activeRound['id'], $amount]);
|
|
|
|
// Update funding_raised in funding_rounds (the dedicated pot)
|
|
$stmt = db()->prepare("UPDATE funding_rounds SET funding_raised = funding_raised + ? WHERE id = ?");
|
|
$stmt->execute([$amount, $activeRound['id']]);
|
|
|
|
// Update legacy field for backward compatibility in listing pages if needed
|
|
$stmt = db()->prepare("UPDATE startups SET funding_raised = funding_raised + ? WHERE id = ?");
|
|
$stmt->execute([$amount, $startup_id]);
|
|
|
|
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
|
$stmt->execute([$startup['founder_id'], "New investment of £" . number_format($amount) . " in " . $startup['name'] . "!"]);
|
|
|
|
db()->commit();
|
|
$success = "Investment successful! You've backed the current round.";
|
|
// Refresh active round data
|
|
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE id = ?");
|
|
$stmt->execute([$activeRound['id']]);
|
|
$activeRound = $stmt->fetch();
|
|
} catch (Exception $e) {
|
|
db()->rollBack();
|
|
$error = "Investment failed: " . $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><?= htmlspecialchars($startup['name']) ?> — <?= 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>
|
|
|
|
<header>
|
|
<div class="container" style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
|
|
<div class="logo"><?= htmlspecialchars($platformName) ?></div>
|
|
<nav class="nav-links">
|
|
<?php if ($user['role'] === 'founder'): ?>
|
|
<a href="startups.php">My Startups</a>
|
|
<a href="discover.php">Find Partners</a>
|
|
<?php else: ?>
|
|
<a href="startups.php">Browse Startups</a>
|
|
<a href="portfolio.php">Portfolio</a>
|
|
<?php endif; ?>
|
|
<a href="messages.php">Messages</a>
|
|
<a href="notifications.php">Notifications</a>
|
|
</nav>
|
|
<div style="display: flex; align-items: center; gap: 15px;">
|
|
<a href="dashboard.php" style="color: var(--text-secondary);"><i class="fas fa-th-large"></i></a>
|
|
<a href="logout.php" class="btn btn-secondary" style="padding: 8px 16px;">Log Out</a>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="container" style="padding-top: 50px; padding-bottom: 50px;">
|
|
<div style="display: grid; grid-template-columns: 2fr 1.2fr; gap: 40px;">
|
|
<div>
|
|
<div style="display: flex; align-items: center; gap: 20px; margin-bottom: 30px;">
|
|
<div style="width: 80px; height: 80px; background: var(--gradient-primary); border-radius: 24px; display: flex; align-items: center; justify-content: center; font-size: 32px; font-weight: 700; color: #fff; box-shadow: 0 10px 30px rgba(0, 122, 255, 0.3);">
|
|
<?= substr($startup['name'], 0, 1) ?>
|
|
</div>
|
|
<div>
|
|
<h1 style="margin-bottom: 5px;"><?= htmlspecialchars($startup['name']) ?></h1>
|
|
<div style="color: var(--text-secondary); font-size: 14px;">
|
|
Founded by <?= $startup['founder_name'] ? htmlspecialchars($startup['founder_name']) : '<em>Account Deleted</em>' ?>
|
|
<?php if ($startup['founder_uni']): ?> (<?= htmlspecialchars($startup['founder_uni']) ?>)<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card" style="margin-bottom: 30px;">
|
|
<h3>About Startup</h3>
|
|
<p style="color: var(--text-secondary); line-height: 1.8; white-space: pre-line;">
|
|
<?= htmlspecialchars($startup['description']) ?>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="card" style="margin-bottom: 30px;">
|
|
<h3>Investment Terms (Dividend-Only Returns)</h3>
|
|
<div style="padding: 20px; background: rgba(0, 122, 255, 0.05); border: 1px solid rgba(0, 122, 255, 0.2); border-radius: 12px; margin-top: 15px;">
|
|
<p style="font-size: 14px; margin-bottom: 10px;"><i class="fas fa-info-circle"></i> <strong>How it works:</strong></p>
|
|
<ul style="font-size: 14px; color: var(--text-secondary); margin-left: 20px; line-height: 1.6;">
|
|
<li>Investors are entitled to a share of future profits as **dividends**.</li>
|
|
<li>No voting rights or equity control are granted to investors.</li>
|
|
<li>Returns are primarily distributed through profit-sharing mechanisms.</li>
|
|
<li>Each funding round is independent and maintains its own investment pot.</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>Funding Round History</h3>
|
|
<div style="margin-top: 20px;">
|
|
<?php foreach ($rounds as $r): ?>
|
|
<div style="display: flex; justify-content: space-between; padding: 15px 0; border-bottom: 1px solid var(--border-color); font-size: 14px;">
|
|
<div>
|
|
<div style="font-weight: 600;"><?= date('M d, Y', strtotime($r['created_at'])) ?> Round</div>
|
|
<div style="color: var(--text-secondary);">Target: £<?= number_format($r['funding_goal']) ?></div>
|
|
</div>
|
|
<div style="text-align: right;">
|
|
<div style="font-weight: 700;">£<?= number_format($r['funding_raised']) ?> Raised</div>
|
|
<span style="font-size: 10px; text-transform: uppercase; color: <?= $r['status'] === 'Active' ? '#00f2ff' : ($r['status'] === 'Closed' ? '#55ff55' : '#ff5555') ?>;">
|
|
<?= $r['status'] ?>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<?php if ($activeRound): ?>
|
|
<div class="card" style="margin-bottom: 30px; background: var(--surface-color); border: 1px solid var(--border-color);">
|
|
<h3 style="margin-bottom: 25px;">Current Funding Round</h3>
|
|
|
|
<div style="margin-bottom: 30px;">
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
|
|
<span style="font-weight: 700; font-size: 24px;">£<?= number_format($activeRound['funding_raised'], 0) ?></span>
|
|
<span style="color: var(--text-secondary); font-size: 14px; align-self: flex-end;">of £<?= number_format($activeRound['funding_goal'], 0) ?></span>
|
|
</div>
|
|
<div style="width: 100%; height: 12px; background: var(--border-color); border-radius: 6px; overflow: hidden;">
|
|
<div style="width: <?= min(100, ($activeRound['funding_raised'] / ($activeRound['funding_goal'] ?: 1)) * 100) ?>%; height: 100%; background: var(--gradient-primary); box-shadow: 0 0 20px rgba(0, 122, 255, 0.5);"></div>
|
|
</div>
|
|
<div style="text-align: right; font-size: 12px; color: var(--text-secondary); margin-top: 8px;">
|
|
<?= round(($activeRound['funding_raised'] / ($activeRound['funding_goal'] ?: 1)) * 100) ?>% Raised
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($success): ?>
|
|
<div style="background: rgba(0, 255, 0, 0.1); border: 1px solid rgba(0, 255, 0, 0.3); color: #55ff55; padding: 12px; border-radius: 8px; margin-bottom: 20px;">
|
|
<?= htmlspecialchars($success) ?>
|
|
</div>
|
|
<?php elseif ($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; ?>
|
|
|
|
<?php if ($user['role'] === 'investor'): ?>
|
|
<form method="POST">
|
|
<input type="hidden" name="action" value="invest">
|
|
<div style="margin-bottom: 20px;">
|
|
<label style="display: block; margin-bottom: 8px; font-size: 14px;">Investment Amount (£)</label>
|
|
<input type="number" name="amount" min="50" step="50" required style="width: 100%; padding: 12px; border-radius: 12px; background: rgba(255,255,255,0.05); border: 1px solid var(--border-color); color: #fff; font-size: 18px; font-weight: 700;">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary" style="width: 100%; padding: 15px;">Back This Project</button>
|
|
</form>
|
|
<?php elseif ($startup['founder_id'] == $_SESSION['user_id']): ?>
|
|
<div style="display: flex; flex-direction: column; gap: 10px;">
|
|
<form method="POST">
|
|
<input type="hidden" name="action" value="finish_round_early">
|
|
<input type="hidden" name="round_id" value="<?= $activeRound['id'] ?>">
|
|
<button type="submit" class="btn btn-secondary" style="width: 100%; padding: 12px; font-size: 14px;">Finish Round Early</button>
|
|
</form>
|
|
<form method="POST" onsubmit="return confirm('Are you sure you want to cancel this funding round? All investors will be automatically refunded.')">
|
|
<input type="hidden" name="action" value="cancel_round">
|
|
<input type="hidden" name="round_id" value="<?= $activeRound['id'] ?>">
|
|
<button type="submit" class="btn btn-secondary" style="width: 100%; padding: 12px; font-size: 14px; border-color: #ff5555; color: #ff5555;">Cancel Funding Round</button>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="card" style="margin-bottom: 30px; text-align: center; border: 1px dashed var(--border-color);">
|
|
<i class="fas fa-hourglass-end" style="font-size: 32px; color: var(--text-secondary); margin-bottom: 15px; opacity: 0.5;"></i>
|
|
<h3>No Active Round</h3>
|
|
<p style="color: var(--text-secondary); font-size: 14px;">This startup is not currently seeking investment.</p>
|
|
|
|
<?php if ($startup['founder_id'] == $_SESSION['user_id']): ?>
|
|
<div style="margin-top: 25px; text-align: left;">
|
|
<h4 style="margin-bottom: 15px; font-size: 14px;">Start a New Round</h4>
|
|
<form method="POST">
|
|
<input type="hidden" name="action" value="start_new_round">
|
|
<div style="margin-bottom: 15px;">
|
|
<label style="display: block; margin-bottom: 5px; font-size: 12px; color: var(--text-secondary);">New Funding Goal (£)</label>
|
|
<input type="number" name="new_target" min="50" step="50" required style="width: 100%; padding: 10px; border-radius: 8px; background: var(--surface-color); border: 1px solid var(--border-color); color: #fff;">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary" style="width: 100%; padding: 10px; font-size: 14px;">Launch Round</button>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="card">
|
|
<h3>Risk Disclosure</h3>
|
|
<p style="font-size: 12px; color: var(--text-secondary); line-height: 1.5;">
|
|
Student startups carry high risk. Dividends are not guaranteed and depend on the profitability of the venture. Each round is independent.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
</body>
|
|
</html>
|