|
|
<?php |
|
|
ini_set('display_errors', 1); |
|
|
ini_set('display_startup_errors', 1); |
|
|
error_reporting(E_ALL); |
|
|
|
|
|
session_start(); |
|
|
|
|
|
|
|
|
$host = '127.0.0.1'; |
|
|
$dbname = 'jmdb'; |
|
|
$username = 'root'; |
|
|
$password = 'YourStrongPassword123'; |
|
|
|
|
|
try { |
|
|
$pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password); |
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
|
|
} catch(PDOException $e) { |
|
|
die("Database connection failed: " . $e->getMessage()); |
|
|
} |
|
|
|
|
|
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) { |
|
|
header('Location: ../../index.php'); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
if (!isset($_SESSION['user_id']) && isset($_SESSION['username'])) { |
|
|
$stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?"); |
|
|
$stmt->execute([$_SESSION['username']]); |
|
|
$user = $stmt->fetch(PDO::FETCH_ASSOC); |
|
|
if ($user) { |
|
|
$_SESSION['user_id'] = $user['id']; |
|
|
} |
|
|
} |
|
|
|
|
|
if (!isset($_SESSION['user_id'])) { |
|
|
header('Location: ../../index.php'); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); |
|
|
$stmt->execute([$_SESSION['user_id']]); |
|
|
$user = $stmt->fetch(PDO::FETCH_ASSOC); |
|
|
|
|
|
if (!$user) { |
|
|
session_destroy(); |
|
|
header('Location: ../../index.php'); |
|
|
exit; |
|
|
} |
|
|
|
|
|
|
|
|
$username = $user['username'] ?? $_SESSION['username']; |
|
|
$email = $user['email'] ?? $_SESSION['email']; |
|
|
$tier = $user['tier'] ?? $_SESSION['tier']; |
|
|
$package = $user['package'] ?? $_SESSION['package']; |
|
|
$balance = $user['balance'] ?? $_SESSION['balance']; |
|
|
$total_deposits = $user['total_deposits'] ?? $_SESSION['total_deposits']; |
|
|
$total_withdrawals = $user['total_withdrawals'] ?? $_SESSION['total_withdrawals']; |
|
|
$rewards = $user['rewards'] ?? $_SESSION['rewards']; |
|
|
|
|
|
|
|
|
$first_name = $user['first_name'] ?? 'Maha'; |
|
|
$last_name = $user['last_name'] ?? 'Ibrahim'; |
|
|
$phone_number = $user['phone_number'] ?? '254712345678'; |
|
|
$country_code = $user['country_code'] ?? 'KE'; |
|
|
$status = $user['status'] ?? 'Dormant'; |
|
|
$member_since = $user['member_since'] ?? '2023-01-15'; |
|
|
|
|
|
|
|
|
$member_since_formatted = date('d M Y', strtotime($member_since)); |
|
|
$earnings = $total_deposits - $total_withdrawals; |
|
|
|
|
|
|
|
|
$_SESSION['username'] = $username; |
|
|
$_SESSION['email'] = $email; |
|
|
$_SESSION['tier'] = $tier; |
|
|
$_SESSION['package'] = $package; |
|
|
$_SESSION['balance'] = $balance; |
|
|
$_SESSION['total_deposits'] = $total_deposits; |
|
|
$_SESSION['total_withdrawals'] = $total_withdrawals; |
|
|
$_SESSION['rewards'] = $rewards; |
|
|
?> |
|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Profile | Japanese Motors</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> |
|
|
<style> |
|
|
:root { |
|
|
--bg: |
|
|
--card: |
|
|
--card-2: |
|
|
--accent: |
|
|
--muted: rgba(255,255,255,0.6); |
|
|
font-family: 'Poppins', system-ui, Arial; |
|
|
} |
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
.card { |
|
|
background: var(--card); |
|
|
border-radius: 12px; |
|
|
padding: 26px; |
|
|
color: white; |
|
|
box-shadow: 0 6px 0 rgba(0,0,0,0.08) inset; |
|
|
display: none; |
|
|
} |
|
|
|
|
|
.card.active { |
|
|
display: block; |
|
|
} |
|
|
|
|
|
.profile-avatar { |
|
|
width: 100px; |
|
|
height: 100px; |
|
|
border-radius: 50%; |
|
|
background: |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
margin: 0 auto; |
|
|
font-size: 2rem; |
|
|
font-weight: bold; |
|
|
} |
|
|
|
|
|
.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%; |
|
|
} |
|
|
|
|
|
.btn-outline { |
|
|
background: transparent; |
|
|
border: 1px solid var(--accent); |
|
|
color: var(--accent); |
|
|
} |
|
|
|
|
|
.tab { |
|
|
padding: 10px 20px; |
|
|
border-bottom: 2px solid transparent; |
|
|
cursor: pointer; |
|
|
} |
|
|
|
|
|
.tab.active { |
|
|
border-bottom: 2px solid var(--accent); |
|
|
color: var(--accent); |
|
|
} |
|
|
|
|
|
.notification { |
|
|
position: fixed; |
|
|
top: 20px; |
|
|
right: 20px; |
|
|
padding: 15px 20px; |
|
|
border-radius: 8px; |
|
|
color: white; |
|
|
z-index: 10000; |
|
|
animation: slideIn 0.3s ease; |
|
|
} |
|
|
|
|
|
.notification.success { background: |
|
|
.notification.error { background: |
|
|
.notification.info { background: |
|
|
|
|
|
.activity-item { |
|
|
padding: 15px; |
|
|
border-bottom: 1px solid rgba(255,255,255,0.1); |
|
|
display: flex; |
|
|
align-items: center; |
|
|
} |
|
|
|
|
|
.activity-item:last-child { |
|
|
border-bottom: none; |
|
|
} |
|
|
|
|
|
.activity-icon { |
|
|
width: 40px; |
|
|
height: 40px; |
|
|
border-radius: 50%; |
|
|
background: rgba(255,255,255,0.1); |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
margin-right: 15px; |
|
|
} |
|
|
|
|
|
@keyframes slideIn { |
|
|
from { transform: translateX(100%); opacity: 0; } |
|
|
to { transform: translateX(0); opacity: 1; } |
|
|
} |
|
|
|
|
|
.loading { |
|
|
opacity: 0.6; |
|
|
pointer-events: none; |
|
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
|
.tabs { |
|
|
flex-direction: column; |
|
|
} |
|
|
} |
|
|
</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"><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" class="active-page"><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 htmlspecialchars($username); ?></h4> |
|
|
<p><?php echo htmlspecialchars($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($first_name, 0, 1) . substr($last_name, 0, 1); ?> |
|
|
</div> |
|
|
</nav> |
|
|
</header> |
|
|
|
|
|
<main class="p-4"> |
|
|
<div class="max-w-3xl mx-auto"> |
|
|
<div class="card mb-6 active"> |
|
|
<div class="flex flex-col md:flex-row items-center gap-6"> |
|
|
<div class="profile-avatar"><?php echo substr($first_name, 0, 1) . substr($last_name, 0, 1); ?></div> |
|
|
<div class="text-center md:text-left"> |
|
|
<h2 class="text-2xl font-bold"><?php echo htmlspecialchars($first_name . ' ' . $last_name); ?></h2> |
|
|
<p class="text-gray-300"><?php echo htmlspecialchars($status); ?> Marketer</p> |
|
|
<p class="text-sm mt-2">Member since: <?php echo $member_since_formatted; ?></p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="flex tabs border-b border-gray-700 mb-6"> |
|
|
<div class="tab active" data-tab="personal">Personal Info</div> |
|
|
<div class="tab" data-tab="security">Security</div> |
|
|
<div class="tab" data-tab="activity">Activity</div> |
|
|
</div> |
|
|
|
|
|
<!-- Personal Info Tab --> |
|
|
<div class="card active" id="personal-tab"> |
|
|
<h3 class="text-lg font-bold mb-6">Personal Information</h3> |
|
|
|
|
|
<form id="profileForm"> |
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
|
<div class="form-group"> |
|
|
<label>First Name</label> |
|
|
<input type="text" name="first_name" value="<?php echo htmlspecialchars($first_name); ?>" id="first_name"> |
|
|
</div> |
|
|
<div class="form-group"> |
|
|
<label>Last Name</label> |
|
|
<input type="text" name="last_name" value="<?php echo htmlspecialchars($last_name); ?>" id="last_name"> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label>Email Address</label> |
|
|
<input type="email" name="email" value="<?php echo htmlspecialchars($email); ?>" id="email"> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label>Phone Number</label> |
|
|
<input type="tel" name="phone_number" value="<?php echo htmlspecialchars($phone_number); ?>" id="phone_number"> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label>Country</label> |
|
|
<select name="country_code" id="country" required> |
|
|
<option value="">Select your country</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
<div class="flex gap-4 mt-6"> |
|
|
<button type="submit" class="btn" id="saveBtn">Save Changes</button> |
|
|
<button type="button" class="btn btn-outline" id="cancelBtn">Cancel</button> |
|
|
</div> |
|
|
</form> |
|
|
</div> |
|
|
|
|
|
<!-- Security Tab --> |
|
|
<div class="card" id="security-tab"> |
|
|
<h3 class="text-lg font-bold mb-6">Security Settings</h3> |
|
|
|
|
|
<form id="securityForm"> |
|
|
<div class="form-group"> |
|
|
<label>Current Password</label> |
|
|
<input type="password" name="current_password" id="current_password" required> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label>New Password</label> |
|
|
<input type="password" name="new_password" id="new_password" required minlength="6"> |
|
|
</div> |
|
|
|
|
|
<div class="form-group"> |
|
|
<label>Confirm New Password</label> |
|
|
<input type="password" name="confirm_password" id="confirm_password" required minlength="6"> |
|
|
</div> |
|
|
|
|
|
<div class="flex gap-4 mt-6"> |
|
|
<button type="submit" class="btn" id="changePasswordBtn">Change Password</button> |
|
|
</div> |
|
|
</form> |
|
|
|
|
|
<div class="mt-8 pt-6 border-t border-gray-700"> |
|
|
<h4 class="text-md font-bold mb-4">Security Recommendations</h4> |
|
|
<ul class="space-y-2 text-sm text-gray-300"> |
|
|
<li>• Use a strong, unique password</li> |
|
|
<li>• Enable two-factor authentication if available</li> |
|
|
<li>• Regularly update your password</li> |
|
|
<li>• Never share your password with anyone</li> |
|
|
</ul> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<!-- Activity Tab --> |
|
|
<div class="card" id="activity-tab"> |
|
|
<h3 class="text-lg font-bold mb-6">Recent Activity</h3> |
|
|
|
|
|
<div id="activityList" class="space-y-4"> |
|
|
<div class="text-center py-8 text-gray-400"> |
|
|
<i data-feather="activity" class="w-12 h-12 mx-auto mb-4"></i> |
|
|
<p>Loading activity history...</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mt-6 text-center"> |
|
|
<button class="btn btn-outline" id="loadMoreActivity">Load More</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</main> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
feather.replace(); |
|
|
|
|
|
// Countries data |
|
|
const countries = [ |
|
|
{ name: "Afghanistan", dial_code: "+93", code: "AF" }, |
|
|
{ name: "Albania", dial_code: "+355", code: "AL" }, |
|
|
{ name: "Algeria", dial_code: "+213", code: "DZ" }, |
|
|
{ name: "Andorra", dial_code: "+376", code: "AD" }, |
|
|
{ name: "Angola", dial_code: "+244", code: "AO" }, |
|
|
{ name: "Antigua and Barbuda", dial_code: "+1-268", code: "AG" }, |
|
|
{ name: "Argentina", dial_code: "+54", code: "AR" }, |
|
|
{ name: "Armenia", dial_code: "+374", code: "AM" }, |
|
|
{ name: "Australia", dial_code: "+61", code: "AU" }, |
|
|
{ name: "Austria", dial_code: "+43", code: "AT" }, |
|
|
{ name: "Azerbaijan", dial_code: "+994", code: "AZ" }, |
|
|
{ name: "Bahamas", dial_code: "+1-242", code: "BS" }, |
|
|
{ name: "Bahrain", dial_code: "+973", code: "BH" }, |
|
|
{ name: "Bangladesh", dial_code: "+880", code: "BD" }, |
|
|
{ name: "Barbados", dial_code: "+1-246", code: "BB" }, |
|
|
{ name: "Belarus", dial_code: "+375", code: "BY" }, |
|
|
{ name: "Belgium", dial_code: "+32", code: "BE" }, |
|
|
{ name: "Belize", dial_code: "+501", code: "BZ" }, |
|
|
{ name: "Benin", dial_code: "+229", code: "BJ" }, |
|
|
{ name: "Bhutan", dial_code: "+975", code: "BT" }, |
|
|
{ name: "Bolivia", dial_code: "+591", code: "BO" }, |
|
|
{ name: "Bosnia and Herzegovina", dial_code: "+387", code: "BA" }, |
|
|
{ name: "Botswana", dial_code: "+267", code: "BW" }, |
|
|
{ name: "Brazil", dial_code: "+55", code: "BR" }, |
|
|
{ name: "Brunei", dial_code: "+673", code: "BN" }, |
|
|
{ name: "Bulgaria", dial_code: "+359", code: "BG" }, |
|
|
{ name: "Burkina Faso", dial_code: "+226", code: "BF" }, |
|
|
{ name: "Burundi", dial_code: "+257", code: "BI" }, |
|
|
{ name: "Cabo Verde", dial_code: "+238", code: "CV" }, |
|
|
{ name: "Cambodia", dial_code: "+855", code: "KH" }, |
|
|
{ name: "Cameroon", dial_code: "+237", code: "CM" }, |
|
|
{ name: "Canada", dial_code: "+1", code: "CA" }, |
|
|
{ name: "Central African Republic", dial_code: "+236", code: "CF" }, |
|
|
{ name: "Chad", dial_code: "+235", code: "TD" }, |
|
|
{ name: "Chile", dial_code: "+56", code: "CL" }, |
|
|
{ name: "China", dial_code: "+86", code: "CN" }, |
|
|
{ name: "Colombia", dial_code: "+57", code: "CO" }, |
|
|
{ name: "Comoros", dial_code: "+269", code: "KM" }, |
|
|
{ name: "Congo (Brazzaville)", dial_code: "+242", code: "CG" }, |
|
|
{ name: "Congo (Kinshasa)", dial_code: "+243", code: "CD" }, |
|
|
{ name: "Costa Rica", dial_code: "+506", code: "CR" }, |
|
|
{ name: "Croatia", dial_code: "+385", code: "HR" }, |
|
|
{ name: "Cuba", dial_code: "+53", code: "CU" }, |
|
|
{ name: "Cyprus", dial_code: "+357", code: "CY" }, |
|
|
{ name: "Czechia", dial_code: "+420", code: "CZ" }, |
|
|
{ name: "Denmark", dial_code: "+45", code: "DK" }, |
|
|
{ name: "Djibouti", dial_code: "+253", code: "DJ" }, |
|
|
{ name: "Dominica", dial_code: "+1-767", code: "DM" }, |
|
|
{ name: "Dominican Republic", dial_code: "+1-809", code: "DO" }, |
|
|
{ name: "Ecuador", dial_code: "+593", code: "EC" }, |
|
|
{ name: "Egypt", dial_code: "+20", code: "EG" }, |
|
|
{ name: "El Salvador", dial_code: "+503", code: "SV" }, |
|
|
{ name: "Equatorial Guinea", dial_code: "+240", code: "GQ" }, |
|
|
{ name: "Eritrea", dial_code: "+291", code: "ER" }, |
|
|
{ name: "Estonia", dial_code: "+372", code: "EE" }, |
|
|
{ name: "Eswatini", dial_code: "+268", code: "SZ" }, |
|
|
{ name: "Ethiopia", dial_code: "+251", code: "ET" }, |
|
|
{ name: "Fiji", dial_code: "+679", code: "FJ" }, |
|
|
{ name: "Finland", dial_code: "+358", code: "FI" }, |
|
|
{ name: "France", dial_code: "+33", code: "FR" }, |
|
|
{ name: "Gabon", dial_code: "+241", code: "GA" }, |
|
|
{ name: "Gambia", dial_code: "+220", code: "GM" }, |
|
|
{ name: "Georgia", dial_code: "+995", code: "GE" }, |
|
|
{ name: "Germany", dial_code: "+49", code: "DE" }, |
|
|
{ name: "Ghana", dial_code: "+233", code: "GH" }, |
|
|
{ name: "Greece", dial_code: "+30", code: "GR" }, |
|
|
{ name: "Grenada", dial_code: "+1-473", code: "GD" }, |
|
|
{ name: "Guatemala", dial_code: "+502", code: "GT" }, |
|
|
{ name: "Guinea", dial_code: "+224", code: "GN" }, |
|
|
{ name: "Guinea-Bissau", dial_code: "+245", code: "GW" }, |
|
|
{ name: "Guyana", dial_code: "+592", code: "GY" }, |
|
|
{ name: "Haiti", dial_code: "+509", code: "HT" }, |
|
|
{ name: "Honduras", dial_code: "+504", code: "HN" }, |
|
|
{ name: "Hungary", dial_code: "+36", code: "HU" }, |
|
|
{ name: "Iceland", dial_code: "+354", code: "IS" }, |
|
|
{ name: "India", dial_code: "+91", code: "IN" }, |
|
|
{ name: "Indonesia", dial_code: "+62", code: "ID" }, |
|
|
{ name: "Iran", dial_code: "+98", code: "IR" }, |
|
|
{ name: "Iraq", dial_code: "+964", code: "IQ" }, |
|
|
{ name: "Ireland", dial_code: "+353", code: "IE" }, |
|
|
{ name: "Israel", dial_code: "+972", code: "IL" }, |
|
|
{ name: "Italy", dial_code: "+39", code: "IT" }, |
|
|
{ name: "Jamaica", dial_code: "+1-876", code: "JM" }, |
|
|
{ name: "Japan", dial_code: "+81", code: "JP" }, |
|
|
{ name: "Jordan", dial_code: "+962", code: "JO" }, |
|
|
{ name: "Kazakhstan", dial_code: "+7", code: "KZ" }, |
|
|
{ name: "Kenya", dial_code: "+254", code: "KE" }, |
|
|
{ name: "Kiribati", dial_code: "+686", code: "KI" }, |
|
|
{ name: "Kuwait", dial_code: "+965", code: "KW" }, |
|
|
{ name: "Kyrgyzstan", dial_code: "+996", code: "KG" }, |
|
|
{ name: "Laos", dial_code: "+856", code: "LA" }, |
|
|
{ name: "Latvia", dial_code: "+371", code: "LV" }, |
|
|
{ name: "Lebanon", dial_code: "+961", code: "LB" }, |
|
|
{ name: "Lesotho", dial_code: "+266", code: "LS" }, |
|
|
{ name: "Liberia", dial_code: "+231", code: "LR" }, |
|
|
{ name: "Libya", dial_code: "+218", code: "LY" }, |
|
|
{ name: "Liechtenstein", dial_code: "+423", code: "LI" }, |
|
|
{ name: "Lithuania", dial_code: "+370", code: "LT" }, |
|
|
{ name: "Luxembourg", dial_code: "+352", code: "LU" }, |
|
|
{ name: "Madagascar", dial_code: "+261", code: "MG" }, |
|
|
{ name: "Malawi", dial_code: "+265", code: "MW" }, |
|
|
{ name: "Malaysia", dial_code: "+60", code: "MY" }, |
|
|
{ name: "Maldives", dial_code: "+960", code: "MV" }, |
|
|
{ name: "Mali", dial_code: "+223", code: "ML" }, |
|
|
{ name: "Malta", dial_code: "+356", code: "MT" }, |
|
|
{ name: "Marshall Islands", dial_code: "+692", code: "MH" }, |
|
|
{ name: "Mauritania", dial_code: "+222", code: "MR" }, |
|
|
{ name: "Mauritius", dial_code: "+230", code: "MU" }, |
|
|
{ name: "Mexico", dial_code: "+52", code: "MX" }, |
|
|
{ name: "Micronesia", dial_code: "+691", code: "FM" }, |
|
|
{ name: "Moldova", dial_code: "+373", code: "MD" }, |
|
|
{ name: "Monaco", dial_code: "+377", code: "MC" }, |
|
|
{ name: "Mongolia", dial_code: "+976", code: "MN" }, |
|
|
{ name: "Montenegro", dial_code: "+382", code: "ME" }, |
|
|
{ name: "Morocco", dial_code: "+212", code: "MA" }, |
|
|
{ name: "Mozambique", dial_code: "+258", code: "MZ" }, |
|
|
{ name: "Myanmar", dial_code: "+95", code: "MM" }, |
|
|
{ name: "Namibia", dial_code: "+264", code: "NA" }, |
|
|
{ name: "Nauru", dial_code: "+674", code: "NR" }, |
|
|
{ name: "Nepal", dial_code: "+977", code: "NP" }, |
|
|
{ name: "Netherlands", dial_code: "+31", code: "NL" }, |
|
|
{ name: "New Zealand", dial_code: "+64", code: "NZ" }, |
|
|
{ name: "Nicaragua", dial_code: "+505", code: "NI" }, |
|
|
{ name: "Niger", dial_code: "+227", code: "NE" }, |
|
|
{ name: "Nigeria", dial_code: "+234", code: "NG" }, |
|
|
{ name: "North Korea", dial_code: "+850", code: "KP" }, |
|
|
{ name: "North Macedonia", dial_code: "+389", code: "MK" }, |
|
|
{ name: "Norway", dial_code: "+47", code: "NO" }, |
|
|
{ name: "Oman", dial_code: "+968", code: "OM" }, |
|
|
{ name: "Pakistan", dial_code: "+92", code: "PK" }, |
|
|
{ name: "Palau", dial_code: "+680", code: "PW" }, |
|
|
{ name: "Palestine", dial_code: "+970", code: "PS" }, |
|
|
{ name: "Panama", dial_code: "+507", code: "PA" }, |
|
|
{ name: "Papua New Guinea", dial_code: "+675", code: "PG" }, |
|
|
{ name: "Paraguay", dial_code: "+595", code: "PY" }, |
|
|
{ name: "Peru", dial_code: "+51", code: "PE" }, |
|
|
{ name: "Philippines", dial_code: "+63", code: "PH" }, |
|
|
{ name: "Poland", dial_code: "+48", code: "PL" }, |
|
|
{ name: "Portugal", dial_code: "+351", code: "PT" }, |
|
|
{ name: "Qatar", dial_code: "+974", code: "QA" }, |
|
|
{ name: "Romania", dial_code: "+40", code: "RO" }, |
|
|
{ name: "Russia", dial_code: "+7", code: "RU" }, |
|
|
{ name: "Rwanda", dial_code: "+250", code: "RW" }, |
|
|
{ name: "Saint Kitts and Nevis", dial_code: "+1-869", code: "KN" }, |
|
|
{ name: "Saint Lucia", dial_code: "+1-758", code: "LC" }, |
|
|
{ name: "Saint Vincent and the Grenadines", dial_code: "+1-784", code: "VC" }, |
|
|
{ name: "Samoa", dial_code: "+685", code: "WS" }, |
|
|
{ name: "San Marino", dial_code: "+378", code: "SM" }, |
|
|
{ name: "Sao Tome and Principe", dial_code: "+239", code: "ST" }, |
|
|
{ name: "Saudi Arabia", dial_code: "+966", code: "SA" }, |
|
|
{ name: "Senegal", dial_code: "+221", code: "SN" }, |
|
|
{ name: "Serbia", dial_code: "+381", code: "RS" }, |
|
|
{ name: "Seychelles", dial_code: "+248", code: "SC" }, |
|
|
{ name: "Sierra Leone", dial_code: "+232", code: "SL" }, |
|
|
{ name: "Singapore", dial_code: "+65", code: "SG" }, |
|
|
{ name: "Slovakia", dial_code: "+421", code: "SK" }, |
|
|
{ name: "Slovenia", dial_code: "+386", code: "SI" }, |
|
|
{ name: "Solomon Islands", dial_code: "+677", code: "SB" }, |
|
|
{ name: "Somalia", dial_code: "+252", code: "SO" }, |
|
|
{ name: "South Africa", dial_code: "+27", code: "ZA" }, |
|
|
{ name: "South Korea", dial_code: "+82", code: "KR" }, |
|
|
{ name: "South Sudan", dial_code: "+211", code: "SS" }, |
|
|
{ name: "Spain", dial_code: "+34", code: "ES" }, |
|
|
{ name: "Sri Lanka", dial_code: "+94", code: "LK" }, |
|
|
{ name: "Sudan", dial_code: "+249", code: "SD" }, |
|
|
{ name: "Suriname", dial_code: "+597", code: "SR" }, |
|
|
{ name: "Sweden", dial_code: "+46", code: "SE" }, |
|
|
{ name: "Switzerland", dial_code: "+41", code: "CH" }, |
|
|
{ name: "Syria", dial_code: "+963", code: "SY" }, |
|
|
{ name: "Taiwan", dial_code: "+886", code: "TW" }, |
|
|
{ name: "Tajikistan", dial_code: "+992", code: "TJ" }, |
|
|
{ name: "Tanzania", dial_code: "+255", code: "TZ" }, |
|
|
{ name: "Thailand", dial_code: "+66", code: "TH" }, |
|
|
{ name: "Timor-Leste", dial_code: "+670", code: "TL" }, |
|
|
{ name: "Togo", dial_code: "+228", code: "TG" }, |
|
|
{ name: "Tonga", dial_code: "+676", code: "TO" }, |
|
|
{ name: "Trinidad and Tobago", dial_code: "+1-868", code: "TT" }, |
|
|
{ name: "Tunisia", dial_code: "+216", code: "TN" }, |
|
|
{ name: "Turkey", dial_code: "+90", code: "TR" }, |
|
|
{ name: "Turkmenistan", dial_code: "+993", code: "TM" }, |
|
|
{ name: "Tuvalu", dial_code: "+688", code: "TV" }, |
|
|
{ name: "Uganda", dial_code: "+256", code: "UG" }, |
|
|
{ name: "Ukraine", dial_code: "+380", code: "UA" }, |
|
|
{ name: "United Arab Emirates", dial_code: "+971", code: "AE" }, |
|
|
{ name: "United Kingdom", dial_code: "+44", code: "GB" }, |
|
|
{ name: "United States", dial_code: "+1", code: "US" }, |
|
|
{ name: "Uruguay", dial_code: "+598", code: "UY" }, |
|
|
{ name: "Uzbekistan", dial_code: "+998", code: "UZ" }, |
|
|
{ name: "Vanuatu", dial_code: "+678", code: "VU" }, |
|
|
{ name: "Vatican City", dial_code: "+379", code: "VA" }, |
|
|
{ name: "Venezuela", dial_code: "+58", code: "VE" }, |
|
|
{ name: "Vietnam", dial_code: "+84", code: "VN" }, |
|
|
{ name: "Yemen", dial_code: "+967", code: "YE" }, |
|
|
{ name: "Zambia", dial_code: "+260", code: "ZM" }, |
|
|
{ name: "Zimbabwe", dial_code: "+263", code: "ZW"}, |
|
|
]; |
|
|
|
|
|
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'); |
|
|
}); |
|
|
|
|
|
|
|
|
const countrySelect = document.getElementById("country"); |
|
|
const userCountryCode = "<?php echo $country_code; ?>"; |
|
|
|
|
|
countries.forEach(c => { |
|
|
const option = document.createElement("option"); |
|
|
option.value = c.code; |
|
|
option.textContent = `${c.name} (${c.dial_code})`; |
|
|
if (c.code === userCountryCode) { |
|
|
option.selected = true; |
|
|
} |
|
|
countrySelect.appendChild(option); |
|
|
}); |
|
|
|
|
|
|
|
|
const tabs = document.querySelectorAll('.tab'); |
|
|
const tabContents = document.querySelectorAll('.card'); |
|
|
|
|
|
tabs.forEach(tab => { |
|
|
tab.addEventListener('click', function() { |
|
|
const tabName = this.getAttribute('data-tab'); |
|
|
|
|
|
// Update tabs |
|
|
tabs.forEach(t => t.classList.remove('active')); |
|
|
this.classList.add('active'); |
|
|
|
|
|
// Update content |
|
|
tabContents.forEach(content => { |
|
|
content.classList.remove('active'); |
|
|
if (content.id === `${tabName}-tab`) { |
|
|
content.classList.add('active'); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
if (tabName === 'activity') { |
|
|
loadActivity(); |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
new ProfileManager(); |
|
|
}); |
|
|
|
|
|
|
|
|
class ProfileManager { |
|
|
constructor() { |
|
|
this.originalData = {}; |
|
|
this.activityOffset = 0; |
|
|
this.init(); |
|
|
} |
|
|
|
|
|
init() { |
|
|
this.setupEventListeners(); |
|
|
this.loadOriginalData(); |
|
|
} |
|
|
|
|
|
loadOriginalData() { |
|
|
this.originalData = { |
|
|
first_name: document.getElementById('first_name').value, |
|
|
last_name: document.getElementById('last_name').value, |
|
|
email: document.getElementById('email').value, |
|
|
phone_number: document.getElementById('phone_number').value, |
|
|
country_code: document.getElementById('country').value |
|
|
}; |
|
|
} |
|
|
|
|
|
setupEventListeners() { |
|
|
|
|
|
const profileForm = document.getElementById('profileForm'); |
|
|
const securityForm = document.getElementById('securityForm'); |
|
|
const loadMoreBtn = document.getElementById('loadMoreActivity'); |
|
|
|
|
|
|
|
|
const inputs = profileForm.querySelectorAll('input, select'); |
|
|
inputs.forEach(input => { |
|
|
input.addEventListener('input', this.debounce((e) => { |
|
|
this.autoSaveField(e.target.name, e.target.value); |
|
|
}, 1000)); |
|
|
}); |
|
|
|
|
|
profileForm.addEventListener('submit', (e) => { |
|
|
e.preventDefault(); |
|
|
this.saveProfile(); |
|
|
}); |
|
|
|
|
|
document.getElementById('cancelBtn').addEventListener('click', () => { |
|
|
this.cancelChanges(); |
|
|
}); |
|
|
|
|
|
|
|
|
securityForm.addEventListener('submit', (e) => { |
|
|
e.preventDefault(); |
|
|
this.changePassword(); |
|
|
}); |
|
|
|
|
|
|
|
|
if (loadMoreBtn) { |
|
|
loadMoreBtn.addEventListener('click', () => { |
|
|
this.loadMoreActivity(); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
async autoSaveField(field, value) { |
|
|
try { |
|
|
const response = await this.makeRequest('profile_handler.php', { |
|
|
action: 'update_profile', |
|
|
[field]: value |
|
|
}); |
|
|
|
|
|
if (response.success) { |
|
|
this.showNotification('Auto-saved successfully', 'success'); |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Auto-save failed:', error); |
|
|
} |
|
|
} |
|
|
|
|
|
async saveProfile() { |
|
|
const formData = new FormData(document.getElementById('profileForm')); |
|
|
const data = Object.fromEntries(formData.entries()); |
|
|
|
|
|
try { |
|
|
this.setLoading(true, 'saveBtn', 'Saving...'); |
|
|
|
|
|
const response = await this.makeRequest('profile_handler.php', { |
|
|
action: 'update_profile', |
|
|
...data |
|
|
}); |
|
|
|
|
|
if (response.success) { |
|
|
this.showNotification('Profile updated successfully!', 'success'); |
|
|
this.loadOriginalData(); |
|
|
this.updateProfileDisplay(data); |
|
|
} else { |
|
|
throw new Error(response.message); |
|
|
} |
|
|
} catch (error) { |
|
|
this.showNotification('Error: ' + error.message, 'error'); |
|
|
} finally { |
|
|
this.setLoading(false, 'saveBtn', 'Save Changes'); |
|
|
} |
|
|
} |
|
|
|
|
|
async changePassword() { |
|
|
const formData = new FormData(document.getElementById('securityForm')); |
|
|
const data = Object.fromEntries(formData.entries()); |
|
|
|
|
|
try { |
|
|
this.setLoading(true, 'changePasswordBtn', 'Changing...'); |
|
|
|
|
|
const response = await this.makeRequest('profile_handler.php', { |
|
|
action: 'change_password', |
|
|
...data |
|
|
}); |
|
|
|
|
|
if (response.success) { |
|
|
this.showNotification('Password changed successfully!', 'success'); |
|
|
document.getElementById('securityForm').reset(); |
|
|
} else { |
|
|
throw new Error(response.message); |
|
|
} |
|
|
} catch (error) { |
|
|
this.showNotification('Error: ' + error.message, 'error'); |
|
|
} finally { |
|
|
this.setLoading(false, 'changePasswordBtn', 'Change Password'); |
|
|
} |
|
|
} |
|
|
|
|
|
async loadActivity() { |
|
|
try { |
|
|
const response = await this.makeRequest('profile_handler.php', { |
|
|
action: 'get_activity' |
|
|
}); |
|
|
|
|
|
if (response.success) { |
|
|
this.displayActivity(response.activities); |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Failed to load activity:', error); |
|
|
document.getElementById('activityList').innerHTML = |
|
|
'<div class="text-center py-8 text-gray-400">Failed to load activity history</div>'; |
|
|
} |
|
|
} |
|
|
|
|
|
async loadMoreActivity() { |
|
|
this.activityOffset += 10; |
|
|
try { |
|
|
const response = await this.makeRequest('../api/profile_handler.php', { |
|
|
action: 'get_activity', |
|
|
offset: this.activityOffset |
|
|
}); |
|
|
|
|
|
if (response.success && response.activities.length > 0) { |
|
|
this.displayActivity(response.activities, true); |
|
|
} else { |
|
|
this.showNotification('No more activities to load', 'info'); |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Failed to load more activity:', error); |
|
|
} |
|
|
} |
|
|
|
|
|
displayActivity(activities, append = false) { |
|
|
const activityList = document.getElementById('activityList'); |
|
|
|
|
|
if (!activities || activities.length === 0) { |
|
|
if (!append) { |
|
|
activityList.innerHTML = |
|
|
'<div class="text-center py-8 text-gray-400">No activity history found</div>'; |
|
|
} |
|
|
return; |
|
|
} |
|
|
|
|
|
const activitiesHTML = activities.map(activity => ` |
|
|
<div class="activity-item"> |
|
|
<div class="activity-icon"> |
|
|
<i data-feather="${this.getActivityIcon(activity.activity_type)}"></i> |
|
|
</div> |
|
|
<div class="flex-1"> |
|
|
<div class="font-medium">${activity.description}</div> |
|
|
<div class="text-sm text-gray-400">${new Date(activity.timestamp).toLocaleString()}</div> |
|
|
</div> |
|
|
<div class="text-sm text-gray-400 capitalize">${activity.activity_type.replace('_', ' ')}</div> |
|
|
</div> |
|
|
`).join(''); |
|
|
|
|
|
if (append) { |
|
|
activityList.innerHTML += activitiesHTML; |
|
|
} else { |
|
|
activityList.innerHTML = activitiesHTML; |
|
|
} |
|
|
|
|
|
feather.replace(); |
|
|
} |
|
|
|
|
|
getActivityIcon(activityType) { |
|
|
const icons = { |
|
|
'profile_update': 'user', |
|
|
'password_change': 'lock', |
|
|
'login': 'log-in', |
|
|
'logout': 'log-out', |
|
|
'default': 'activity' |
|
|
}; |
|
|
return icons[activityType] || icons.default; |
|
|
} |
|
|
|
|
|
cancelChanges() { |
|
|
document.getElementById('first_name').value = this.originalData.first_name; |
|
|
document.getElementById('last_name').value = this.originalData.last_name; |
|
|
document.getElementById('email').value = this.originalData.email; |
|
|
document.getElementById('phone_number').value = this.originalData.phone_number; |
|
|
document.getElementById('country').value = this.originalData.country_code; |
|
|
|
|
|
this.showNotification('Changes cancelled', 'info'); |
|
|
} |
|
|
|
|
|
updateProfileDisplay(data) { |
|
|
|
|
|
const avatar = document.querySelector('.profile-avatar'); |
|
|
const nameDisplay = document.querySelector('.text-2xl.font-bold'); |
|
|
const userAvatar = document.querySelector('.w-9.h-9.rounded-full'); |
|
|
|
|
|
if (avatar) { |
|
|
avatar.textContent = (data.first_name?.[0] || '') + (data.last_name?.[0] || ''); |
|
|
} |
|
|
if (nameDisplay) { |
|
|
nameDisplay.textContent = `${data.first_name} ${data.last_name}`; |
|
|
} |
|
|
if (userAvatar) { |
|
|
userAvatar.textContent = (data.first_name?.[0] || '') + (data.last_name?.[0] || ''); |
|
|
} |
|
|
} |
|
|
|
|
|
setLoading(loading, buttonId, text) { |
|
|
const button = document.getElementById(buttonId); |
|
|
if (loading) { |
|
|
button.classList.add('loading'); |
|
|
button.textContent = text; |
|
|
button.disabled = true; |
|
|
} else { |
|
|
button.classList.remove('loading'); |
|
|
button.textContent = text; |
|
|
button.disabled = false; |
|
|
} |
|
|
} |
|
|
|
|
|
async makeRequest(url, data) { |
|
|
const formData = new FormData(); |
|
|
for (const key in data) { |
|
|
formData.append(key, data[key]); |
|
|
} |
|
|
|
|
|
const response = await fetch(url, { |
|
|
method: 'POST', |
|
|
body: formData |
|
|
}); |
|
|
|
|
|
return await response.json(); |
|
|
} |
|
|
|
|
|
showNotification(message, type = 'info') { |
|
|
|
|
|
const existingNotifications = document.querySelectorAll('.notification'); |
|
|
existingNotifications.forEach(notification => notification.remove()); |
|
|
|
|
|
|
|
|
const notification = document.createElement('div'); |
|
|
notification.className = `notification ${type}`; |
|
|
notification.textContent = message; |
|
|
|
|
|
document.body.appendChild(notification); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
notification.remove(); |
|
|
}, 3000); |
|
|
} |
|
|
|
|
|
debounce(func, wait) { |
|
|
let timeout; |
|
|
return function executedFunction(...args) { |
|
|
const later = () => { |
|
|
clearTimeout(timeout); |
|
|
func(...args); |
|
|
}; |
|
|
clearTimeout(timeout); |
|
|
timeout = setTimeout(later, wait); |
|
|
}; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function loadActivity() { |
|
|
const profileManager = new ProfileManager(); |
|
|
profileManager.loadActivity(); |
|
|
} |
|
|
</script> |
|
|
</body> |
|
|
</html> |