Editing: /home/goacom/public_html/scratch_extract/admin/deposits.php
<?php require_once 'db.php'; require_once 'auth.php'; check_admin_auth(); $status_filter = trim($_GET['status'] ?? 'all'); $search = trim($_GET['search'] ?? ''); $page = (int)($_GET['page'] ?? 1); if ($page < 1) $page = 1; $limit = 15; $offset = ($page - 1) * $limit; // Build query conditions $where_clauses = ["h.type = 'deposit'"]; $params = []; if ($status_filter !== 'all') { $where_clauses[] = "h.status = ?"; $params[] = $status_filter; } if (!empty($search)) { $where_clauses[] = "u.phone LIKE ?"; $params[] = "%$search%"; } $where_sql = implode(" AND ", $where_clauses); try { // Count total records $count_sql = "SELECT COUNT(*) FROM deposit_withdrawal_history h JOIN users u ON h.user_id = u.id WHERE $where_sql"; $stmt_count = $pdo->prepare($count_sql); $stmt_count->execute($params); $total_records = (int)$stmt_count->fetchColumn(); // Fetch records $sql = "SELECT h.*, u.phone, u.balance as user_balance FROM deposit_withdrawal_history h JOIN users u ON h.user_id = u.id WHERE $where_sql ORDER BY h.created_at DESC LIMIT ? OFFSET ?"; $stmt = $pdo->prepare($sql); // Bind parameters dynamically $param_index = 1; foreach ($params as $p) { $stmt->bindValue($param_index++, $p, PDO::PARAM_STR); } $stmt->bindValue($param_index++, $limit, PDO::PARAM_INT); $stmt->bindValue($param_index++, $offset, PDO::PARAM_INT); $stmt->execute(); $deposits = $stmt->fetchAll(); $total_pages = ceil($total_records / $limit); if ($total_pages < 1) $total_pages = 1; } catch (Exception $e) { $deposits = []; $total_records = 0; $total_pages = 1; } // Handle Approve / Reject actions if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; $id = (int)($_POST['deposit_id'] ?? 0); $admin_note = trim($_POST['admin_note'] ?? ''); if ($id > 0) { $pdo->beginTransaction(); try { // Get deposit details $stmt_d = $pdo->prepare("SELECT * FROM deposit_withdrawal_history WHERE id = ? AND type = 'deposit' FOR UPDATE"); $stmt_d->execute([$id]); $deposit = $stmt_d->fetch(); if (!$deposit) { set_flash("Deposit request not found.", "error"); $pdo->rollBack(); } elseif ($deposit['status'] === 'approved' || $deposit['status'] === 'rejected') { set_flash("Deposit has already been " . $deposit['status'] . ".", "error"); $pdo->rollBack(); } else { if ($action === 'approve') { // Update user balance $stmt_up = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?"); $stmt_up->execute([$deposit['amount'], $deposit['user_id']]); // Update deposit status $stmt_status = $pdo->prepare("UPDATE deposit_withdrawal_history SET status = 'approved', admin_note = ? WHERE id = ?"); $stmt_status->execute([$admin_note, $id]); $pdo->commit(); set_flash("Deposit approved and ৳" . number_format($deposit['amount'], 2) . " credited to user balance."); } elseif ($action === 'reject') { // Update status only $stmt_status = $pdo->prepare("UPDATE deposit_withdrawal_history SET status = 'rejected', admin_note = ? WHERE id = ?"); $stmt_status->execute([$admin_note, $id]); $pdo->commit(); set_flash("Deposit request rejected."); } } } catch (Exception $e) { $pdo->rollBack(); set_flash("Failed to process request: " . $e->getMessage(), "error"); } } redirect("deposits.php?status=$status_filter&search=" . urlencode($search) . "&page=$page"); } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Deposit Requests - MELBETE</title> <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700;800&display=swap" rel="stylesheet"> <script src="https://cdn.tailwindcss.com"></script> <script> tailwind.config = { theme: { extend: { fontFamily: { sans: ['Outfit', 'sans-serif'], }, colors: { darkBg: '#0b0f19', darkCard: '#111827', primary: '#f06827', primaryHover: '#d85315' } } } } </script> </head> <body class="bg-darkBg text-slate-100 min-h-screen flex flex-col md:flex-row"> <!-- Sidebar Navigation --> <?php include 'sidebar.php'; ?> <!-- Main Content Area --> <main class="flex-1 p-6 md:p-10 overflow-y-auto space-y-8"> <!-- Header --> <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-4 border-b border-slate-900 pb-6"> <div> <h1 class="text-2xl md:text-3xl font-extrabold text-white tracking-tight">Deposit Ledger</h1> <p class="text-slate-400 text-sm mt-1">Verify incoming payments, approve user credits, add audit logs</p> </div> </div> <!-- Flash Message --> <?php echo get_flash(); ?> <!-- Search & Filter Options bar --> <div class="bg-darkCard/30 border border-slate-900/60 rounded-3xl p-6 flex flex-col lg:flex-row items-center justify-between gap-6"> <div class="flex flex-wrap gap-2 w-full lg:w-auto"> <?php $statuses = ['all' => 'All Statuses', 'pending' => 'Pending Only', 'processing' => 'Processing Only', 'approved' => 'Approved', 'rejected' => 'Rejected']; foreach ($statuses as $val => $label): $btnClass = $status_filter === $val ? 'bg-primary text-white border-primary shadow-md shadow-primary/10' : 'bg-slate-950 border-slate-900 text-slate-400 hover:text-slate-200'; ?> <a href="deposits.php?status=<?php echo $val; ?>&search=<?php echo urlencode($search); ?>" class="px-4 py-2 border rounded-xl text-xs font-bold transition-all <?php echo $btnClass; ?>"> <?php echo $label; ?> </a> <?php endforeach; ?> </div> <form method="GET" action="deposits.php" class="w-full lg:max-w-xs relative"> <input type="hidden" name="status" value="<?php echo htmlspecialchars($status_filter); ?>"> <span class="absolute inset-y-0 left-0 pl-4 flex items-center text-slate-500"> <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /> </svg> </span> <input type="text" name="search" value="<?php echo htmlspecialchars($search); ?>" class="w-full bg-slate-950 border border-slate-900 rounded-2xl pl-12 pr-4 py-2.5 text-white placeholder-slate-500 focus:outline-none focus:border-primary text-xs" placeholder="Search phone number..."> </form> </div> <!-- Table Listing --> <div class="bg-darkCard/30 border border-slate-900/60 rounded-3xl p-6"> <div class="overflow-x-auto"> <table class="w-full text-left border-collapse text-sm"> <thead> <tr class="border-b border-slate-900 text-slate-400 font-medium"> <th class="py-3.5 px-4">User</th> <th class="py-3.5 px-4">Ledger Value</th> <th class="py-3.5 px-4">Payment Source</th> <th class="py-3.5 px-4">Transaction hash</th> <th class="py-3.5 px-4">Submitted At</th> <th class="py-3.5 px-4">Audit Note</th> <th class="py-3.5 px-4 text-right">Actions</th> </tr> </thead> <tbody class="divide-y divide-slate-900/40 text-slate-300"> <?php if (empty($deposits)): ?> <tr> <td colspan="7" class="py-6 text-center text-slate-500">No deposit records found matching criteria.</td> </tr> <?php else: ?> <?php foreach ($deposits as $row): switch($row['status']) { case 'approved': $statusClass = 'text-emerald-400 bg-emerald-400/10 border border-emerald-500/10'; break; case 'rejected': $statusClass = 'text-rose-400 bg-rose-400/10 border border-rose-500/10'; break; case 'processing': $statusClass = 'text-amber-400 bg-amber-400/10 border border-amber-500/20'; break; default: $statusClass = 'text-slate-400 bg-slate-400/10 border border-slate-500/5'; } ?> <tr class="hover:bg-slate-900/20 transition-colors"> <td class="py-4 px-4 space-y-1"> <div class="font-bold text-white"><?php echo htmlspecialchars($row['phone']); ?></div> <div class="text-[10px] text-slate-500">Curr. Bal: ৳<?php echo number_format($row['user_balance'], 2); ?></div> </td> <td class="py-4 px-4"> <span class="text-white font-bold font-mono">৳ <?php echo number_format($row['amount'], 2); ?></span> </td> <td class="py-4 px-4 text-slate-300 font-semibold uppercase text-xs"> <?php echo htmlspecialchars($row['payment_method']); ?> <?php if (!empty($row['account_number'])): ?> <div class="text-[10px] text-slate-500 mt-0.5 font-mono lowercase">From: <?php echo htmlspecialchars($row['account_number']); ?></div> <?php endif; ?> </td> <td class="py-4 px-4 font-mono text-xs text-slate-400 max-w-[150px] truncate" title="<?php echo htmlspecialchars($row['transaction_hash']); ?>"> <?php echo htmlspecialchars($row['transaction_hash'] ?: 'N/A'); ?> </td> <td class="py-4 px-4 text-xs text-slate-500"> <?php echo htmlspecialchars(date('M d, Y H:i', strtotime($row['created_at']))); ?> </td> <td class="py-4 px-4 max-w-[150px] truncate text-xs text-slate-400" title="<?php echo htmlspecialchars($row['admin_note'] ?? ''); ?>"> <?php echo htmlspecialchars($row['admin_note'] ?: '-'); ?> </td> <td class="py-4 px-4 text-right"> <?php if ($row['status'] === 'pending' || $row['status'] === 'processing'): ?> <button onclick="openActionModal(<?php echo htmlspecialchars(json_encode($row)); ?>)" class="bg-primary hover:bg-primaryHover text-white px-3 py-1.5 rounded-xl text-xs font-semibold transition-all"> Review </button> <?php else: ?> <span class="text-xs px-2.5 py-1 rounded-full font-bold uppercase tracking-wider <?php echo $statusClass; ?>"> <?php echo htmlspecialchars($row['status']); ?> </span> <?php endif; ?> </td> </tr> <?php endforeach; ?> <?php endif; ?> </tbody> </table> </div> <!-- Pagination --> <?php if ($total_pages > 1): ?> <div class="mt-6 flex items-center justify-between border-t border-slate-900 pt-6"> <span class="text-xs text-slate-500 font-medium">Page <?php echo $page; ?> of <?php echo $total_pages; ?></span> <div class="flex gap-2"> <?php if ($page > 1): ?> <a href="deposits.php?status=<?php echo $status_filter; ?>&search=<?php echo urlencode($search); ?>&page=<?php echo $page - 1; ?>" class="px-4 py-2 bg-slate-900 text-slate-300 hover:text-white text-xs font-bold rounded-xl border border-slate-800 transition-all">Prev</a> <?php endif; ?> <?php if ($page < $total_pages): ?> <a href="deposits.php?status=<?php echo $status_filter; ?>&search=<?php echo urlencode($search); ?>&page=<?php echo $page + 1; ?>" class="px-4 py-2 bg-slate-900 text-slate-300 hover:text-white text-xs font-bold rounded-xl border border-slate-800 transition-all">Next</a> <?php endif; ?> </div> </div> <?php endif; ?> </div> </main> <!-- Deposit Action Dialog Modal --> <div id="depositModal" class="fixed inset-0 bg-black/70 backdrop-blur-sm hidden items-center justify-center z-50 p-4"> <div class="bg-darkCard w-full max-w-md border border-slate-800 rounded-3xl overflow-hidden shadow-2xl animate-in fade-in zoom-in duration-200"> <div class="bg-slate-900 px-6 py-4 flex items-center justify-between border-b border-slate-800/80"> <div> <h3 class="font-bold text-white text-base">Verify Deposit Payment</h3> <p class="text-[10px] text-slate-400 font-medium uppercase tracking-wider mt-0.5" id="modalTrxLabel">TRX ID: #</p> </div> <button onclick="closeActionModal()" class="text-slate-400 hover:text-white text-xl font-bold">×</button> </div> <form method="POST" class="p-6 space-y-6"> <input type="hidden" name="deposit_id" id="modalDepositId"> <input type="hidden" name="action" id="modalAction" value="approve"> <div class="bg-slate-950/40 border border-slate-900 p-4 rounded-2xl space-y-2.5 text-xs text-slate-300"> <div class="flex justify-between"><span class="text-slate-500">Phone Account:</span><span class="font-bold text-white" id="modalPhone">---</span></div> <div class="flex justify-between"><span class="text-slate-500">Payment Gateway:</span><span class="font-semibold text-white uppercase" id="modalMethod">---</span></div> <div class="flex justify-between"><span class="text-slate-500">Sender account number:</span><span class="font-mono text-white" id="modalAccount">---</span></div> <div class="flex justify-between"><span class="text-slate-500">Transaction ID (Hash):</span><span class="font-mono text-white text-right max-w-[200px] truncate" id="modalHash">---</span></div> <div class="flex justify-between pt-2 border-t border-slate-900/60"><span class="text-slate-400 font-semibold">Credited Amount:</span><span class="text-emerald-400 font-bold font-mono text-sm" id="modalAmount">৳ 0.00</span></div> </div> <div> <label class="block text-[11px] text-slate-500 mb-1.5 font-bold uppercase">Audit Note (Visible in transaction log)</label> <textarea name="admin_note" id="modalNote" rows="2" class="w-full bg-slate-950 border border-slate-900 rounded-xl px-4 py-3 text-white focus:outline-none focus:border-primary text-xs" placeholder="Add review feedback, transaction validation details..."></textarea> </div> <div class="flex gap-3"> <button type="submit" onclick="setAction('reject')" class="flex-1 bg-slate-900 hover:bg-rose-950/20 hover:text-rose-400 border border-slate-800 hover:border-rose-500/20 text-slate-400 py-3.5 rounded-xl text-xs font-bold transition-all"> Reject </button> <button type="submit" onclick="setAction('approve')" class="flex-1 bg-emerald-500 hover:bg-emerald-600 text-slate-950 py-3.5 rounded-xl text-xs font-bold transition-all"> Approve Payment </button> </div> </form> </div> </div> <!-- Modal Handler --> <script> const modal = document.getElementById('depositModal'); function openActionModal(row) { document.getElementById('modalDepositId').value = row.id; document.getElementById('modalTrxLabel').innerText = 'ID: #' + row.id + ' | Date: ' + row.created_at; document.getElementById('modalPhone').innerText = row.phone; document.getElementById('modalMethod').innerText = row.payment_method; document.getElementById('modalAccount').innerText = row.account_number ? row.account_number : 'N/A'; document.getElementById('modalHash').innerText = row.transaction_hash ? row.transaction_hash : 'N/A'; document.getElementById('modalAmount').innerText = '৳ ' + parseFloat(row.amount).toLocaleString('en-US', {minimumFractionDigits: 2}); document.getElementById('modalNote').value = row.admin_note ? row.admin_note : ''; modal.style.display = 'flex'; } function closeActionModal() { modal.style.display = 'none'; } function setAction(act) { document.getElementById('modalAction').value = act; } </script> </body> </html>
💾 Save