diff --git a/add_user.php b/add_user.php new file mode 100644 index 0000000..418b7d0 --- /dev/null +++ b/add_user.php @@ -0,0 +1,41 @@ +prepare('INSERT INTO users (name, email, password, referral_code, role, agent_tier, phone, company, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)'); + $stmt->execute([$name, $email, $hashed_password, $referral_code, $role, $agent_tier, $phone, $company, $notes]); + + header('Location: admin_dashboard.php'); + exit; +} else { + header('Location: admin_dashboard.php'); + exit; +} +?> \ No newline at end of file diff --git a/admin/bookings.php b/admin/bookings.php new file mode 100644 index 0000000..7d48990 --- /dev/null +++ b/admin/bookings.php @@ -0,0 +1,115 @@ +prepare("UPDATE bookings SET status = 'approved' WHERE id = :id AND status = 'pending'"); + $stmt->execute([':id' => $bookingId]); + + // Calculate commissions + calculate_commissions($bookingId); + + $message = "Booking #$bookingId has been approved and commissions have been processed."; + } catch (Exception $e) { + $error = "Error approving booking: " . $e->getMessage(); + } + } elseif ($action === 'reject') { + $stmt = $db->prepare("UPDATE bookings SET status = 'rejected' WHERE id = :id AND status = 'pending'"); + $stmt->execute([':id' => $bookingId]); + $message = "Booking #$bookingId has been rejected."; + } +} + +// 3. Fetch Bookings +$db = db(); +$stmt = $db->query("SELECT b.*, u.name as user_name, u.email as user_email FROM bookings b JOIN users u ON b.user_id = u.id ORDER BY b.created_at DESC"); +$bookings = $stmt->fetchAll(PDO::FETCH_ASSOC); + +?> + + + + + + Manage Bookings + + + + +
+

Manage Bookings

+

Review, approve, or reject new bookings.

+ + +
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDUserPlot IDAmountBooking DateProofStatusSubmitted AtActions

View Proof + +
+ + +
+
+ + +
+ +
+
+ Back to Dashboard +
+ + \ No newline at end of file diff --git a/admin/withdrawals.php b/admin/withdrawals.php new file mode 100644 index 0000000..eb66870 --- /dev/null +++ b/admin/withdrawals.php @@ -0,0 +1,193 @@ +prepare("SELECT * FROM withdrawals WHERE id = ? AND status = 'pending'"); + $stmt->execute([$withdrawal_id]); + $withdrawal = $stmt->fetch(); + + if ($withdrawal) { + try { + $db->beginTransaction(); + + if ($action === 'approve') { + // Update withdrawal status + $stmt = $db->prepare("UPDATE withdrawals SET status = 'approved', processed_at = CURRENT_TIMESTAMP WHERE id = ?"); + $stmt->execute([$withdrawal_id]); + + // Update the corresponding transaction description + $stmt = $db->prepare("UPDATE transactions SET description = 'Withdrawal approved and processed' WHERE type = 'withdrawal_request' AND related_withdrawal_id = ?"); + $stmt->execute([$withdrawal_id]); + + $message = 'Withdrawal has been approved.'; + + } elseif ($action === 'reject') { + $rejection_reason = $_POST['rejection_reason'] ?? 'Rejected by admin.'; + + // 1. Update withdrawal status + $stmt = $db->prepare("UPDATE withdrawals SET status = 'rejected', rejection_reason = ?, processed_at = CURRENT_TIMESTAMP WHERE id = ?"); + $stmt->execute([$rejection_reason, $withdrawal_id]); + + // 2. Refund the amount to the user's wallet + $stmt = $db->prepare("UPDATE users SET wallet_balance = wallet_balance + ? WHERE id = ?"); + $stmt->execute([$withdrawal['amount'], $withdrawal['user_id']]); + + // 3. Record the reversal transaction + $stmt = $db->prepare("INSERT INTO transactions (user_id, amount, type, description, related_withdrawal_id) VALUES (?, ?, 'withdrawal_reversal', ?, ?)"); + $stmt->execute([$withdrawal['user_id'], $withdrawal['amount'], 'Withdrawal request rejected. Amount refunded.', $withdrawal_id]); + + // 4. Invalidate the original withdrawal request transaction + $stmt = $db->prepare("UPDATE transactions SET description = 'Withdrawal request rejected' WHERE type = 'withdrawal_request' AND related_withdrawal_id = ?"); + $stmt->execute([$withdrawal_id]); + + + $message = 'Withdrawal has been rejected and the amount refunded.'; + } + + $db->commit(); + } catch (PDOException $e) { + $db->rollBack(); + $error = 'Database error: ' . $e->getMessage(); + } + } else { + $error = 'Invalid or already processed withdrawal request.'; + } +} + +// Pagination +$limit = 20; +$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; +$offset = ($page - 1) * $limit; +$status_filter = $_GET['status'] ?? 'all'; + +// Fetch total withdrawals +$count_sql = "SELECT COUNT(*) FROM withdrawals w JOIN users u ON w.user_id = u.id"; +$params = []; +if($status_filter !== 'all') { + $count_sql .= " WHERE w.status = ?"; + $params[] = $status_filter; +} +$total_stmt = $db->prepare($count_sql); +$total_stmt->execute($params); +$total_withdrawals = $total_stmt->fetchColumn(); +$total_pages = ceil($total_withdrawals / $limit); + +// Fetch withdrawals with user info +$sql = "SELECT w.*, u.name as user_name, u.email as user_email FROM withdrawals w JOIN users u ON w.user_id = u.id"; +if($status_filter !== 'all') { + $sql .= " WHERE w.status = ?"; +} +$sql .= " ORDER BY w.created_at DESC LIMIT ? OFFSET ?"; +$stmt = $db->prepare($sql); +$params[] = $limit; +$params[] = $offset; +$stmt->execute($params); +$withdrawals = $stmt->fetchAll(); + +?> + + + + + + Manage Withdrawals + + + +
+

Manage Withdrawals

+ Back to Dashboard + + $message
"; ?> + $error"; ?> + + + +
+ + + + + + + + + + + + + + + + +
IDUserAmountDateStatusActions
' . htmlspecialchars($w['user_email']) . ''; ?> + +
+ + + +
+ + + + + + Processed on
+ Reason: ".htmlspecialchars($w['rejection_reason']).""; ?> + +
+
+ + + + + + + diff --git a/admin_dashboard.php b/admin_dashboard.php new file mode 100644 index 0000000..af1a446 --- /dev/null +++ b/admin_dashboard.php @@ -0,0 +1,154 @@ + + + + + + + Admin Dashboard + + + + + + + + +
+
+

User Management

+ +
+ +
+
+
+
+ + + + + + + + + + + + + + + query('SELECT id, name, email, phone, company, role, agent_tier FROM users ORDER BY id DESC'); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ''; + echo ""; + } + ?> + +
IDNameEmailPhoneCompanyRoleAgent TierActions
" . htmlspecialchars($row['id']) . "" . htmlspecialchars($row['name']) . "" . htmlspecialchars($row['email']) . "" . htmlspecialchars($row['phone']) . "" . htmlspecialchars($row['company']) . "" . htmlspecialchars($row['role']) . "" . htmlspecialchars($row['agent_tier']) . " + + +
+
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/ai_agent.php b/ai_agent.php new file mode 100644 index 0000000..c9c2a53 --- /dev/null +++ b/ai_agent.php @@ -0,0 +1,33 @@ + 'Please provide a message.']); + exit; +} + +$resp = LocalAIApi::createResponse([ + 'input' => [ + ['role' => 'system', 'content' => 'You are a helpful assistant for a real estate MLM company called Kutumbh Infra.'], + ['role' => 'user', 'content' => $user_message], + ], +]); + +if (!empty($resp['success'])) { + $text = LocalAIApi::extractText($resp); + if ($text === '') { + $decoded = LocalAIApi::decodeJsonFromResponse($resp); + $text = $decoded ? json_encode($decoded, JSON_UNESCAPED_UNICODE) : (string)($resp['data'] ?? ''); + } + $aiReply = $text; +} else { + error_log('AI error: ' . ($resp['error'] ?? 'unknown')); + $aiReply = 'Sorry, I am having trouble connecting to the AI service.'; +} + +header('Content-Type: application/json'); +echo json_encode(['reply' => $aiReply]); diff --git a/assets/css/auth.css b/assets/css/auth.css new file mode 100644 index 0000000..7ac7b97 --- /dev/null +++ b/assets/css/auth.css @@ -0,0 +1,132 @@ + +:root { + --primary-color: #6a11cb; + --secondary-color: #2575fc; + --input-bg: #f0f2f5; + --text-color: #333; + --light-text-color: #777; + --card-bg: #ffffff; + --box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1); +} + +.auth-wrapper { + font-family: 'Poppins', sans-serif; + background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-color); +} + +.auth-container { + display: flex; + width: 100%; + max-width: 1000px; + background-color: var(--card-bg); + border-radius: 20px; + box-shadow: var(--box-shadow); + overflow: hidden; + min-height: 600px; +} + +.auth-form-section { + flex: 1; + padding: 3rem 2.5rem; + display: flex; + flex-direction: column; + justify-content: center; +} + +.auth-branding-section { + flex: 1; + background: linear-gradient(135deg, var(--secondary-color), var(--primary-color)); + color: white; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 3rem; +} + +.auth-branding-section h1 { + font-weight: 700; + font-size: 2.5rem; + margin-bottom: 1rem; +} + +.auth-branding-section p { + font-size: 1.1rem; + max-width: 350px; +} + +.auth-form-section h2 { + font-weight: 600; + font-size: 2rem; + margin-bottom: 0.5rem; +} + +.auth-form-section .lead { + color: var(--light-text-color); + margin-bottom: 2rem; +} + +.form-label { + font-weight: 500; +} + +.form-control { + background-color: var(--input-bg); + border: none; + border-radius: 10px; + padding: 12px 15px; + transition: all 0.3s ease; +} + +.form-control:focus { + background-color: var(--card-bg); + box-shadow: none; + border: 1px solid var(--primary-color); +} + +.input-group-text { + background-color: var(--input-bg); + border: none; + border-radius: 10px 0 0 10px; +} + +.btn-primary { + background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); + border: none; + border-radius: 10px; + padding: 12px; + font-weight: 600; + letter-spacing: 0.5px; + transition: all 0.3s ease; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); +} + +.btn-primary:hover { + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15); +} + +.auth-form-section a { + color: var(--primary-color); + text-decoration: none; + font-weight: 500; +} + +.auth-form-section a:hover { + text-decoration: underline; +} + +@media (max-width: 768px) { + .auth-container { + flex-direction: column; + } + .auth-branding-section { + display: none; /* Or a simplified version */ + } +} diff --git a/assets/css/custom.css b/assets/css/custom.css deleted file mode 100644 index fa9a2e1..0000000 --- a/assets/css/custom.css +++ /dev/null @@ -1,54 +0,0 @@ -body { - background-color: #f9fafb; - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; - color: #111827; -} - -.card { - border-radius: 0.5rem; - border: 1px solid #e5e7eb; -} - -.btn-primary { - background-color: #1e3a8a; - border-color: #1e3a8a; -} - -.btn-primary:hover { - background-color: #1c327a; - border-color: #1c327a; -} - -.btn-secondary { - background-color: #f59e0b; - border-color: #f59e0b; -} - -.genealogy-tree ul { - padding-left: 20px; - list-style-type: none; -} - -.genealogy-tree li { - margin: 10px 0; - position: relative; -} - -.genealogy-tree li::before { - content: ''; - position: absolute; - top: -10px; - left: -20px; - border-left: 1px solid #ccc; - border-bottom: 1px solid #ccc; - width: 20px; - height: 20px; -} - -.genealogy-tree li:first-child::before { - border-top: 1px solid #ccc; -} - -.genealogy-tree li:last-child::before { - height: 20px; -} diff --git a/assets/css/dashboard.css b/assets/css/dashboard.css new file mode 100644 index 0000000..543f47e --- /dev/null +++ b/assets/css/dashboard.css @@ -0,0 +1,250 @@ +:root { + --primary-color: #6f42c1; + --secondary-color: #f8f9fa; + --text-color: #343a40; + --heading-font: 'Poppins', sans-serif; + --body-font: 'Poppins', sans-serif; + --sidebar-bg: #1e1e2d; + --sidebar-text: #a5a5a9; + --sidebar-active: #ffffff; + --content-bg: #f4f7f6; +} + +body { + font-family: var(--body-font); + color: var(--text-color); + background-color: var(--content-bg); +} + +.sidebar { + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 260px; + background-color: var(--sidebar-bg); + padding-top: 20px; + transition: all 0.3s; + z-index: 1000; +} + +.sidebar .logo { + font-family: var(--heading-font); + font-weight: 700; + color: var(--sidebar-active) !important; + font-size: 1.5rem; + text-align: center; + display: block; + margin-bottom: 30px; +} + +.sidebar .nav-link { + color: var(--sidebar-text); + font-weight: 500; + padding: 12px 25px; + display: flex; + align-items: center; + transition: all 0.3s; +} + +.sidebar .nav-link i { + margin-right: 15px; + font-size: 1.1rem; + width: 20px; + text-align: center; +} + +.sidebar .nav-link:hover, +.sidebar .nav-link.active { + color: var(--sidebar-active); + background-color: rgba(255, 255, 255, 0.05); +} + +.sidebar .nav-item-header { + text-transform: uppercase; + font-size: 0.8rem; + font-weight: 600; + color: #4a4a5a; + padding: 10px 25px; + margin-top: 15px; +} + +.main-content { + margin-left: 260px; + padding: 0; + transition: all 0.3s; +} + +.header { + background-color: #fff; + padding: 20px 30px; + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid #e5e9f2; +} + +.wallet-card { + background: linear-gradient(135deg, var(--primary-color), #2575fc); + color: white; + border-radius: 15px; +} + +.wallet-balance { + font-weight: 700; +} + +.income-card { + background: #fff; + border: none; + border-radius: 15px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); +} + +.income-card .card-body { + display: flex; + align-items: center; +} + +.income-card .icon { + font-size: 2.5rem; + margin-right: 20px; + padding: 20px; + border-radius: 50%; + background-color: rgba(0,0,0,0.05); +} + +.table-striped > tbody > tr:nth-of-type(odd) > * { + background-color: rgba(0,0,0,0.02); +} + +.feature-card { + background: white; + border-radius: 10px; + padding: 40px; + text-align: center; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); + transition: transform 0.3s; +} + +.feature-card:hover { + transform: translateY(-10px); +} + +.feature-icon { + font-size: 3rem; + color: var(--primary-color); + margin-bottom: 20px; +} +.chat-open-button { + position: fixed; + bottom: 20px; + right: 20px; + background-color: var(--primary-color); + color: white; + padding: 15px 20px; + border-radius: 50%; + cursor: pointer; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + z-index: 1000; + border: none; + font-size: 24px; +} + +.chat-popup { + display: none; + position: fixed; + bottom: 20px; + right: 20px; + width: 350px; + height: 500px; + background-color: white; + flex-direction: column; + border-radius: 10px; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); + z-index: 1001; +} +.chat-header { + background-color: var(--primary-color); + color: white; + padding: 15px; + border-top-left-radius: 10px; + border-top-right-radius: 10px; + display: flex; + justify-content: space-between; + align-items: center; +} +.chat-messages { + flex-grow: 1; + padding: 15px; + overflow-y: auto; + background-color: #f9f9f9; +} +.chat-input { + display: flex; + padding: 10px; + border-top: 1px solid #ddd; +} +.chat-message { + margin-bottom: 10px; + padding: 8px 12px; + border-radius: 18px; + max-width: 80%; +} +.user-message { + background-color: var(--primary-color); + color: white; + align-self: flex-end; + margin-left: auto; +} +.bot-message { + background-color: #e9e9eb; + color: var(--text-color); + align-self: flex-start; +} + +.nav-link-custom { + font-weight: 500; + color: var(--text-color); + transition: color 0.3s; + position: relative; + padding-bottom: 0.5rem; +} + +.nav-link-custom::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 0; + height: 2px; + background-color: var(--primary-color); + transition: width 0.3s ease-in-out; +} + +.nav-link-custom:hover::after, .nav-link-custom.active::after { + width: 100%; +} + +.nav-link-custom:hover { + color: var(--primary-color); +} + +.navbar-nav .btn { + margin-left: 0.5rem; +} + +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); +} + +.btn-primary:hover { + background-color: #5a3e9a; + border-color: #5a3e9a; +} + +.btn-outline-secondary:hover { + background-color: var(--primary-color); + color: white; +} \ No newline at end of file diff --git a/assets/images/about-us.jpg b/assets/images/about-us.jpg new file mode 100644 index 0000000..57d1359 Binary files /dev/null and b/assets/images/about-us.jpg differ diff --git a/auth.php b/auth.php index 4734aeb..af0b087 100644 --- a/auth.php +++ b/auth.php @@ -19,7 +19,7 @@ function register($name, $email, $password, $sponsor_code) { $referral_code = uniqid(); try { - $stmt = $db->prepare("INSERT INTO users (name, email, password, referral_code, sponsor_id) VALUES (?, ?, ?, ?, ?)"); + $stmt = $db->prepare("INSERT INTO users (name, email, password, referral_code, sponsor_id, role, agent_tier) VALUES (?, ?, ?, ?, ?, 'Agent', 'Normal')"); $stmt->execute([$name, $email, $password_hash, $referral_code, $sponsor_id]); return true; } catch (PDOException $e) { @@ -38,6 +38,7 @@ function login($email, $password) { if ($user && password_verify($password, $user['password'])) { $_SESSION['user_id'] = $user['id']; + $_SESSION['role'] = $user['role']; return true; } return false; @@ -56,3 +57,54 @@ function get_downline($user_id) { $stmt->execute([$user_id]); return $stmt->fetchAll(); } + +function is_logged_in() { + return isset($_SESSION['user_id']); +} + +function is_admin() { + return isset($_SESSION['role']) && $_SESSION['role'] === 'Admin'; +} + +function is_super_admin() { + return isset($_SESSION['role']) && $_SESSION['role'] === 'Super Admin'; +} + +function is_agent() { + return isset($_SESSION['role']) && $_SESSION['role'] === 'Agent'; +} + +function update_agent_tier($user_id) { + $db = db(); + $stmt = $db->prepare("SELECT cumulative_bookings, agent_tier FROM users WHERE id = ?"); + $stmt->execute([$user_id]); + $user = $stmt->fetch(); + + if (!$user) { + return; + } + + $cumulative_bookings = $user['cumulative_bookings']; + $current_tier = $user['agent_tier']; + $new_tier = 'Normal'; + + // Tier thresholds in INR + $tier_thresholds = [ + 'Diamond' => 1000000, + 'Gold' => 500000, + 'Silver' => 100000, + 'Normal' => 0 + ]; + + foreach ($tier_thresholds as $tier => $threshold) { + if ($cumulative_bookings >= $threshold) { + $new_tier = $tier; + break; + } + } + + if ($new_tier !== $current_tier) { + $stmt = $db->prepare("UPDATE users SET agent_tier = ? WHERE id = ?"); + $stmt->execute([$new_tier, $user_id]); + } +} diff --git a/contact_error.php b/contact_error.php new file mode 100644 index 0000000..60f69d5 --- /dev/null +++ b/contact_error.php @@ -0,0 +1,25 @@ + + + + + + + Error | <?php echo htmlspecialchars($content['site_title']); ?> + + + + +
+
+
+

Something went wrong!

+

There was an error sending your message. Please try again later.

+ Go back and try again +
+
+
+ + \ No newline at end of file diff --git a/contact_success.php b/contact_success.php new file mode 100644 index 0000000..dfc77dc --- /dev/null +++ b/contact_success.php @@ -0,0 +1,25 @@ + + + + + + + Message Sent | <?php echo htmlspecialchars($content['site_title']); ?> + + + + +
+
+
+

Message Sent!

+

Thank you for contacting us. We will get back to you shortly.

+ Go back to Homepage +
+
+
+ + \ No newline at end of file diff --git a/content.json b/content.json new file mode 100644 index 0000000..8daaedb --- /dev/null +++ b/content.json @@ -0,0 +1,19 @@ +{ + "site_title": "Kutumbh Infra - Welcome to the Future of Real Estate", + "site_name": "Kutumbh Infra", + "hero_title": "Welcome to the Future of Real Estate", + "hero_subtitle": "Your partner in building a successful real estate business.", + "about_us_title": "About Our Mission", + "about_us_content_1": "We are dedicated to redefining the real estate landscape. Our mission is to empower individuals to achieve financial independence through our innovative multi-level marketing (MLM) platform.", + "about_us_content_2": "Our company is built on a foundation of integrity, transparency, and a deep understanding of the real estate market. We provide our members with the tools, training, and support they need to thrive.", + "features_title": "Why Choose Us?", + "feature_1_title": "Innovative Platform", + "feature_1_content": "Access a wide range of properties with our user-friendly platform, designed for you to easily search, filter, and manage listings.", + "feature_2_title": "Growth Opportunity", + "feature_2_content": "Our MLM program is designed to help you build a successful business with a competitive commission structure and a supportive community.", + "feature_3_title": "Cutting-Edge Tools", + "feature_3_content": "We provide advanced analytics, marketing materials, and a CRM system to help you manage leads and close deals efficiently.", + "contact_us_title": "Get In Touch", + "contact_us_content": "Have questions? We're here to help. Reach out to us to learn more about our program and join the Kutumbh Infra family.", + "contact_us_button_text": "Contact Us Now" +} \ No newline at end of file diff --git a/cron/process_passive_income.php b/cron/process_passive_income.php new file mode 100644 index 0000000..bfd1119 --- /dev/null +++ b/cron/process_passive_income.php @@ -0,0 +1,60 @@ +beginTransaction(); + +try { + // 1. Find pending payments + $stmt = $db->prepare("SELECT * FROM passive_income_schedule WHERE status = 'pending' AND payment_date <= CURDATE()"); + $stmt->execute(); + $pending_payments = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if (empty($pending_payments)) { + echo "No pending passive income payments to process.\n"; + $db->commit(); + exit; + } + + echo "Found " . count($pending_payments) . " pending payment(s).\n"; + + foreach ($pending_payments as $payment) { + $userId = $payment['user_id']; + $amount = $payment['amount']; + $scheduleId = $payment['id']; + + // 2. Insert into transactions + $trans_stmt = $db->prepare( + "INSERT INTO transactions (user_id, amount, type, description, related_user_id) VALUES (:user_id, :amount, 'passive_income', :description, NULL)" + ); + $trans_stmt->execute([ + ':user_id' => $userId, + ':amount' => $amount, + ':description' => 'Monthly passive income payment from schedule #' . $scheduleId + ]); + + // 3. Update user's wallet + $user_stmt = $db->prepare("UPDATE users SET wallet_balance = wallet_balance + :amount, total_passive_income = total_passive_income + :amount WHERE id = :user_id"); + $user_stmt->execute([':amount' => $amount, ':user_id' => $userId]); + + // 4. Update schedule status to 'paid' + $schedule_stmt = $db->prepare("UPDATE passive_income_schedule SET status = 'paid' WHERE id = :id"); + $schedule_stmt->execute([':id' => $scheduleId]); + + echo "Processed payment for user #$userId (Amount: $amount).\n"; + } + + $db->commit(); + echo "Passive income processing finished successfully.\n"; + +} catch (Exception $e) { + $db->rollBack(); + echo "Error processing passive income: " . $e->getMessage() . "\n"; + // It's crucial to log this error to a file in a real-world scenario + error_log("Passive Income Cron Failed: " . $e->getMessage()); +} \ No newline at end of file diff --git a/dashboard.php b/dashboard.php index 2a9433d..d0e8748 100644 --- a/dashboard.php +++ b/dashboard.php @@ -1,78 +1,186 @@ prepare("SELECT * FROM users WHERE id = :id"); +$stmt->execute([':id' => $_SESSION['user_id']]); +$user = $stmt->fetch(PDO::FETCH_ASSOC); +// Fetch last 5 transactions +$stmt = $db->prepare("SELECT * FROM transactions WHERE user_id = :user_id ORDER BY created_at DESC LIMIT 5"); +$stmt->execute([':user_id' => $_SESSION['user_id']]); +$recent_transactions = $stmt->fetchAll(PDO::FETCH_ASSOC); + +$site_name = 'Kutumbh Infra'; ?> - + - Dashboard + + + Dashboard - <?php echo htmlspecialchars($site_name); ?> - + + + - + -
-
-
-
-
Dashboard
-
-

Welcome, !

-

Your referral code is:

-

Your user type is:

+
+ +
+
+
+
+
Wallet Balance
+

+ Request Withdrawal +
-
-
-
-
-
Genealogy Tree
-
-
    - -
  • Upline:
  • - -
  • - You: - 0): ?> -
      - -
    • ()
    • - -
    - -

    You have no direct downline members yet.

    - -
  • -
+ +
+
+
+
+
+
+
Direct Income
+

+
+
+
+
+
+
+
+
+
+
Team Income
+

+
+
+
+
+
+
+
+
+
+
Leg Match Bonus
+

+
+
+
+
+
+
+
+
+
+
Passive Income
+

+
+
-
+ + +
+
+
+
+
Recent Transactions
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
DateTypeAmountDescription
No recent transactions.
+
+ +
+
+
+
+
+ + diff --git a/db/setup.php b/db/setup.php index 496f6ef..f656ec9 100644 --- a/db/setup.php +++ b/db/setup.php @@ -1,21 +1,164 @@ exec($sql); + echo $message . "
"; + } catch (PDOException $e) { + // Suppress errors if the alteration already exists, but show others + if (!str_contains($e->getMessage(), 'Duplicate') && !str_contains($e->getMessage(), 'already exists') && !str_contains($e->getMessage(), 'Unknown table')) { + echo "Error: " . $e->getMessage() . "
"; + } + } +} + try { $db = db(); - $sql = "CREATE TABLE IF NOT EXISTS `users` ( + + // 0. Drop dependent tables first to avoid foreign key issues + run_sql($db, "DROP TABLE IF EXISTS `passive_income_schedule`", "Table 'passive_income_schedule' dropped if exists."); + run_sql($db, "DROP TABLE IF EXISTS `commissions`", "Table 'commissions' dropped if exists."); + run_sql($db, "DROP TABLE IF EXISTS `wallet_ledger`", "Table 'wallet_ledger' dropped if exists."); + + // 1. Users table + $sqlUsers = "CREATE TABLE IF NOT EXISTS `users` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(255) NOT NULL, `email` VARCHAR(255) NOT NULL UNIQUE, `password` VARCHAR(255) NOT NULL, `referral_code` VARCHAR(50) NOT NULL UNIQUE, `sponsor_id` INT NULL, - `user_type` ENUM('Normal', 'Silver', 'Gold') NOT NULL DEFAULT 'Normal', + `role` ENUM('Super Admin', 'Admin', 'Finance', 'Agent', 'Support') NOT NULL DEFAULT 'Agent', + `agent_tier` ENUM('Normal', 'Silver', 'Gold', 'Diamond') NULL DEFAULT 'Normal', + `cumulative_bookings` DECIMAL(15, 2) DEFAULT 0.00, + `phone` VARCHAR(255) NULL, + `company` VARCHAR(255) NULL, + `notes` TEXT NULL, + `wallet_balance` DECIMAL(15, 2) NOT NULL DEFAULT 0.00, + `total_direct_income` DECIMAL(15, 2) NOT NULL DEFAULT 0.00, + `total_team_income` DECIMAL(15, 2) NOT NULL DEFAULT 0.00, + `total_passive_income` DECIMAL(15, 2) NOT NULL DEFAULT 0.00, + `total_leg_match_income` DECIMAL(15, 2) NOT NULL DEFAULT 0.00, `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (sponsor_id) REFERENCES users(id) ON DELETE SET NULL )"; - $db->exec($sql); - echo "Table 'users' created successfully."; + run_sql($db, $sqlUsers, "Table 'users' created or already exists."); + + // Add columns to users table if they don't exist + run_sql($db, "ALTER TABLE users ADD COLUMN wallet_balance DECIMAL(15, 2) NOT NULL DEFAULT 0.00", "Column 'wallet_balance' added to 'users' table."); + run_sql($db, "ALTER TABLE users ADD COLUMN total_direct_income DECIMAL(15, 2) NOT NULL DEFAULT 0.00", "Column 'total_direct_income' added to 'users' table."); + run_sql($db, "ALTER TABLE users ADD COLUMN total_team_income DECIMAL(15, 2) NOT NULL DEFAULT 0.00", "Column 'total_team_income' added to 'users' table."); + run_sql($db, "ALTER TABLE users ADD COLUMN total_passive_income DECIMAL(15, 2) NOT NULL DEFAULT 0.00", "Column 'total_passive_income' added to 'users' table."); + run_sql($db, "ALTER TABLE users ADD COLUMN total_leg_match_income DECIMAL(15, 2) NOT NULL DEFAULT 0.00", "Column 'total_leg_match_income' added to 'users' table."); + run_sql($db, "ALTER TABLE users MODIFY cumulative_bookings DECIMAL(15, 2) DEFAULT 0.00", "Column 'cumulative_bookings' in 'users' table modified."); + run_sql($db, "ALTER TABLE users MODIFY `role` ENUM('Super Admin', 'Admin', 'Finance', 'Agent', 'Support') NOT NULL DEFAULT 'Agent'", "Column 'role' in 'users' table modified."); + + + // 2. Bookings table + $sqlBookings = "CREATE TABLE IF NOT EXISTS `bookings` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `user_id` INT NOT NULL, + `plot_id` VARCHAR(255) NOT NULL, + `amount` DECIMAL(15, 2) NOT NULL, + `booking_date` DATE NOT NULL, + `proof_document` VARCHAR(255) NOT NULL, + `status` ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending', + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + )"; + run_sql($db, $sqlBookings, "Table 'bookings' created or already exists."); + run_sql($db, "ALTER TABLE bookings MODIFY amount DECIMAL(15, 2) NOT NULL", "Column 'amount' in 'bookings' table modified."); + + // 3. Transactions table (replaces wallet_ledger and commissions) + $sqlTransactions = "CREATE TABLE IF NOT EXISTS `transactions` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `user_id` INT NOT NULL, + `amount` DECIMAL(15, 2) NOT NULL, + `type` ENUM('commission_direct', 'commission_team', 'passive_income', 'leg_match_bonus', 'withdrawal', 'withdrawal_fee', 'deposit', 'booking_refund') NOT NULL, + `description` TEXT, + `related_booking_id` INT NULL, + `related_user_id` INT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY (related_booking_id) REFERENCES bookings(id) ON DELETE SET NULL, + FOREIGN KEY (related_user_id) REFERENCES users(id) ON DELETE SET NULL + )"; + run_sql($db, $sqlTransactions, "Table 'transactions' created or already exists."); + + // 4. Withdrawals table + $sqlWithdrawals = "CREATE TABLE IF NOT EXISTS `withdrawals` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `user_id` INT NOT NULL, + `amount` DECIMAL(15, 2) NOT NULL, + `status` ENUM('pending', 'approved', 'rejected') NOT NULL DEFAULT 'pending', + `rejection_reason` TEXT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + `processed_at` TIMESTAMP NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + )"; + run_sql($db, $sqlWithdrawals, "Table 'withdrawals' created or already exists."); + run_sql($db, "ALTER TABLE withdrawals MODIFY amount DECIMAL(15, 2) NOT NULL", "Column 'amount' in 'withdrawals' table modified."); + + // 5. Leg Milestones table + $sqlLegMilestones = "CREATE TABLE IF NOT EXISTS `leg_milestones` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `user_id` INT NOT NULL, + `leg_user_id` INT NOT NULL, /* The user in the downline whose leg reached the milestone */ + `milestone_amount` DECIMAL(15, 2) NOT NULL, + `bonus_amount` DECIMAL(15, 2) NOT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, + FOREIGN KEY (leg_user_id) REFERENCES users(id) ON DELETE CASCADE + )"; + run_sql($db, $sqlLegMilestones, "Table 'leg_milestones' created or already exists."); + + // 6. Passive Income Schedule table (now references transactions) + $sqlPassiveIncome = "CREATE TABLE IF NOT EXISTS `passive_income_schedule` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `transaction_id` INT NOT NULL, /* The direct commission transaction */ + `user_id` INT NOT NULL, + `amount` DECIMAL(15, 2) NOT NULL, + `payment_date` DATE NOT NULL, + `status` ENUM('pending', 'paid', 'cancelled') NOT NULL DEFAULT 'pending', + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (transaction_id) REFERENCES transactions(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + )"; + run_sql($db, $sqlPassiveIncome, "Table 'passive_income_schedule' created or already exists."); + + + // 7. Insert/Update Super Admin User + $adminName = 'Super Admin'; + $adminEmail = 'admin@example.com'; + $adminPassword = 'admin'; + $hashedPassword = password_hash($adminPassword, PASSWORD_BCRYPT); + $adminReferralCode = 'ADMIN'; + + $stmt = $db->prepare("SELECT id FROM users WHERE email = :email"); + $stmt->execute([':email' => $adminEmail]); + if ($stmt->rowCount() == 0) { + $sql = "INSERT INTO users (name, email, password, referral_code, `role`) VALUES (:name, :email, :password, :referral_code, 'Super Admin')"; + $stmt = $db->prepare($sql); + $stmt->execute([ + ':name' => $adminName, + ':email' => $adminEmail, + ':password' => $hashedPassword, + ':referral_code' => $adminReferralCode + ]); + echo "Super Admin user created successfully."; + } else { + $sql = "UPDATE users SET password = :password, `role` = 'Super Admin' WHERE email = :email"; + $stmt = $db->prepare($sql); + $stmt->execute([ + ':password' => $hashedPassword, + ':email' => $adminEmail + ]); + echo "Super Admin user updated successfully."; + } + echo "
Database setup/update complete."; + } catch (PDOException $e) { die("DB ERROR: ". $e->getMessage()); -} +} \ No newline at end of file diff --git a/delete_user.php b/delete_user.php new file mode 100644 index 0000000..5341d27 --- /dev/null +++ b/delete_user.php @@ -0,0 +1,23 @@ +prepare('DELETE FROM users WHERE id = ?'); + $stmt->execute([$user_id]); + + header('Location: admin_dashboard.php'); + exit; +} else { + header('Location: admin_dashboard.php'); + exit; +} +?> \ No newline at end of file diff --git a/edit_content.php b/edit_content.php new file mode 100644 index 0000000..17afbee --- /dev/null +++ b/edit_content.php @@ -0,0 +1,83 @@ + $value) { + if (array_key_exists($key, $content)) { + $content[$key] = $value; + } + } + file_put_contents($content_file, json_encode($content, JSON_PRETTY_PRINT)); + header('Location: edit_content.php?success=true'); + exit; +} +?> + + + + + + Edit Landing Page Content + + + + + + + + + + +
+
+

Edit Landing Page Content

+
+ + +
Content updated successfully!
+ + +
+
+
+ $value): ?> +
+
+ + 100): ?> + + + + +
+
+ +
+
+ + Cancel +
+
+
+
+ + + + \ No newline at end of file diff --git a/edit_user.php b/edit_user.php new file mode 100644 index 0000000..2d7eb31 --- /dev/null +++ b/edit_user.php @@ -0,0 +1,134 @@ +prepare('SELECT id, name, email, role, agent_tier, cumulative_bookings, phone, company, notes FROM users WHERE id = ?'); + $stmt->execute([$user_id]); + $user = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$user) { + header('Location: admin_dashboard.php?error=user_not_found'); + exit; + } +} + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $name = $_POST['name']; + $email = $_POST['email']; + $role = $_POST['role']; + $agent_tier = $_POST['agent_tier']; + $phone = $_POST['phone']; + $company = $_POST['company']; + $notes = $_POST['notes']; + $user_id = $_POST['user_id']; + + if (empty($name) || empty($email) || empty($role)) { + header('Location: edit_user.php?id=' . $user_id . '&error=empty_fields'); + exit; + } + + $db = db(); + $stmt = $db->prepare('UPDATE users SET name = ?, email = ?, role = ?, agent_tier = ?, phone = ?, company = ?, notes = ? WHERE id = ?'); + $stmt->execute([$name, $email, $role, $agent_tier, $phone, $company, $notes, $user_id]); + + header('Location: admin_dashboard.php'); + exit; +} + +?> + + + + + + Edit User + + + + + + + + + + +
+
+

Edit User

+
+ +
+ +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+ +
User not found.
+ +
+
+ + + + \ No newline at end of file diff --git a/genealogy.php b/genealogy.php new file mode 100644 index 0000000..b75b15a --- /dev/null +++ b/genealogy.php @@ -0,0 +1,168 @@ +prepare("SELECT id, name, email, agent_tier FROM users WHERE sponsor_id = :sponsor_id ORDER BY name"); + $stmt->execute([':sponsor_id' => $userId]); + $downline = $stmt->fetchAll(PDO::FETCH_ASSOC); + + foreach ($downline as $member) { + $member['downline'] = get_downline_tree($member['id'], $db); + $tree[] = $member; + } + + return $tree; +} + +// Function to recursively display the tree as a nested list +function display_tree_node($node) { + echo '
  • '; + echo '
    '; + echo '
    '; + echo '
    ' . htmlspecialchars($node['name']) . '
    '; + echo '

    ' . htmlspecialchars($node['email']) . '

    '; + echo ' ' . htmlspecialchars($node['agent_tier']) . ''; + echo '
    '; + echo '
    '; + + if (!empty($node['downline'])) { + echo '
      '; + foreach ($node['downline'] as $child) { + display_tree_node($child); + } + echo '
    '; + } + + echo '
  • '; +} + + +$stmt = $db->prepare("SELECT * FROM users WHERE id = :id"); +$stmt->execute([':id' => $_SESSION['user_id']]); +$user = $stmt->fetch(PDO::FETCH_ASSOC); + +$genealogy_tree = get_downline_tree($user['id'], $db); + +$site_name = 'Kutumbh Infra'; +?> + + + + + + Genealogy Tree - <?php echo htmlspecialchars($site_name); ?> + + + + + + + + +
    +
    +

    Genealogy Tree

    + +
    + +
    +
    +
    +
    Your Downline
    +
    +
    +
    +
      + +

      You have no users in your downline yet.

      + + + + + +
    +
    +
    +
    +
    +
    + + + + diff --git a/index.php b/index.php index 7e7f0c8..37a5f13 100644 --- a/index.php +++ b/index.php @@ -1,49 +1,202 @@ - + - Kutumbh Infra MLM + + + <?php echo htmlspecialchars($content['site_title']); ?> - + + + + + -