v15
This commit is contained in:
parent
e904e15720
commit
fc3fe3f0a0
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';
|
||||||
35
discover.php
35
discover.php
@ -20,39 +20,55 @@ if (!$user) {
|
|||||||
|
|
||||||
$user_role = $user['role'];
|
$user_role = $user['role'];
|
||||||
|
|
||||||
|
// Blocked users filter
|
||||||
|
$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), '?'));
|
||||||
|
|
||||||
// Leaderboard: Most Followed This Week
|
// Leaderboard: Most Followed This Week
|
||||||
$stmt = db()->prepare("
|
$sql = "
|
||||||
SELECT s.id, s.name, s.description, u.full_name as founder_name, COUNT(sf.id) as followers_count
|
SELECT s.id, s.name, s.description, u.full_name as founder_name, COUNT(sf.id) as followers_count
|
||||||
FROM startups s
|
FROM startups s
|
||||||
JOIN users u ON s.founder_id = u.id
|
JOIN users u ON s.founder_id = u.id
|
||||||
JOIN startup_followers sf ON s.id = sf.startup_id
|
JOIN startup_followers sf ON s.id = sf.startup_id
|
||||||
WHERE sf.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
WHERE sf.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||||
|
AND u.id NOT IN ($placeholders)
|
||||||
GROUP BY s.id
|
GROUP BY s.id
|
||||||
ORDER BY followers_count DESC
|
ORDER BY followers_count DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
");
|
";
|
||||||
$stmt->execute();
|
$stmt = db()->prepare($sql);
|
||||||
|
$stmt->execute($all_blocked ?: []);
|
||||||
$mostFollowed = $stmt->fetchAll();
|
$mostFollowed = $stmt->fetchAll();
|
||||||
|
|
||||||
// Leaderboard: Most Funded This Week
|
// Leaderboard: Most Funded This Week
|
||||||
$stmt = db()->prepare("
|
$sql = "
|
||||||
SELECT s.id, s.name, s.description, u.full_name as founder_name, SUM(i.amount) as funded_amount
|
SELECT s.id, s.name, s.description, u.full_name as founder_name, SUM(i.amount) as funded_amount
|
||||||
FROM startups s
|
FROM startups s
|
||||||
JOIN users u ON s.founder_id = u.id
|
JOIN users u ON s.founder_id = u.id
|
||||||
JOIN investments i ON s.id = i.startup_id
|
JOIN investments i ON s.id = i.startup_id
|
||||||
WHERE i.status = 'approved' AND i.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
WHERE i.status = 'approved' AND i.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||||
|
AND u.id NOT IN ($placeholders)
|
||||||
GROUP BY s.id
|
GROUP BY s.id
|
||||||
ORDER BY funded_amount DESC
|
ORDER BY funded_amount DESC
|
||||||
LIMIT 10
|
LIMIT 10
|
||||||
");
|
";
|
||||||
$stmt->execute();
|
$stmt = db()->prepare($sql);
|
||||||
|
$stmt->execute($all_blocked ?: []);
|
||||||
$mostFunded = $stmt->fetchAll();
|
$mostFunded = $stmt->fetchAll();
|
||||||
|
|
||||||
// Search logic
|
// Search logic
|
||||||
$q = $_GET['q'] ?? '';
|
$q = $_GET['q'] ?? '';
|
||||||
$browseStartups = [];
|
$browseStartups = [];
|
||||||
$where = "s.status = 'public'";
|
$where = "s.status = 'public' AND u.id NOT IN ($placeholders)";
|
||||||
$params = [];
|
$params = $all_blocked ?: [];
|
||||||
if ($q) {
|
if ($q) {
|
||||||
$where .= " AND (s.name LIKE ? OR s.description LIKE ? OR u.full_name LIKE ?)";
|
$where .= " AND (s.name LIKE ? OR s.description LIKE ? OR u.full_name LIKE ?)";
|
||||||
$params[] = "%$q%";
|
$params[] = "%$q%";
|
||||||
@ -85,10 +101,8 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
.hub-header { padding: 60px 0 40px; text-align: center; }
|
.hub-header { padding: 60px 0 40px; text-align: center; }
|
||||||
.hub-header h1 { font-size: 48px; font-weight: 800; background: var(--gradient-primary); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 12px; }
|
.hub-header h1 { font-size: 48px; font-weight: 800; background: var(--gradient-primary); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 12px; }
|
||||||
.hub-header p { color: var(--text-secondary); font-size: 18px; }
|
.hub-header p { color: var(--text-secondary); font-size: 18px; }
|
||||||
|
|
||||||
.leaderboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 60px; }
|
.leaderboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 60px; }
|
||||||
@media (max-width: 900px) { .leaderboard-grid { grid-template-columns: 1fr; } }
|
@media (max-width: 900px) { .leaderboard-grid { grid-template-columns: 1fr; } }
|
||||||
|
|
||||||
.lb-card { background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 24px; padding: 30px; backdrop-filter: blur(20px); }
|
.lb-card { background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 24px; padding: 30px; backdrop-filter: blur(20px); }
|
||||||
.lb-title { display: flex; align-items: center; gap: 12px; margin-bottom: 25px; font-size: 20px; font-weight: 700; }
|
.lb-title { display: flex; align-items: center; gap: 12px; margin-bottom: 25px; font-size: 20px; font-weight: 700; }
|
||||||
.lb-item { display: flex; align-items: center; gap: 15px; padding: 15px; background: rgba(255,255,255,0.03); border-radius: 16px; margin-bottom: 12px; transition: all 0.3s; text-decoration: none; color: inherit; }
|
.lb-item { display: flex; align-items: center; gap: 15px; padding: 15px; background: rgba(255,255,255,0.03); border-radius: 16px; margin-bottom: 12px; transition: all 0.3s; text-decoration: none; color: inherit; }
|
||||||
@ -97,7 +111,6 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
.rank-1 { background: gold; color: #000; }
|
.rank-1 { background: gold; color: #000; }
|
||||||
.rank-2 { background: silver; color: #000; }
|
.rank-2 { background: silver; color: #000; }
|
||||||
.rank-3 { background: #cd7f32; color: #000; }
|
.rank-3 { background: #cd7f32; color: #000; }
|
||||||
|
|
||||||
.startup-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 25px; }
|
.startup-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); gap: 25px; }
|
||||||
.startup-card { background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 24px; padding: 30px; transition: all 0.3s; }
|
.startup-card { background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 24px; padding: 30px; transition: all 0.3s; }
|
||||||
.startup-card:hover { transform: translateY(-5px); border-color: var(--accent-blue); }
|
.startup-card:hover { transform: translateY(-5px); border-color: var(--accent-blue); }
|
||||||
|
|||||||
128
messages.php
128
messages.php
@ -14,7 +14,7 @@ $user = $stmt->fetch();
|
|||||||
|
|
||||||
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
$platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
||||||
|
|
||||||
// Handle Accept/Reject Actions
|
// Handle Actions (Accept/Reject/Unmatch/Block)
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && isset($_POST['other_user_id'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && isset($_POST['other_user_id'])) {
|
||||||
$other_id = (int)$_POST['other_user_id'];
|
$other_id = (int)$_POST['other_user_id'];
|
||||||
$action = $_POST['action'];
|
$action = $_POST['action'];
|
||||||
@ -22,11 +22,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && isset($_
|
|||||||
if ($action === 'accept') {
|
if ($action === 'accept') {
|
||||||
$stmt = db()->prepare("UPDATE messages SET status = 'accepted' WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
$stmt = db()->prepare("UPDATE messages SET status = 'accepted' WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
||||||
$stmt->execute([$other_id, $user_id]);
|
$stmt->execute([$other_id, $user_id]);
|
||||||
|
|
||||||
// Notify the sender
|
|
||||||
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||||
$stmt->execute([$other_id, "Your message request to " . $user['full_name'] . " has been accepted."]);
|
$stmt->execute([$other_id, "Your message request to " . $user['full_name'] . " has been accepted."]);
|
||||||
|
|
||||||
header("Location: messages.php?chat_with=$other_id");
|
header("Location: messages.php?chat_with=$other_id");
|
||||||
exit;
|
exit;
|
||||||
} elseif ($action === 'reject') {
|
} elseif ($action === 'reject') {
|
||||||
@ -34,13 +31,38 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && isset($_
|
|||||||
$stmt->execute([$other_id, $user_id]);
|
$stmt->execute([$other_id, $user_id]);
|
||||||
header("Location: messages.php");
|
header("Location: messages.php");
|
||||||
exit;
|
exit;
|
||||||
|
} elseif ($action === 'unmatch') {
|
||||||
|
$stmt = db()->prepare("UPDATE matches SET status = 'unmatched' WHERE (user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)");
|
||||||
|
$stmt->execute([$user_id, $other_id, $other_id, $user_id]);
|
||||||
|
header("Location: messages.php");
|
||||||
|
exit;
|
||||||
|
} elseif ($action === 'block') {
|
||||||
|
$stmt = db()->prepare("INSERT IGNORE INTO blocked_users (blocker_id, blocked_id) VALUES (?, ?)");
|
||||||
|
$stmt->execute([$user_id, $other_id]);
|
||||||
|
// Also unmatch if they were matched
|
||||||
|
$stmt = db()->prepare("UPDATE matches SET status = 'unmatched' WHERE (user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)");
|
||||||
|
$stmt->execute([$user_id, $other_id, $other_id, $user_id]);
|
||||||
|
header("Location: messages.php");
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch Matches for Founders
|
// Fetch Blocked Users to filter them out
|
||||||
|
$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 = [];
|
$matches = [];
|
||||||
if ($user['role'] === 'founder') {
|
if ($user['role'] === 'founder') {
|
||||||
$stmt = db()->prepare("
|
$sql = "
|
||||||
SELECT m.*,
|
SELECT m.*,
|
||||||
u.full_name as match_name,
|
u.full_name as match_name,
|
||||||
u.id as match_id,
|
u.id as match_id,
|
||||||
@ -50,21 +72,28 @@ if ($user['role'] === 'founder') {
|
|||||||
JOIN users u ON (m.user1_id = u.id OR m.user2_id = u.id)
|
JOIN users u ON (m.user1_id = u.id OR m.user2_id = u.id)
|
||||||
WHERE (m.user1_id = ? OR m.user2_id = ?)
|
WHERE (m.user1_id = ? OR m.user2_id = ?)
|
||||||
AND u.id != ?
|
AND u.id != ?
|
||||||
");
|
AND m.status = 'active'
|
||||||
$stmt->execute([$user_id, $user_id, $user_id]);
|
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();
|
$matches = $stmt->fetchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch Conversations (accepted or pending from others)
|
// Fetch Conversations (accepted or pending from others, excluding blocked)
|
||||||
$stmt = db()->prepare("
|
$sql = "
|
||||||
SELECT DISTINCT u.id as other_user_id, u.full_name as other_user_name, u.role as other_role
|
SELECT DISTINCT u.id as other_user_id, u.full_name as other_user_name, u.role as other_role
|
||||||
FROM messages m
|
FROM messages m
|
||||||
JOIN users u ON (m.sender_id = u.id OR m.receiver_id = u.id)
|
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 != ?)
|
WHERE ((m.sender_id = ? OR m.receiver_id = ?) AND u.id != ?)
|
||||||
AND (m.status = 'accepted' OR (m.status = 'pending' AND m.receiver_id = ?))
|
AND (m.status = 'accepted' OR (m.status = 'pending' AND m.receiver_id = ?))
|
||||||
|
AND u.id NOT IN ($placeholders)
|
||||||
ORDER BY (SELECT MAX(created_at) FROM messages WHERE (sender_id = m.sender_id AND receiver_id = m.receiver_id) OR (sender_id = m.receiver_id AND receiver_id = m.sender_id)) DESC
|
ORDER BY (SELECT MAX(created_at) FROM messages WHERE (sender_id = m.sender_id AND receiver_id = m.receiver_id) OR (sender_id = m.receiver_id AND receiver_id = m.sender_id)) DESC
|
||||||
");
|
";
|
||||||
$stmt->execute([$user_id, $user_id, $user_id, $user_id]);
|
$stmt = db()->prepare($sql);
|
||||||
|
$params = array_merge([$user_id, $user_id, $user_id, $user_id], $all_blocked ?: []);
|
||||||
|
$stmt->execute($params);
|
||||||
$conversations = $stmt->fetchAll();
|
$conversations = $stmt->fetchAll();
|
||||||
|
|
||||||
$active_chat_id = isset($_GET['chat_with']) ? (int)$_GET['chat_with'] : null;
|
$active_chat_id = isset($_GET['chat_with']) ? (int)$_GET['chat_with'] : null;
|
||||||
@ -73,14 +102,20 @@ $active_chat_user = null;
|
|||||||
$chat_messages = [];
|
$chat_messages = [];
|
||||||
$can_reply = true;
|
$can_reply = true;
|
||||||
$needs_acceptance = false;
|
$needs_acceptance = false;
|
||||||
|
$is_currently_matched = false;
|
||||||
|
|
||||||
if ($active_chat_id) {
|
if ($active_chat_id) {
|
||||||
|
// Check if blocked
|
||||||
|
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 = db()->prepare("SELECT id, full_name, role FROM users WHERE id = ?");
|
||||||
$stmt->execute([$active_chat_id]);
|
$stmt->execute([$active_chat_id]);
|
||||||
$active_chat_user = $stmt->fetch();
|
$active_chat_user = $stmt->fetch();
|
||||||
|
|
||||||
if ($active_chat_user) {
|
if ($active_chat_user) {
|
||||||
// Fetch messages (only show accepted or pending ones)
|
|
||||||
$stmt = db()->prepare("
|
$stmt = db()->prepare("
|
||||||
SELECT * FROM messages
|
SELECT * FROM messages
|
||||||
WHERE ((sender_id = ? AND receiver_id = ?)
|
WHERE ((sender_id = ? AND receiver_id = ?)
|
||||||
@ -91,21 +126,19 @@ if ($active_chat_id) {
|
|||||||
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||||
$chat_messages = $stmt->fetchAll();
|
$chat_messages = $stmt->fetchAll();
|
||||||
|
|
||||||
// Check if there are any accepted messages or a match
|
|
||||||
$stmt = db()->prepare("SELECT 1 FROM messages WHERE ((sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?)) AND status = 'accepted'");
|
$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]);
|
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||||
$has_accepted = (bool)$stmt->fetchColumn();
|
$has_accepted = (bool)$stmt->fetchColumn();
|
||||||
|
|
||||||
$stmt = db()->prepare("SELECT 1 FROM matches WHERE (user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)");
|
$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]);
|
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||||
$has_match = (bool)$stmt->fetchColumn();
|
$is_currently_matched = (bool)$stmt->fetchColumn();
|
||||||
|
|
||||||
// If receiver of pending messages, can't reply yet
|
|
||||||
$stmt = db()->prepare("SELECT 1 FROM messages WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
$stmt = db()->prepare("SELECT 1 FROM messages WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
||||||
$stmt->execute([$active_chat_id, $user_id]);
|
$stmt->execute([$active_chat_id, $user_id]);
|
||||||
$has_pending_from_other = (bool)$stmt->fetchColumn();
|
$has_pending_from_other = (bool)$stmt->fetchColumn();
|
||||||
|
|
||||||
if (!$has_accepted && !$has_match && $has_pending_from_other) {
|
if (!$has_accepted && !$is_currently_matched && $has_pending_from_other) {
|
||||||
$can_reply = false;
|
$can_reply = false;
|
||||||
$needs_acceptance = true;
|
$needs_acceptance = true;
|
||||||
}
|
}
|
||||||
@ -116,29 +149,22 @@ if ($active_chat_id) {
|
|||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active_chat_id && $can_reply) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active_chat_id && $can_reply) {
|
||||||
$content = trim($_POST['content']);
|
$content = trim($_POST['content']);
|
||||||
if (!empty($content)) {
|
if (!empty($content)) {
|
||||||
// Determine status
|
|
||||||
$status = 'accepted';
|
$status = 'accepted';
|
||||||
|
$stmt = db()->prepare("SELECT 1 FROM matches WHERE ((user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)) AND status = 'active'");
|
||||||
// Check if a match exists
|
|
||||||
$stmt = db()->prepare("SELECT 1 FROM matches WHERE (user1_id = ? AND user2_id = ?) OR (user1_id = ? AND user2_id = ?)");
|
|
||||||
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||||
$is_match = (bool)$stmt->fetchColumn();
|
$is_match = (bool)$stmt->fetchColumn();
|
||||||
|
|
||||||
// Check if previous accepted exists
|
|
||||||
$stmt = db()->prepare("SELECT 1 FROM messages WHERE ((sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?)) AND status = 'accepted'");
|
$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]);
|
$stmt->execute([$user_id, $active_chat_id, $active_chat_id, $user_id]);
|
||||||
$is_accepted = (bool)$stmt->fetchColumn();
|
$is_accepted = (bool)$stmt->fetchColumn();
|
||||||
|
|
||||||
if (!$is_match && !$is_accepted) {
|
if (!$is_match && !$is_accepted) {
|
||||||
// Check startup status
|
|
||||||
if ($startup_id) {
|
if ($startup_id) {
|
||||||
$stmt = db()->prepare("SELECT status, name FROM startups WHERE id = ?");
|
$stmt = db()->prepare("SELECT status, name FROM startups WHERE id = ?");
|
||||||
$stmt->execute([$startup_id]);
|
$stmt->execute([$startup_id]);
|
||||||
$s = $stmt->fetch();
|
$s = $stmt->fetch();
|
||||||
if ($s && $s['status'] === 'private') {
|
if ($s && $s['status'] === 'private') {
|
||||||
$status = 'pending';
|
$status = 'pending';
|
||||||
|
|
||||||
// Notify receiver about the request
|
|
||||||
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||||
$stmt->execute([$active_chat_id, "New message request from " . $user['full_name'] . " regarding " . $s['name'] . "."]);
|
$stmt->execute([$active_chat_id, "New message request from " . $user['full_name'] . " regarding " . $s['name'] . "."]);
|
||||||
}
|
}
|
||||||
@ -199,7 +225,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active
|
|||||||
width: 40px; height: 40px; border-radius: 12px; background: var(--gradient-primary);
|
width: 40px; height: 40px; border-radius: 12px; background: var(--gradient-primary);
|
||||||
display: flex; align-items: center; justify-content: center; font-weight: 700; color: #fff;
|
display: flex; align-items: center; justify-content: center; font-weight: 700; color: #fff;
|
||||||
}
|
}
|
||||||
.chat-header { padding: 15px 25px; border-bottom: 1px solid var(--border-color); display: flex; align-items: center; gap: 15px; }
|
.chat-header { padding: 15px 25px; border-bottom: 1px solid var(--border-color); display: flex; align-items: center; justify-content: space-between; }
|
||||||
.chat-messages { flex: 1; overflow-y: auto; padding: 25px; display: flex; flex-direction: column; gap: 15px; }
|
.chat-messages { flex: 1; overflow-y: auto; padding: 25px; display: flex; flex-direction: column; gap: 15px; }
|
||||||
.msg-bubble {
|
.msg-bubble {
|
||||||
max-width: 70%; padding: 12px 18px; border-radius: 18px; font-size: 14px; line-height: 1.5;
|
max-width: 70%; padding: 12px 18px; border-radius: 18px; font-size: 14px; line-height: 1.5;
|
||||||
@ -219,6 +245,24 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active
|
|||||||
padding: 20px; background: rgba(255, 204, 0, 0.1); border-top: 1px solid rgba(255, 204, 0, 0.2);
|
padding: 20px; background: rgba(255, 204, 0, 0.1); border-top: 1px solid rgba(255, 204, 0, 0.2);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Action Menu */
|
||||||
|
.action-menu { position: relative; }
|
||||||
|
.action-menu-content {
|
||||||
|
display: none; position: absolute; right: 0; top: 100%;
|
||||||
|
background: var(--surface-color); border: 1px solid var(--border-color);
|
||||||
|
border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
||||||
|
z-index: 100; min-width: 150px;
|
||||||
|
}
|
||||||
|
.action-menu:hover .action-menu-content { display: block; }
|
||||||
|
.action-link {
|
||||||
|
display: block; padding: 10px 15px; color: var(--text-secondary);
|
||||||
|
text-decoration: none; font-size: 13px; transition: all 0.2s;
|
||||||
|
background: none; border: none; width: 100%; text-align: left; cursor: pointer;
|
||||||
|
}
|
||||||
|
.action-link:hover { background: rgba(255,255,255,0.05); color: #fff; }
|
||||||
|
.action-link.danger { color: #ff3b30; }
|
||||||
|
.action-link.danger:hover { background: rgba(255, 59, 48, 0.1); }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -253,7 +297,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active
|
|||||||
<div style="padding: 10px 20px; font-size: 11px; text-transform: uppercase; color: var(--text-secondary); letter-spacing: 1px;">New Matches</div>
|
<div style="padding: 10px 20px; font-size: 11px; text-transform: uppercase; color: var(--text-secondary); letter-spacing: 1px;">New Matches</div>
|
||||||
<?php foreach ($matches as $match): ?>
|
<?php foreach ($matches as $match): ?>
|
||||||
<?php
|
<?php
|
||||||
// Check if already has conversation
|
|
||||||
$hasConv = false;
|
$hasConv = false;
|
||||||
foreach ($conversations as $c) { if ($c['other_user_id'] == $match['match_id']) $hasConv = true; }
|
foreach ($conversations as $c) { if ($c['other_user_id'] == $match['match_id']) $hasConv = true; }
|
||||||
if ($hasConv) continue;
|
if ($hasConv) continue;
|
||||||
@ -274,7 +317,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active
|
|||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?php foreach ($conversations as $conv): ?>
|
<?php foreach ($conversations as $conv): ?>
|
||||||
<?php
|
<?php
|
||||||
// Check if has pending from others
|
|
||||||
$stmt = db()->prepare("SELECT 1 FROM messages WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
$stmt = db()->prepare("SELECT 1 FROM messages WHERE sender_id = ? AND receiver_id = ? AND status = 'pending'");
|
||||||
$stmt->execute([$conv['other_user_id'], $user_id]);
|
$stmt->execute([$conv['other_user_id'], $user_id]);
|
||||||
$isPending = (bool)$stmt->fetchColumn();
|
$isPending = (bool)$stmt->fetchColumn();
|
||||||
@ -298,10 +340,27 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active
|
|||||||
<div class="chat-main">
|
<div class="chat-main">
|
||||||
<?php if ($active_chat_user): ?>
|
<?php if ($active_chat_user): ?>
|
||||||
<div class="chat-header">
|
<div class="chat-header">
|
||||||
<div class="avatar-sm"><?= substr($active_chat_user['full_name'], 0, 1) ?></div>
|
<div style="display: flex; align-items: center; gap: 15px;">
|
||||||
<div>
|
<div class="avatar-sm"><?= substr($active_chat_user['full_name'], 0, 1) ?></div>
|
||||||
<div style="font-weight: 700;"><?= htmlspecialchars($active_chat_user['full_name']) ?></div>
|
<div>
|
||||||
<div style="font-size: 12px; color: var(--text-secondary);"><?= ucfirst($active_chat_user['role']) ?></div>
|
<div style="font-weight: 700;"><?= htmlspecialchars($active_chat_user['full_name']) ?></div>
|
||||||
|
<div style="font-size: 12px; color: var(--text-secondary);"><?= ucfirst($active_chat_user['role']) ?></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="action-menu">
|
||||||
|
<button class="btn btn-secondary" style="padding: 5px 12px;"><i class="fas fa-ellipsis-v"></i></button>
|
||||||
|
<div class="action-menu-content">
|
||||||
|
<form method="POST" onsubmit="return confirm('Unmatch with this founder?')">
|
||||||
|
<input type="hidden" name="other_user_id" value="<?= $active_chat_id ?>">
|
||||||
|
<input type="hidden" name="action" value="unmatch">
|
||||||
|
<button type="submit" class="action-link">Unmatch</button>
|
||||||
|
</form>
|
||||||
|
<form method="POST" onsubmit="return confirm('Block this user? They will not be able to see you or message you.')">
|
||||||
|
<input type="hidden" name="other_user_id" value="<?= $active_chat_id ?>">
|
||||||
|
<input type="hidden" name="action" value="block">
|
||||||
|
<button type="submit" class="action-link danger">Block User</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-messages" id="chat-box">
|
<div class="chat-messages" id="chat-box">
|
||||||
@ -309,9 +368,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['content']) && $active
|
|||||||
<div style="text-align: center; color: var(--text-secondary); margin-top: 50px;">
|
<div style="text-align: center; color: var(--text-secondary); margin-top: 50px;">
|
||||||
<i class="fas fa-hand-sparkles" style="font-size: 40px; margin-bottom: 20px; opacity: 0.3;"></i>
|
<i class="fas fa-hand-sparkles" style="font-size: 40px; margin-bottom: 20px; opacity: 0.3;"></i>
|
||||||
<p>This is the start of your conversation with <?= htmlspecialchars(explode(' ', $active_chat_user['full_name'])[0]) ?>.</p>
|
<p>This is the start of your conversation with <?= htmlspecialchars(explode(' ', $active_chat_user['full_name'])[0]) ?>.</p>
|
||||||
<?php if ($startup_id): ?>
|
|
||||||
<p style="font-size: 12px;">Regarding their private startup. Your first message will be a request.</p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?php foreach ($chat_messages as $msg): ?>
|
<?php foreach ($chat_messages as $msg): ?>
|
||||||
|
|||||||
298
partners.php
298
partners.php
@ -17,39 +17,38 @@ if (!$user || $user['role'] !== 'founder') {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Onboarding check
|
|
||||||
if (!$user['onboarding_completed']) {
|
if (!$user['onboarding_completed']) {
|
||||||
header("Location: founder_onboarding.php");
|
header("Location: founder_onboarding.php");
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skill-based Matching Helper
|
// Blocked users filter
|
||||||
|
$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) {
|
function calculateMatchScore($me, $them) {
|
||||||
$score = 0;
|
$score = 0;
|
||||||
|
|
||||||
// 1. My preferred skills vs Their skills
|
|
||||||
$myNeeds = array_filter(array_map('trim', explode(',', strtolower($me['preferred_co_founder_skills'] ?? ''))));
|
$myNeeds = array_filter(array_map('trim', explode(',', strtolower($me['preferred_co_founder_skills'] ?? ''))));
|
||||||
$theirSkills = array_filter(array_map('trim', explode(',', strtolower($them['skills'] ?? ''))));
|
$theirSkills = array_filter(array_map('trim', explode(',', strtolower($them['skills'] ?? ''))));
|
||||||
$skillMatches = array_intersect($myNeeds, $theirSkills);
|
$skillMatches = array_intersect($myNeeds, $theirSkills);
|
||||||
$score += count($skillMatches) * 10;
|
$score += count($skillMatches) * 10;
|
||||||
|
|
||||||
// 2. Their preferred skills vs My skills
|
|
||||||
$theirNeeds = array_filter(array_map('trim', explode(',', strtolower($them['preferred_co_founder_skills'] ?? ''))));
|
$theirNeeds = array_filter(array_map('trim', explode(',', strtolower($them['preferred_co_founder_skills'] ?? ''))));
|
||||||
$mySkills = array_filter(array_map('trim', explode(',', strtolower($me['skills'] ?? ''))));
|
$mySkills = array_filter(array_map('trim', explode(',', strtolower($me['skills'] ?? ''))));
|
||||||
$reciprocalMatches = array_intersect($theirNeeds, $mySkills);
|
$reciprocalMatches = array_intersect($theirNeeds, $mySkills);
|
||||||
$score += count($reciprocalMatches) * 10;
|
$score += count($reciprocalMatches) * 10;
|
||||||
|
|
||||||
// 3. Industry overlap
|
|
||||||
$myIndustries = array_filter(array_map('trim', explode(',', strtolower($me['startup_industries'] ?? ''))));
|
$myIndustries = array_filter(array_map('trim', explode(',', strtolower($me['startup_industries'] ?? ''))));
|
||||||
$theirIndustries = array_filter(array_map('trim', explode(',', strtolower($them['startup_industries'] ?? ''))));
|
$theirIndustries = array_filter(array_map('trim', explode(',', strtolower($them['startup_industries'] ?? ''))));
|
||||||
$industryMatches = array_intersect($myIndustries, $theirIndustries);
|
$industryMatches = array_intersect($myIndustries, $theirIndustries);
|
||||||
$score += count($industryMatches) * 5;
|
$score += count($industryMatches) * 5;
|
||||||
|
if (!empty($me['university']) && $me['university'] === $them['university']) { $score += 5; }
|
||||||
// 4. University match (bonus)
|
|
||||||
if (!empty($me['university']) && $me['university'] === $them['university']) {
|
|
||||||
$score += 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'total' => $score,
|
'total' => $score,
|
||||||
'skillMatches' => array_values($skillMatches),
|
'skillMatches' => array_values($skillMatches),
|
||||||
@ -57,27 +56,23 @@ function calculateMatchScore($me, $them) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle Swipe Logic
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'swipe') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'swipe') {
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
$swiped_id = (int)$_POST['swiped_id'];
|
$swiped_id = (int)$_POST['swiped_id'];
|
||||||
$direction = $_POST['direction']; // 'like' or 'dislike'
|
$direction = $_POST['direction'];
|
||||||
|
|
||||||
if ($swiped_id > 0 && in_array($direction, ['like', 'dislike'])) {
|
if ($swiped_id > 0 && in_array($direction, ['like', 'dislike'])) {
|
||||||
$stmt = db()->prepare("INSERT IGNORE INTO swipes (swiper_id, swiped_id, direction) VALUES (?, ?, ?)");
|
$stmt = db()->prepare("INSERT IGNORE INTO swipes (swiper_id, swiped_id, direction) VALUES (?, ?, ?)");
|
||||||
$stmt->execute([$current_user_id, $swiped_id, $direction]);
|
$stmt->execute([$current_user_id, $swiped_id, $direction]);
|
||||||
|
|
||||||
$isMatch = false;
|
$isMatch = false;
|
||||||
if ($direction === 'like') {
|
if ($direction === 'like') {
|
||||||
$stmt = db()->prepare("SELECT id FROM swipes WHERE swiper_id = ? AND swiped_id = ? AND 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]);
|
$stmt->execute([$swiped_id, $current_user_id]);
|
||||||
if ($stmt->fetch()) {
|
if ($stmt->fetch()) {
|
||||||
$isMatch = true;
|
$isMatch = true;
|
||||||
$stmt = db()->prepare("INSERT IGNORE INTO matches (user1_id, user2_id) VALUES (?, ?)");
|
$stmt = db()->prepare("INSERT INTO matches (user1_id, user2_id, status) VALUES (?, ?, 'active') ON DUPLICATE KEY UPDATE status = 'active'");
|
||||||
$u1 = min($current_user_id, $swiped_id);
|
$u1 = min($current_user_id, $swiped_id);
|
||||||
$u2 = max($current_user_id, $swiped_id);
|
$u2 = max($current_user_id, $swiped_id);
|
||||||
$stmt->execute([$u1, $u2]);
|
$stmt->execute([$u1, $u2]);
|
||||||
|
|
||||||
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$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([$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."]);
|
$stmt->execute([$current_user_id, "You have a new match! Start a conversation now."]);
|
||||||
@ -90,26 +85,32 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch matches
|
// Fetch active matches not blocked
|
||||||
$stmt = db()->prepare("
|
$sql = "
|
||||||
SELECT u.*, m.created_at as matched_at FROM matches m
|
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)
|
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 != ?
|
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
|
ORDER BY m.created_at DESC
|
||||||
");
|
";
|
||||||
$stmt->execute([$current_user_id, $current_user_id, $current_user_id]);
|
$stmt = db()->prepare($sql);
|
||||||
|
$stmt->execute(array_merge([$current_user_id, $current_user_id, $current_user_id], $all_blocked ?: []));
|
||||||
$matches = $stmt->fetchAll();
|
$matches = $stmt->fetchAll();
|
||||||
|
|
||||||
// Fetch swipe candidates with scoring
|
// Fetch swipe candidates
|
||||||
$stmt = db()->prepare("
|
$sql = "
|
||||||
SELECT * FROM users
|
SELECT * FROM users
|
||||||
WHERE role = 'founder'
|
WHERE role = 'founder'
|
||||||
AND id != ?
|
AND id != ?
|
||||||
AND onboarding_completed = 1
|
AND onboarding_completed = 1
|
||||||
AND id NOT IN (SELECT swiped_id FROM swipes WHERE swiper_id = ?)
|
AND id NOT IN (SELECT swiped_id FROM swipes WHERE swiper_id = ?)
|
||||||
|
AND id NOT IN ($placeholders)
|
||||||
LIMIT 50
|
LIMIT 50
|
||||||
");
|
";
|
||||||
$stmt->execute([$current_user_id, $current_user_id]);
|
$stmt = db()->prepare($sql);
|
||||||
|
$stmt->execute(array_merge([$current_user_id, $current_user_id], $all_blocked ?: []));
|
||||||
$allCandidates = $stmt->fetchAll();
|
$allCandidates = $stmt->fetchAll();
|
||||||
|
|
||||||
foreach ($allCandidates as &$c) {
|
foreach ($allCandidates as &$c) {
|
||||||
@ -121,8 +122,8 @@ $swipeCandidates = array_slice($allCandidates, 0, 10);
|
|||||||
|
|
||||||
// Fetch partners for Browse view
|
// Fetch partners for Browse view
|
||||||
$search = $_GET['q'] ?? '';
|
$search = $_GET['q'] ?? '';
|
||||||
$where = "role = 'founder' AND id != ? AND onboarding_completed = 1 AND id NOT IN (SELECT swiped_id FROM swipes WHERE swiper_id = ?)";
|
$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 = [$current_user_id, $current_user_id];
|
$params = array_merge([$current_user_id, $current_user_id], $all_blocked ?: []);
|
||||||
if ($search) {
|
if ($search) {
|
||||||
$where .= " AND (full_name LIKE ? OR skills LIKE ? OR university LIKE ? OR startup_industries LIKE ?)";
|
$where .= " AND (full_name LIKE ? OR skills LIKE ? OR university LIKE ? OR startup_industries LIKE ?)";
|
||||||
$params[] = "%$search%";
|
$params[] = "%$search%";
|
||||||
@ -154,138 +155,25 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
<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">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
.page-header {
|
.page-header { padding: 60px 0 40px; text-align: center; }
|
||||||
padding: 60px 0 40px;
|
.page-header h1 { font-size: 48px; font-weight: 800; margin-bottom: 12px; background: var(--gradient-primary); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
||||||
text-align: center;
|
.page-header p { color: var(--text-secondary); font-size: 18px; }
|
||||||
}
|
.matches-section { margin-bottom: 50px; }
|
||||||
.page-header h1 {
|
.matches-scroller { display: flex; gap: 20px; overflow-x: auto; padding: 15px 5px; scrollbar-width: none; }
|
||||||
font-size: 48px;
|
|
||||||
font-weight: 800;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
background: var(--gradient-primary);
|
|
||||||
-webkit-background-clip: text;
|
|
||||||
-webkit-text-fill-color: transparent;
|
|
||||||
}
|
|
||||||
.page-header p {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Matches Scroller */
|
|
||||||
.matches-section {
|
|
||||||
margin-bottom: 50px;
|
|
||||||
}
|
|
||||||
.matches-scroller {
|
|
||||||
display: flex;
|
|
||||||
gap: 20px;
|
|
||||||
overflow-x: auto;
|
|
||||||
padding: 15px 5px;
|
|
||||||
scrollbar-width: none;
|
|
||||||
}
|
|
||||||
.matches-scroller::-webkit-scrollbar { display: none; }
|
.matches-scroller::-webkit-scrollbar { display: none; }
|
||||||
.match-card {
|
.match-card { flex: 0 0 80px; text-align: center; cursor: pointer; transition: transform 0.2s; }
|
||||||
flex: 0 0 80px;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: transform 0.2s;
|
|
||||||
}
|
|
||||||
.match-card:hover { transform: scale(1.05); }
|
.match-card:hover { transform: scale(1.05); }
|
||||||
.match-avatar {
|
.match-avatar { width: 80px; height: 80px; border-radius: 24px; background: var(--surface-color); border: 2px solid var(--accent-blue); display: flex; align-items: center; justify-content: center; font-size: 28px; font-weight: 700; color: #fff; margin-bottom: 8px; box-shadow: 0 10px 20px rgba(0, 242, 255, 0.2); position: relative; }
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
border-radius: 24px;
|
|
||||||
background: var(--surface-color);
|
|
||||||
border: 2px solid var(--accent-blue);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 28px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: #fff;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
box-shadow: 0 10px 20px rgba(0, 242, 255, 0.2);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.match-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 22px; }
|
.match-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 22px; }
|
||||||
.match-name { font-size: 12px; font-weight: 600; color: var(--text-primary); }
|
.match-name { font-size: 12px; font-weight: 600; color: var(--text-primary); }
|
||||||
|
.tabs { display: flex; justify-content: center; gap: 15px; margin-bottom: 40px; }
|
||||||
/* Tabs */
|
.tab-btn { padding: 12px 24px; border-radius: 50px; background: var(--surface-color); border: 1px solid var(--border-color); color: var(--text-secondary); font-weight: 600; cursor: pointer; transition: all 0.3s; }
|
||||||
.tabs {
|
.tab-btn.active { background: var(--gradient-primary); color: #fff; border-color: transparent; box-shadow: 0 10px 20px rgba(0, 122, 255, 0.3); }
|
||||||
display: flex;
|
.swipe-container { display: flex; flex-direction: column; align-items: center; padding: 20px 0; }
|
||||||
justify-content: center;
|
.card-stack { position: relative; width: 100%; max-width: 400px; height: 550px; }
|
||||||
gap: 15px;
|
.swipe-card { position: absolute; width: 100%; height: 100%; background: var(--surface-color); border: 1px solid var(--border-color); border-radius: 32px; overflow: hidden; box-shadow: 0 20px 40px rgba(0,0,0,0.4); transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.5s ease; cursor: grab; display: flex; flex-direction: column; }
|
||||||
margin-bottom: 40px;
|
.card-header-img { height: 280px; background: var(--gradient-primary); display: flex; align-items: center; justify-content: center; font-size: 100px; color: rgba(255,255,255,0.2); position: relative; }
|
||||||
}
|
.match-badge { position: absolute; top: 20px; right: 20px; background: rgba(0,0,0,0.6); backdrop-filter: blur(10px); padding: 8px 16px; border-radius: 50px; color: var(--accent-blue); font-weight: 700; font-size: 14px; border: 1px solid var(--accent-blue); display: flex; align-items: center; gap: 8px; }
|
||||||
.tab-btn {
|
|
||||||
padding: 12px 24px;
|
|
||||||
border-radius: 50px;
|
|
||||||
background: var(--surface-color);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
color: var(--text-secondary);
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
.tab-btn.active {
|
|
||||||
background: var(--gradient-primary);
|
|
||||||
color: #fff;
|
|
||||||
border-color: transparent;
|
|
||||||
box-shadow: 0 10px 20px rgba(0, 122, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Swipe UI */
|
|
||||||
.swipe-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
padding: 20px 0;
|
|
||||||
}
|
|
||||||
.card-stack {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
height: 550px;
|
|
||||||
}
|
|
||||||
.swipe-card {
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background: var(--surface-color);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 32px;
|
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: 0 20px 40px rgba(0,0,0,0.4);
|
|
||||||
transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275), opacity 0.5s ease;
|
|
||||||
cursor: grab;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.card-header-img {
|
|
||||||
height: 280px;
|
|
||||||
background: var(--gradient-primary);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 100px;
|
|
||||||
color: rgba(255,255,255,0.2);
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.match-badge {
|
|
||||||
position: absolute;
|
|
||||||
top: 20px;
|
|
||||||
right: 20px;
|
|
||||||
background: rgba(0,0,0,0.6);
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 50px;
|
|
||||||
color: var(--accent-blue);
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 14px;
|
|
||||||
border: 1px solid var(--accent-blue);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
.card-details { padding: 25px; flex-grow: 1; display: flex; flex-direction: column; }
|
.card-details { padding: 25px; flex-grow: 1; display: flex; flex-direction: column; }
|
||||||
.card-title { font-size: 26px; font-weight: 800; margin-bottom: 5px; }
|
.card-title { font-size: 26px; font-weight: 800; margin-bottom: 5px; }
|
||||||
.card-subtitle { font-size: 14px; color: var(--accent-blue); font-weight: 600; margin-bottom: 15px; }
|
.card-subtitle { font-size: 14px; color: var(--accent-blue); font-weight: 600; margin-bottom: 15px; }
|
||||||
@ -293,52 +181,18 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
.card-tags { display: flex; flex-wrap: wrap; gap: 8px; }
|
.card-tags { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||||
.card-tag { font-size: 11px; padding: 5px 12px; background: rgba(255,255,255,0.05); border-radius: 20px; border: 1px solid var(--border-color); }
|
.card-tag { font-size: 11px; padding: 5px 12px; background: rgba(255,255,255,0.05); border-radius: 20px; border: 1px solid var(--border-color); }
|
||||||
.card-tag.highlight { border-color: var(--accent-blue); color: var(--accent-blue); background: rgba(0, 242, 255, 0.05); }
|
.card-tag.highlight { border-color: var(--accent-blue); color: var(--accent-blue); background: rgba(0, 242, 255, 0.05); }
|
||||||
|
|
||||||
.swipe-actions { display: flex; gap: 20px; margin-top: 30px; }
|
.swipe-actions { display: flex; gap: 20px; margin-top: 30px; }
|
||||||
.action-btn {
|
.action-btn { width: 70px; height: 70px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 28px; cursor: pointer; border: none; transition: transform 0.2s; box-shadow: 0 10px 20px rgba(0,0,0,0.2); }
|
||||||
width: 70px; height: 70px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
|
|
||||||
font-size: 28px; cursor: pointer; border: none; transition: transform 0.2s; box-shadow: 0 10px 20px rgba(0,0,0,0.2);
|
|
||||||
}
|
|
||||||
.action-btn:hover { transform: scale(1.1); }
|
.action-btn:hover { transform: scale(1.1); }
|
||||||
.btn-dislike { background: #1a1a24; color: #ff3b30; border: 1px solid rgba(255, 39, 48, 0.2); }
|
.btn-dislike { background: #1a1a24; color: #ff3b30; border: 1px solid rgba(255, 39, 48, 0.2); }
|
||||||
.btn-like { background: var(--gradient-primary); color: #fff; }
|
.btn-like { background: var(--gradient-primary); color: #fff; }
|
||||||
|
.browse-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 25px; }
|
||||||
/* Browse UI */
|
.candidate-card { background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 24px; padding: 25px; transition: transform 0.3s; cursor: pointer; position: relative; }
|
||||||
.browse-container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
||||||
gap: 25px;
|
|
||||||
}
|
|
||||||
.candidate-card {
|
|
||||||
background: var(--card-bg);
|
|
||||||
border: 1px solid var(--border-color);
|
|
||||||
border-radius: 24px;
|
|
||||||
padding: 25px;
|
|
||||||
transition: transform 0.3s;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.candidate-card:hover { transform: translateY(-5px); border-color: var(--accent-blue); }
|
.candidate-card:hover { transform: translateY(-5px); border-color: var(--accent-blue); }
|
||||||
.candidate-header { display: flex; gap: 15px; align-items: center; margin-bottom: 20px; }
|
.candidate-header { display: flex; gap: 15px; align-items: center; margin-bottom: 20px; }
|
||||||
.candidate-avatar { width: 60px; height: 60px; border-radius: 18px; background: var(--gradient-primary); display: flex; align-items: center; justify-content: center; font-weight: 700; color: #fff; font-size: 20px; }
|
.candidate-avatar { width: 60px; height: 60px; border-radius: 18px; background: var(--gradient-primary); display: flex; align-items: center; justify-content: center; font-weight: 700; color: #fff; font-size: 20px; }
|
||||||
|
.score-indicator { position: absolute; top: 25px; right: 25px; font-size: 11px; font-weight: 700; color: var(--accent-blue); text-transform: uppercase; }
|
||||||
.score-indicator {
|
#match-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(10, 10, 15, 0.95); z-index: 2000; display: none; align-items: center; justify-content: center; text-align: center; backdrop-filter: blur(20px); }
|
||||||
position: absolute;
|
|
||||||
top: 25px;
|
|
||||||
right: 25px;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 700;
|
|
||||||
color: var(--accent-blue);
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Match Modal */
|
|
||||||
#match-modal {
|
|
||||||
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
|
||||||
background: rgba(10, 10, 15, 0.95); z-index: 2000; display: none;
|
|
||||||
align-items: center; justify-content: center; text-align: center;
|
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
}
|
|
||||||
.match-popup { max-width: 400px; padding: 40px; }
|
.match-popup { max-width: 400px; padding: 40px; }
|
||||||
.match-title { font-size: 56px; font-weight: 900; background: var(--gradient-primary); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 20px; }
|
.match-title { font-size: 56px; font-weight: 900; background: var(--gradient-primary); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 20px; }
|
||||||
</style>
|
</style>
|
||||||
@ -514,72 +368,38 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
document.getElementById('tab-swipe').classList.toggle('active', tab === 'swipe');
|
document.getElementById('tab-swipe').classList.toggle('active', tab === 'swipe');
|
||||||
document.getElementById('tab-browse').classList.toggle('active', tab === 'browse');
|
document.getElementById('tab-browse').classList.toggle('active', tab === 'browse');
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSwipe(direction) {
|
function handleSwipe(direction) {
|
||||||
const stack = document.getElementById('card-stack');
|
const stack = document.getElementById('card-stack');
|
||||||
const cards = stack.querySelectorAll('.swipe-card');
|
const cards = stack.querySelectorAll('.swipe-card');
|
||||||
if (cards.length === 0) return;
|
if (cards.length === 0) return;
|
||||||
|
|
||||||
const topCard = cards[cards.length - 1];
|
const topCard = cards[cards.length - 1];
|
||||||
const swipedId = topCard.getAttribute('data-id');
|
const swipedId = topCard.getAttribute('data-id');
|
||||||
|
|
||||||
// Animation
|
|
||||||
const rotate = direction === 'like' ? 30 : -30;
|
const rotate = direction === 'like' ? 30 : -30;
|
||||||
const x = direction === 'like' ? 1000 : -1000;
|
const x = direction === 'like' ? 1000 : -1000;
|
||||||
topCard.style.transform = `translateX(${x}px) rotate(${rotate}deg)`;
|
topCard.style.transform = `translateX(${x}px) rotate(${rotate}deg)`;
|
||||||
topCard.style.opacity = '0';
|
topCard.style.opacity = '0';
|
||||||
|
|
||||||
// POST request
|
|
||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append('action', 'swipe');
|
fd.append('action', 'swipe');
|
||||||
fd.append('swiped_id', swipedId);
|
fd.append('swiped_id', swipedId);
|
||||||
fd.append('direction', direction);
|
fd.append('direction', direction);
|
||||||
|
|
||||||
fetch('partners.php', { method: 'POST', body: fd })
|
fetch('partners.php', { method: 'POST', body: fd })
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.match) {
|
if (data.match) { document.getElementById('match-modal').style.display = 'flex'; }
|
||||||
document.getElementById('match-modal').style.display = 'flex';
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
topCard.remove();
|
topCard.remove();
|
||||||
if (stack.querySelectorAll('.swipe-card').length === 0) {
|
if (stack.querySelectorAll('.swipe-card').length === 0) { location.reload(); }
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
}, 500);
|
}, 500);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function closeMatch() { document.getElementById('match-modal').style.display = 'none'; }
|
||||||
function closeMatch() {
|
|
||||||
document.getElementById('match-modal').style.display = 'none';
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
header {
|
header { background: rgba(10, 10, 15, 0.8); backdrop-filter: blur(20px); border-bottom: 1px solid var(--border-color); padding: 15px 0; position: sticky; top: 0; z-index: 1000; }
|
||||||
background: rgba(10, 10, 15, 0.8);
|
.nav-links a { color: var(--text-secondary); text-decoration: none; margin: 0 15px; font-size: 14px; font-weight: 500; transition: color 0.2s; }
|
||||||
backdrop-filter: blur(20px);
|
.nav-links a:hover, .nav-links a.active { color: #fff; }
|
||||||
border-bottom: 1px solid var(--border-color);
|
.form-control:focus { outline: none; border-color: var(--accent-blue); }
|
||||||
padding: 15px 0;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.nav-links a {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
text-decoration: none;
|
|
||||||
margin: 0 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: color 0.2s;
|
|
||||||
}
|
|
||||||
.nav-links a:hover, .nav-links a.active {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.form-control:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: var(--accent-blue);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -23,6 +23,14 @@ if (!$startup) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if blocked or blocker
|
||||||
|
$stmt = db()->prepare("SELECT 1 FROM blocked_users WHERE (blocker_id = ? AND blocked_id = ?) OR (blocker_id = ? AND blocked_id = ?)");
|
||||||
|
$stmt->execute([$user_id, $startup['founder_id'], $startup['founder_id'], $user_id]);
|
||||||
|
if ($stmt->fetchColumn()) {
|
||||||
|
header('Location: discover.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if current user is following
|
// Check if current user is following
|
||||||
$stmt = db()->prepare("SELECT 1 FROM startup_followers WHERE startup_id = ? AND user_id = ?");
|
$stmt = db()->prepare("SELECT 1 FROM startup_followers WHERE startup_id = ? AND user_id = ?");
|
||||||
$stmt->execute([$startup_id, $user_id]);
|
$stmt->execute([$startup_id, $user_id]);
|
||||||
@ -40,7 +48,7 @@ $success = '';
|
|||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||||
$action = $_POST['action'];
|
$action = $_POST['action'];
|
||||||
|
|
||||||
// Follow/Unfollow Actions (Available to all logged in users except the founder of this startup)
|
// Follow/Unfollow Actions
|
||||||
if ($action === 'follow' && $startup['founder_id'] != $user_id) {
|
if ($action === 'follow' && $startup['founder_id'] != $user_id) {
|
||||||
$stmt = db()->prepare("INSERT IGNORE INTO startup_followers (startup_id, user_id) VALUES (?, ?)");
|
$stmt = db()->prepare("INSERT IGNORE INTO startup_followers (startup_id, user_id) VALUES (?, ?)");
|
||||||
$stmt->execute([$startup_id, $user_id]);
|
$stmt->execute([$startup_id, $user_id]);
|
||||||
@ -56,37 +64,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
// Founder Actions
|
// Founder Actions
|
||||||
if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id) {
|
if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id) {
|
||||||
$round_id = isset($_POST['round_id']) ? (int)$_POST['round_id'] : 0;
|
$round_id = isset($_POST['round_id']) ? (int)$_POST['round_id'] : 0;
|
||||||
|
|
||||||
if ($action === 'finish_round' && $activeRound && $activeRound['id'] == $round_id) {
|
if ($action === 'finish_round' && $activeRound && $activeRound['id'] == $round_id) {
|
||||||
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Closed' WHERE id = ?");
|
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Closed' WHERE id = ?");
|
||||||
$stmt->execute([$round_id]);
|
$stmt->execute([$round_id]);
|
||||||
$success = "Funding round finished early. No new investments allowed.";
|
$success = "Funding round finished early. No new investments allowed.";
|
||||||
$activeRound = null; // Refresh for UI
|
$activeRound = null;
|
||||||
} elseif ($action === 'cancel_round' && $activeRound && $activeRound['id'] == $round_id) {
|
} elseif ($action === 'cancel_round' && $activeRound && $activeRound['id'] == $round_id) {
|
||||||
db()->beginTransaction();
|
db()->beginTransaction();
|
||||||
try {
|
try {
|
||||||
// 1. Cancel round
|
|
||||||
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Cancelled' WHERE id = ?");
|
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Cancelled' WHERE id = ?");
|
||||||
$stmt->execute([$round_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 = db()->prepare("SELECT * FROM investments WHERE funding_round_id = ? AND status = 'approved'");
|
||||||
$stmt->execute([$round_id]);
|
$stmt->execute([$round_id]);
|
||||||
$investmentsToRefund = $stmt->fetchAll();
|
$investmentsToRefund = $stmt->fetchAll();
|
||||||
|
|
||||||
foreach ($investmentsToRefund as $inv) {
|
foreach ($investmentsToRefund as $inv) {
|
||||||
// Mark investment as refunded
|
|
||||||
$upd = db()->prepare("UPDATE investments SET status = 'Refunded' WHERE id = ?");
|
$upd = db()->prepare("UPDATE investments SET status = 'Refunded' WHERE id = ?");
|
||||||
$upd->execute([$inv['id']]);
|
$upd->execute([$inv['id']]);
|
||||||
|
|
||||||
// Notify investor
|
|
||||||
$notif = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$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."]);
|
$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();
|
db()->commit();
|
||||||
$success = "Funding round cancelled and investors refunded.";
|
$success = "Funding round cancelled and investors refunded.";
|
||||||
$activeRound = null; // Refresh for UI
|
$activeRound = null;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
db()->rollBack();
|
db()->rollBack();
|
||||||
$error = "Cancellation failed: " . $e->getMessage();
|
$error = "Cancellation failed: " . $e->getMessage();
|
||||||
@ -101,7 +100,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
$stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')");
|
$stmt = db()->prepare("INSERT INTO funding_rounds (startup_id, funding_goal, status) VALUES (?, ?, 'Active')");
|
||||||
$stmt->execute([$startup_id, $newTarget]);
|
$stmt->execute([$startup_id, $newTarget]);
|
||||||
$success = "New funding round launched!";
|
$success = "New funding round launched!";
|
||||||
// Refresh active round
|
|
||||||
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE startup_id = ? AND status = 'Active' LIMIT 1");
|
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE startup_id = ? AND status = 'Active' LIMIT 1");
|
||||||
$stmt->execute([$startup_id]);
|
$stmt->execute([$startup_id]);
|
||||||
$activeRound = $stmt->fetch();
|
$activeRound = $stmt->fetch();
|
||||||
@ -109,17 +107,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
} elseif ($action === 'post_update') {
|
} elseif ($action === 'post_update') {
|
||||||
$title = trim($_POST['update_title'] ?? '');
|
$title = trim($_POST['update_title'] ?? '');
|
||||||
$content = trim($_POST['update_content'] ?? '');
|
$content = trim($_POST['update_content'] ?? '');
|
||||||
|
|
||||||
if (empty($title) || empty($content)) {
|
if (empty($title) || empty($content)) {
|
||||||
$error = "Update title and content are required.";
|
$error = "Update title and content are required.";
|
||||||
} else {
|
} else {
|
||||||
db()->beginTransaction();
|
db()->beginTransaction();
|
||||||
try {
|
try {
|
||||||
// 1. Insert Update
|
|
||||||
$stmt = db()->prepare("INSERT INTO startup_updates (startup_id, founder_id, title, content) VALUES (?, ?, ?, ?)");
|
$stmt = db()->prepare("INSERT INTO startup_updates (startup_id, founder_id, title, content) VALUES (?, ?, ?, ?)");
|
||||||
$stmt->execute([$startup_id, $user_id, $title, $content]);
|
$stmt->execute([$startup_id, $user_id, $title, $content]);
|
||||||
|
|
||||||
// 2. Identify All Unique Investors AND Followers for this startup
|
|
||||||
$stmt = db()->prepare("
|
$stmt = db()->prepare("
|
||||||
SELECT DISTINCT u.id, u.email, u.full_name
|
SELECT DISTINCT u.id, u.email, u.full_name
|
||||||
FROM users u
|
FROM users u
|
||||||
@ -129,20 +123,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
");
|
");
|
||||||
$stmt->execute([$startup_id, $startup_id]);
|
$stmt->execute([$startup_id, $startup_id]);
|
||||||
$peopleToNotify = $stmt->fetchAll();
|
$peopleToNotify = $stmt->fetchAll();
|
||||||
|
|
||||||
// 3. Notify them
|
|
||||||
foreach ($peopleToNotify as $targetUser) {
|
foreach ($peopleToNotify as $targetUser) {
|
||||||
// DB Notification
|
|
||||||
$notif = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$notif = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||||
$notif->execute([$targetUser['id'], "New progress update from " . $startup['name'] . ": " . $title]);
|
$notif->execute([$targetUser['id'], "New progress update from " . $startup['name'] . ": " . $title]);
|
||||||
|
|
||||||
// Email Notification
|
|
||||||
$subject = "New Update: " . $startup['name'];
|
$subject = "New Update: " . $startup['name'];
|
||||||
$emailHtml = "<h1>New Update: " . htmlspecialchars($title) . "</h1><p>Hi " . htmlspecialchars($targetUser['full_name']) . ", <strong>" . htmlspecialchars($startup['name']) . "</strong> has posted a new progress update:</p><hr><p>" . nl2br(htmlspecialchars($content)) . "</p>";
|
$emailHtml = "<h1>New Update: " . htmlspecialchars($title) . "</h1><p>Hi " . htmlspecialchars($targetUser['full_name']) . ", <strong>" . htmlspecialchars($startup['name']) . "</strong> has posted a new progress update:</p><hr><p>" . nl2br(htmlspecialchars($content)) . "</p>";
|
||||||
$emailText = "New Update: " . $title . "\n\nHi " . $targetUser['full_name'] . ", " . $startup['name'] . " has posted a new progress update: " . $content;
|
$emailText = "New Update: " . $title . "\n\nHi " . $targetUser['full_name'] . ", " . $startup['name'] . " has posted a new progress update: " . $content;
|
||||||
MailService::sendMail($targetUser['email'], $subject, $emailHtml, $emailText);
|
MailService::sendMail($targetUser['email'], $subject, $emailHtml, $emailText);
|
||||||
}
|
}
|
||||||
|
|
||||||
db()->commit();
|
db()->commit();
|
||||||
$success = "Update posted and " . count($peopleToNotify) . " backers/followers notified.";
|
$success = "Update posted and " . count($peopleToNotify) . " backers/followers notified.";
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
@ -166,53 +154,33 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
} else {
|
} else {
|
||||||
db()->beginTransaction();
|
db()->beginTransaction();
|
||||||
try {
|
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 = 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]);
|
$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 = db()->prepare("UPDATE funding_rounds SET funding_raised = funding_raised + ? WHERE id = ?");
|
||||||
$stmt->execute([$amount, $activeRound['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 = db()->prepare("UPDATE startups SET funding_raised = funding_raised + ? WHERE id = ?");
|
||||||
$stmt->execute([$amount, $startup_id]);
|
$stmt->execute([$amount, $startup_id]);
|
||||||
|
|
||||||
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||||
$stmt->execute([$startup['founder_id'], "New investment of £" . number_format($amount) . " in " . $startup['name'] . "!"]);
|
$stmt->execute([$startup['founder_id'], "New investment of £" . number_format($amount) . " in " . $startup['name'] . "!"]);
|
||||||
|
|
||||||
// Check if goal reached for automated notification system
|
|
||||||
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE id = ?");
|
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE id = ?");
|
||||||
$stmt->execute([$activeRound['id']]);
|
$stmt->execute([$activeRound['id']]);
|
||||||
$updatedRound = $stmt->fetch();
|
$updatedRound = $stmt->fetch();
|
||||||
|
|
||||||
if ($updatedRound['funding_raised'] >= $updatedRound['funding_goal']) {
|
if ($updatedRound['funding_raised'] >= $updatedRound['funding_goal']) {
|
||||||
// Update status to 'Closed'
|
|
||||||
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Closed' WHERE id = ?");
|
$stmt = db()->prepare("UPDATE funding_rounds SET status = 'Closed' WHERE id = ?");
|
||||||
$stmt->execute([$updatedRound['id']]);
|
$stmt->execute([$updatedRound['id']]);
|
||||||
|
|
||||||
// Notify Founder (DB)
|
|
||||||
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||||
$stmt->execute([$startup['founder_id'], "Congratulations! The funding round for " . $startup['name'] . " has reached its goal of £" . number_format($updatedRound['funding_goal']) . "!"]);
|
$stmt->execute([$startup['founder_id'], "Congratulations! The funding round for " . $startup['name'] . " has reached its goal of £" . number_format($updatedRound['funding_goal']) . "!"]);
|
||||||
|
|
||||||
// Notify All Investors for this round (DB + Email)
|
|
||||||
$stmt = db()->prepare("SELECT DISTINCT u.id, u.email, u.full_name FROM investments i JOIN users u ON i.investor_id = u.id WHERE i.funding_round_id = ? AND i.status = 'approved'");
|
$stmt = db()->prepare("SELECT DISTINCT u.id, u.email, u.full_name FROM investments i JOIN users u ON i.investor_id = u.id WHERE i.funding_round_id = ? AND i.status = 'approved'");
|
||||||
$stmt->execute([$updatedRound['id']]);
|
$stmt->execute([$updatedRound['id']]);
|
||||||
$investorsToNotify = $stmt->fetchAll();
|
$investorsToNotify = $stmt->fetchAll();
|
||||||
|
|
||||||
foreach ($investorsToNotify as $invUser) {
|
foreach ($investorsToNotify as $invUser) {
|
||||||
// DB Notification
|
|
||||||
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
$stmt = db()->prepare("INSERT INTO notifications (user_id, content) VALUES (?, ?)");
|
||||||
$stmt->execute([$invUser['id'], "Great news! The funding round for " . $startup['name'] . " that you invested in has reached its goal!"]);
|
$stmt->execute([$invUser['id'], "Great news! The funding round for " . $startup['name'] . " that you invested in has reached its goal!"]);
|
||||||
|
|
||||||
// Email Notification
|
|
||||||
$subject = "Funding Goal Reached for " . $startup['name'];
|
$subject = "Funding Goal Reached for " . $startup['name'];
|
||||||
$html = "<h1>Goal Reached!</h1><p>Hi " . htmlspecialchars($invUser['full_name']) . ", the funding round for <strong>" . htmlspecialchars($startup['name']) . "</strong> has successfully reached its goal. Thank you for being a part of this journey!</p>";
|
$html = "<h1>Goal Reached!</h1><p>Hi " . htmlspecialchars($invUser['full_name']) . ", the funding round for <strong>" . htmlspecialchars($startup['name']) . "</strong> has successfully reached its goal. Thank you for being a part of this journey!</p>";
|
||||||
$text = "Goal Reached! Hi " . $invUser['full_name'] . ", the funding round for " . $startup['name'] . " has successfully reached its goal. Thank you for being a part of this journey!";
|
$text = "Goal Reached! Hi " . $invUser['full_name'] . ", the funding round for " . $startup['name'] . " has successfully reached its goal. Thank you for being a part of this journey!";
|
||||||
MailService::sendMail($invUser['email'], $subject, $html, $text);
|
MailService::sendMail($invUser['email'], $subject, $html, $text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Email Founder
|
|
||||||
$stmt = db()->prepare("SELECT email, full_name FROM users WHERE id = ?");
|
$stmt = db()->prepare("SELECT email, full_name FROM users WHERE id = ?");
|
||||||
$stmt->execute([$startup['founder_id']]);
|
$stmt->execute([$startup['founder_id']]);
|
||||||
$founderUser = $stmt->fetch();
|
$founderUser = $stmt->fetch();
|
||||||
@ -223,10 +191,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|||||||
MailService::sendMail($founderUser['email'], $subject, $html, $text);
|
MailService::sendMail($founderUser['email'], $subject, $html, $text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db()->commit();
|
db()->commit();
|
||||||
$success = "Investment successful! You've backed the current round.";
|
$success = "Investment successful! You've backed the current round.";
|
||||||
// Refresh active round data
|
|
||||||
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE id = ?");
|
$stmt = db()->prepare("SELECT * FROM funding_rounds WHERE id = ?");
|
||||||
$stmt->execute([$activeRound['id']]);
|
$stmt->execute([$activeRound['id']]);
|
||||||
$activeRound = $stmt->fetch();
|
$activeRound = $stmt->fetch();
|
||||||
@ -314,7 +280,6 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
<p style="font-size: 18px; line-height: 1.6; color: var(--text-secondary); white-space: pre-wrap;"><?= htmlspecialchars($startup['description']) ?></p>
|
<p style="font-size: 18px; line-height: 1.6; color: var(--text-secondary); white-space: pre-wrap;"><?= htmlspecialchars($startup['description']) ?></p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Public Updates Section -->
|
|
||||||
<section class="card" style="margin-bottom: 40px;">
|
<section class="card" style="margin-bottom: 40px;">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||||||
<h2 style="margin: 0;">Public Updates</h2>
|
<h2 style="margin: 0;">Public Updates</h2>
|
||||||
@ -322,7 +287,6 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
<button class="btn btn-outline" onclick="document.getElementById('postUpdateForm').style.display='block'">Post Update</button>
|
<button class="btn btn-outline" onclick="document.getElementById('postUpdateForm').style.display='block'">Post Update</button>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id): ?>
|
<?php if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id): ?>
|
||||||
<div id="postUpdateForm" style="display: none; background: rgba(255,255,255,0.02); padding: 25px; border-radius: 15px; margin-bottom: 30px; border: 1px solid var(--border-color);">
|
<div id="postUpdateForm" style="display: none; background: rgba(255,255,255,0.02); padding: 25px; border-radius: 15px; margin-bottom: 30px; border: 1px solid var(--border-color);">
|
||||||
<h4 style="margin-top: 0;">New Progress Report</h4>
|
<h4 style="margin-top: 0;">New Progress Report</h4>
|
||||||
@ -341,13 +305,11 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$stmt = db()->prepare("SELECT * FROM startup_updates WHERE startup_id = ? ORDER BY created_at DESC");
|
$stmt = db()->prepare("SELECT * FROM startup_updates WHERE startup_id = ? ORDER BY created_at DESC");
|
||||||
$stmt->execute([$startup_id]);
|
$stmt->execute([$startup_id]);
|
||||||
$updates = $stmt->fetchAll();
|
$updates = $stmt->fetchAll();
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<?php if (empty($updates)): ?>
|
<?php if (empty($updates)): ?>
|
||||||
<p style="color: var(--text-secondary); font-style: italic;">No updates have been posted yet.</p>
|
<p style="color: var(--text-secondary); font-style: italic;">No updates have been posted yet.</p>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
@ -367,9 +329,7 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
<section class="card" style="border-left: 5px solid var(--accent-blue);">
|
<section class="card" style="border-left: 5px solid var(--accent-blue);">
|
||||||
<h3 style="margin-top: 0;">Active Funding Round</h3>
|
<h3 style="margin-top: 0;">Active Funding Round</h3>
|
||||||
<div style="margin: 20px 0;">
|
<div style="margin: 20px 0;">
|
||||||
<?php
|
<?php $percent = ($activeRound['funding_goal'] > 0) ? min(100, ($activeRound['funding_raised'] / $activeRound['funding_goal']) * 100) : 0; ?>
|
||||||
$percent = ($activeRound['funding_goal'] > 0) ? min(100, ($activeRound['funding_raised'] / $activeRound['funding_goal']) * 100) : 0;
|
|
||||||
?>
|
|
||||||
<div style="width: 100%; height: 10px; background: var(--border-color); border-radius: 5px; overflow: hidden;">
|
<div style="width: 100%; height: 10px; background: var(--border-color); border-radius: 5px; overflow: hidden;">
|
||||||
<div style="width: <?= $percent ?>%; height: 100%; background: var(--gradient-primary);"></div>
|
<div style="width: <?= $percent ?>%; height: 100%; background: var(--gradient-primary);"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -378,7 +338,6 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
<span style="font-size: 24px;">£<?= number_format($activeRound['funding_raised']) ?> raised</span>
|
<span style="font-size: 24px;">£<?= number_format($activeRound['funding_raised']) ?> raised</span>
|
||||||
<span style="color: var(--text-secondary);">Target: £<?= number_format($activeRound['funding_goal']) ?></span>
|
<span style="color: var(--text-secondary);">Target: £<?= number_format($activeRound['funding_goal']) ?></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id): ?>
|
<?php if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id): ?>
|
||||||
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
||||||
<form method="POST" onsubmit="return confirm('Finish this round early? No more investments will be accepted.');">
|
<form method="POST" onsubmit="return confirm('Finish this round early? No more investments will be accepted.');">
|
||||||
@ -400,7 +359,6 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
<input type="number" name="amount" min="50" step="10" value="100" class="form-control" style="flex: 1; background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
<input type="number" name="amount" min="50" step="10" value="100" class="form-control" style="flex: 1; background: var(--surface-color); color: #fff; border: 1px solid var(--border-color);">
|
||||||
<button type="submit" class="btn btn-primary">Back this Venture</button>
|
<button type="submit" class="btn btn-primary">Back this Venture</button>
|
||||||
</div>
|
</div>
|
||||||
<p style="margin-top: 10px; font-size: 14px; color: var(--text-secondary);">Minimum investment is £50. Your support helps students grow.</p>
|
|
||||||
</form>
|
</form>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</section>
|
</section>
|
||||||
@ -408,18 +366,15 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
<section class="card" style="background: rgba(255,255,255,0.02); text-align: center; padding: 40px; border: 1px dashed var(--border-color);">
|
<section class="card" style="background: rgba(255,255,255,0.02); text-align: center; padding: 40px; border: 1px dashed var(--border-color);">
|
||||||
<div style="font-size: 48px; color: var(--text-secondary); margin-bottom: 20px;"><i class="fas fa-lock"></i></div>
|
<div style="font-size: 48px; color: var(--text-secondary); margin-bottom: 20px;"><i class="fas fa-lock"></i></div>
|
||||||
<h3>No Active Funding Round</h3>
|
<h3>No Active Funding Round</h3>
|
||||||
<p style="color: var(--text-secondary);">This startup is not currently raising funds, or the previous round has closed.</p>
|
|
||||||
|
|
||||||
<?php if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id): ?>
|
<?php if ($user['role'] === 'founder' && $startup['founder_id'] == $user_id): ?>
|
||||||
<button class="btn btn-primary" style="margin-top: 20px;" onclick="document.getElementById('newRoundForm').style.display='block'">Launch New Funding Round</button>
|
<button class="btn btn-primary" style="margin-top: 20px;" onclick="document.getElementById('newRoundForm').style.display='block'">Launch New Funding Round</button>
|
||||||
|
|
||||||
<div id="newRoundForm" style="display: none; margin-top: 30px; text-align: left; background: var(--surface-color); padding: 25px; border-radius: 15px; border: 1px solid var(--border-color);">
|
<div id="newRoundForm" style="display: none; margin-top: 30px; text-align: left; background: var(--surface-color); padding: 25px; border-radius: 15px; border: 1px solid var(--border-color);">
|
||||||
<h4>Round Details</h4>
|
<h4>Round Details</h4>
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input type="hidden" name="action" value="start_new_round">
|
<input type="hidden" name="action" value="start_new_round">
|
||||||
<div class="form-group" style="margin-bottom: 20px;">
|
<div class="form-group" style="margin-bottom: 20px;">
|
||||||
<label>New Funding Target (£)</label>
|
<label>New Funding Target (£)</label>
|
||||||
<input type="number" name="new_target" min="50" step="50" class="form-control" placeholder="e.g. 5000" required style="background: var(--bg-color); color: #fff; border: 1px solid var(--border-color);">
|
<input type="number" name="new_target" min="50" step="50" class="form-control" required style="background: var(--bg-color); color: #fff; border: 1px solid var(--border-color);">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">Start Round</button>
|
<button type="submit" class="btn btn-primary">Start Round</button>
|
||||||
<button type="button" class="btn btn-secondary" onclick="document.getElementById('newRoundForm').style.display='none'">Cancel</button>
|
<button type="button" class="btn btn-secondary" onclick="document.getElementById('newRoundForm').style.display='none'">Cancel</button>
|
||||||
@ -475,14 +430,10 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div style="font-weight: 600;"><?= htmlspecialchars($founder['full_name']) ?></div>
|
<div style="font-weight: 600;"><?= htmlspecialchars($founder['full_name']) ?></div>
|
||||||
<div style="font-size: 13px; color: var(--text-secondary);">
|
<div style="font-size: 13px; color: var(--text-secondary);"><?= htmlspecialchars($founder['university']) ?></div>
|
||||||
<?= htmlspecialchars($founder['university']) ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a href="messages.php?chat_with=<?= $founder['id'] ?>&startup_id=<?= $startup_id ?>" class="btn btn-outline" style="width: 100%; text-align: center; display: block; border-radius: 12px; border: 1px solid var(--border-color);">Send Message</a>
|
<a href="messages.php?chat_with=<?= $founder['id'] ?>&startup_id=<?= $startup_id ?>" class="btn btn-outline" style="width: 100%; text-align: center; display: block; border-radius: 12px; border: 1px solid var(--border-color);">Send Message</a>
|
||||||
<?php else: ?>
|
|
||||||
<div style="color: var(--text-secondary); font-style: italic;">Founder account deleted. Venture is community-managed.</div>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -490,26 +441,9 @@ $platformName = defined('PLATFORM_NAME') ? PLATFORM_NAME : 'Gatsby';
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
header {
|
header { background: rgba(10, 10, 15, 0.8); backdrop-filter: blur(20px); border-bottom: 1px solid var(--border-color); padding: 15px 0; position: sticky; top: 0; z-index: 1000; }
|
||||||
background: rgba(10, 10, 15, 0.8);
|
.nav-links a { color: var(--text-secondary); text-decoration: none; margin: 0 15px; font-size: 14px; font-weight: 500; transition: color 0.2s; }
|
||||||
backdrop-filter: blur(20px);
|
.nav-links a:hover { color: #fff; }
|
||||||
border-bottom: 1px solid var(--border-color);
|
|
||||||
padding: 15px 0;
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
.nav-links a {
|
|
||||||
color: var(--text-secondary);
|
|
||||||
text-decoration: none;
|
|
||||||
margin: 0 15px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: color 0.2s;
|
|
||||||
}
|
|
||||||
.nav-links a:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user