|
|
<?php |
|
|
|
|
|
session_start(); |
|
|
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) { |
|
|
header('Location: ../../index.php'); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
$host = '127.0.0.1'; |
|
|
$dbname = 'jmdb'; |
|
|
$username = 'root'; |
|
|
$password = 'YourStrongPassword123'; |
|
|
|
|
|
try { |
|
|
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $username, $password); |
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
|
|
|
|
|
|
|
|
$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 |
|
|
); |
|
|
"); |
|
|
|
|
|
|
|
|
$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(); |
|
|
|
|
|
|
|
|
$_SESSION['pin_setup_complete'] = false; |
|
|
} else { |
|
|
$_SESSION['pin_setup_complete'] = (bool)$user['pin_setup_complete']; |
|
|
} |
|
|
} catch (PDOException $e) { |
|
|
|
|
|
error_log("Database connection failed: " . $e->getMessage()); |
|
|
$pdo = null; |
|
|
$_SESSION['pin_setup_complete'] = $_SESSION['pin_setup_complete'] ?? false; |
|
|
} |
|
|
|
|
|
|
|
|
$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; |
|
|
|
|
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['setup_pin'])) { |
|
|
$new_pin = $_POST['new_pin']; |
|
|
$confirm_pin = $_POST['confirm_pin']; |
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
|
$pin_hash = password_hash($new_pin, PASSWORD_DEFAULT); |
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("UPDATE users SET pin_hash = ?, pin_setup_complete = TRUE WHERE username = ?"); |
|
|
$stmt->execute([$pin_hash, $username]); |
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("INSERT INTO pin_setup (user_id, pin_hash) SELECT id, ? FROM users WHERE username = ?"); |
|
|
$stmt->execute([$pin_hash, $username]); |
|
|
|
|
|
|
|
|
$_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 { |
|
|
|
|
|
$_SESSION['pin_hash'] = $new_pin; |
|
|
$_SESSION['pin_setup_complete'] = true; |
|
|
$pin_setup_complete = true; |
|
|
$_SESSION['success'] = "PIN setup successful! You can now make transfers."; |
|
|
} |
|
|
|
|
|
header("Location: transfer.php"); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['transfer'])) { |
|
|
|
|
|
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'] ?? ''; |
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
|
$pdo->beginTransaction(); |
|
|
|
|
|
|
|
|
$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."); |
|
|
} |
|
|
|
|
|
|
|
|
if (!password_verify($pin, $sender['pin_hash'])) { |
|
|
throw new Exception("Invalid PIN."); |
|
|
} |
|
|
|
|
|
|
|
|
if ($sender['balance'] < $amount) { |
|
|
throw new Exception("Insufficient balance."); |
|
|
} |
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("SELECT id, username, balance FROM users WHERE username = ?"); |
|
|
$stmt->execute([$recipient_username]); |
|
|
$recipient = $stmt->fetch(PDO::FETCH_ASSOC); |
|
|
|
|
|
if (!$recipient) { |
|
|
|
|
|
$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."); |
|
|
} |
|
|
|
|
|
|
|
|
$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(); |
|
|
|
|
|
|
|
|
$new_sender_balance = $sender['balance'] - $amount; |
|
|
$stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?"); |
|
|
$stmt->execute([$new_sender_balance, $sender['id']]); |
|
|
|
|
|
|
|
|
$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]); |
|
|
|
|
|
|
|
|
$new_recipient_balance = $recipient['balance'] + $amount; |
|
|
$stmt = $pdo->prepare("UPDATE users SET balance = ? WHERE id = ?"); |
|
|
$stmt->execute([$new_recipient_balance, $recipient['id']]); |
|
|
|
|
|
|
|
|
$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]); |
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("UPDATE transactions SET status = 'completed', completed_at = NOW() WHERE id = ?"); |
|
|
$stmt->execute([$transaction_id]); |
|
|
|
|
|
|
|
|
$pdo->commit(); |
|
|
|
|
|
|
|
|
$_SESSION['balance'] = $new_sender_balance; |
|
|
$balance = $new_sender_balance; |
|
|
|
|
|
$_SESSION['success'] = "Transfer of KES " . number_format($amount, 2) . " to @$recipient_username was successful!"; |
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
|
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 { |
|
|
|
|
|
$_SESSION['balance'] = $balance - $amount; |
|
|
$balance = $_SESSION['balance']; |
|
|
|
|
|
$_SESSION['success'] = "Transfer of KES " . number_format($amount, 2) . " to @$recipient_username was successful!"; |
|
|
|
|
|
|
|
|
if (!isset($_SESSION['transactions'])) { |
|
|
$_SESSION['transactions'] = []; |
|
|
} |
|
|
|
|
|
$_SESSION['transactions'][] = [ |
|
|
'recipient' => $recipient_username, |
|
|
'amount' => $amount, |
|
|
'message' => $message, |
|
|
'timestamp' => time(), |
|
|
'status' => 'completed' |
|
|
]; |
|
|
} |
|
|
} |
|
|
|
|
|
header("Location: transfer.php"); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
$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'])) { |
|
|
|
|
|
$transactions = $_SESSION['transactions']; |
|
|
} |
|
|
|
|
|
|
|
|
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: |
|
|
--card: |
|
|
--card-2: |
|
|
--accent: |
|
|
--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: |
|
|
--banner-gradient-end: |
|
|
--spacing-unit: 1rem; |
|
|
--accent-primary: |
|
|
--accent-secondary: |
|
|
--shadow-hover: 0 6px 18px rgba(0, 0, 0, 0.1); |
|
|
--premium-gold: |
|
|
} |
|
|
|
|
|
body { |
|
|
background: var(--bg); |
|
|
font-family: 'Poppins', sans-serif; |
|
|
transition: all 0.3s ease; |
|
|
min-height: 100vh; |
|
|
} |
|
|
|
|
|
|
|
|
.sidebar { |
|
|
width: 250px; |
|
|
height: 100vh; |
|
|
background: |
|
|
color: |
|
|
position: fixed; |
|
|
top: 0; |
|
|
left: -250px; |
|
|
transition: all 0.3s ease; |
|
|
z-index: 1000; |
|
|
overflow-y: auto; |
|
|
} |
|
|
|
|
|
.sidebar.active { |
|
|
left: 0; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
margin-left: 0; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.sidebar.active ~ |
|
|
margin-left: 250px; |
|
|
} |
|
|
|
|
|
|
|
|
header { |
|
|
background: |
|
|
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 ~ |
|
|
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 |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 10px; |
|
|
} |
|
|
|
|
|
.brand { |
|
|
font-size: 1.2rem; |
|
|
font-weight: 700; |
|
|
color: |
|
|
} |
|
|
|
|
|
.subtitle { |
|
|
font-size: 0.75rem; |
|
|
color: |
|
|
} |
|
|
|
|
|
|
|
|
.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: |
|
|
} |
|
|
|
|
|
.menu li a i { |
|
|
margin-right: 12px; |
|
|
} |
|
|
|
|
|
|
|
|
.user-footer { |
|
|
padding: 15px; |
|
|
background: |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 10px; |
|
|
position: sticky; |
|
|
bottom: 0; |
|
|
} |
|
|
|
|
|
.avatar { |
|
|
width: 35px; |
|
|
height: 35px; |
|
|
background: |
|
|
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: |
|
|
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 { |
|
|
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: |
|
|
font-weight: 700; |
|
|
border: none; |
|
|
cursor: pointer; |
|
|
width: 100%; |
|
|
} |
|
|
|
|
|
|
|
|
.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 { |
|
|
animation: slideIn 0.5s ease; |
|
|
} |
|
|
|
|
|
@keyframes slideIn { |
|
|
from { transform: translateY(-20px); opacity: 0; } |
|
|
to { transform: translateY(0); opacity: 1; } |
|
|
} |
|
|
|
|
|
|
|
|
.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; |
|
|
} |
|
|
|
|
|
|
|
|
@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 • 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> |