v74
This commit is contained in:
parent
d2d6703960
commit
0053cb8830
@ -126,7 +126,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
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 = ?
|
||||
recommended_return_rate = ?, recommended_return_reasoning = ?, founder_return_rate = ?, repayment_term = ?
|
||||
WHERE id = ? AND founder_id = ?");
|
||||
|
||||
$stmt->execute([
|
||||
@ -135,7 +135,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$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,
|
||||
$recommended_return_rate, $recommended_return_reasoning, $founder_return_rate, $repayment_term,
|
||||
$existingStartup['id'], $_SESSION['user_id']
|
||||
]);
|
||||
$final_id = $existingStartup['id'];
|
||||
@ -145,7 +145,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
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, status
|
||||
founder_id, recommended_return_rate, recommended_return_reasoning, founder_return_rate, repayment_term, status
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'private')");
|
||||
|
||||
$stmt->execute([
|
||||
@ -290,6 +290,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
</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>
|
||||
|
||||
@ -6,6 +6,8 @@ if (!isset($_SESSION['user_id'])) {
|
||||
}
|
||||
|
||||
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']]);
|
||||
@ -17,14 +19,12 @@ if (!$user) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Security: Check if verified
|
||||
if ($user['verified'] == 0) {
|
||||
session_destroy();
|
||||
header("Location: login.php?error=not_verified");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Check if onboarding is complete
|
||||
if ($user['role'] === 'founder' && $user['onboarding_completed'] == 0) {
|
||||
header("Location: founder_onboarding.php");
|
||||
exit;
|
||||
@ -32,10 +32,7 @@ if ($user['role'] === 'founder' && $user['onboarding_completed'] == 0) {
|
||||
|
||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
|
||||
// Identify Trending Startups (Top 3 in followers or funding)
|
||||
$trendingIds = [];
|
||||
|
||||
// Top 3 Followed
|
||||
$stmt = db()->prepare("
|
||||
SELECT s.id
|
||||
FROM startups s
|
||||
@ -48,7 +45,6 @@ $stmt->execute();
|
||||
$topFollowed = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$trendingIds = array_merge($trendingIds, $topFollowed);
|
||||
|
||||
// Top 3 Funded (Total)
|
||||
$stmt = db()->prepare("
|
||||
SELECT id
|
||||
FROM startups
|
||||
@ -59,9 +55,15 @@ $stmt->execute();
|
||||
$topFunded = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||
$trendingIds = array_unique(array_merge($trendingIds, $topFunded));
|
||||
|
||||
// Fetch user's data based on role
|
||||
$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("
|
||||
@ -73,6 +75,21 @@ if ($user['role'] === 'founder') {
|
||||
");
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$myStartups = $stmt->fetchAll();
|
||||
|
||||
// Repayment Summary Calculation
|
||||
$stmt = db()->prepare("
|
||||
SELECT
|
||||
SUM(i.amount) as total_raised,
|
||||
SUM(i.total_return) 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']]);
|
||||
@ -104,8 +121,6 @@ function number_get_formatted($num) {
|
||||
.profile-link-card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* Modal Styles */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
@ -117,6 +132,26 @@ function number_get_formatted($num) {
|
||||
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>
|
||||
@ -167,6 +202,35 @@ function number_get_formatted($num) {
|
||||
<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'): ?>
|
||||
@ -433,7 +497,6 @@ function updateRound(roundId, status) {
|
||||
}
|
||||
}
|
||||
|
||||
// Close modal when clicking outside
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('wallet-modal');
|
||||
if (event.target == modal) {
|
||||
@ -443,4 +506,4 @@ window.onclick = function(event) {
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
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';
|
||||
32
discover.php
32
discover.php
@ -209,13 +209,13 @@ $browseStartups = $stmt->fetchAll();
|
||||
$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: 24px;">
|
||||
<div style="width: 60px; height: 60px; background: var(--accent-primary); border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 900; color: #000;">
|
||||
<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: 20px; color: var(--text-primary);"><?= htmlspecialchars($s['name']) ?></div>
|
||||
<div style="font-size: 13px; color: var(--text-secondary);">by <?= htmlspecialchars($s['founder_name']) ?></div>
|
||||
<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'] ?>"
|
||||
@ -224,14 +224,24 @@ $browseStartups = $stmt->fetchAll();
|
||||
<i class="<?= $isFollowing ? 'fas' : 'far' ?> fa-heart"></i>
|
||||
</button>
|
||||
</div>
|
||||
<p style="color: var(--text-secondary); font-size: 14px; margin-bottom: 24px; line-height: 1.6; height: 42px; overflow: hidden;">
|
||||
<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: flex; justify-content: space-between; align-items: center;">
|
||||
<?php if (!empty($s['industry'])): ?>
|
||||
<span style="font-size: 11px; font-weight: 700; color: var(--accent-primary); text-transform: uppercase; background: var(--bg-color); padding: 4px 10px; border-radius: 6px; border: 1px solid var(--border-color);"><?= htmlspecialchars($s['industry']) ?></span>
|
||||
<?php endif; ?>
|
||||
<span style="font-weight: 900; color: var(--text-primary);">£<?= number_format($s['active_raised']) ?></span>
|
||||
|
||||
<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; ?>
|
||||
@ -298,4 +308,4 @@ document.querySelectorAll('.follow-btn').forEach(btn => {
|
||||
</script>
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@ -104,18 +104,18 @@ $activeRounds = $stmt->fetchAll();
|
||||
<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: 30px; border: 1px solid var(--border-color);">
|
||||
<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;">Platform Yield</div>
|
||||
<div style="font-weight: 800; color: #fff;"><?= number_format($round['recommended_return_rate'] ?? 5.0, 1) ?>%</div>
|
||||
<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;">Founder Yield</div>
|
||||
<div style="font-weight: 800; color: #fff;"><?= $round['founder_return_rate'] ? number_format($round['founder_return_rate'], 1) . '%' : 'N/A' ?></div>
|
||||
<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>
|
||||
|
||||
@ -137,4 +137,4 @@ $activeRounds = $stmt->fetchAll();
|
||||
|
||||
<script src="assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
46
invest.php
46
invest.php
@ -43,8 +43,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$investor_id = $_SESSION['user_id'];
|
||||
$remaining = $startup['funding_goal'] - $startup['funding_raised'];
|
||||
|
||||
if ($amount <= 0) {
|
||||
$error = "Please enter a valid investment amount.";
|
||||
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) {
|
||||
@ -52,11 +52,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
} 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, equity_pct, status) VALUES (?, ?, ?, ?, ?, 'approved')");
|
||||
$stmt->execute([$startupId, $investor_id, $startup['round_id'], $amount, $equity_pct]);
|
||||
$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 = ?");
|
||||
@ -76,7 +93,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$stmt->execute([$amount, $startup['founder_id']]);
|
||||
|
||||
db()->commit();
|
||||
$success = "Investment of £" . number_format($amount, 2) . " confirmed successfully! Funds moved to the founder's pot.";
|
||||
$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();
|
||||
@ -129,18 +146,16 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
<?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;">Funding Goal</span>
|
||||
<span style="font-weight: 700;">£<?= number_format($startup['funding_goal'], 2) ?></span>
|
||||
<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;">Already Raised</span>
|
||||
<span style="font-weight: 700;">£<?= number_format($startup['funding_raised'], 2) ?></span>
|
||||
<span style="color: #999;">Repayment Term</span>
|
||||
<span style="font-weight: 700; color: #fff;"><?= htmlspecialchars($startup['repayment_term'] ?? 12) ?> Months</span>
|
||||
</div>
|
||||
<?php
|
||||
$remaining = $startup['funding_goal'] - $startup['funding_raised'];
|
||||
?>
|
||||
<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</span>
|
||||
<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>
|
||||
@ -148,8 +163,9 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
<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="1" step="0.01" required placeholder="Enter amount..."
|
||||
<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;">
|
||||
@ -162,4 +178,4 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
144
portfolio.php
144
portfolio.php
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
require_once __DIR__ . "/sync_funding.php";
|
||||
syncRepayments();
|
||||
session_start();
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
@ -26,7 +28,7 @@ $myInvestments = $stmt->fetchAll();
|
||||
|
||||
$totalInvested = 0;
|
||||
foreach ($myInvestments as $inv) {
|
||||
if ($inv['status'] === 'approved') {
|
||||
if ($inv['status'] === 'approved' || $inv['status'] === 'completed') {
|
||||
$totalInvested += $inv['amount'];
|
||||
}
|
||||
}
|
||||
@ -43,7 +45,30 @@ foreach ($myInvestments as $inv) {
|
||||
<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>
|
||||
/* Modal Styles */
|
||||
.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;
|
||||
@ -75,23 +100,16 @@ foreach ($myInvestments as $inv) {
|
||||
<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" class="active">Portfolio</a>
|
||||
<a href="discover.php">Discovery Hub</a>
|
||||
<?php endif; ?>
|
||||
<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;">
|
||||
<!-- Money Pot Widget in Header -->
|
||||
<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>
|
||||
@ -114,11 +132,11 @@ foreach ($myInvestments as $inv) {
|
||||
<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 in student-led startups.</p>
|
||||
<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 Invested</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>
|
||||
@ -129,7 +147,7 @@ foreach ($myInvestments as $inv) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr; gap: 20px;">
|
||||
<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>
|
||||
@ -138,30 +156,79 @@ foreach ($myInvestments as $inv) {
|
||||
<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): ?>
|
||||
<div class="card" style="display: flex; justify-content: space-between; align-items: center; padding: 30px; transition: all 0.3s; cursor: pointer;" onclick="location.href='startup_details.php?id=<?= $inv['startup_id'] ?>'">
|
||||
<div style="display: flex; align-items: center; gap: 25px;">
|
||||
<div style="width: 60px; height: 60px; background: var(--gradient-primary); border-radius: 18px; display: flex; align-items: center; justify-content: center; font-size: 24px; color: #fff; font-weight: 800;">
|
||||
<?= substr($inv['startup_name'], 0, 1) ?>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 11px; text-transform: uppercase; color: var(--accent-blue); margin-bottom: 5px; font-weight: 700;">Invested on <?= date('M d, Y', strtotime($inv['created_at'])) ?></div>
|
||||
<h3 style="margin-bottom: 5px; font-size: 22px; font-weight: 800;"><?= htmlspecialchars($inv['startup_name']) ?></h3>
|
||||
<p style="font-size: 14px; color: var(--text-secondary); margin: 0; opacity: 0.8;"><?= htmlspecialchars(substr($inv['startup_desc'], 0, 100)) ?>...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right; display: flex; align-items: center; gap: 50px;">
|
||||
<div>
|
||||
<div style="font-size: 10px; text-transform: uppercase; color: var(--text-secondary); font-weight: 700; letter-spacing: 1px; margin-bottom: 5px;">Amount</div>
|
||||
<div style="font-size: 22px; font-weight: 900; color: #fff;">£<?= number_format($inv['amount'], 0) ?></div>
|
||||
</div>
|
||||
<div style="min-width: 100px;">
|
||||
<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: 13px; font-weight: 800; color: <?= $inv['status'] === 'approved' ? '#4cd964' : ($inv['status'] === 'pending' ? '#ffcc00' : '#ff3b30') ?>; letter-spacing: 1px;">
|
||||
<?= strtoupper($inv['status']) ?>
|
||||
<?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>
|
||||
<a href="startup_details.php?id=<?= $inv['startup_id'] ?>" class="btn btn-secondary" style="padding: 10px 20px; border-radius: 12px; font-size: 13px; font-weight: 700;">Details</a>
|
||||
<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; ?>
|
||||
@ -248,7 +315,6 @@ document.getElementById('wallet-form').addEventListener('submit', function(e) {
|
||||
});
|
||||
});
|
||||
|
||||
// Close modal when clicking outside
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('wallet-modal');
|
||||
if (event.target == modal) {
|
||||
@ -258,4 +324,4 @@ window.onclick = function(event) {
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -47,8 +47,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
try {
|
||||
// Update startup with round-specific settings
|
||||
// We also update funding_target so that general views show the current target
|
||||
$stmt = db()->prepare("UPDATE startups SET status = ?, founder_return_rate = ?, funding_target = ? WHERE id = ?");
|
||||
$stmt->execute([$status, $founder_rate, $goal, $startup_id]);
|
||||
$stmt = db()->prepare("UPDATE startups SET status = ?, founder_return_rate = ?, funding_target = ?, repayment_term = ? WHERE id = ?");
|
||||
$stmt->execute([$status, $founder_rate, $goal, $repayment_term, $startup_id]);
|
||||
|
||||
// Create the round
|
||||
$stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')");
|
||||
@ -110,6 +110,15 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||
style="width: 100%; padding: 14px; background: var(--surface-color); border: 1px solid var(--border-color); border-radius: 12px; color: #fff; font-size: 18px; font-weight: 700;">
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 600; font-size: 14px;">Repayment Term (Months) *</label>
|
||||
<input type="number" name="repayment_term" min="1" max="60" required placeholder="e.g. 12"
|
||||
value="<?= htmlspecialchars($startup["repayment_term"] ?: "12") ?>"
|
||||
style="width: 100%; padding: 14px; background: var(--surface-color); border: 1px solid var(--border-color); border-radius: 12px; color: #fff; font-size: 16px; font-weight: 700;">
|
||||
<small style="color: var(--text-secondary); display: block; margin-top: 8px; line-height: 1.4;">
|
||||
The duration over which you will repay the investment plus interest.
|
||||
</small>
|
||||
</div>
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 600; font-size: 14px;">Your Proposed Dividend (%) <span style="font-weight: 400; opacity: 0.6;">(Optional)</span></label>
|
||||
<input type="number" name="founder_return_rate" step="0.1" min="0" max="100" placeholder="e.g. 8.5"
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
require_once __DIR__ . "/sync_funding.php";
|
||||
syncRepayments();
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
@ -60,6 +62,14 @@ if ($canSeeHistory) {
|
||||
$fundingHistory = $stmt->fetchAll();
|
||||
}
|
||||
|
||||
// Check if the current user (investor) has an investment here
|
||||
$myInvestment = null;
|
||||
if ($isInvestor) {
|
||||
$stmt = db()->prepare("SELECT * FROM investments WHERE investor_id = ? AND startup_id = ? AND status != 'rejected' LIMIT 1");
|
||||
$stmt->execute([$user_id, $startupId]);
|
||||
$myInvestment = $stmt->fetch();
|
||||
}
|
||||
|
||||
// Fetch approved investments for dividends calculation (Founder only)
|
||||
$approvedInvestments = [];
|
||||
if ($isFounder) {
|
||||
@ -85,32 +95,6 @@ $goal = $startup['active_goal'] ?: 0;
|
||||
$raised = $startup['active_raised'] ?: 0;
|
||||
$progress = ($goal > 0) ? round(($raised / $goal) * 100) : 0;
|
||||
|
||||
/**
|
||||
* Helper to calculate time left for next dividend
|
||||
*/
|
||||
function getNextDividendInfo($createdAt) {
|
||||
$created = new DateTime($createdAt);
|
||||
$day = $created->format('d');
|
||||
|
||||
$now = new DateTime();
|
||||
$thisMonth = new DateTime($now->format('Y-m-') . $day);
|
||||
|
||||
// If today is past the day, next is next month
|
||||
if ($thisMonth <= $now) {
|
||||
$next = clone $thisMonth;
|
||||
$next->modify('+1 month');
|
||||
} else {
|
||||
$next = $thisMonth;
|
||||
}
|
||||
|
||||
$interval = $now->diff($next);
|
||||
$days = $interval->days;
|
||||
|
||||
return [
|
||||
'date' => $next->format('M d, Y'),
|
||||
'days_left' => $days
|
||||
];
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -228,8 +212,6 @@ function getNextDividendInfo($createdAt) {
|
||||
background: var(--success-color);
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Modal Styles */
|
||||
.modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
@ -241,7 +223,6 @@ function getNextDividendInfo($createdAt) {
|
||||
background-color: rgba(0,0,0,0.9);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.follow-btn {
|
||||
padding: 16px 24px;
|
||||
border-radius: 999px;
|
||||
@ -354,9 +335,11 @@ function getNextDividendInfo($createdAt) {
|
||||
<a href="messages.php?chat_with=<?= $startup['founder_id'] ?>" class="btn btn-secondary" style="padding: 16px 24px;">
|
||||
<i class="far fa-comment-dots"></i> Message Founder
|
||||
</a>
|
||||
<a href="invest.php?id=<?= $startup['id'] ?>" class="invest-btn">
|
||||
<i class="fas fa-rocket"></i> Invest Now
|
||||
</a>
|
||||
<?php if ($startup['round_status'] === 'Active'): ?>
|
||||
<a href="invest.php?id=<?= $startup['id'] ?>" class="invest-btn">
|
||||
<i class="fas fa-rocket"></i> Invest Now
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php elseif ($isFounder): ?>
|
||||
<a href="create_startup.php?id=<?= $startup['id'] ?>" class="btn btn-secondary" style="padding: 16px 24px;">
|
||||
<i class="fas fa-edit"></i> Edit Profile
|
||||
@ -365,9 +348,42 @@ function getNextDividendInfo($createdAt) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($myInvestment): ?>
|
||||
<!-- My Investment Card -->
|
||||
<section class="card" style="margin-bottom: 40px; border: 2px solid var(--accent-primary) !important; background: linear-gradient(145deg, rgba(0, 242, 255, 0.05), transparent);">
|
||||
<h2 class="section-title"><i class="fas fa-piggy-bank" style="color: var(--accent-primary);"></i> My Investment</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px;">
|
||||
<div>
|
||||
<div class="data-label">Invested</div>
|
||||
<div style="font-size: 20px; font-weight: 900;">£<?= number_format($myInvestment['amount'], 2) ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="data-label">Total Return</div>
|
||||
<div style="font-size: 20px; font-weight: 900; color: var(--accent-primary);">£<?= number_format($myInvestment['total_return'], 2) ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="data-label">Monthly Div</div>
|
||||
<div style="font-size: 20px; font-weight: 900; color: #4cd964;">£<?= number_format($myInvestment['monthly_dividend'], 2) ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="data-label">Next Payment</div>
|
||||
<div style="font-size: 16px; font-weight: 900;"><?= date('M d, Y', strtotime($myInvestment['next_payment_date'])) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.05); display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="font-size: 13px; color: var(--text-secondary);">
|
||||
Interest: <strong><?= number_format($myInvestment['interest_rate'], 1) ?>%</strong> |
|
||||
Term: <strong><?= $myInvestment['repayment_term'] ?> Months</strong> |
|
||||
Status: <strong style="color: var(--accent-primary);"><?= ($myInvestment['status'] === 'approved' ? 'ACTIVE' : strtoupper($myInvestment['status'])) ?></strong>
|
||||
</div>
|
||||
<a href="portfolio.php" class="btn btn-secondary" style="padding: 8px 16px; font-size: 12px;">Full Portfolio</a>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($startup['round_status'] === 'Active'): ?>
|
||||
<!-- Funding Progress -->
|
||||
<section class="card" style="margin-bottom: 40px; border-color: var(--accent-primary) !important;">
|
||||
<section class="card" style="margin-bottom: 40px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<h2 class="section-title" style="margin-bottom: 0;"><i class="fas fa-chart-pie" style="color: var(--accent-primary);"></i> Active Funding Round</h2>
|
||||
<span style="font-weight: 800; color: var(--accent-primary);"><?= $progress ?>% Complete</span>
|
||||
@ -427,33 +443,33 @@ function getNextDividendInfo($createdAt) {
|
||||
<div style="font-size: 24px; font-weight: 900; color: var(--accent-primary); margin-top: 5px;">£<?= number_format($startup['funding_raised'], 2) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<p style="margin-top: 20px; color: var(--text-secondary); font-size: 13px; opacity: 0.8;">
|
||||
<i class="fas fa-info-circle"></i> This pot holds all investments received. You can withdraw funds for business operations or add funds to cover investor dividends.
|
||||
</p>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($isFounder && !empty($approvedInvestments)): ?>
|
||||
<!-- Dividend Management (Founder Only) -->
|
||||
<section class="card" style="margin-bottom: 40px; border-color: var(--success-color) !important;">
|
||||
<h2 class="section-title"><i class="fas fa-hand-holding-usd" style="color: var(--success-color);"></i> Monthly Dividends Due</h2>
|
||||
<h2 class="section-title"><i class="fas fa-hand-holding-usd" style="color: var(--success-color);"></i> Active Repayments</h2>
|
||||
<div style="margin-bottom: 20px;">
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">Track upcoming monthly payments to your investors based on your <strong><?= number_format($startup['founder_return_rate'] ?? 0, 1) ?>%</strong> offered return.</p>
|
||||
<p style="color: var(--text-secondary); font-size: 14px;">Tracking monthly payments to your active investors.</p>
|
||||
</div>
|
||||
|
||||
<?php foreach ($approvedInvestments as $inv):
|
||||
$monthlyYield = ($inv['amount'] * ($startup['founder_return_rate'] ?? 0) / 100) / 12;
|
||||
$nextPay = getNextDividendInfo($inv['created_at']);
|
||||
$monthlyYield = $inv['monthly_dividend'];
|
||||
$nextPayDate = $inv['next_payment_date'];
|
||||
$daysLeft = (new DateTime())->diff(new DateTime($nextPayDate))->days;
|
||||
?>
|
||||
<div class="dividend-item">
|
||||
<div>
|
||||
<div style="font-weight: 700; font-size: 15px;"><?= htmlspecialchars($inv['investor_name']) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);">Invested £<?= number_format($inv['amount']) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);">
|
||||
£<?= number_format($inv['amount']) ?> @ <?= number_format($inv['interest_rate'], 1) ?>% over <?= $inv['repayment_term'] ?>mo
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 18px; font-weight: 900; color: #fff;">£<?= number_format($monthlyYield, 2) ?></div>
|
||||
<div style="font-size: 11px; color: <?= $nextPay['days_left'] < 7 ? 'var(--error-color)' : 'var(--success-color)' ?>; font-weight: 700;">
|
||||
<i class="far fa-clock"></i> <?= $nextPay['days_left'] ?> days left
|
||||
<div style="font-size: 11px; color: <?= $daysLeft < 7 ? 'var(--error-color)' : 'var(--success-color)' ?>; font-weight: 700;">
|
||||
<i class="far fa-clock"></i> Next: <?= date('M d', strtotime($nextPayDate)) ?> (<?= $daysLeft ?>d)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -467,19 +483,9 @@ function getNextDividendInfo($createdAt) {
|
||||
<p style="font-size: 18px; line-height: 1.6; color: var(--text-primary);">
|
||||
<?= nl2br(htmlspecialchars($startup['product_service'])) ?>
|
||||
</p>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-top: 40px;">
|
||||
<div>
|
||||
<h4 style="color: var(--text-secondary); text-transform: uppercase; font-size: 12px; letter-spacing: 1px;">Business Model</h4>
|
||||
<p style="font-weight: 700; font-size: 16px; color: var(--text-primary);"><?= htmlspecialchars($startup['business_model']) ?></p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="color: var(--text-secondary); text-transform: uppercase; font-size: 12px; letter-spacing: 1px;">Operational Stage</h4>
|
||||
<p style="font-weight: 700; font-size: 16px; color: var(--text-primary);"><?= htmlspecialchars($startup['operational_stage']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Financial Health -->
|
||||
<section class="card" style="margin-bottom: 40px;">
|
||||
<h2 class="section-title"><i class="fas fa-chart-line" style="color: var(--accent-primary);"></i> Financial Health</h2>
|
||||
|
||||
@ -495,19 +501,7 @@ function getNextDividendInfo($createdAt) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="background: var(--bg-color); padding: 15px; border-radius: 12px; margin-bottom: 25px; border: 1px solid var(--border-color);">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
|
||||
<div>
|
||||
<div class="data-label" style="font-size: 10px;">Outstanding Debt</div>
|
||||
<div style="font-size: 14px; color: var(--text-primary);"><?= htmlspecialchars($startup['outstanding_debt'] ?: 'None') ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="data-label" style="font-size: 10px;">Accounts Receivable/Payable</div>
|
||||
<div style="font-size: 14px; color: var(--text-primary);"><?= htmlspecialchars($startup['accounts_receivable_payable'] ?: 'N/A') ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h4 style="margin-bottom: 15px; font-size: 14px; text-transform: uppercase; color: var(--text-secondary); opacity: 0.7;">Historical Documentation</h4>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<?php
|
||||
@ -530,25 +524,25 @@ function getNextDividendInfo($createdAt) {
|
||||
<!-- Return Rates Comparison -->
|
||||
<section class="card" style="margin-bottom: 40px; border-color: var(--accent-primary) !important;">
|
||||
<h2 style="margin-top: 0; margin-bottom: 25px; display: flex; align-items: center; gap: 12px;">
|
||||
<i class="fas fa-percentage" style="color: var(--accent-primary);"></i> Expected Investor Returns
|
||||
<i class="fas fa-percentage" style="color: var(--accent-primary);"></i> Investment Terms
|
||||
</h2>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 20px;">
|
||||
<div style="padding: 20px; background: var(--bg-color); border-radius: 12px; border: 1px solid var(--border-color); text-align: center;">
|
||||
<div style="font-size: 12px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px;">Platform Recommendation</div>
|
||||
<div style="font-size: 32px; font-weight: 900; color: var(--accent-primary);"><?= number_format($startup['recommended_return_rate'] ?? 5.0, 1) ?>%</div>
|
||||
<div style="font-size: 11px; color: var(--text-secondary); margin-top: 5px;">AI analysis based on uploaded financials</div>
|
||||
<div style="font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px;">Interest Rate</div>
|
||||
<div style="font-size: 28px; font-weight: 900; color: var(--accent-primary);"><?= number_format($startup['founder_return_rate'] ?? 0, 1) ?>%</div>
|
||||
</div>
|
||||
<div style="padding: 20px; background: var(--bg-color); border-radius: 12px; border: 1px solid var(--border-color); text-align: center;">
|
||||
<div style="font-size: 12px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px;">Founder's Proposal</div>
|
||||
<div style="font-size: 32px; font-weight: 900; color: #fff;">
|
||||
<?= $startup['founder_return_rate'] !== null ? number_format($startup['founder_return_rate'], 1) . '%' : 'N/A' ?>
|
||||
</div>
|
||||
<div style="font-size: 11px; color: var(--text-secondary); margin-top: 5px;">Target annual dividend yield set by founder</div>
|
||||
<div style="font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px;">Repayment Term</div>
|
||||
<div style="font-size: 28px; font-weight: 900; color: #fff;"><?= $startup['repayment_term'] ?? 12 ?> Mo</div>
|
||||
</div>
|
||||
<div style="padding: 20px; background: var(--bg-color); border-radius: 12px; border: 1px solid var(--border-color); text-align: center;">
|
||||
<div style="font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 1px; margin-bottom: 10px;">Min Invest</div>
|
||||
<div style="font-size: 28px; font-weight: 900; color: #fff;">£50</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!empty($startup['recommended_return_reasoning'])): ?>
|
||||
<div style="margin-top: 20px; padding: 15px; background: var(--surface-color); border-radius: 12px; border: 1px solid var(--border-color); font-size: 13px; line-height: 1.5; color: var(--text-secondary);">
|
||||
<div style="font-weight: 700; margin-bottom: 5px; color: var(--accent-primary); text-transform: uppercase; font-size: 10px; letter-spacing: 0.5px;">Calculation Reasoning</div>
|
||||
<div style="font-weight: 700; margin-bottom: 5px; color: var(--accent-primary); text-transform: uppercase; font-size: 10px; letter-spacing: 0.5px;">AI Yield Recommendation: <?= number_format($startup['recommended_return_rate'] ?? 5.0, 1) ?>%</div>
|
||||
<?= htmlspecialchars($startup['recommended_return_reasoning']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
@ -569,25 +563,11 @@ function getNextDividendInfo($createdAt) {
|
||||
?>
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; padding: 20px; background: var(--elevated-color); border-radius: 12px; border: 1px solid var(--border-color);">
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<?php if ($inv['investor_user_id']): ?>
|
||||
<a href="profile.php?id=<?= $inv['investor_user_id'] ?>" style="text-decoration: none;">
|
||||
<div style="width: 45px; height: 45px; border-radius: 8px; background: var(--surface-color); display: flex; align-items: center; justify-content: center;">
|
||||
<span style="font-weight: 800; color: var(--accent-primary);"><?= substr($investorName, 0, 1) ?></span>
|
||||
</div>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<div style="width: 45px; height: 45px; border-radius: 8px; background: var(--surface-color); display: flex; align-items: center; justify-content: center;">
|
||||
<span style="font-weight: 800; color: var(--accent-primary);"><?= substr($investorName, 0, 1) ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div style="width: 45px; height: 45px; border-radius: 8px; background: var(--surface-color); display: flex; align-items: center; justify-content: center;">
|
||||
<span style="font-weight: 800; color: var(--accent-primary);"><?= substr($investorName, 0, 1) ?></span>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight: 700; color: var(--text-primary);">
|
||||
<?php if ($inv['investor_user_id']): ?>
|
||||
<a href="profile.php?id=<?= $inv['investor_user_id'] ?>" style="color: inherit; text-decoration: none;"><?= htmlspecialchars($investorName) ?></a>
|
||||
<?php else: ?>
|
||||
<?= htmlspecialchars($investorName) ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div style="font-weight: 700; color: var(--text-primary);"><?= htmlspecialchars($investorName) ?></div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary);"><?= date('M d, Y', strtotime($inv['created_at'])) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
@ -679,7 +659,6 @@ document.getElementById('wallet-form').addEventListener('submit', function(e) {
|
||||
});
|
||||
});
|
||||
|
||||
// Close modal when clicking outside
|
||||
window.onclick = function(event) {
|
||||
const modal = document.getElementById('wallet-modal');
|
||||
if (event.target == modal) {
|
||||
@ -730,4 +709,4 @@ function toggleFollow(startupId) {
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@ -1,32 +1,62 @@
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
echo "Recalculating funding totals...\n";
|
||||
|
||||
// 1. Reset all funding_raised to 0
|
||||
db()->exec("UPDATE startups SET funding_raised = 0");
|
||||
db()->exec("UPDATE funding_rounds SET funding_raised = 0");
|
||||
|
||||
// 2. Update funding_rounds totals
|
||||
$stmt = db()->query("SELECT funding_round_id, SUM(amount) as total FROM investments WHERE status != 'rejected' GROUP BY funding_round_id");
|
||||
$roundTotals = $stmt->fetchAll();
|
||||
|
||||
foreach ($roundTotals as $t) {
|
||||
if (!$t['funding_round_id']) continue;
|
||||
echo "Updating Round ID: {$t['funding_round_id']} with £{$t['total']}\n";
|
||||
$stmt2 = db()->prepare("UPDATE funding_rounds SET funding_raised = ? WHERE id = ?");
|
||||
$stmt2->execute([$t['total'], $t['funding_round_id']]);
|
||||
function syncRepayments() {
|
||||
$db = db();
|
||||
$now = date('Y-m-d');
|
||||
|
||||
// Find all active investments where a payment is due
|
||||
$stmt = $db->prepare("
|
||||
SELECT i.*, s.founder_id
|
||||
FROM investments i
|
||||
JOIN startups s ON i.startup_id = s.id
|
||||
WHERE i.status = 'approved' AND i.next_payment_date <= ? AND i.next_payment_date IS NOT NULL
|
||||
");
|
||||
$stmt->execute([$now]);
|
||||
$dueInvestments = $stmt->fetchAll();
|
||||
|
||||
foreach ($dueInvestments as $inv) {
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
$amountToPay = $inv['monthly_dividend'];
|
||||
|
||||
// Ensure we don't overpay
|
||||
if ($inv['paid_amount'] + $amountToPay > $inv['total_return']) {
|
||||
$amountToPay = $inv['total_return'] - $inv['paid_amount'];
|
||||
}
|
||||
|
||||
if ($amountToPay > 0) {
|
||||
// 1. Deduct from founder
|
||||
$stmt = $db->prepare("UPDATE users SET balance = balance - ? WHERE id = ?");
|
||||
$stmt->execute([$amountToPay, $inv['founder_id']]);
|
||||
|
||||
// 2. Add to investor
|
||||
$stmt = $db->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
|
||||
$stmt->execute([$amountToPay, $inv['investor_id']]);
|
||||
|
||||
// 3. Update investment record
|
||||
$newPaidAmount = $inv['paid_amount'] + $amountToPay;
|
||||
$newStatus = ($newPaidAmount >= $inv['total_return']) ? 'completed' : 'approved';
|
||||
$nextPayment = date('Y-m-d', strtotime($inv['next_payment_date'] . ' +1 month'));
|
||||
|
||||
// If completed, clear next payment date
|
||||
if ($newStatus === 'completed') {
|
||||
$nextPayment = null;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("UPDATE investments SET paid_amount = ?, status = ?, next_payment_date = ? WHERE id = ?");
|
||||
$stmt->execute([$newPaidAmount, $newStatus, $nextPayment, $inv['id']]);
|
||||
|
||||
// 4. Create a notification for both parties (Optional but good)
|
||||
$stmt = $db->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||
$stmt->execute([$inv['investor_id'], "You received a dividend payment of £" . number_format($amountToPay, 2) . " from " . $inv['id']]);
|
||||
$stmt->execute([$inv['founder_id'], "A dividend payment of £" . number_format($amountToPay, 2) . " was paid to an investor."]);
|
||||
}
|
||||
|
||||
$db->commit();
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
// Log error or ignore for now
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Update startups totals (sum of all their rounds)
|
||||
$stmt = db()->query("SELECT startup_id, SUM(amount) as total FROM investments WHERE status != 'rejected' GROUP BY startup_id");
|
||||
$startupTotals = $stmt->fetchAll();
|
||||
|
||||
foreach ($startupTotals as $t) {
|
||||
if (!$t['startup_id']) continue;
|
||||
echo "Updating Startup ID: {$t['startup_id']} with £{$t['total']}\n";
|
||||
$stmt3 = db()->prepare("UPDATE startups SET funding_raised = ? WHERE id = ?");
|
||||
$stmt3->execute([$t['total'], $t['startup_id']]);
|
||||
}
|
||||
|
||||
echo "Done!\n";
|
||||
Loading…
x
Reference in New Issue
Block a user