Файловый менеджер - Редактировать - /home/gqdcvggs/idsma.imators.com/dashboard.php
Назад
<?php session_start(); require_once 'db.php'; require 'vendor/autoload.php'; if (!isset($_SESSION['user_id'])) { header('Location: login.php'); exit; } $db = new Database(); $conn = $db->connect(); $stmt = $conn->prepare("SELECT is_enabled FROM two_factor_auth WHERE user_id = ?"); $stmt->execute([$_SESSION['user_id']]); $twoFaStatus = $stmt->fetch(PDO::FETCH_COLUMN) ? true : false; function safe_json_decode($json, $default = []) { if ($json === null) return $default; $decoded = json_decode($json, true); return $decoded ?: $default; } function safe_datetime($datetime) { return $datetime ? date('M j, Y g:i A', strtotime($datetime)) : 'Not Available'; } $errors = []; $success = ''; try { $stmt = $conn->prepare(" SELECT u.*, COALESCE(cw.`ip-connected`, '{}') as `ip-connected`, COALESCE(cw.`identified-screen`, '{}') as `identified-screen`, cw.`hours-of-connect`, cw.`date-of-connect` FROM utilisateurs u LEFT JOIN `connection-watchguard` cw ON u.id = cw.user_id WHERE u.id = ? ORDER BY cw.`date-of-connect` DESC LIMIT 1 "); $stmt->execute([$_SESSION['user_id']]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if (!$user) { header('Location: logout.php'); exit; } $security_query = $conn->prepare(" SELECT cw.* FROM `connection-watchguard` cw WHERE cw.user_id = ? ORDER BY cw.`date-of-connect` DESC LIMIT 5 "); $security_query->execute([$_SESSION['user_id']]); $connections = $security_query->fetchAll(PDO::FETCH_ASSOC); } catch(PDOException $e) { error_log("Error fetching user data: " . $e->getMessage()); $errors[] = "An error occurred while retrieving your data."; } $subscriptions = [ 'academ' => $user['academ'] ?? false, 'ohmypanel' => $user['ohmypanel'] ?? false, 'something' => $user['something'] ?? false ]; if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['update_profile'])) { $username = trim(filter_var($_POST['username'], FILTER_SANITIZE_FULL_SPECIAL_CHARS)); $email = trim(filter_var($_POST['email'], FILTER_SANITIZE_EMAIL)); try { $check_email = $conn->prepare("SELECT id FROM utilisateurs WHERE email = ? AND id != ?"); $check_email->execute([$email, $_SESSION['user_id']]); if ($check_email->rowCount() > 0) { $errors[] = "This email is already taken by another user"; } else { $update_query = "UPDATE utilisateurs SET username = ?, email = ?"; $update_params = [$username, $email]; if (isset($_FILES['profile_picture']) && $_FILES['profile_picture']['error'] === 0) { $allowed = ['jpg', 'jpeg', 'png', 'webp']; $filename = $_FILES['profile_picture']['name']; $filetype = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if (!in_array($filetype, $allowed)) { $errors[] = "Invalid file type. Allowed: JPG, JPEG, PNG, WEBP"; } else { $newName = time() . rand(1000, 9999) . '.' . $filetype; $uploadPath = $_SERVER['DOCUMENT_ROOT'] . '/../cdn.imators.com/uploads/'; if (!is_dir($uploadPath)) { mkdir($uploadPath, 0755, true); } if (move_uploaded_file($_FILES['profile_picture']['tmp_name'], $uploadPath . $newName)) { $cdnUrl = 'https://cdn.imators.com/uploads/' . $newName; $update_query .= ", `profile-picture` = ?"; $update_params[] = $cdnUrl; } else { $errors[] = "Failed to upload profile picture"; } } } $update_query .= " WHERE id = ?"; $update_params[] = $_SESSION['user_id']; if (empty($errors)) { $stmt = $conn->prepare($update_query); if ($stmt->execute($update_params)) { $success = "Profile updated successfully!"; $_SESSION['username'] = $username; $stmt = $conn->prepare("SELECT * FROM utilisateurs WHERE id = ?"); $stmt->execute([$_SESSION['user_id']]); $user = $stmt->fetch(PDO::FETCH_ASSOC); } else { $errors[] = "Failed to update profile"; } } } } catch(PDOException $e) { error_log("Profile update error: " . $e->getMessage()); $errors[] = "An error occurred while updating your profile"; } } if (isset($_POST['change_password'])) { $currentPassword = $_POST['current_password']; $newPassword = $_POST['new_password']; $confirmPassword = $_POST['confirm_password']; if (!password_verify($currentPassword, $user['password'])) { $errors[] = "Current password is incorrect"; } elseif ($newPassword !== $confirmPassword) { $errors[] = "New passwords do not match"; } elseif (strlen($newPassword) < 8) { $errors[] = "New password must be at least 8 characters long"; } elseif (!preg_match("/[A-Z]/", $newPassword) || !preg_match("/[a-z]/", $newPassword) || !preg_match("/[0-9]/", $newPassword)) { $errors[] = "New password must contain uppercase, lowercase, and numbers"; } else { try { $hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT); $stmt = $conn->prepare("UPDATE utilisateurs SET password = ? WHERE id = ?"); if ($stmt->execute([$hashedPassword, $_SESSION['user_id']])) { $success = "Password changed successfully!"; } else { $errors[] = "Failed to update password"; } } catch(PDOException $e) { error_log("Password update error: " . $e->getMessage()); $errors[] = "An error occurred while updating your password"; } } } } $stmt = $conn->prepare("SELECT passkey_enabled FROM utilisateurs WHERE id = ?"); $stmt->execute([$_SESSION['user_id']]); $passkey_enabled = $stmt->fetch(PDO::FETCH_COLUMN) ? true : false; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Imators Auth.</title> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet"> <script src="https://cdn.tailwindcss.com"></script> <style> body { font-family: 'Inter', sans-serif; background: linear-gradient(135deg, #000000, #0a0a0a, #1a1a1a); background-attachment: fixed; } .glass-effect { backdrop-filter: blur(16px); background: rgba(255, 255, 255, 0.02); border: 1px solid rgba(255, 255, 255, 0.05); } .gradient-border { position: relative; border-radius: 1rem; background: linear-gradient(145deg, rgba(26, 26, 26, 0.8), rgba(45, 45, 45, 0.4)); padding: 1px; overflow: hidden; } .gradient-border::before { content: ''; position: absolute; inset: -1px; border-radius: 1rem; padding: 1px; background: linear-gradient(145deg, rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.02)); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; } .hover-scale { transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .hover-scale:hover { transform: translateY(-2px) scale(1.005); } .profile-upload { position: relative; width: 120px; height: 120px; border-radius: 50%; overflow: hidden; cursor: pointer; transition: all 0.3s ease; margin: 1rem; } .profile-upload:hover::after { content: 'Change'; position: absolute; inset: 0; background: rgba(0, 0, 0, 0.7); display: flex; align-items: center; justify-content: center; color: white; font-size: 14px; } .connection-card { background: linear-gradient(165deg, rgba(26, 26, 26, 0.9), rgba(42, 42, 42, 0.5)); transition: all 0.3s ease; border-radius: 0.75rem; } .connection-card:hover { transform: translateY(-1px); background: linear-gradient(165deg, rgba(36, 36, 36, 0.95), rgba(52, 52, 52, 0.6)); } input, select, textarea { background: rgba(0, 0, 0, 0.3); border: 1px solid rgba(255, 255, 255, 0.1); } input:focus, select:focus, textarea:focus { border-color: rgba(255, 255, 255, 0.2); outline: none; } button { transition: all 0.2s ease; } button:hover { transform: translateY(-1px); } .success-animation { animation: fadeInUp 0.6s cubic-bezier(0.4, 0, 0.2, 1); } @keyframes fadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .nav-blur { backdrop-filter: blur(20px); background: rgba(0, 0, 0, 0.5); border-bottom: 1px solid rgba(255, 255, 255, 0.05); } @keyframes ripple { 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4); } 100% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); } } .pulse { animation: ripple 1.5s infinite; } .subscription-actions { opacity: 0; transition: opacity 0.3s ease; } .subscription-card:hover .subscription-actions { opacity: 1; } </style> </head> <body class="bg-black min-h-screen text-white"> <nav class="border-b border-white/5 nav-blur sticky top-0 z-50"> <div class="flex justify-between items-center max-w-6xl mx-auto px-4 sm:px-6 py-4"> <div class="flex items-center space-x-6"> <img src="https://cdn.imators.com/logo.png" alt="Logo" class="h-8 sm:h-10 hover-scale"> <div class="hidden md:flex space-x-4"> <a href="#profile" class="text-gray-300 hover:text-white transition-colors">Profile</a> <a href="#security" class="text-gray-300 hover:text-white transition-colors">Security</a> <a href="#payment" class="text-gray-300 hover:text-white transition-colors">Payment</a> <a href="#support" class="text-gray-300 hover:text-white transition-colors">Support</a> </div> </div> <div class="flex items-center space-x-4 sm:space-x-6"> <div class="flex items-center space-x-3"> <p class="text-sm text-gray-300"><?php echo htmlspecialchars($_SESSION['username']); ?></p> <div class="w-8 h-8 sm:w-10 sm:h-10 rounded-full overflow-hidden"> <img src="<?php echo $user['profile-picture'] ?? 'https://cdn.imators.com/default-avatar.png'; ?>" alt="Profile" class="w-full h-full object-cover"> </div> </div> <a href="logout.php" class="px-3 py-2 sm:px-4 sm:py-2 rounded-lg bg-white/5 hover:bg-white/10 text-sm text-gray-300 hover:text-white transition-all"> Logout </a> </div> </div> </nav> <main class="max-w-6xl mx-auto px-4 sm:px-6 py-8 sm:py-12"> <?php if ($success): ?> <div class="bg-green-500/10 border border-green-500/20 text-green-400 p-4 rounded-lg mb-8 success-animation"> <?php echo htmlspecialchars($success); ?> </div> <?php endif; ?> <?php if (!empty($errors)): ?> <div class="bg-red-500/10 border border-red-500/20 text-red-400 p-4 rounded-lg mb-8 success-animation"> <ul class="list-disc pl-4"> <?php foreach ($errors as $error): ?> <li><?php echo htmlspecialchars($error); ?></li> <?php endforeach; ?> </ul> </div> <?php endif; ?> <div class="mb-6 bg-transparent p-4 rounded-lg"> <h1 class="text-2xl sm:text-3xl font-semibold text-white"> Welcome, <span class="text-blue-400"><?php echo htmlspecialchars($_SESSION['username']); ?></span> </h1> <p class="text-gray-400 mt-2">Manage your Imators account and preferences</p> </div> <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> <div class="lg:col-span-2 space-y-6"> <div id="profile" class="gradient-border hover-scale"> <div class="glass-effect rounded-lg p-4 sm:p-6 md:p-8"> <div class="flex flex-col sm:flex-row items-center sm:items-start gap-6 mb-8"> <div class="order-2 sm:order-1 text-center sm:text-left"> <h2 class="text-xl sm:text-2xl font-semibold flex items-center justify-center sm:justify-start"> <svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" /> </svg> Profile Settings </h2> <p class="text-sm font-light mt-2 text-gray-400">Manage your account information</p> </div> <div class="order-1 sm:order-2 flex-shrink-0"> <div class="relative"> <label class="profile-upload block"> <input type="file" accept="image/*" class="hidden" name="profile_picture" id="profilePictureInput"> <img src="<?php echo $user['profile-picture'] ?? 'https://cdn.imators.com/default-avatar.png'; ?>" alt="Profile" class="w-full h-full object-cover" id="profilePreview"> </label> <div id="uploadStatus" class="absolute inset-0 bg-black/75 items-center justify-center hidden rounded-full"> <div class="text-center"> <svg class="animate-spin h-8 w-8 mx-auto text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> <p class="mt-2 text-xs text-white">Uploading...</p> </div> </div> </div> </div> </div> <form method="POST" enctype="multipart/form-data" class="space-y-6"> <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> <div> <label class="block text-sm font-medium mb-2 text-gray-300">Username</label> <input type="text" name="username" required value="<?php echo htmlspecialchars($user['username']); ?>" class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none"> </div> <div> <label class="block text-sm font-medium mb-2 text-gray-300">Email</label> <input type="email" name="email" required value="<?php echo htmlspecialchars($user['email']); ?>" class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none"> </div> </div> <input type="hidden" name="update_profile" value="1"> <button type="submit" class="w-full bg-white text-black py-3 px-6 rounded-lg font-medium hover:bg-gray-100 transition-all hover-scale"> Update Profile </button> </form> </div> </div> <div id="security" class="gradient-border hover-scale"> <div class="glass-effect rounded-lg p-6 sm:p-8"> <h2 class="text-xl sm:text-2xl font-semibold mb-6 flex items-center"> <svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" /> </svg> Security & Connections </h2> <div class="space-y-6"> <div class="bg-black/30 rounded-lg p-4"> <div class="flex items-center justify-between"> <div> <h3 class="text-sm font-medium">Current Session</h3> <p class="text-xs text-gray-400 mt-1"> <?php $location = safe_json_decode($user['ip-connected'], [])['location'] ?? 'Unknown'; echo htmlspecialchars($location); ?> </p> </div> <div class="flex items-center"> <div class="w-2 h-2 bg-green-500 rounded-full pulse"></div> <span class="ml-2 text-xs text-gray-400">Active now</span> </div> </div> </div> <div class="space-y-4"> <h3 class="text-sm font-medium">Recent Connections</h3> <?php foreach ($connections as $connection): ?> <?php $deviceInfo = safe_json_decode($connection['identified-screen']); $ipInfo = safe_json_decode($connection['ip-connected']); ?> <div class="connection-card p-4"> <div class="flex justify-between items-start"> <div> <p class="text-sm"><?php echo htmlspecialchars($deviceInfo['device'] ?? 'Unknown Device'); ?></p> <p class="text-xs text-gray-400 mt-1"> <?php echo htmlspecialchars($ipInfo['location'] ?? 'Unknown Location'); ?> </p> </div> <p class="text-xs text-gray-500"> <?php echo safe_datetime($connection['date-of-connect']); ?> </p> </div> </div> <?php endforeach; ?> </div> <div class="border-t border-white/5 pt-6"> <h3 class="text-sm font-medium mb-4">Change Password</h3> <form method="POST" class="space-y-4"> <div> <label class="block text-xs font-medium mb-2 text-gray-300">Current Password</label> <input type="password" name="current_password" required class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none"> </div> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div> <label class="block text-xs font-medium mb-2 text-gray-300">New Password</label> <input type="password" name="new_password" required class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none"> </div> <div> <label class="block text-xs font-medium mb-2 text-gray-300">Confirm Password</label> <input type="password" name="confirm_password" required class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none"> </div> </div> <input type="hidden" name="change_password" value="1"> <button type="submit" class="w-full bg-white/10 text-white py-3 px-6 rounded-lg font-medium hover:bg-white/20 transition-all"> Update Password </button> </form> </div> </div> </div> </div> <div id="payment" class="gradient-border hover-scale"> <div class="glass-effect rounded-lg p-6 sm:p-8"> <h2 class="text-xl sm:text-2xl font-semibold mb-6 flex items-center"> <svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" /> </svg> Payment Methods </h2> <div id="savedCards" class="space-y-4 mb-6"> <?php try { $cards_query = $conn->prepare(" SELECT * FROM payment_methods WHERE user_id = ? ORDER BY is_default DESC, created_at DESC "); $cards_query->execute([$_SESSION['user_id']]); $cards = $cards_query->fetchAll(PDO::FETCH_ASSOC); if (empty($cards)) { echo '<p class="text-gray-400 text-center py-4">No payment methods added yet</p>'; } else { foreach ($cards as $card) { $last4 = $card['last4']; $brand = strtoupper($card['brand']); $exp_month = str_pad($card['exp_month'], 2, '0', STR_PAD_LEFT); $exp_year = $card['exp_year']; $is_default = $card['is_default']; echo '<div class="bg-black/30 rounded-lg p-4 flex items-center justify-between"> <div class="flex items-center space-x-4"> <div class="w-12 h-8 flex items-center justify-center bg-white/10 rounded text-xs font-bold"> ' . htmlspecialchars($brand) . ' </div> <div> <p class="font-medium">•••• ' . htmlspecialchars($last4) . '</p> <p class="text-xs text-gray-400">Expires ' . htmlspecialchars($exp_month) . '/' . htmlspecialchars($exp_year) . '</p> </div> </div> <div class="flex items-center space-x-2"> ' . ($is_default ? '<span class="text-xs bg-green-500/10 text-green-400 px-2 py-1 rounded border border-green-500/20">Default</span>' : '') . ' <button onclick="setDefaultCard(' . $card['id'] . ')" class="text-blue-400 hover:text-blue-300 p-1 transition-colors" ' . ($is_default ? 'style="opacity:0.5" disabled' : '') . '> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" /> </svg> </button> <button onclick="deleteCard(' . $card['id'] . ')" class="text-red-400 hover:text-red-300 p-1 transition-colors"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" /> </svg> </button> </div> </div>'; } } } catch(PDOException $e) { error_log("Error fetching payment methods: " . $e->getMessage()); echo '<p class="text-red-400 text-center py-4">Could not load payment methods</p>'; } ?> </div> <button id="addCardBtn" class="w-full bg-white/10 text-white py-3 px-6 rounded-lg font-medium hover:bg-white/20 transition-all flex items-center justify-center"> <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" /> </svg> Add Payment Method </button> </div> </div> <div id="support" class="gradient-border mb-8 hover-scale"> <div class="glass-effect rounded-lg p-6 sm:p-8"> <div class="flex justify-between items-center mb-6"> <div> <h2 class="text-xl sm:text-2xl font-semibold flex items-center"> <svg class="w-6 h-6 mr-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z" /> </svg> Support Tickets </h2> <p class="text-sm font-light mt-2 text-gray-400">Get help from our team</p> </div> <button onclick="openTicketModal()" class="px-4 py-2 bg-white text-black rounded-lg font-medium hover:bg-gray-100 transition-all hover-scale inline-flex items-center"> <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" /> </svg> New Ticket </button> </div> <div class="overflow-x-auto"> <table class="w-full"> <thead> <tr class="text-left text-sm text-gray-400 border-b border-white/5"> <th class="pb-4 pr-4">ID</th> <th class="pb-4 pr-4">Subject</th> <th class="pb-4 pr-4">Status</th> <th class="pb-4 pr-4">Priority</th> <th class="pb-4 pr-4">Created</th> <th class="pb-4">Action</th> </tr> </thead> <tbody class="text-sm"> <?php try { $tickets_query = $conn->prepare(" SELECT * FROM support_tickets WHERE user_id = ? ORDER BY created_at DESC "); $tickets_query->execute([$_SESSION['user_id']]); $tickets = $tickets_query->fetchAll(PDO::FETCH_ASSOC); foreach ($tickets as $ticket): $status_colors = [ 'open' => ['bg' => 'bg-yellow-400/10', 'text' => 'text-yellow-400', 'border' => 'border-yellow-400/20'], 'in_progress' => ['bg' => 'bg-blue-400/10', 'text' => 'text-blue-400', 'border' => 'border-blue-400/20'], 'resolved' => ['bg' => 'bg-green-400/10', 'text' => 'text-green-400', 'border' => 'border-green-400/20'], 'closed' => ['bg' => 'bg-gray-400/10', 'text' => 'text-gray-400', 'border' => 'border-gray-400/20'] ][$ticket['status']] ?? ['bg' => 'bg-gray-400/10', 'text' => 'text-gray-400', 'border' => 'border-gray-400/20']; ?> <tr class="border-b border-white/5"> <td class="py-4 pr-4">#<?php echo $ticket['id']; ?></td> <td class="py-4 pr-4"><?php echo htmlspecialchars($ticket['subject']); ?></td> <td class="py-4 pr-4"> <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium border <?php echo $status_colors['bg'] . ' ' . $status_colors['text'] . ' ' . $status_colors['border']; ?>"> <?php echo str_replace('_', ' ', $ticket['status']); ?> </span> </td> <td class="py-4 pr-4 capitalize"><?php echo $ticket['priority']; ?></td> <td class="py-4 pr-4"><?php echo date('M j, Y', strtotime($ticket['created_at'])); ?></td> <td class="py-4"> <a href="view_ticket.php?id=<?php echo $ticket['id']; ?>" class="text-indigo-400 hover:text-indigo-300 transition-colors"> View Details </a> </td> </tr> <?php endforeach; } catch(PDOException $e) { error_log("Error fetching tickets: " . $e->getMessage()); } ?> </tbody> </table> <?php if (empty($tickets)): ?> <p class="text-gray-400 text-center py-8">No tickets found. Create one to get started!</p> <?php endif; ?> </div> </div> </div> </div> <div class="space-y-6"> <?php if($user['role']): ?> <div class="gradient-border hover-scale"> <div class="glass-effect rounded-lg p-6"> <div class="flex items-center space-x-4"> <div class="w-12 h-12 rounded-full bg-indigo-500/10 flex items-center justify-center"> <svg class="w-6 h-6 text-indigo-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" /> </svg> </div> <div> <h3 class="font-medium">Imators Staff Member</h3> <p class="text-sm text-gray-400"><?php echo htmlspecialchars($user['roleinimators']); ?> of the company</p> </div> </div> </div> </div> <?php endif; ?> <div class="gradient-border hover-scale"> <div class="glass-effect rounded-lg p-6"> <h3 class="font-medium mb-4">Your Active Subscriptions</h3> <div class="space-y-4"> <?php if($subscriptions['academ']): ?> <div class="subscription-card p-4 flex items-center justify-between group"> <div class="flex items-center space-x-4"> <img src="https://cdn.imators.com/Academ.png" alt="Academ" class="w-10 h-10"> <div> <p class="text-purple-200 text-sm">Academ</p> <p class="text-xs text-gray-400">Connected Account</p> </div> </div> <div class="subscription-actions flex space-x-2"> <button onclick="disconnectService('academ')" class="text-red-400 hover:text-red-300 p-1"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> </svg> </button> </div> </div> <?php endif; ?> <?php if($subscriptions['ohmypanel']): ?> <div class="subscription-card p-4 flex items-center justify-between group"> <div class="flex items-center space-x-4"> <div class="relative"> <img src="https://cdn.imators.com/smile_not_found.png" alt="OhMyPanel" class="w-10 h-10"> <div class="absolute inset-0 bg-yellow-400/20 rounded-full filter blur-md opacity-0 group-hover:opacity-100 transition-opacity"></div> </div> <div> <p class="text-yellow-400 text-sm">OhMyPanel</p> <p class="text-xs text-gray-400">Active Subscription</p> </div> </div> <div class="subscription-actions flex space-x-2"> <button onclick="cancelSubscription('ohmypanel')" class="text-orange-400 hover:text-orange-300 p-1"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> </button> </div> </div> <?php endif; ?> <?php if($subscriptions['something']): ?> <div class="subscription-card p-4 flex items-center justify-between group"> <div class="flex items-center space-x-4"> <div class="relative"> <img src="https://cdn.imators.com/logo.png" alt="Something" class="w-10 h-10"> <div class="absolute inset-0 bg-green-400/20 rounded-full filter blur-md opacity-0 group-hover:opacity-100 transition-opacity"></div> </div> <div> <p class="text-green-400 text-sm">Something</p> <p class="text-xs text-gray-400">Premium Access</p> </div> </div> <div class="subscription-actions flex space-x-2"> <button onclick="cancelSubscription('something')" class="text-orange-400 hover:text-orange-300 p-1"> <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> </button> </div> </div> <?php endif; ?> <?php if(!$subscriptions['academ'] && !$subscriptions['ohmypanel'] && !$subscriptions['something']): ?> <p class="text-gray-400 text-sm text-center py-4">No subscription or account connected to an Imators service</p> <?php endif; ?> </div> </div> </div> <div class="gradient-border hover-scale"> <div class="glass-effect rounded-lg p-6"> <h3 class="font-medium mb-4">Connection Info</h3> <div class="space-y-3"> <div class="flex justify-between text-sm"> <span class="text-gray-400">Location</span> <span><?php echo htmlspecialchars(safe_json_decode($user['ip-connected'], [])['location'] ?? 'Unknown'); ?></span> </div> <div class="flex justify-between text-sm"> <span class="text-gray-400">Device</span> <span><?php echo htmlspecialchars(safe_json_decode($user['identified-screen'], [])['device'] ?? 'Unknown'); ?></span> </div> <div class="flex justify-between text-sm"> <span class="text-gray-400">Last Login</span> <span><?php echo safe_datetime($user['date-of-connect']); ?></span> </div> </div> </div> </div> </div> </div> </main> <div id="addCardModal" class="fixed inset-0 z-50 hidden overflow-y-auto"> <div class="fixed inset-0 bg-black bg-opacity-50 transition-opacity backdrop-blur-sm"></div> <div class="flex min-h-screen items-center justify-center p-4"> <div class="gradient-border relative w-full max-w-md"> <div class="glass-effect rounded-xl p-6"> <div class="flex items-center justify-between mb-6"> <h3 class="text-xl font-semibold text-white">Add Payment Method</h3> <button onclick="closeAddCardModal()" class="text-gray-400 hover:text-white transition-colors"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> </svg> </button> </div> <form id="payment-form" class="space-y-6"> <div class="space-y-4"> <div> <label class="block text-sm font-medium text-gray-300 mb-2">Card Information</label> <div id="card-element" class="p-4 bg-black/50 border border-white/10 rounded-lg"></div> <div id="card-errors" class="text-red-400 text-sm mt-2"></div> </div> <div> <label class="flex items-center space-x-3"> <input type="checkbox" id="makeDefault" name="makeDefault" class="rounded bg-black/30 border-white/20 text-indigo-600"> <span class="text-sm text-gray-300">Make this my default payment method</span> </label> </div> </div> <div class="flex justify-end gap-4"> <button type="button" onclick="closeAddCardModal()" class="px-4 py-2 rounded-lg border border-white/10 hover:bg-white/5 transition-colors text-gray-300"> Cancel </button> <button type="submit" id="submit-button" class="px-6 py-2 bg-white text-black rounded-lg font-medium hover:bg-gray-100 transition-all"> Add Card </button> </div> </form> </div> </div> </div> </div> <div id="ticketModal" class="fixed inset-0 z-50 hidden overflow-y-auto"> <div class="fixed inset-0 bg-black bg-opacity-50 transition-opacity backdrop-blur-sm"></div> <div class="flex min-h-screen items-center justify-center p-4"> <div class="gradient-border relative w-full max-w-2xl"> <div class="glass-effect rounded-xl p-6 sm:p-8"> <div class="flex items-center justify-between mb-6"> <h3 class="text-xl font-semibold text-white">Create New Support Ticket</h3> <button onclick="closeTicketModal()" class="text-gray-400 hover:text-white transition-colors"> <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /> </svg> </button> </div> <form action="create_ticket.php" method="POST" class="space-y-6" id="ticketForm"> <div> <label class="block text-sm font-medium text-gray-300 mb-2">Subject</label> <input type="text" name="subject" required class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none text-white placeholder-gray-500" placeholder="Brief description of your issue"> </div> <div> <label class="block text-sm font-medium text-gray-300 mb-2">Priority</label> <select name="priority" required class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none text-white"> <option value="low">Low</option> <option value="medium">Medium</option> <option value="high">High</option> </select> </div> <div> <label class="block text-sm font-medium text-gray-300 mb-2">Description</label> <textarea name="description" required rows="6" class="w-full px-4 py-3 rounded-lg bg-black/50 border border-white/10 focus:border-white/30 focus:outline-none text-white placeholder-gray-500" placeholder="Please provide detailed information about your issue..."></textarea> </div> <div class="flex justify-end gap-4"> <button type="button" onclick="closeTicketModal()" class="px-4 py-2 rounded-lg border border-white/10 hover:bg-white/5 transition-colors text-gray-300"> Cancel </button> <button type="submit" id="submitTicket" class="px-6 py-2 bg-white text-black rounded-lg font-medium hover:bg-gray-100 transition-all hover-scale"> Create Ticket </button> </div> </form> </div> </div> </div> </div> <script src="https://js.stripe.com/v3/"></script> <script> let stripe; let elements; let cardElement; document.addEventListener('DOMContentLoaded', function() { initializeStripe(); initializeEventListeners(); initializeProfileUpload(); }); function initializeStripe() { try { stripe = Stripe('pk_live_51LmhGsHQanXHoJn0qgKjMAisGwy6TzfZyUnzSq2Yc9qDmAQv8Syu9wuFDZVjgpg8kWUxm9bQ8MMi8E3WwNayGXus00Oe5tyNIP'); } catch (error) { console.error('Stripe initialization failed:', error); } } function initializeEventListeners() { const addCardBtn = document.getElementById('addCardBtn'); if (addCardBtn) { addCardBtn.addEventListener('click', openAddCardModal); } setupModalCloseEvents(); setupFormSubmissions(); } function initializeProfileUpload() { const profileInput = document.getElementById('profilePictureInput'); if (profileInput) { profileInput.addEventListener('change', handleProfileUpload); } } function handleProfileUpload(e) { if (e.target.files && e.target.files[0]) { const file = e.target.files[0]; const validTypes = ['image/jpeg', 'image/png', 'image/webp']; if (!validTypes.includes(file.type)) { showMessage('Please select a valid image (JPG, PNG, or WEBP)', 'error'); return; } if (file.size > 5 * 1024 * 1024) { showMessage('File size must be less than 5MB', 'error'); return; } const reader = new FileReader(); reader.onload = function(e) { const profilePreview = document.getElementById('profilePreview'); const uploadStatus = document.getElementById('uploadStatus'); if (profilePreview) profilePreview.src = e.target.result; if (uploadStatus) uploadStatus.style.display = 'flex'; const formData = new FormData(); formData.append('profile_picture', file); formData.append('update_profile', '1'); fetch(window.location.href, { method: 'POST', body: formData }) .then(response => { if (!response.ok) throw new Error('Network error'); return response.text(); }) .then(() => { showMessage('Profile picture updated successfully!'); setTimeout(() => window.location.reload(), 1000); }) .catch(error => { console.error('Upload error:', error); showMessage('Error uploading image', 'error'); }) .finally(() => { if (uploadStatus) uploadStatus.style.display = 'none'; }); }; reader.readAsDataURL(file); } } function setupModalCloseEvents() { document.addEventListener('click', function(e) { if (e.target.classList.contains('fixed') && e.target.classList.contains('inset-0')) { if (e.target.closest('#addCardModal')) closeAddCardModal(); if (e.target.closest('#ticketModal')) closeTicketModal(); } }); document.addEventListener('keydown', function(e) { if (e.key === 'Escape') { closeAddCardModal(); closeTicketModal(); } }); } function setupFormSubmissions() { const paymentForm = document.getElementById('payment-form'); if (paymentForm) { paymentForm.addEventListener('submit', handlePaymentSubmit); } const ticketForm = document.getElementById('ticketForm'); if (ticketForm) { ticketForm.addEventListener('submit', handleTicketSubmit); } document.querySelectorAll('form[method="POST"]').forEach(form => { if (form.id === 'payment-form' || form.id === 'ticketForm') return; form.addEventListener('submit', function(e) { const submitButton = this.querySelector('button[type="submit"]'); if (submitButton && !submitButton.disabled) { submitButton.disabled = true; submitButton.innerHTML = ` <svg class="animate-spin -ml-1 mr-3 h-5 w-5 inline-block" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> Processing... `; } }); }); } function openAddCardModal() { const modal = document.getElementById('addCardModal'); if (!modal) return; modal.classList.remove('hidden'); document.body.style.overflow = 'hidden'; if (!elements && stripe) { try { elements = stripe.elements(); cardElement = elements.create('card', { style: { base: { color: '#ffffff', fontFamily: 'Inter, sans-serif', fontSmoothing: 'antialiased', fontSize: '16px', '::placeholder': { color: '#6b7280' } }, invalid: { color: '#ef4444', iconColor: '#ef4444' } } }); const cardElementDiv = document.getElementById('card-element'); if (cardElementDiv) { cardElement.mount('#card-element'); cardElement.on('change', function(event) { const displayError = document.getElementById('card-errors'); if (displayError) { displayError.textContent = event.error ? event.error.message : ''; } }); } } catch (error) { console.error('Error creating Stripe elements:', error); } } // Force l'attachment de l'event listener ici const paymentForm = document.getElementById('payment-form'); if (paymentForm) { // Retire les anciens listeners paymentForm.removeEventListener('submit', handlePaymentSubmit); // Ajoute le nouveau paymentForm.addEventListener('submit', handlePaymentSubmit); console.log('Event listener attached to payment form'); } } function closeAddCardModal() { const modal = document.getElementById('addCardModal'); if (modal) { modal.classList.add('hidden'); document.body.style.overflow = 'auto'; } } async function handlePaymentSubmit(event) { event.preventDefault(); const submitButton = document.getElementById('submit-button'); const cardErrors = document.getElementById('card-errors'); if (submitButton) { submitButton.disabled = true; submitButton.innerHTML = ` <svg class="animate-spin -ml-1 mr-3 h-5 w-5 inline-block" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> Processing... `; } try { if (!stripe || !cardElement) { throw new Error('Stripe not properly initialized'); } const {token, error} = await stripe.createToken(cardElement); if (error) { console.error('Stripe token error:', error); if (cardErrors) cardErrors.textContent = error.message; return; } const makeDefaultCheckbox = document.getElementById('makeDefault'); const makeDefault = makeDefaultCheckbox ? makeDefaultCheckbox.checked : false; const requestData = { token: token.id, makeDefault: makeDefault }; console.log('Sending data:', requestData); const jsonString = JSON.stringify(requestData); console.log('JSON string:', jsonString); console.log('JSON string length:', jsonString.length); const response = await fetch('./add_payment_method.php', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: jsonString }); console.log('Response status:', response.status); console.log('Response ok:', response.ok); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const responseText = await response.text(); console.log('Response text:', responseText); if (!responseText || responseText.trim() === '') { throw new Error('Empty response from server'); } let result; try { result = JSON.parse(responseText.trim()); } catch (parseError) { console.error('JSON parse error:', parseError); console.error('Response text was:', responseText); throw new Error('Invalid JSON response from server'); } console.log('Parsed result:', result); if (result.success) { showMessage('Payment method added successfully!'); closeAddCardModal(); setTimeout(() => window.location.reload(), 1000); } else { throw new Error(result.error || 'Unknown error occurred'); } } catch (error) { console.error('Payment submission error:', error); if (cardErrors) cardErrors.textContent = error.message || 'An error occurred.'; showMessage(error.message || 'An error occurred', 'error'); } finally { if (submitButton) { submitButton.disabled = false; submitButton.innerHTML = 'Add Card'; } } } function openTicketModal() { const modal = document.getElementById('ticketModal'); if (modal) { modal.classList.remove('hidden'); document.body.style.overflow = 'hidden'; } } function closeTicketModal() { const modal = document.getElementById('ticketModal'); const form = document.getElementById('ticketForm'); if (modal) { modal.classList.add('hidden'); document.body.style.overflow = 'auto'; } if (form) { form.reset(); } } function handleTicketSubmit(e) { const submitButton = document.getElementById('submitTicket'); if (submitButton) { submitButton.disabled = true; submitButton.innerHTML = ` <svg class="animate-spin -ml-1 mr-3 h-5 w-5 inline-block" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> </svg> Creating ticket... `; } } function setDefaultCard(cardId) { if (confirm('Set this as your default payment method?')) { fetch('./update_payment_method.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ card_id: cardId, action: 'set_default' }) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage('Default payment method updated!'); setTimeout(() => window.location.reload(), 1000); } else { throw new Error(result.error || 'Failed to update payment method'); } }) .catch(error => { console.error('Set default error:', error); showMessage(error.message || 'An error occurred. Please try again.', 'error'); }); } } function deleteCard(cardId) { if (confirm('Are you sure you want to delete this payment method?')) { fetch('./update_payment_method.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ card_id: cardId, action: 'delete' }) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage('Payment method deleted successfully!'); setTimeout(() => window.location.reload(), 1000); } else { throw new Error(result.error || 'Failed to delete payment method'); } }) .catch(error => { console.error('Delete card error:', error); showMessage(error.message || 'An error occurred. Please try again.', 'error'); }); } } function cancelSubscription(service) { if (confirm('Are you sure you want to cancel this subscription?')) { fetch('./manage_subscription.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'cancel', service: service }) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage('Subscription cancelled successfully'); setTimeout(() => window.location.reload(), 1000); } else { throw new Error(result.error || 'Error cancelling subscription'); } }) .catch(error => { showMessage(error.message, 'error'); }); } } function disconnectService(service) { if (confirm('Are you sure you want to disconnect this service?')) { fetch('./manage_subscription.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'disconnect', service: service }) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage('Service successfully disconnected'); setTimeout(() => window.location.reload(), 1000); } else { throw new Error(result.error || 'Error disconnecting service'); } }) .catch(error => { showMessage(error.message, 'error'); }); } } function showMessage(message, type = 'success') { const flashContainer = document.createElement('div'); flashContainer.className = `fixed top-4 right-4 p-4 rounded-lg z-50 transform transition-all duration-300 opacity-0 translate-y-[-20px] ${ type === 'success' ? 'bg-green-500/10 border border-green-500/20 text-green-400' : 'bg-red-500/10 border border-red-500/20 text-red-400' }`; flashContainer.textContent = message; document.body.appendChild(flashContainer); setTimeout(() => { flashContainer.style.opacity = '1'; flashContainer.style.transform = 'translateY(0)'; }, 100); setTimeout(() => { flashContainer.style.opacity = '0'; flashContainer.style.transform = 'translateY(-20px)'; setTimeout(() => flashContainer.remove(), 300); }, 5000); } window.addEventListener('error', function(e) { console.error('Global error:', e.error); }); window.addEventListener('unhandledrejection', function(e) { console.error('Unhandled promise rejection:', e.reason); }); </script> <footer class="py-8 mt-12 border-t border-white/5"> <div class="max-w-6xl mx-auto px-4 sm:px-6"> <div class="flex flex-col items-center justify-center space-y-4"> <img src="https://cdn.imators.com/logo.png" alt="Imators Logo" class="h-8 opacity-50"> <p class="text-gray-400 text-sm text-center"> <?php echo date('Y'); ?> Imators. All rights reserved.<br> <span class="text-gray-500">Secure authentication system</span> </p> </div> </div> </footer> </body> </html>
| ver. 1.6 |
Github
|
.
| PHP 8.1.33 | Генерация страницы: 0.01 |
proxy
|
phpinfo
|
Настройка