fellybikush's picture
Upload 99 files
0dff816 verified
raw
history blame
50.4 kB
<?php
// Start session and check if user is logged in
session_start();
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
header('Location: ../../index.php');
exit;
}
// Database connection
$host = '127.0.0.1';
$dbname = 'jmdb';
$username = 'root'; // Change as needed
$password = 'YourStrongPassword123'; // Change as needed
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Create tables if they don't exist (including pin_setup table)
$pdo->exec("
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
tier VARCHAR(20) DEFAULT 'Basic',
package VARCHAR(50) DEFAULT 'Starter',
balance DECIMAL(10, 2) DEFAULT 5000.00,
pin_hash VARCHAR(255) DEFAULT NULL,
pin_setup_complete BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS pin_setup (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
pin_hash VARCHAR(255) NOT NULL,
setup_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
sender_id INT NOT NULL,
recipient_id INT NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
message TEXT,
status ENUM('pending', 'completed', 'failed') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP NULL
);
CREATE TABLE IF NOT EXISTS balance_history (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
transaction_id INT NULL,
amount DECIMAL(10, 2) NOT NULL,
balance_before DECIMAL(10, 2) NOT NULL,
balance_after DECIMAL(10, 2) NOT NULL,
type ENUM('transfer_sent', 'transfer_received', 'deposit', 'withdrawal'),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
");
// Check if demo user exists, if not create it
$stmt = $pdo->prepare("SELECT id, pin_setup_complete FROM users WHERE username = ?");
$stmt->execute([$_SESSION['username']]);
$user = $stmt->fetch();
if (!$user) {
$stmt = $pdo->prepare("INSERT INTO users (username, email, tier, package, balance) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([
$_SESSION['username'],
$_SESSION['email'],
$_SESSION['tier'],
$_SESSION['package'],
$_SESSION['balance']
]);
$user_id = $pdo->lastInsertId();
// Set pin_setup_complete to false for new users
$_SESSION['pin_setup_complete'] = false;
} else {
$_SESSION['pin_setup_complete'] = (bool)$user['pin_setup_complete'];
}
} catch (PDOException $e) {
// If database connection fails, continue with session data only
error_log("Database connection failed: " . $e->getMessage());
$pdo = null;
$_SESSION['pin_setup_complete'] = $_SESSION['pin_setup_complete'] ?? false;
}
// 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'];
$pin_setup_complete = $_SESSION['pin_setup_complete'];
$earnings = $total_deposits - $total_withdrawals;
// Process PIN setup if form is submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['setup_pin'])) {
$new_pin = $_POST['new_pin'];
$confirm_pin = $_POST['confirm_pin'];
// Validate PINs
if (strlen($new_pin) !== 4 || !is_numeric($new_pin)) {
$_SESSION['error'] = "PIN must be exactly 4 digits.";
header("Location: transfer.php");
exit;
}
if ($new_pin !== $confirm_pin) {
$_SESSION['error'] = "PINs do not match.";
header("Location: transfer.php");
exit;
}
// Check if PIN is not a simple pattern
if (preg_match('/^(\d)\1{3}$/', $new_pin) ||
preg_match('/^0123|1234|2345|3456|4567|5678|6789|7890$/', $new_pin) ||
preg_match('/^0987|9876|8765|7654|6543|5432|4321|3210$/', $new_pin)) {
$_SESSION['error'] = "Please choose a more secure PIN. Avoid simple patterns.";
header("Location: transfer.php");
exit;
}
if ($pdo) {
try {
// Hash the PIN (in a real application, use password_hash with a proper algorithm)
$pin_hash = password_hash($new_pin, PASSWORD_DEFAULT);
// Update user record with PIN hash and mark setup as complete
$stmt = $pdo->prepare("UPDATE users SET pin_hash = ?, pin_setup_complete = TRUE WHERE username = ?");
$stmt->execute([$pin_hash, $username]);
// Record PIN setup in history
$stmt = $pdo->prepare("INSERT INTO pin_setup (user_id, pin_hash) SELECT id, ? FROM users WHERE username = ?");
$stmt->execute([$pin_hash, $username]);
// Update session
$_SESSION['pin_setup_complete'] = true;
$pin_setup_complete = true;
$_SESSION['success'] = "PIN setup successful! You can now make transfers.";
} catch (Exception $e) {
$_SESSION['error'] = "PIN setup failed: " . $e->getMessage();
}
} else {
// Fallback to session-only processing if database is not available
$_SESSION['pin_hash'] = $new_pin; // In a real app, this would be hashed
$_SESSION['pin_setup_complete'] = true;
$pin_setup_complete = true;
$_SESSION['success'] = "PIN setup successful! You can now make transfers.";
}
header("Location: transfer.php");
exit;
}
// Process transfer if form is submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['transfer'])) {
// Check if PIN is set up
if (!$pin_setup_complete) {
$_SESSION['error'] = "You must set up your security PIN before making transfers.";
header("Location: transfer.php");
exit;
}
$recipient_username = $_POST['recipient'];
$amount = floatval($_POST['amount']);
$pin = $_POST['pin'];
$message = $_POST['message'] ?? '';
// Validate inputs
if (empty($recipient_username) || $amount <= 0 || strlen($pin) !== 4 || !is_numeric($pin)) {
$_SESSION['error'] = "Invalid input data.";
header("Location: transfer.php");
exit;
}
if ($pdo) {
try {
// Begin transaction
$pdo->beginTransaction();
// Get sender info
$stmt = $pdo->prepare("SELECT id, balance, pin_hash FROM users WHERE username = ?");
$stmt->execute([$username]);
$sender = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$sender) {
throw new Exception("Sender not found.");
}
// Verify PIN
if (!password_verify($pin, $sender['pin_hash'])) {
throw new Exception("Invalid PIN.");
}
// Check if sender has sufficient balance
if ($sender['balance'] < $amount) {
throw new Exception("Insufficient balance.");
}
// Get recipient info
$stmt = $pdo->prepare("SELECT id, username, balance FROM users WHERE username = ?");
$stmt->execute([$recipient_username]);
$recipient = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$recipient) {
// Create recipient if they don't exist (for demo purposes)
$stmt = $pdo->prepare("INSERT INTO users (username, email, balance) VALUES (?, ?, ?)");
$stmt->execute([$recipient_username, $recipient_username . '@example.com', 5000.00]);
$recipient_id = $pdo->lastInsertId();
$stmt = $pdo->prepare("SELECT id, username, balance FROM users WHERE id = ?");
$stmt->execute([$recipient_id]);
$recipient = $stmt->fetch(PDO::FETCH_ASSOC);
}
if ($sender['id'] === $recipient['id']) {
throw new Exception("Cannot transfer to yourself.");
}
// Create transaction record
$stmt = $pdo->prepare("INSERT INTO transactions (sender_id, recipient_id, amount, message, status) VALUES (?, ?, ?, ?, 'completed')");
$stmt->execute([$sender['id'], $recipient['id'], $amount, $message]);
$transaction_id = $pdo->lastInsertId();
// Update sender balance
$new_sender_balance = $sender['balance'] - $amount;
$stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?");
$stmt->execute([$new_sender_balance, $sender['id']]);
// Record sender balance change
$stmt = $pdo->prepare("INSERT INTO balance_history (user_id, transaction_id, amount, balance_before, balance_after, type) VALUES (?, ?, ?, ?, ?, 'transfer_sent')");
$stmt->execute([$sender['id'], $transaction_id, -$amount, $sender['balance'], $new_sender_balance]);
// Update recipient balance
$new_recipient_balance = $recipient['balance'] + $amount;
$stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?");
$stmt->execute([$new_recipient_balance, $recipient['id']]);
// Record recipient balance change
$stmt = $pdo->prepare("INSERT INTO balance_history (user_id, transaction_id, amount, balance_before, balance_after, type) VALUES (?, ?, ?, ?, ?, 'transfer_received')");
$stmt->execute([$recipient['id'], $transaction_id, $amount, $recipient['balance'], $new_recipient_balance]);
// Update transaction status to completed
$stmt = $pdo->prepare("UPDATE transactions SET status = 'completed', completed_at = NOW() WHERE id = ?");
$stmt->execute([$transaction_id]);
// Commit transaction
$pdo->commit();
// Update session balance
$_SESSION['balance'] = $new_sender_balance;
$balance = $new_sender_balance;
$_SESSION['success'] = "Transfer of KES " . number_format($amount, 2) . " to @$recipient_username was successful!";
// Store notification in session
if (!isset($_SESSION['notifications'])) {
$_SESSION['notifications'] = [];
}
$_SESSION['notifications'][] = [
'type' => 'transfer_sent',
'to' => $recipient_username,
'amount' => $amount,
'message' => $message,
'timestamp' => time()
];
} catch (Exception $e) {
$pdo->rollBack();
$_SESSION['error'] = "Transfer failed: " . $e->getMessage();
}
} else {
// Fallback to session-only processing if database is not available
if (!$pin_setup_complete || $pin !== ($_SESSION['pin_hash'] ?? '')) {
$_SESSION['error'] = "Invalid PIN or PIN not set up.";
} else if ($amount > $balance) {
$_SESSION['error'] = "Insufficient balance.";
} else {
// Update session balance
$_SESSION['balance'] = $balance - $amount;
$balance = $_SESSION['balance'];
$_SESSION['success'] = "Transfer of KES " . number_format($amount, 2) . " to @$recipient_username was successful!";
// Store transaction in session
if (!isset($_SESSION['transactions'])) {
$_SESSION['transactions'] = [];
}
$_SESSION['transactions'][] = [
'recipient' => $recipient_username,
'amount' => $amount,
'message' => $message,
'timestamp' => time(),
'status' => 'completed'
];
}
}
header("Location: transfer.php");
exit;
}
// Get transaction history
$transactions = [];
if ($pdo) {
try {
$stmt = $pdo->prepare("
SELECT t.*,
sender.username as sender_username,
recipient.username as recipient_username,
CASE
WHEN t.sender_id = u.id THEN 'sent'
ELSE 'received'
END as direction
FROM transactions t
JOIN users sender ON t.sender_id = sender.id
JOIN users recipient ON t.recipient_id = recipient.id
JOIN users u ON (t.sender_id = u.id OR t.recipient_id = u.id)
WHERE u.username = ?
ORDER BY t.created_at DESC LIMIT 10
");
$stmt->execute([$username]);
$transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
error_log("Error fetching transactions: " . $e->getMessage());
}
} else if (isset($_SESSION['transactions'])) {
// Fallback to session transactions
$transactions = $_SESSION['transactions'];
}
// Get current balance from database if available
if ($pdo) {
try {
$stmt = $pdo->prepare("SELECT balance, pin_setup_complete FROM users WHERE username = ?");
$stmt->execute([$username]);
$user_data = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user_data) {
$balance = $user_data['balance'];
$pin_setup_complete = (bool)$user_data['pin_setup_complete'];
$_SESSION['balance'] = $balance;
$_SESSION['pin_setup_complete'] = $pin_setup_complete;
}
} catch (PDOException $e) {
error_log("Error fetching balance: " . $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 — Transfer</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://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<style>
:root {
--bg: #7b848d;
--card: #2f3b7a;
--card-2: #26306f;
--accent: #2ddfef;
--muted: rgba(255,255,255,0.6);
--glass: rgba(255,255,255,0.04);
--promo-gradient: linear-gradient(180deg,#3da1f0 0%, #2a8bff 50%, #0b5dd7 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 styles */
.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 shift when sidebar opens */
#content {
margin-left: 0;
transition: all 0.3s ease;
}
.sidebar.active ~ #content {
margin-left: 250px;
}
/* Header styles */
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 button */
.menu-toggle {
background: transparent;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
}
/* Logo section */
.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: #2ddfef;
}
.subtitle {
font-size: 0.75rem;
color: #aaa;
}
/* Menu styles */
.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 */
.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 styles */
.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 styles */
.form-group {
margin: 12px 0;
}
label {
display: block;
margin-bottom: 8px;
color: rgba(255,255,255,0.85);
}
input, select {
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%;
}
/* History section */
.history-inner {
background: rgba(255,255,255,0.03);
padding: 24px;
border-radius: 10px;
margin-top: 14px;
max-height: 400px;
overflow-y: auto;
}
.muted {
color: rgba(255,255,255,0.6);
}
.transaction-item {
padding: 12px;
border-bottom: 1px solid rgba(255,255,255,0.1);
margin-bottom: 8px;
}
.transaction-item:last-child {
border-bottom: none;
margin-bottom: 0;
}
/* Notification styles */
.notification {
animation: slideIn 0.5s ease;
}
@keyframes slideIn {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* PIN Setup Modal */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
animation: fadeIn 0.3s ease;
}
.modal {
background: var(--card);
border-radius: 12px;
padding: 30px;
width: 90%;
max-width: 450px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
animation: slideUp 0.4s ease;
}
@keyframes slideUp {
from { transform: translateY(30px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.modal-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}
.modal-title {
font-size: 1.5rem;
font-weight: 700;
}
.pin-input-container {
display: flex;
justify-content: space-between;
margin: 20px 0;
}
.pin-input {
width: 50px;
height: 60px;
text-align: center;
font-size: 1.5rem;
border: 2px solid rgba(255, 255, 255, 0.1);
border-radius: 8px;
background: rgba(255, 255, 255, 0.05);
color: white;
transition: all 0.2s;
}
.pin-input:focus {
border-color: var(--accent);
outline: none;
background: rgba(255, 255, 255, 0.1);
}
.security-tips {
background: rgba(255, 255, 255, 0.05);
padding: 15px;
border-radius: 8px;
margin: 15px 0;
font-size: 0.85rem;
}
.security-tips ul {
padding-left: 20px;
margin: 10px 0;
}
.security-tips li {
margin-bottom: 5px;
}
/* Responsive styles */
@media (max-width: 768px) {
.cards {
flex-direction: column;
}
.promo {
width: 92%;
}
.pin-input-container {
justify-content: space-around;
}
.pin-input {
width: 45px;
height: 55px;
}
}
</style>
</head>
<body>
<!-- Sidebar -->
<aside class="sidebar" id="sidebar">
<div class="logo-section">
<i data-feather="zap" class="text-cyan-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"><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" class="active-page"><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-cyan-300">Transfer</a>
<a href="loan.php" class="hover:text-cyan-300">Loans</a>
<a href="dailyproduct.php" class="hover:text-cyan-300">New Product</a>
<div class="w-9 h-9 rounded-full bg-gradient-to-r from-cyan-300 to-blue-400 flex items-center justify-center font-bold"><?php echo substr($username, 0, 2); ?></div>
</nav>
</header>
<main class="p-4">
<!-- Notifications -->
<?php if (isset($_SESSION['error'])): ?>
<div class="bg-red-500 text-white p-3 rounded mb-4 notification">
<?php echo $_SESSION['error']; unset($_SESSION['error']); ?>
</div>
<?php endif; ?>
<?php if (isset($_SESSION['success'])): ?>
<div class="bg-green-500 text-white p-3 rounded mb-4 notification">
<?php echo $_SESSION['success']; unset($_SESSION['success']); ?>
</div>
<?php endif; ?>
<div class="banner">
<div class="title">🚀 Instant Transfers! Only at Jmotors</div>
<p>Send money to <strong>any MetaWave user</strong> instantly with <strong>zero fees</strong> ...</p>
<div class="footer">💸 Instant transfers &nbsp; • &nbsp; Powered by Jmotors</div>
</div>
<div class="flex flex-col md:flex-row gap-6 mt-6">
<!-- Left Card -->
<div class="card">
<div class="flex items-center gap-3">
<div class="w-11 h-11 rounded-lg bg-gray-800 bg-opacity-30 flex items-center justify-center text-2xl">💸</div>
<div>
<h3 class="text-2xl font-bold">Send Money</h3>
<small class="text-gray-300">Transfer to another Jmotors user</small>
</div>
</div>
<div class="balance">
<div class="flex items-center gap-2">
<i data-feather="shield" class="text-gray-400"></i>
<span>Available Balance:</span>
</div>
<div class="font-bold text-cyan-400"><?php echo number_format($balance, 2); ?> KES</div>
</div>
<?php if (!$pin_setup_complete): ?>
<div class="bg-yellow-600 bg-opacity-30 p-4 rounded-lg mb-4">
<div class="flex items-center gap-2 mb-2">
<i data-feather="alert-triangle" class="text-yellow-300"></i>
<span class="font-bold">Security PIN Required</span>
</div>
<p class="text-sm">You need to set up a security PIN before making transfers.</p>
<button id="setup-pin-btn" class="btn mt-3 bg-yellow-500 hover:bg-yellow-400 text-gray-900">Set Up PIN Now</button>
</div>
<?php endif; ?>
<form id="transfer-form" method="POST" <?php echo !$pin_setup_complete ? 'style="opacity: 0.5; pointer-events: none;"' : ''; ?>>
<input type="hidden" name="transfer" value="1">
<div class="form-group">
<label>Recipient Username</label>
<input id="recipient" name="recipient" type="text" placeholder="Enter recipient username" class="bg-gray-800 bg-opacity-30" required>
</div>
<div class="form-group">
<label>Amount (KES)</label>
<input id="amount" name="amount" type="number" placeholder="Enter amount" min="1" step="0.01" class="bg-gray-800 bg-opacity-30" required>
</div>
<div class="form-group">
<label>Security PIN</label>
<input id="pin" name="pin" type="password" placeholder="Enter your 4-digit PIN" maxlength="4" pattern="\d{4}" class="bg-gray-800 bg-opacity-30" required>
</div>
<div class="form-group">
<label>Message (Optional)</label>
<input id="message" name="message" type="text" placeholder="Add a note" class="bg-gray-800 bg-opacity-30">
</div>
<button type="submit" class="btn mt-4" id="send-btn" <?php echo !$pin_setup_complete ? 'disabled' : ''; ?>>Send Money <i data-feather="arrow-right" class="ml-1"></i></button>
</form>
</div>
<!-- Right Card -->
<div class="card">
<div class="flex items-center gap-3">
<div class="w-11 h-11 rounded-lg bg-gray-800 bg-opacity-30 flex items-center justify-center text-2xl">📜</div>
<div>
<h3 class="text-2xl font-bold">Transfer History</h3>
<small class="text-gray-300">Your recent transfer activity</small>
</div>
</div>
<div class="history-inner">
<?php if (!empty($transactions)): ?>
<div class="space-y-4">
<?php foreach ($transactions as $transaction):
$is_sent = isset($transaction['direction']) ? $transaction['direction'] === 'sent' :
(isset($transaction['recipient']) && $transaction['recipient'] !== $username);
$other_party = $is_sent ?
(isset($transaction['recipient_username']) ? $transaction['recipient_username'] : $transaction['recipient']) :
(isset($transaction['sender_username']) ? $transaction['sender_username'] : 'Unknown');
?>
<div class="transaction-item">
<div class="flex justify-between items-center">
<span class="font-medium"><?php echo $is_sent ? 'To: @' . $other_party : 'From: @' . $other_party; ?></span>
<span class="<?php echo $is_sent ? 'text-red-400' : 'text-green-400'; ?> font-bold">
<?php echo ($is_sent ? '-' : '+') . number_format($transaction['amount'], 2); ?> KES
</span>
</div>
<?php if (!empty($transaction['message'])): ?>
<div class="text-sm text-gray-300 mt-1">"<?php echo htmlspecialchars($transaction['message']); ?>"</div>
<?php endif; ?>
<div class="text-xs text-gray-400 mt-2">
<?php echo isset($transaction['created_at']) ? date('M j, Y g:i A', strtotime($transaction['created_at'])) : date('M j, Y g:i A', $transaction['timestamp']); ?>
<span class="ml-2 px-2 py-1 bg-<?php echo (isset($transaction['status']) && $transaction['status'] === 'completed') ? 'green' : 'yellow'; ?>-700 text-white rounded text-xs">
<?php echo isset($transaction['status']) ? ucfirst($transaction['status']) : 'Completed'; ?>
</span>
</div>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="text-center py-8">
<i data-feather="clock" class="text-4xl opacity-85 mx-auto"></i>
<h4 class="my-2 font-bold">No transfers yet</h4>
<div class="muted">Your transfer history will appear here</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<footer class="text-center text-gray-500 text-sm mt-8">
Jmotors Transfer System © <?php echo date('Y'); ?>
</footer>
</main>
</div>
<!-- PIN Setup Modal -->
<?php if (!$pin_setup_complete): ?>
<div class="modal-overlay" id="pin-modal">
<div class="modal">
<div class="modal-header">
<div class="w-11 h-11 rounded-lg bg-gray-800 bg-opacity-30 flex items-center justify-center text-2xl">🔒</div>
<h3 class="modal-title">Set Up Security PIN</h3>
</div>
<p class="muted">Create a 4-digit PIN to secure your transactions</p>
<form id="pin-setup-form" method="POST">
<input type="hidden" name="setup_pin" value="1">
<div class="form-group">
<label>New PIN</label>
<div class="pin-input-container">
<input type="password" class="pin-input" name="pin1" maxlength="1" required autocomplete="off" oninput="moveToNext(this, 'pin2')">
<input type="password" class="pin-input" name="pin2" maxlength="1" required autocomplete="off" oninput="moveToNext(this, 'pin3')">
<input type="password" class="pin-input" name="pin3" maxlength="1" required autocomplete="off" oninput="moveToNext(this, 'pin4')">
<input type="password" class="pin-input" name="pin4" maxlength="1" required autocomplete="off" oninput="moveToNext(this, 'confirm-pin1')">
</div>
</div>
<div class="form-group">
<label>Confirm PIN</label>
<div class="pin-input-container">
<input type="password" class="pin-input" name="confirm-pin1" maxlength="1" required autocomplete="off" oninput="moveToNext(this, 'confirm-pin2')">
<input type="password" class="pin-input" name="confirm-pin2" maxlength="1" required autocomplete="off" oninput="moveToNext(this, 'confirm-pin3')">
<input type="password" class="pin-input" name="confirm-pin3" maxlength="1" required autocomplete="off" oninput="moveToNext(this, 'confirm-pin4')">
<input type="password" class="pin-input" name="confirm-pin4" maxlength="1" required autocomplete="off">
</div>
</div>
<div class="security-tips">
<strong>Security Tips:</strong>
<ul>
<li>Don't use simple patterns like 1234 or 0000</li>
<li>Avoid using your birth year</li>
<li>Don't share your PIN with anyone</li>
<li>Change your PIN regularly for better security</li>
</ul>
</div>
<button type="submit" class="btn">Set Up PIN</button>
</form>
</div>
</div>
<?php endif; ?>
<script>
// Initialize feather icons
feather.replace();
// Sidebar toggle functionality
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');
});
// Show PIN setup modal if button exists
const setupPinBtn = document.getElementById('setup-pin-btn');
if (setupPinBtn) {
setupPinBtn.addEventListener('click', function() {
document.getElementById('pin-modal').style.display = 'flex';
});
}
// PIN setup form validation
const pinSetupForm = document.getElementById('pin-setup-form');
if (pinSetupForm) {
pinSetupForm.addEventListener('submit', function(e) {
// Combine PIN digits
const newPin = document.querySelector('[name="pin1"]').value +
document.querySelector('[name="pin2"]').value +
document.querySelector('[name="pin3"]').value +
document.querySelector('[name="pin4"]').value;
const confirmPin = document.querySelector('[name="confirm-pin1"]').value +
document.querySelector('[name="confirm-pin2"]').value +
document.querySelector('[name="confirm-pin3"]').value +
document.querySelector('[name="confirm-pin4"]').value;
// Create hidden fields for the complete PINs
const newPinInput = document.createElement('input');
newPinInput.type = 'hidden';
newPinInput.name = 'new_pin';
newPinInput.value = newPin;
const confirmPinInput = document.createElement('input');
confirmPinInput.type = 'hidden';
confirmPinInput.name = 'confirm_pin';
confirmPinInput.value = confirmPin;
pinSetupForm.appendChild(newPinInput);
pinSetupForm.appendChild(confirmPinInput);
});
}
// Transfer form validation
const transferForm = document.getElementById('transfer-form');
if (transferForm) {
transferForm.addEventListener('submit', function(e) {
const recipient = document.getElementById('recipient').value.trim();
const amount = document.getElementById('amount').value;
const pin = document.getElementById('pin').value.trim();
if(!recipient) {
e.preventDefault();
alert('Please enter recipient username.');
return;
}
if(!amount || Number(amount) <= 0) {
e.preventDefault();
alert('Enter a valid amount.');
return;
}
if(pin.length !== 4 || !/^\d+$/.test(pin)) {
e.preventDefault();
alert('Enter a valid 4-digit PIN.');
return;
}
// Show loading state
const btn = document.getElementById('send-btn');
btn.disabled = true;
btn.innerHTML = 'Processing... <i data-feather="loader" class="ml-1 animate-spin"></i>';
feather.replace();
});
}
// Simulate real-time notifications and incoming transfers
simulateRealTimeNotifications();
simulateIncomingTransfer();
});
// Helper function to move to next PIN input field
function moveToNext(current, nextFieldId) {
if (current.value.length >= current.maxLength) {
document.getElementsByName(nextFieldId)[0].focus();
}
}
function simulateRealTimeNotifications() {
// Check for new notifications every 30 seconds
setInterval(() => {
// In a real app, you would make an AJAX request to check for new notifications
console.log("Checking for new notifications...");
// Simulate receiving a notification
if (Math.random() > 0.8) { // 20% chance of receiving a fake notification
const fakeNotifications = [
"You received KES 1,500 from @john_doe",
"Your transfer to @sarah_smith was completed",
"New promotion: Send money with zero fees this week!",
"Your balance was updated: KES <?php echo number_format($balance, 2); ?>"
];
const notification = fakeNotifications[Math.floor(Math.random() * fakeNotifications.length)];
// Create a temporary notification banner
const notificationBanner = document.createElement('div');
notificationBanner.className = 'bg-blue-600 text-white p-3 rounded mb-4 animate-pulse notification';
notificationBanner.innerHTML = `
<div class="flex items-center">
<i data-feather="bell" class="mr-2"></i>
<span>${notification}</span>
</div>
`;
// Insert at the top of the main content
const main = document.querySelector('main');
if (main && main.firstChild) {
main.insertBefore(notificationBanner, main.firstChild);
feather.replace();
// Remove after 5 seconds
setTimeout(() => {
notificationBanner.remove();
}, 5000);
}
}
}, 30000);
}
function simulateIncomingTransfer() {
// Only simulate if the page is visible
if (document.hidden) return;
// 5% chance of receiving a fake transfer every minute
if (Math.random() > 0.95) {
const fakeSenders = ['@john_doe', '@sarah_smith', '@mike_jones', '@lisa_ray', '@david_kim'];
const fakeAmounts = [500, 750, 1000, 1250, 1500, 2000];
const fakeMessages = ['For services', 'Loan repayment', 'Gift', 'Thanks for your help', ''];
const sender = fakeSenders[Math.floor(Math.random() * fakeSenders.length)];
const amount = fakeAmounts[Math.floor(Math.random() * fakeAmounts.length)];
const message = fakeMessages[Math.floor(Math.random() * fakeMessages.length)];
// Create notification
const notification = document.createElement('div');
notification.className = 'bg-green-600 text-white p-3 rounded mb-4 notification';
notification.innerHTML = `
<div class="flex items-center">
<i data-feather="dollar-sign" class="mr-2"></i>
<span>You received KES ${amount.toLocaleString()} from ${sender}</span>
</div>
${message ? `<div class="text-sm mt-1">"${message}"</div>` : ''}
`;
// Insert at the top of the main content
const main = document.querySelector('main');
if (main && main.firstChild) {
main.insertBefore(notification, main.firstChild);
feather.replace();
// Remove after 10 seconds
setTimeout(() => {
notification.remove();
}, 10000);
}
// Update balance display (just visually, not in database)
const balanceElement = document.querySelector('.balance .font-bold');
if (balanceElement) {
const currentBalance = parseFloat(balanceElement.textContent.replace('KES', '').replace(/,/g, ''));
const newBalance = currentBalance + amount;
balanceElement.textContent = newBalance.toLocaleString() + ' KES';
// Add to transaction history
const historyElement = document.querySelector('.history-inner');
if (historyElement) {
let transactionsContainer = historyElement.querySelector('.space-y-4');
if (!transactionsContainer) {
historyElement.innerHTML = '<div class="space-y-4"></div>';
transactionsContainer = historyElement.querySelector('.space-y-4');
}
const transactionHtml = `
<div class="transaction-item">
<div class="flex justify-between items-center">
<span class="font-medium">From: ${sender}</span>
<span class="text-green-400 font-bold">+${amount.toLocaleString()} KES</span>
</div>
${message ? `<div class="text-sm text-gray-300 mt-1">"${message}"</div>` : ''}
<div class="text-xs text-gray-400 mt-2">
${new Date().toLocaleString()}
<span class="ml-2 px-2 py-1 bg-green-700 text-white rounded text-xs">Completed</span>
</div>
</div>
`;
transactionsContainer.insertAdjacentHTML('afterbegin', transactionHtml);
}
}
}
// Run the simulation every minute
setTimeout(simulateIncomingTransfer, 60000);
}
</script>
</body>
</html>