fellybikush's picture
Upload 99 files
0dff816 verified
raw
history blame
44.4 kB
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
session_start();
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
header('Location: ../../index.php');
exit;
}
// Include database connection
require_once '../../config.php';
// Check if $pdo is set, if not create it
if (!isset($pdo)) {
// Database configuration
$db_host = '127.0.0.1';
$db_name = 'jmdb';
$db_user = 'root';
$db_pass = 'YourStrongPassword123';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $e) {
die("Database connection failed: " . $e->getMessage());
}
}
// Get user data from session
$username = $_SESSION['username'];
$email = $_SESSION['email'];
$tier = $_SESSION['tier'];
$package = $_SESSION['package'];
$balance = $_SESSION['balance'];
$total_deposits = $_SESSION['total_deposits'];
$total_withdrawals = $_SESSION['total_withdrawals'];
$rewards = $_SESSION['rewards'];
$earnings = $total_deposits - $total_withdrawals;
$user_id = $_SESSION['user_id'];
// Get user's available balance (balance minus any holds)
$available_balance = $balance;
$pending_withdrawals = 0;
// Check for pending withdrawals
try {
$stmt = $pdo->prepare("SELECT SUM(amount) as pending_amount FROM withdrawals WHERE user_id = ? AND status IN ('pending', 'processing')");
$stmt->execute([$user_id]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$pending_withdrawals = $result['pending_amount'] ?? 0;
$available_balance = $balance - $pending_withdrawals;
} catch (Exception $e) {
// Log error but continue
error_log("Error fetching pending withdrawals: " . $e->getMessage());
}
// Get withdrawal destinations for this user
$destinations = [];
try {
$stmt = $pdo->prepare("SELECT id, type, details, is_default FROM withdrawal_destinations WHERE user_id = ? AND is_active = 1 ORDER BY is_default DESC, created_at DESC");
$stmt->execute([$user_id]);
$destinations = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log("Error fetching withdrawal destinations: " . $e->getMessage());
}
// Process withdrawal request
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$data = json_decode(file_get_contents('php://input'), true);
$amount = floatval($data['amount']);
$destination_id = intval($data['destination_id']);
$idempotency_key = $data['idempotency_key'] ?? '';
// Validate input
if ($amount <= 0) {
echo json_encode(['success' => false, 'message' => 'Invalid amount.']);
exit;
}
if (empty($destination_id)) {
echo json_encode(['success' => false, 'message' => 'Please select a withdrawal destination.']);
exit;
}
if (empty($idempotency_key)) {
echo json_encode(['success' => false, 'message' => 'Security error. Please refresh and try again.']);
exit;
}
// Check if user has sufficient available balance
if ($available_balance < $amount) {
echo json_encode(['success' => false, 'message' => 'Insufficient available balance.']);
exit;
}
// Check minimum and maximum limits
$min_withdrawal = 100;
$max_withdrawal = 70000;
if ($amount < $min_withdrawal) {
echo json_encode(['success' => false, 'message' => "Minimum withdrawal amount is {$min_withdrawal} KES."]);
exit;
}
if ($amount > $max_withdrawal) {
echo json_encode(['success' => false, 'message' => "Maximum withdrawal amount is {$max_withdrawal} KES."]);
exit;
}
// Calculate fee (15 KES or 1.5%, whichever is higher)
$fee = max(15, $amount * 0.015);
$net_amount = $amount - $fee;
// Start transaction
$pdo->beginTransaction();
try {
// Check for idempotency (prevent duplicate requests)
$stmt = $pdo->prepare("SELECT id, status FROM withdrawals WHERE user_id = ? AND idempotency_key = ?");
$stmt->execute([$user_id, $idempotency_key]);
$existing_withdrawal = $stmt->fetch(PDO::FETCH_ASSOC);
if ($existing_withdrawal) {
// Idempotent response - return existing withdrawal
$pdo->commit();
echo json_encode([
'success' => true,
'idempotent' => true,
'withdrawal_id' => $existing_withdrawal['id'],
'status' => $existing_withdrawal['status'],
'message' => 'Withdrawal request already processed.'
]);
exit;
}
// Lock user row for update
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ? FOR UPDATE");
$stmt->execute([$user_id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user || $user['balance'] < $amount) {
throw new Exception('Insufficient balance.');
}
// Deduct from user balance
$stmt = $pdo->prepare("UPDATE users SET balance = balance - ?, total_withdrawals = total_withdrawals + ? WHERE id = ?");
$stmt->execute([$amount, $amount, $user_id]);
// Create withdrawal record
$reference = "WDL-" . date('Ymd') . "-" . mt_rand(1000, 9999);
$stmt = $pdo->prepare("INSERT INTO withdrawals (user_id, destination_id, amount, fee, net_amount, status, idempotency_key, reference) VALUES (?, ?, ?, ?, ?, 'pending', ?, ?)");
$stmt->execute([$user_id, $destination_id, $amount, $fee, $net_amount, $idempotency_key, $reference]);
$withdrawal_id = $pdo->lastInsertId();
// Record transaction in ledger
$new_balance = $user['balance'] - $amount;
$stmt = $pdo->prepare("INSERT INTO ledger (user_id, change_amount, balance_after, type, reference, description) VALUES (?, ?, ?, 'withdrawal', ?, ?)");
$stmt->execute([$user_id, -$amount, $new_balance, $withdrawal_id, "Withdrawal request #{$withdrawal_id}"]);
// Commit transaction
$pdo->commit();
// Update session
$_SESSION['balance'] -= $amount;
$_SESSION['total_withdrawals'] += $amount;
echo json_encode([
'success' => true,
'withdrawal_id' => $withdrawal_id,
'reference' => $reference,
'message' => 'Withdrawal request submitted successfully! You will receive a confirmation message shortly.'
]);
} catch (Exception $e) {
$pdo->rollBack();
error_log("Withdrawal error: " . $e->getMessage());
echo json_encode(['success' => false, 'message' => 'Withdrawal failed: ' . $e->getMessage()]);
}
exit;
}
// Get recent withdrawals for this user
$recent_withdrawals = [];
try {
$stmt = $pdo->prepare("
SELECT w.*, wd.details, wd.type
FROM withdrawals w
LEFT JOIN withdrawal_destinations wd ON w.destination_id = wd.id
WHERE w.user_id = ?
ORDER BY w.created_at DESC
LIMIT 5
");
$stmt->execute([$user_id]);
$recent_withdrawals = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (Exception $e) {
error_log("Error fetching recent withdrawals: " . $e->getMessage());
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Japanese Motors — Withdraw Funds</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700;800&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uuid/8.3.2/uuid.min.js"></script>
<style>
:root {
--bg: #7b848d;
--card: #7a2f3b;
--card-2: #6f2630;
--accent: #efdf2d;
--muted: rgba(255,255,255,0.6);
--glass: rgba(255,255,255,0.04);
--promo-gradient: linear-gradient(180deg,#a13df0 0%, #ff2a79 50%, #d70b1a 100%);
font-family: 'Poppins', system-ui, Arial;
--banner-gradient-start: #a855f7;
--banner-gradient-end: #ec4899;
--spacing-unit: 1rem;
--accent-primary: #7c3aed;
--accent-secondary: #a855f7;
--shadow-hover: 0 6px 18px rgba(0, 0, 0, 0.1);
--premium-gold: #d97706;
}
body {
background: var(--bg);
font-family: 'Poppins', sans-serif;
transition: all 0.3s ease;
min-height: 100vh;
}
.sidebar {
width: 250px;
height: 100vh;
background: #0d1321;
color: #fff;
position: fixed;
top: 0;
left: -250px;
transition: all 0.3s ease;
z-index: 1000;
overflow-y: auto;
}
.sidebar.active {
left: 0;
}
#content {
margin-left: 0;
transition: all 0.3s ease;
}
.sidebar.active ~ #content {
margin-left: 250px;
}
header {
background: #222;
color: white;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
z-index: 900;
transition: all 0.3s ease;
}
.sidebar.active ~ #content header {
margin-left: 250px;
}
.menu-toggle {
background: transparent;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
}
.logo-section {
padding: 15px;
border-bottom: 1px solid #1c2230;
display: flex;
align-items: center;
gap: 10px;
}
.brand {
font-size: 1.2rem;
font-weight: 700;
color: #ff9800;
}
.subtitle {
font-size: 0.75rem;
color: #aaa;
}
.menu {
list-style: none;
padding: 0;
margin: 0;
}
.menu li a {
display: flex;
align-items: center;
padding: 12px 20px;
color: white;
text-decoration: none;
transition: background 0.3s;
}
.menu li a:hover {
background: #1c2230;
}
.menu li a i {
margin-right: 12px;
}
.user-footer {
padding: 15px;
background: #222;
display: flex;
align-items: center;
gap: 10px;
position: sticky;
bottom: 0;
}
.avatar {
width: 35px;
height: 35px;
background: #444;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
color: white;
}
.banner {
max-width: 450px;
margin: 0 auto calc(var(--spacing-unit) * 2);
background: linear-gradient(135deg, var(--accent-primary), var(--accent-secondary));
border-radius: 12px;
padding: calc(var(--spacing-unit) * 1.5);
text-align: center;
box-shadow: var(--shadow-hover);
animation: fadeIn 0.5s ease;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0.3; }
100% { opacity: 1; }
}
.banner .title {
font-size: 1.25rem;
margin-bottom: calc(var(--spacing-unit) * 1);
color: #ffffff;
font-weight: 700;
animation: blink 1.5s infinite;
}
.banner p {
font-size: 0.95rem;
line-height: 1.6;
margin-bottom: calc(var(--spacing-unit) * 1);
color: var(--premium-gold);
animation: blink 1.5s infinite;
}
.banner .footer {
font-size: 0.75rem;
color: rgba(255, 255, 255, 0.9);
font-style: italic;
animation: blink 1.5s infinite;
}
.card {
background: var(--card);
border-radius: 12px;
padding: 26px;
color: white;
box-shadow: 0 6px 0 rgba(0,0,0,0.08) inset;
flex: 1;
}
.balance {
background: rgba(255,255,255,0.03);
padding: 14px;
border-radius: 10px;
margin: 18px 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.form-group {
margin: 12px 0;
}
label {
display: block;
margin-bottom: 8px;
color: rgba(255,255,255,0.85);
}
input, select, textarea {
width: 100%;
padding: 14px;
border-radius: 10px;
border: 1px solid rgba(255,255,255,0.05);
background: transparent;
color: white;
}
.btn {
display: inline-block;
padding: 14px 24px;
border-radius: 10px;
background: var(--accent);
color: #111;
font-weight: 700;
border: none;
cursor: pointer;
width: 100%;
}
.btn-outline {
background: transparent;
border: 2px solid var(--accent);
color: var(--accent);
}
.btn-disabled {
background: rgba(255,255,255,0.1);
color: rgba(255,255,255,0.5);
cursor: not-allowed;
}
.dashboard-card {
background: rgba(0,0,0,0.2);
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
}
.stat-card {
background: rgba(0,0,0,0.15);
border-radius: 10px;
padding: 16px;
margin-bottom: 16px;
}
.withdrawal-option {
background: rgba(0,0,0,0.15);
border-radius: 10px;
padding: 16px;
margin-bottom: 16px;
transition: transform 0.3s ease;
cursor: pointer;
border: 2px solid transparent;
}
.withdrawal-option:hover {
transform: translateY(-3px);
}
.withdrawal-option.selected {
border-color: var(--accent);
}
.faq-item {
background: rgba(0,0,0,0.15);
border-radius: 10px;
padding: 16px;
margin-bottom: 16px;
cursor: pointer;
}
.faq-answer {
display: none;
padding-top: 12px;
color: var(--muted);
}
.active-page {
background: #1c2230;
border-right: 4px solid var(--accent);
}
.confirmation-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background: var(--card);
border-radius: 12px;
padding: 30px;
width: 90%;
max-width: 500px;
color: white;
}
.progress-bar {
height: 6px;
background: rgba(255,255,255,0.1);
border-radius: 3px;
overflow: hidden;
margin: 15px 0;
}
.progress-fill {
height: 100%;
background: var(--accent);
width: 0%;
transition: width 0.5s ease;
}
.status-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 600;
}
.status-pending {
background-color: #fef3c7;
color: #92400e;
}
.status-processing {
background-color: #dbeafe;
color: #1e40af;
}
.status-completed {
background-color: #d1fae5;
color: #065f46;
}
.status-failed {
background-color: #fee2e2;
color: #b91c1c;
}
@media (max-width: 768px) {
.cards {
flex-direction: column;
}
.promo {
width: 92%;
}
.grid-cols-2 {
grid-template-columns: 1fr;
}
.grid-cols-3 {
grid-template-columns: 1fr;
}
}
.destination-item {
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
padding: 12px;
margin-bottom: 10px;
cursor: pointer;
transition: all 0.2s ease;
}
.destination-item:hover {
background: rgba(255,255,255,0.05);
}
.destination-item.selected {
border-color: var(--accent);
background: rgba(239, 223, 45, 0.1);
}
.destination-default-badge {
background: var(--accent);
color: #000;
font-size: 0.7rem;
padding: 2px 6px;
border-radius: 4px;
margin-left: 8px;
}
</style>
</head>
<body>
<!-- Sidebar -->
<aside class="sidebar" id="sidebar">
<div class="logo-section">
<i data-feather="zap" class="text-yellow-400"></i>
<div>
<h2 class="brand">JMOTORS</h2>
<p class="subtitle">Marketing Platform</p>
</div>
</div>
<ul class="menu">
<li><a href="index.php"><i data-feather="home"></i> Dashboard</a></li>
<li><a href="meta-uploads.php"><i data-feather="upload"></i> Meta Uploads</a></li>
<li><a href="transactions.php"><i data-feather="repeat"></i> Transactions</a></li>
<li><a href="transfer.php"><i data-feather="send"></i> Transfer</a></li>
<li><a href="daily-product.php"><i data-feather="shopping-bag"></i> Daily Product</a></li>
<li><a href="withdraw.php" class="active-page"><i data-feather="dollar-sign"></i> Withdraw</a></li>
<li><a href="packages.php"><i data-feather="package"></i> Packages</a></li>
<li><a href="loan.php"><i data-feather="credit-card"></i> Loan</a></li>
<li><a href="recharge.php"><i data-feather="battery-charging"></i> Recharge</a></li>
<li><a href="agent-approval.php"><i data-feather="user-check"></i> Agent Approval</a></li>
<li><a href="access-token.php"><i data-feather="key"></i> Access Token</a></li>
<li><a href="agent-claim.php"><i data-feather="tag"></i> Agent Claim</a></li>
<li><a href="team.php"><i data-feather="users"></i> Team</a></li>
</ul>
<ul class="menu bottom">
<li><a href="profile.php"><i data-feather="user"></i> Profile</a></li>
<li><a href="settings.php"><i data-feather="settings"></i> Settings</a></li>
<li><a href="whatsapp-channel.php"><i data-feather="message-square"></i> Whatsapp Channel</a></li>
<li><a href="customer-care.php"><i data-feather="headphones"></i> Customer Care</a></li>
</ul>
<div class="user-footer">
<div class="avatar"><?php echo substr($username, 0, 2); ?></div>
<div>
<h4><?php echo $username; ?></h4>
<p><?php echo $tier; ?> - Marketer</p>
</div>
</div>
</aside>
<!-- Main Content -->
<div id="content">
<header class="bg-gray-800 text-white p-4">
<div class="flex items-center">
<button class="menu-toggle" id="menu-toggle">
<i data-feather="menu"></i>
</button>
<div class="ml-4 font-bold text-xl">Jmotors</div>
</div>
<nav class="flex items-center space-x-6">
<a href="transfer.php" class="hover:text-yellow-300">Transfer</a>
<a href="loan.php" class="hover:text-yellow-300">Loans</a>
<a href="dailyproduct.php" class="hover:text-yellow-300">New Product</a>
<div class="w-9 h-9 rounded-full bg-gradient-to-r from-yellow-300 to-orange-400 flex items-center justify-center font-bold"><?php echo substr($username, 0, 2); ?></div>
</nav>
</header>
<main class="p-4">
<div class="banner">
<div class="title">💵 Withdraw Your Earnings</div>
<p>Transfer your hard-earned money to your preferred payment method</p>
<div class="footer">⚡ Instant processing &nbsp; • &nbsp; Low fees &nbsp; • &nbsp; Secure transactions</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-6">
<div class="dashboard-card md:col-span-2">
<h3 class="text-lg font-bold mb-4 flex items-center gap-2">
<i data-feather="dollar-sign" class="text-green-400"></i> Withdrawal Details
</h3>
<div class="balance">
<div>
<p class="text-sm">Available Balance</p>
<h3 class="text-xl font-bold"><?php echo number_format($available_balance, 2); ?> KES</h3>
</div>
<div class="text-right">
<p class="text-sm">Pending Clearance</p>
<p class="font-bold"><?php echo number_format($pending_withdrawals, 2); ?> KES</p>
</div>
</div>
<form id="withdrawal-form">
<input type="hidden" id="idempotency_key" value="">
<div class="form-group">
<label for="withdrawal-destination">Withdrawal Destination</label>
<div id="destination-list">
<?php if (!empty($destinations)): ?>
<?php foreach ($destinations as $destination): ?>
<div class="destination-item" data-id="<?php echo $destination['id']; ?>">
<div class="flex justify-between items-center">
<div>
<strong><?php echo ucfirst($destination['type']); ?></strong>
<?php if ($destination['is_default']): ?>
<span class="destination-default-badge">Default</span>
<?php endif; ?>
</div>
<i data-feather="check-circle" class="text-green-400 hidden"></i>
</div>
<p class="text-sm mt-1"><?php echo $destination['details']; ?></p>
</div>
<?php endforeach; ?>
<?php else: ?>
<p class="text-gray-400 py-4 text-center">No withdrawal destinations found. <a href="settings.php" class="text-yellow-400 underline">Add one in settings</a>.</p>
<?php endif; ?>
</div>
<input type="hidden" id="destination_id" name="destination_id" required>
</div>
<div class="form-group">
<label for="amount">Amount to Withdraw (KES)</label>
<input type="number" id="amount" name="amount" placeholder="Enter amount" min="100" max="70000" step="0.01" required>
<p class="text-xs text-gray-400 mt-1">Minimum: 100 KES | Maximum: 70,000 KES per day | Fee: 15 KES or 1.5% (whichever is higher)</p>
</div>
<div class="form-group">
<label for="password">Security Password</label>
<input type="password" id="password" name="password" placeholder="Enter your password" required>
</div>
<div class="form-group flex items-center">
<input type="checkbox" id="confirm-cashout" class="w-5 h-5 mr-2">
<label for="confirm-cashout" class="mb-0">I confirm that I want to cash out this amount</label>
</div>
<div class="bg-yellow-400 bg-opacity-20 p-3 rounded-lg mt-4 flex items-start">
<i data-feather="info" class="text-yellow-400 mr-2 mt-1"></i>
<p class="text-sm">Withdrawals are typically processed within 24-72 hours. You'll receive a confirmation message when completed.</p>
</div>
<button type="submit" class="btn mt-4" id="withdraw-btn" disabled>Withdraw Now</button>
</form>
</div>
<div class="dashboard-card">
<h3 class="text-lg font-bold mb-4 flex items-center gap-2">
<i data-feather="clock" class="text-blue-400"></i> Recent Withdrawals
</h3>
<?php if (empty($recent_withdrawals)): ?>
<div class="text-center py-8" id="no-withdrawals">
<i data-feather="dollar-sign" class="mx-auto text-gray-400 text-4xl"></i>
<p class="mt-2 text-gray-400">No recent withdrawals</p>
</div>
<?php else: ?>
<div id="withdrawal-history">
<?php foreach ($recent_withdrawals as $withdrawal): ?>
<div class="stat-card">
<div class="flex justify-between items-center">
<div>
<h4 class="font-bold"><?php echo ucfirst($withdrawal['type']); ?></h4>
<p class="text-sm"><?php echo $withdrawal['details']; ?></p>
</div>
<div class="text-right">
<p class="font-bold"><?php echo number_format($withdrawal['amount'], 2); ?> KES</p>
<span class="status-badge status-<?php echo $withdrawal['status']; ?>">
<?php echo ucfirst($withdrawal['status']); ?>
</span>
</div>
</div>
<p class="text-xs text-gray-400 mt-2">
<?php echo date('M j, Y H:i', strtotime($withdrawal['created_at'])); ?>
| Ref: <?php echo $withdrawal['reference']; ?>
</p>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<a href="transactions.php" class="btn btn-outline mt-4 block text-center">View Full History</a>
<div class="mt-6">
<h4 class="font-bold mb-3 flex items-center gap-2">
<i data-feather="zap" class="text-yellow-400"></i> Quick Cashout
</h4>
<div class="grid grid-cols-2 gap-2">
<button class="bg-gray-700 py-2 rounded-lg text-sm quick-amount" data-amount="500">500 KES</button>
<button class="bg-gray-700 py-2 rounded-lg text-sm quick-amount" data-amount="1000">1,000 KES</button>
<button class="bg-gray-700 py-2 rounded-lg text-sm quick-amount" data-amount="2000">2,000 KES</button>
<button class="bg-gray-700 py-2 rounded-lg text-sm quick-amount" data-amount="5000">5,000 KES</button>
</div>
</div>
</div>
</div>
<div class="dashboard-card mt-8">
<h3 class="text-lg font-bold mb-4 flex items-center gap-2">
<i data-feather="help-circle" class="text-purple-400"></i> Withdrawal Information
</h3>
<div class="faq-item">
<div class="flex justify-between items-center">
<h4 class="font-bold">What are the withdrawal limits?</h4>
<i data-feather="chevron-down" class="faq-toggle"></i>
</div>
<div class="faq-answer">
<p>Minimum withdrawal: 100 KES | Maximum per transaction: 70,000 KES | Daily limit: 70,000 KES | Weekly limit: 140,000 KES. Limits may vary based on your account level and verification status.</p>
</div>
</div>
<div class="faq-item">
<div class="flex justify-between items-center">
<h4 class="font-bold">How long do withdrawals take?</h4>
<i data-feather="chevron-down" class="faq-toggle"></i>
</div>
<div class="faq-answer">
<p>M-Pesa withdrawals are typically processed within 24-72 hours. Bank transfers may take 1-3 business days. Delays can occur during weekends, holidays, or system maintenance.</p>
</div>
</div>
<div class="faq-item">
<div class="flex justify-between items-center">
<h4 class="font-bold">Why was my withdrawal declined?</h4>
<i data-feather="chevron-down" class="faq-toggle"></i>
</div>
<div class="faq-answer">
<p>Withdrawals may be declined due to: insufficient balance, incorrect recipient details, security checks, exceeded limits, or account restrictions. Contact support if you need assistance.</p>
</div>
</div>
</div>
</main>
</div>
<!-- Confirmation Modal -->
<div class="confirmation-modal" id="confirmation-modal">
<div class="modal-content">
<h3 class="text-xl font-bold mb-4 flex items-center gap-2">
<i data-feather="check-circle" class="text-green-400"></i> Confirm Withdrawal
</h3>
<div class="bg-gray-700 p-4 rounded-lg mb-4">
<div class="flex justify-between mb-2">
<span>Amount:</span>
<span class="font-bold" id="confirm-amount">0 KES</span>
</div>
<div class="flex justify-between mb-2">
<span>Fee:</span>
<span class="font-bold" id="confirm-fee">0 KES</span>
</div>
<div class="flex justify-between mb-2">
<span>You'll Receive:</span>
<span class="font-bold" id="confirm-net">0 KES</span>
</div>
<div class="flex justify-between">
<span>To:</span>
<span class="font-bold" id="confirm-destination">Not selected</span>
</div>
</div>
<p class="text-sm mb-4">Your withdrawal will be processed within 24-72 hours. You'll receive a confirmation message when completed.</p>
<div class="progress-bar">
<div class="progress-fill" id="progress-fill"></div>
</div>
<div class="flex gap-3">
<button class="btn btn-outline flex-1" id="cancel-withdrawal">Cancel</button>
<button class="btn flex-1" id="confirm-withdrawal">Confirm</button>
</div>
</div>
</div>
<script>
feather.replace();
document.addEventListener('DOMContentLoaded', function() {
const toggleBtn = document.getElementById('menu-toggle');
const sidebar = document.getElementById('sidebar');
const content = document.getElementById('content');
toggleBtn.addEventListener('click', function() {
sidebar.classList.toggle('active');
content.classList.toggle('active');
});
// Generate idempotency key
document.getElementById('idempotency_key').value = uuid.v4();
// FAQ toggle functionality
const faqItems = document.querySelectorAll('.faq-item');
faqItems.forEach(item => {
item.addEventListener('click', function() {
const answer = this.querySelector('.faq-answer');
const icon = this.querySelector('.faq-toggle');
if (answer.style.display === 'block') {
answer.style.display = 'none';
icon.setAttribute('data-feather', 'chevron-down');
} else {
answer.style.display = 'block';
icon.setAttribute('data-feather', 'chevron-up');
}
feather.replace();
});
});
// Destination selection
const destinationItems = document.querySelectorAll('.destination-item');
const destinationIdInput = document.getElementById('destination_id');
destinationItems.forEach(item => {
item.addEventListener('click', function() {
// Remove selected class from all items
destinationItems.forEach(i => {
i.classList.remove('selected');
i.querySelector('i').classList.add('hidden');
});
// Add selected class to clicked item
this.classList.add('selected');
this.querySelector('i').classList.remove('hidden');
// Set the destination ID
destinationIdInput.value = this.getAttribute('data-id');
checkFormValidity();
});
});
// Select first destination by default if available
if (destinationItems.length > 0) {
destinationItems[0].click();
}
// Quick amount buttons
const quickAmountButtons = document.querySelectorAll('.quick-amount');
const amountInput = document.getElementById('amount');
quickAmountButtons.forEach(button => {
button.addEventListener('click', function() {
amountInput.value = this.getAttribute('data-amount');
checkFormValidity();
});
});
// Form validation and confirmation
const withdrawalForm = document.getElementById('withdrawal-form');
const confirmCheckbox = document.getElementById('confirm-cashout');
const withdrawBtn = document.getElementById('withdraw-btn');
const confirmationModal = document.getElementById('confirmation-modal');
const confirmAmount = document.getElementById('confirm-amount');
const confirmFee = document.getElementById('confirm-fee');
const confirmNet = document.getElementById('confirm-net');
const confirmDestination = document.getElementById('confirm-destination');
const cancelWithdrawal = document.getElementById('cancel-withdrawal');
const confirmWithdrawal = document.getElementById('confirm-withdrawal');
const progressFill = document.getElementById('progress-fill');
function checkFormValidity() {
const amount = parseFloat(amountInput.value) || 0;
const hasDestination = destinationIdInput.value !== '';
const isAmountValid = amount >= 100 && amount <= 70000 && amount <= <?php echo $available_balance; ?>;
if (withdrawalForm.checkValidity() && confirmCheckbox.checked && hasDestination && isAmountValid) {
withdrawBtn.classList.remove('btn-disabled');
withdrawBtn.disabled = false;
} else {
withdrawBtn.classList.add('btn-disabled');
withdrawBtn.disabled = true;
}
}
// Calculate fee
function calculateFee(amount) {
return Math.max(15, amount * 0.015);
}
// Check form validity on input changes
withdrawalForm.addEventListener('input', checkFormValidity);
confirmCheckbox.addEventListener('change', checkFormValidity);
amountInput.addEventListener('input', checkFormValidity);
// Withdrawal form submission
withdrawalForm.addEventListener('submit', function(e) {
e.preventDefault();
const amount = parseFloat(amountInput.value);
const fee = calculateFee(amount);
const netAmount = amount - fee;
const selectedDestination = document.querySelector('.destination-item.selected');
const destinationText = selectedDestination ? selectedDestination.querySelector('strong').textContent + ' - ' + selectedDestination.querySelector('p').textContent : 'Not selected';
// Show confirmation modal with details
confirmAmount.textContent = amount.toFixed(2) + ' KES';
confirmFee.textContent = fee.toFixed(2) + ' KES';
confirmNet.textContent = netAmount.toFixed(2) + ' KES';
confirmDestination.textContent = destinationText;
confirmationModal.style.display = 'flex';
});
// Cancel withdrawal
cancelWithdrawal.addEventListener('click', function() {
confirmationModal.style.display = 'none';
});
// Confirm withdrawal
confirmWithdrawal.addEventListener('click', function() {
const amount = parseFloat(amountInput.value);
const destinationId = destinationIdInput.value;
const idempotencyKey = document.getElementById('idempotency_key').value;
// Disable buttons and show processing state
confirmWithdrawal.disabled = true;
cancelWithdrawal.disabled = true;
confirmWithdrawal.textContent = 'Processing...';
// Simulate processing
let width = 0;
const interval = setInterval(function() {
if (width >= 100) {
clearInterval(interval);
// Send AJAX request
fetch('withdraw.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: amount,
destination_id: destinationId,
idempotency_key: idempotencyKey
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Success message
alert(data.message || 'Withdrawal successful! Your funds will be sent shortly.');
confirmationModal.style.display = 'none';
// Reset form
withdrawalForm.reset();
checkFormValidity();
// Generate new idempotency key for next request
document.getElementById('idempotency_key').value = uuid.v4();
// Reload page to update balances and history
setTimeout(() => {
window.location.reload();
}, 2000);
} else {
alert(data.message || 'Withdrawal failed. Please try again.');
confirmationModal.style.display = 'none';
confirmWithdrawal.disabled = false;
cancelWithdrawal.disabled = false;
confirmWithdrawal.textContent = 'Confirm';
}
})
.catch(error => {
console.error('Error:', error);
alert('An error occurred. Please try again.');
confirmationModal.style.display = 'none';
confirmWithdrawal.disabled = false;
cancelWithdrawal.disabled = false;
confirmWithdrawal.textContent = 'Confirm';
});
} else {
width += 5;
progressFill.style.width = width + '%';
}
}, 50);
});
// Initial check
checkFormValidity();
});
</script>
</body>
</html>