AliceInBorderlandsS1 / admin.html
hrmndev's picture
Add 1 files
c3eee25 verified
raw
history blame
96 kB
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin - Harmon Yazılım</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
min-height: 100vh;
font-family: 'Inter', sans-serif;
background: #0a0a0a;
color: #e1e1e1;
font-size: 14px;
}
.login-container {
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 20px;
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a1a 100%);
}
.login-form {
background: #1a1a1a;
padding: 30px;
border-radius: 12px;
width: 100%;
max-width: 400px;
box-shadow: 0 8px 16px rgba(0,0,0,0.2);
}
.login-form h1 {
font-size: 24px;
margin-bottom: 20px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-size: 14px;
}
.form-group input {
width: 100%;
padding: 10px;
border: 1px solid #2d3748;
border-radius: 6px;
background: #0a0a0a;
color: #e1e1e1;
font-size: 14px;
}
.btn {
padding: 10px 20px;
font-size: 14px;
border-radius: 6px;
cursor: pointer;
border: none;
background: #3498db;
color: white;
transition: all 0.3s ease;
}
.btn:hover {
background: #2980b9;
}
.admin-container {
display: none;
min-height: 100vh;
margin-left: 250px;
}
.sidebar {
width: 250px;
position: fixed;
left: 0;
top: 0;
height: 100vh;
background: #1a1a1a;
padding: 20px;
box-sizing: border-box;
}
.sidebar-header {
padding: 0 0 20px 0;
margin-bottom: 20px;
border-bottom: 1px solid #2d3748;
}
.sidebar-header h2 {
font-size: 20px;
color: #3498db;
}
.sidebar-menu {
list-style: none;
padding: 0;
margin: 0;
}
.sidebar-menu li {
margin-bottom: 10px;
}
.sidebar-menu a {
display: flex;
align-items: center;
padding: 12px 15px;
color: #e1e1e1;
text-decoration: none;
border-radius: 6px;
transition: all 0.3s ease;
}
.sidebar-menu a.active {
background: #3498db;
color: white;
}
.sidebar-menu a:hover {
background: rgba(52, 152, 219, 0.1);
}
.sidebar-menu a.active:hover {
background: #3498db;
}
.sidebar-menu i {
margin-right: 10px;
width: 20px;
}
.navbar {
position: fixed;
top: 0;
right: 0;
left: 250px;
height: 8vh;
background: #1a1a1a;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 100;
}
.navbar-brand {
display: flex;
align-items: center;
gap: 0.5rem;
color: #3498db;
font-size: 1.25rem;
font-weight: 600;
}
.navbar-menu {
display: flex;
align-items: center;
gap: 1rem;
}
.navbar-menu .btn {
padding: 0.5rem 1rem;
min-width: auto;
}
.content-area {
padding: 10vh 20px 20px;
}
.page-title {
margin-bottom: 2rem;
color: #3498db;
font-size: 1.5rem;
font-weight: 600;
}
.user-list {
display: grid;
gap: 1.5rem;
}
.user-card {
background: #1a1a1a;
border-radius: 8px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 10px;
word-wrap: break-word;
overflow-wrap: break-word;
}
.user-header {
margin-bottom: 20px;
}
.user-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-item {
background: #0a0a0a;
padding: 15px;
border-radius: 6px;
}
.user-actions {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.user-actions .btn {
flex: 1;
min-width: 120px;
padding: 0.75rem 1rem;
}
.btn-secondary {
background-color: transparent;
border: 2px solid #3498db;
color: #3498db;
}
.btn-secondary:hover {
background-color: rgba(52,152,219,0.1);
transform: translateY(-1px);
}
.btn-danger {
background-color: #e74c3c;
color: white;
}
.btn-danger:hover {
background-color: #c0392b;
}
.status-badge {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
display: inline-flex;
align-items: center;
gap: 4px;
}
.status-badge.verified {
background-color: #2ecc71;
color: white;
}
.status-badge.unverified {
background-color: #e74c3c;
color: white;
}
.stat-value {
word-break: break-all;
max-height: 15vh;
overflow-y: auto;
padding-right: 5px;
}
.api-details {
background: #0a0a0a;
padding: 1rem;
border-radius: 4px;
overflow-x: auto;
color: #e1e1e1;
font-family: monospace;
font-size: 0.9rem;
white-space: pre-wrap;
word-wrap: break-word;
max-height: 50vh;
overflow-y: auto;
}
.modal-body {
padding: 1rem;
max-height: 80vh;
overflow-y: auto;
word-wrap: break-word;
overflow-wrap: break-word;
}
.user-auth {
word-break: break-all;
max-width: 100%;
display: inline-block;
}
/* Custom scrollbar styles */
.stat-value::-webkit-scrollbar,
.api-details::-webkit-scrollbar,
.modal-body::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.stat-value::-webkit-scrollbar-track,
.api-details::-webkit-scrollbar-track,
.modal-body::-webkit-scrollbar-track {
background: #1a1a1a;
border-radius: 4px;
}
.stat-value::-webkit-scrollbar-thumb,
.api-details::-webkit-scrollbar-thumb,
.modal-body::-webkit-scrollbar-thumb {
background: #2d3748;
border-radius: 4px;
}
.stat-value::-webkit-scrollbar-thumb:hover,
.api-details::-webkit-scrollbar-thumb:hover,
.modal-body::-webkit-scrollbar-thumb:hover {
background: #3498db;
}
@media (max-width: 768px) {
.admin-container {
margin-left: 0;
}
.sidebar {
transform: translateX(-100%);
z-index: 1001;
box-shadow: 2px 0 10px rgba(0,0,0,0.5);
}
.sidebar.active {
transform: translateX(0);
}
.navbar {
left: 0;
padding: 0 0.8rem;
height: 7vh;
}
.navbar-brand {
font-size: 1.1rem;
}
.content-area {
padding: 8vh 0.8rem 0.8rem;
}
.user-stats {
grid-template-columns: 1fr;
gap: 0.8rem;
}
.user-actions {
flex-direction: column;
gap: 0.8rem;
}
.user-actions .btn {
width: 100%;
min-width: unset;
}
.user-card {
padding: 0.8rem;
}
.modal-content {
width: 95%;
padding: 1rem;
margin: 0.8rem;
}
.detail-grid {
grid-template-columns: 1fr;
}
.input-group {
flex-direction: column;
gap: 0.8rem;
}
.input-group .btn {
width: 100%;
}
.settings-form {
padding: 0.8rem;
}
}
@media (max-width: 480px) {
.login-form {
padding: 1rem;
margin: 0.8rem;
}
.navbar {
padding: 0 0.6rem;
height: 6vh;
}
.navbar-brand {
font-size: 1rem;
}
.navbar-menu .btn {
padding: 0.35rem 0.6rem;
font-size: 0.85rem;
}
.content-area {
padding: 7vh 0.6rem 0.6rem;
}
.page-title {
font-size: 1.2rem;
margin-bottom: 1rem;
}
.user-card {
padding: 0.6rem;
}
.user-header {
margin-bottom: 0.8rem;
}
.stat-item {
padding: 0.6rem;
}
.form-group {
margin-bottom: 0.8rem;
}
.form-group input {
padding: 0.4rem;
font-size: 0.9rem;
}
.btn {
padding: 0.35rem 0.6rem;
font-size: 0.85rem;
}
.modal-content {
padding: 0.8rem;
}
.modal-header {
padding: 0.6rem;
}
.modal-body {
padding: 0.6rem;
}
.detail-section {
padding: 0.6rem;
margin-bottom: 0.8rem;
}
.detail-section h4 {
font-size: 1rem;
margin-bottom: 0.8rem;
}
.api-details {
padding: 0.6rem;
font-size: 0.8rem;
}
.status-badge {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
}
}
.mobile-menu-toggle {
display: none;
background: none;
border: none;
color: #3498db;
font-size: 1.5rem;
cursor: pointer;
}
@media (max-width: 768px) {
.mobile-menu-toggle {
display: block;
}
}
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
background: #1a1a1a;
padding: 20px;
border-radius: 12px;
width: 90%;
max-width: 600px;
max-height: 90vh;
overflow-y: auto;
}
.modal-header {
padding: 1rem;
border-bottom: 1px solid #2c2c2c;
display: flex;
justify-content: space-between;
align-items: center;
}
.detail-section {
background: #1f1f1f;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.detail-section h4 {
color: #3498db;
margin-bottom: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 1.1rem;
}
.detail-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
.detail-item {
background: #2c2c2c;
padding: 1rem;
border-radius: 6px;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.detail-label {
color: #888;
font-size: 0.9rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.detail-value {
color: #e1e1e1;
font-size: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
}
.input-group {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.input-group .form-control {
flex: 1;
min-width: 200px;
padding: 0.5rem;
background: #2c2c2c;
border: 1px solid #3d3d3d;
border-radius: 4px;
color: #e1e1e1;
}
.input-group .btn {
white-space: nowrap;
}
.btn-sm {
padding: 0.25rem 0.5rem;
font-size: 0.875rem;
}
.status-badge {
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.875rem;
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-weight: 500;
}
/* Responsive container */
.container {
width: 100%;
max-width: 100%;
padding: 10px;
box-sizing: border-box;
margin-left: 250px;
}
/* Responsive cards */
.stat-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 20px;
}
.stat-card {
background: #1a1a1a;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Responsive tables */
.table-responsive {
overflow-x: auto;
margin: 15px 0;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #2d3748;
}
/* Alert düzeltmesi */
.alert {
padding: 12px;
border-radius: 6px;
margin-bottom: 15px;
}
.alert-success {
background: #2ecc71;
color: white;
}
.alert-error {
background: #e74c3c;
color: white;
}
/* Scrollbar düzeltmesi */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #1a1a1a;
}
::-webkit-scrollbar-thumb {
background: #2d3748;
border-radius: 4px;
}
/* Ana içerik alanı */
.main-content {
margin-top: 60px;
padding: 15px;
box-sizing: border-box;
}
@media (max-width: 768px) {
.main-content {
margin-top: 50px;
padding: 10px;
}
}
/* Kullanıcı kartları */
.user-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
padding: 15px;
}
.user-card {
background: #1a1a1a;
border-radius: 8px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 10px;
}
@media (max-width: 480px) {
.user-cards {
grid-template-columns: 1fr;
padding: 10px;
}
.user-card {
padding: 10px;
}
}
/* Domain listesi */
.domain-list {
display: grid;
gap: 10px;
padding: 10px;
max-height: 60vh;
}
.domain-item {
background: #1a1a1a;
border-radius: 8px;
padding: 10px;
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: 10px;
}
@media (max-width: 480px) {
.domain-list {
padding: 5px;
}
.domain-item {
grid-template-columns: 1fr;
padding: 8px;
}
}
/* Ayarlar formu */
.settings-form {
max-width: 600px;
margin: 0 auto;
padding: 15px;
}
.settings-form .form-group {
margin-bottom: 15px;
}
@media (max-width: 480px) {
.settings-form {
padding: 10px;
}
}
/* Loading spinner */
.loading-spinner {
width: 20px;
height: 20px;
border: 2px solid #f3f3f3;
border-top: 2px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Uzun metinler için */
.text-truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
}
/* Grid layout için */
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
padding: 10px;
}
/* Flex container için */
.flex-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 10px;
}
/* Tooltip için */
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltip-text {
visibility: hidden;
background-color: #2d3748;
color: #e1e1e1;
text-align: center;
padding: 5px;
border-radius: 4px;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
font-size: 11px;
white-space: nowrap;
}
.tooltip:hover .tooltip-text {
visibility: visible;
}
.modal-close {
background: none;
border: none;
color: #e1e1e1;
font-size: 1.5rem;
cursor: pointer;
padding: 0.5rem;
transition: color 0.3s ease;
}
.modal-close:hover {
color: #3498db;
}
/* Add new styles for stats and search */
.stats-bar {
display: flex;
gap: 20px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.stat-box {
background: #1a1a1a;
padding: 15px 20px;
border-radius: 8px;
display: flex;
align-items: center;
gap: 15px;
flex: 1;
min-width: 200px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.stat-box i {
font-size: 24px;
color: #3498db;
}
.stat-info {
display: flex;
flex-direction: column;
}
.stat-label {
font-size: 14px;
color: #888;
}
.stat-value {
font-size: 24px;
font-weight: 600;
color: #e1e1e1;
}
.search-bar {
margin-bottom: 20px;
}
.search-bar input {
width: 100%;
padding: 12px;
border: 1px solid #2d3748;
border-radius: 8px;
background: #1a1a1a;
color: #e1e1e1;
font-size: 14px;
transition: all 0.3s ease;
}
.search-bar input:focus {
border-color: #3498db;
box-shadow: 0 0 0 2px rgba(52,152,219,0.2);
outline: none;
}
.user-item.hidden,
.domain-item.hidden {
display: none;
}
/* Add styles for copy button */
.btn-icon {
background: none;
border: none;
color: #3498db;
cursor: pointer;
padding: 5px;
margin-left: 5px;
border-radius: 4px;
transition: all 0.3s ease;
}
.btn-icon:hover {
background: rgba(52, 152, 219, 0.1);
transform: scale(1.1);
}
.user-auth {
display: flex;
align-items: center;
gap: 5px;
}
/* Add new styles for verification badges */
.status-badges {
display: flex;
gap: 8px;
align-items: center;
}
.status-badge.verified {
background: #2ecc71;
color: white;
}
.status-badge.unverified {
background: #e67e22;
color: white;
}
.btn-success {
background: #2ecc71;
color: white;
}
.btn-success:hover {
background: #27ae60;
}
.user-card[data-auth="1r2yvw8guhpd1rzu29uarxkm4nveqxf2"] {
border: 1px solid #3498db;
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.2);
}
.reseller-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
padding: 1rem 0;
}
.reseller-card {
background: #1f1f1f;
border-radius: 8px;
padding: 1.5rem;
display: flex;
flex-direction: column;
gap: 1rem;
transition: all 0.3s ease;
border: 1px solid #2c2c2c;
}
.reseller-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
border-color: #3498db;
}
.reseller-header {
display: flex;
align-items: center;
gap: 1rem;
}
.reseller-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
object-fit: cover;
border: 2px solid #3498db;
}
.reseller-info {
flex: 1;
}
.reseller-name {
font-size: 1.1rem;
font-weight: 500;
color: #3498db;
margin-bottom: 0.25rem;
}
.reseller-website {
font-size: 0.9rem;
color: #888;
text-decoration: none;
transition: color 0.3s ease;
}
.reseller-website:hover {
color: #3498db;
}
.reseller-description {
color: #e1e1e1;
font-size: 0.9rem;
line-height: 1.4;
}
.form-group textarea {
width: 100%;
min-height: 150px;
resize: vertical;
padding: 10px;
border: 1px solid #2d3748;
border-radius: 6px;
background: #0a0a0a;
color: #e1e1e1;
font-size: 14px;
font-family: 'Inter', sans-serif;
line-height: 1.5;
}
.form-group textarea:focus {
border-color: #3498db;
outline: none;
box-shadow: 0 0 0 2px rgba(52,152,219,0.2);
}
.user-avatar {
width: 60px;
height: 60px;
border-radius: 50%;
border: 2px solid #3498db;
flex-shrink: 0;
background: #1a1a1a;
position: relative;
overflow: hidden;
}
.user-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.user-header {
display: flex;
align-items: center;
gap: 1rem;
}
.user-info {
flex: 1;
}
.user-info h3 {
color: #3498db;
margin-bottom: 0.25rem;
}
.user-info a {
color: #888;
text-decoration: none;
font-size: 0.9rem;
transition: color 0.3s ease;
}
.user-info a:hover {
color: #3498db;
}
#toastContainer {
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
}
.toast {
background: #333;
color: white;
padding: 12px 24px;
border-radius: 4px;
margin-bottom: 10px;
min-width: 200px;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
animation: slideIn 0.3s ease-in-out;
}
.toast.toast-success {
background: #2ecc71;
}
.toast.toast-error {
background: #e74c3c;
}
.toast.toast-warning {
background: #f1c40f;
}
.toast.fade-out {
animation: slideOut 0.3s ease-in-out forwards;
}
@keyframes slideIn {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
@keyframes slideOut {
from {
transform: translateX(0);
opacity: 1;
}
to {
transform: translateX(100%);
opacity: 0;
}
}
.detail-item {
display: flex;
align-items: center;
gap: 8px;
}
.detail-item .btn-sm {
padding: 2px 8px;
font-size: 12px;
}
.detail-value.user-auth {
display: flex;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
background: #1a1a1a;
padding: 0.5rem;
border-radius: 4px;
font-family: monospace;
}
.detail-value.user-auth .input-group {
margin-top: 0.5rem;
width: 100%;
}
.detail-value.user-auth .btn-sm {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
}
.detail-value.user-auth .form-control {
background: #2c2c2c;
border: 1px solid #3d3d3d;
color: #e1e1e1;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-family: monospace;
}
</style>
</head>
<body>
<div class="login-container" id="loginContainer">
<form class="login-form" id="loginForm" onsubmit="login(event)">
<h1>Admin Girişi</h1>
<div class="form-group">
<label>Kullanıcı Adı</label>
<input type="text" id="username" required>
</div>
<div class="form-group">
<label>Şifre</label>
<input type="password" id="password" required>
</div>
<button type="submit" class="btn">Giriş Yap</button>
</form>
</div>
<div class="admin-container" id="adminContainer">
<aside class="sidebar" id="sidebar">
<div class="sidebar-header">
<h2>Admin Panel</h2>
</div>
<ul class="sidebar-menu">
<li>
<a href="#" data-page="users" onclick="changePage('users')" class="active">
<i class="fas fa-users"></i>
Kullanıcılar
</a>
</li>
<li>
<a href="#" data-page="domains" onclick="changePage('domains')">
<i class="fas fa-globe"></i>
Domainler
</a>
</li>
<li>
<a href="#" data-page="promo" onclick="changePage('promo')">
<i class="fas fa-gift"></i>
Promo Kodları
</a>
</li>
<li>
<a href="#" data-page="settings" onclick="changePage('settings')">
<i class="fas fa-cog"></i>
Ayarlar
</a>
</li>
<li>
<a href="#" data-page="resellers" onclick="changePage('resellers')">
<i class="fas fa-user-check"></i>
Resellerlar
</a>
</li>
</ul>
</aside>
<nav class="navbar">
<button class="mobile-menu-toggle" onclick="toggleSidebar()">
<i class="fas fa-bars"></i>
</button>
<div class="navbar-brand">
<i class="fas fa-shield-alt"></i>
Admin - Harmon Yazılım
</div>
<div class="navbar-menu">
<button class="btn btn-secondary" onclick="logout()">
<i class="fas fa-sign-out-alt"></i>
Çıkış Yap
</button>
</div>
</nav>
<main class="content-area">
<div id="usersPage" class="page active">
<h1 class="page-title">Kullanıcı Yönetimi</h1>
<div class="stats-bar">
<div class="stat-box">
<i class="fas fa-users"></i>
<div class="stat-info">
<span class="stat-label">Toplam Kullanıcı</span>
<span class="stat-value" id="totalUserCount">0</span>
</div>
</div>
</div>
<div class="search-bar">
<input type="text" id="userSearch" placeholder="Kullanıcı ara..." onkeyup="searchUsers()">
</div>
<div class="user-list" id="userList">
<!-- Users will be loaded here -->
</div>
</div>
<div id="domainsPage" class="page">
<h2 class="page-title">Domainler</h2>
<div class="stats-bar">
<div class="stat-box">
<i class="fas fa-globe"></i>
<div class="stat-info">
<span class="stat-label">Toplam Domain</span>
<span class="stat-value" id="totalDomainCount">0</span>
</div>
</div>
</div>
<div class="search-bar">
<input type="text" id="domainSearch" placeholder="Domain ara..." onkeyup="searchDomains()">
</div>
<div class="user-actions" style="margin-bottom: 20px;">
<button class="btn" onclick="loadAllDomainsFromApi()">
<i class="fas fa-sync"></i>
Tüm Domainleri Yükle
</button>
</div>
<div id="domainList" class="user-list">
<!-- Domain cards will be loaded here -->
</div>
</div>
<div id="promoPage" class="page">
<h2 class="page-title">Promo Kodları</h2>
<div class="user-actions" style="margin-bottom: 20px;">
<button class="btn" onclick="createPromoCode()">
<i class="fas fa-plus"></i>
Yeni Promo Kodu Oluştur
</button>
</div>
<div id="promoList" class="user-list">
<!-- Promo code cards will be loaded here -->
</div>
</div>
<div id="resellersPage" class="page">
<h2 class="page-title">Reseller Yönetimi</h2>
<div class="user-actions" style="margin-bottom: 20px;">
<button class="btn" onclick="addReseller()">
<i class="fas fa-plus"></i>
Yeni Reseller Ekle
</button>
</div>
<div id="resellerList" class="user-list">
<!-- Reseller cards will be loaded here -->
</div>
</div>
<div id="settingsPage" class="page">
<h1 class="page-title">Sistem Ayarları</h1>
<div class="settings-form">
<div class="form-group">
<label>API URL</label>
<input type="text" id="apiUrl" value="https://harmon.web.tr" readonly>
</div>
<div class="form-group">
<label>Admin Kullanıcı Adı</label>
<input type="text" id="adminUsername">
</div>
<div class="form-group">
<label>Yeni Şifre</label>
<input type="password" id="newPassword">
</div>
<button class="btn" onclick="saveSettings()">Kaydet</button>
</div>
</div>
</main>
</div>
<script>
const BASE_URL = 'https://harmon.web.tr';
const API_URL = `${BASE_URL}/control.php`;
let adminToken = localStorage.getItem('adminToken');
// Check if already logged in
if (adminToken) {
showAdminPanel();
loadUsers();
// Set initial active tab
document.querySelector('[data-page="users"]').classList.add('active');
}
async function login(event) {
event.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
try {
const response = await fetch(`${API_URL}?action=adminLogin`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (data.success) {
adminToken = data.data.token;
// Use permanent storage instead of session storage
localStorage.setItem('adminToken', adminToken);
localStorage.setItem('adminUsername', username); // Store username too
showAdminPanel();
loadUsers();
} else {
alert(data.message);
}
} catch (error) {
console.error('Login error:', error);
alert('Giriş yapılırken bir hata oluştu.');
}
}
function showAdminPanel() {
document.getElementById('loginContainer').style.display = 'none';
document.getElementById('adminContainer').style.display = 'block';
}
function logout() {
localStorage.removeItem('adminToken');
location.reload();
}
async function loadUsers() {
try {
const response = await fetch(`${API_URL}?action=getAllUsers`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (data.success) {
const userList = document.getElementById('userList');
// Update total user count
document.getElementById('totalUserCount').textContent = data.data.length;
// Sort users to keep the pinned auth code at top
const sortedUsers = data.data.sort((a, b) => {
if (a.auth_code === '1r2YvW8GUhpD1RZu29uarXKM4NveQXf2') return -1;
if (b.auth_code === '1r2YvW8GUhpD1RZu29uarXKM4NveQXf2') return 1;
return 0;
});
userList.innerHTML = sortedUsers.map(user => `
<div class="user-card" data-auth="${user.auth_code.toLowerCase()}">
<div class="user-header">
<span class="user-auth">${user.auth_code}${user.auth_code === '1r2YvW8GUhpD1RZu29uarXKM4NveQXf2' ? ' <i class="fas fa-thumbtack" style="color: #3498db;"></i>' : ''}</span>
<span class="status-badge ${user.status !== 'active' ? 'inactive' : ''}">${
user.status.charAt(0).toUpperCase() + user.status.slice(1)
}</span>
</div>
<div class="user-stats">
<div class="stat-item">
<div class="stat-label">Domain Sayısı</div>
<div class="stat-value">${user.domain_count}</div>
</div>
<div class="stat-item">
<div class="stat-label">Domain Kredisi</div>
<div class="stat-value">${user.domain_credit}</div>
</div>
<div class="stat-item">
<div class="stat-label">Son Giriş</div>
<div class="stat-value">${new Date(user.last_login).toLocaleDateString('tr-TR')}</div>
</div>
</div>
<div class="user-actions">
<button class="btn" onclick="updateCredit(${user.id}, ${user.domain_credit})">
Kredi Güncelle
</button>
<button class="btn btn-secondary" onclick="viewDomains(${user.id})">
Domainler
</button>
<button class="btn ${user.status === 'active' ? 'btn-danger' : ''}"
onclick="toggleStatus(${user.id}, '${user.status}')">
${user.status === 'active' ? 'Devre Dışı Bırak' : 'Aktifleştir'}
</button>
<button class="btn btn-secondary" onclick="loginAsUser('${user.auth_code}')">
<i class="fas fa-sign-in-alt"></i> Kullanıcı Olarak Giriş
</button>
<button class="btn btn-success" onclick="verifyUserDomains(${user.id})">
<i class="fas fa-check-double"></i> Tüm Domainleri Doğrula
</button>
</div>
</div>
`).join('');
} else {
alert(data.message);
}
} catch (error) {
console.error('Error loading users:', error);
alert('Kullanıcılar yüklenirken bir hata oluştu.');
}
}
async function updateCredit(userId, currentCredit) {
const credit = prompt('Yeni kredi miktarı:', currentCredit);
if (credit === null) return;
try {
const response = await fetch(`${API_URL}?action=updateUserCredit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ userId, credit: parseInt(credit) })
});
const data = await response.json();
if (data.success) {
loadUsers();
} else {
alert(data.message);
}
} catch (error) {
console.error('Error updating credit:', error);
alert('Kredi güncellenirken bir hata oluştu.');
}
}
async function toggleStatus(userId, currentStatus) {
const newStatus = currentStatus === 'active' ? 'inactive' : 'active';
try {
const response = await fetch(`${API_URL}?action=updateUserStatus`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ userId, status: newStatus })
});
const data = await response.json();
if (data.success) {
loadUsers();
} else {
alert(data.message);
}
} catch (error) {
console.error('Error updating status:', error);
alert('Durum güncellenirken bir hata oluştu.');
}
}
async function viewDomains(userId) {
try {
const response = await fetch(`${API_URL}?action=getUserDomains&userId=${userId}`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (data.success) {
// Create modal content
const modalContent = `
<div class="modal-content">
<div class="modal-header">
<h3>Kullanıcı Domainleri</h3>
<button class="modal-close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<div class="domain-list">
${data.data.length > 0 ? data.data.map(domain => `
<div class="domain-item">
<div class="domain-info">
<div class="domain-name">${domain.domain_name}</div>
<div class="domain-status">
<span class="status-badge ${domain.status !== 'active' ? 'inactive' : ''}">${domain.status}</span>
<span class="status-badge ${domain.verified ? 'verified' : 'unverified'}">
<i class="fas ${domain.verified ? 'fa-check-circle' : 'fa-exclamation-circle'}"></i>
${domain.verified ? 'Doğrulanmış' : 'Doğrulanmamış'}
</span>
</div>
</div>
<div class="domain-date">
Kayıt: ${new Date(domain.created_at).toLocaleDateString('tr-TR')}
</div>
</div>
`).join('') : '<p>Bu kullanıcının domaini bulunmuyor.</p>'}
</div>
</div>
</div>
`;
// Create and show modal
const modal = document.createElement('div');
modal.className = 'modal';
modal.id = 'domainsModal';
modal.innerHTML = modalContent;
document.body.appendChild(modal);
// Add modal close event
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});
// Add styles for domain list
const style = document.createElement('style');
style.textContent = `
.domain-list {
display: flex;
flex-direction: column;
gap: 10px;
max-height: 60vh;
overflow-y: auto;
padding: 10px;
}
.domain-item {
background: #1a1a1a;
border-radius: 8px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 10px;
}
.domain-info {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.domain-name {
font-weight: 500;
word-break: break-all;
}
.domain-status {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.domain-date {
font-size: 0.9em;
color: #888;
}
`;
document.head.appendChild(style);
} else {
alert(data.message);
}
} catch (error) {
console.error('Error loading domains:', error);
alert('Domainler yüklenirken bir hata oluştu.');
}
}
function toggleSidebar() {
const sidebar = document.getElementById('sidebar');
sidebar.classList.toggle('active');
}
// Close sidebar when clicking outside on mobile
document.addEventListener('click', function(event) {
const sidebar = document.getElementById('sidebar');
const mobileMenuToggle = document.querySelector('.mobile-menu-toggle');
if (window.innerWidth <= 768 &&
!sidebar.contains(event.target) &&
!mobileMenuToggle.contains(event.target) &&
sidebar.classList.contains('active')) {
sidebar.classList.remove('active');
}
});
function changePage(page) {
// Remove active class from all pages and menu items
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
document.querySelectorAll('.sidebar-menu a').forEach(a => a.classList.remove('active'));
// Add active class to selected page and menu item
document.getElementById(page + 'Page').classList.add('active');
document.querySelector(`[data-page="${page}"]`).classList.add('active');
// Close sidebar on mobile after page change
if (window.innerWidth <= 768) {
document.getElementById('sidebar').classList.remove('active');
}
// Load page specific content
switch(page) {
case 'users':
loadUsers();
break;
case 'domains':
loadAllDomains();
break;
case 'promo':
loadPromoCodes();
break;
case 'settings':
loadSettings();
break;
case 'resellers':
loadResellers();
break;
}
}
async function loadAllDomains() {
try {
const response = await fetch(`${API_URL}?action=getAllDomains`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (data.success) {
const domainList = document.getElementById('domainList');
document.getElementById('totalDomainCount').textContent = data.data.length;
domainList.innerHTML = data.data.map(domain => `
<div class="user-card" data-domain="${domain.domain_name}">
<div class="user-header">
<div class="user-info">
<h3>${domain.domain_name}</h3>
<div class="user-meta">
<span class="user-auth">
<i class="fas fa-user"></i>
${domain.user_auth_code || 'Atanmamış'}
</span>
<span>
<i class="fas fa-calendar"></i>
${new Date(domain.registration_date).toLocaleDateString('tr-TR')}
</span>
<span>
<i class="fas fa-clock"></i>
${new Date(domain.expiry_date).toLocaleDateString('tr-TR')}
</span>
<span class="status-badge ${domain.status === 'active' ? 'active' : 'inactive'}">
<i class="fas fa-${domain.status === 'active' ? 'check' : 'times'}-circle"></i>
${domain.status === 'active' ? 'Aktif' : 'Pasif'}
</span>
</div>
</div>
<div class="user-actions">
${domain.status !== 'active' ? `
<button class="btn btn-sm btn-success" onclick="verifyDomain('${domain.domain_name}')">
<i class="fas fa-check"></i> Doğrula
</button>
` : ''}
<button class="btn btn-sm btn-primary" onclick="viewDomainDetails('${domain.domain_name}')">
<i class="fas fa-info-circle"></i> Detaylar
</button>
<button class="btn btn-sm btn-danger" onclick="deleteDomain('${domain.domain_name}')">
<i class="fas fa-trash"></i> Sil
</button>
</div>
</div>
</div>
`).join('');
} else {
alert(data.message);
}
} catch (error) {
console.error('Error loading domains:', error);
alert('Domainler yüklenirken bir hata oluştu.');
}
}
async function viewDomainDetails(domain) {
try {
const response = await fetch(`${API_URL}?action=getDomainDetails&domain=${domain}`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (data.success) {
const domainData = data.data.domain;
const apiDetails = data.data.api_details;
// Create modal content
const modalContent = `
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Domain Detayları</h3>
<button class="modal-close" onclick="closeModal()">&times;</button>
</div>
<div class="modal-body">
<div class="detail-section">
<h4>
<i class="fas fa-globe"></i>
${domain}
</h4>
<div class="detail-grid">
<div class="detail-item">
<div class="detail-label">
<i class="fas fa-info-circle"></i>
Durum
</div>
<div class="detail-value">
<span class="status-badge ${domainData.status === 'active' ? 'active' : 'inactive'}">
<i class="fas fa-${domainData.status === 'active' ? 'check' : 'times'}-circle"></i>
${domainData.status === 'active' ? 'Aktif' : 'Pasif'}
</span>
</div>
</div>
<div class="detail-item">
<div class="detail-label">
<i class="fas fa-calendar"></i>
Kayıt Tarihi
</div>
<div class="detail-value">
${new Date(domainData.created_at).toLocaleDateString('tr-TR')}
</div>
</div>
<div class="detail-item">
<div class="detail-label">
<i class="fas fa-user"></i>
Mevcut Kullanıcı
</div>
<div class="detail-value user-auth">
${domainData.user_auth_code || 'Atanmamış'}
</div>
</div>
<div class="detail-item">
<div class="detail-label">
<i class="fas fa-shield-alt"></i>
Doğrulama Durumu
</div>
<div class="detail-value">
<span class="status-badge ${domainData.verified ? 'verified' : 'unverified'}">
<i class="fas fa-${domainData.verified ? 'check' : 'exclamation'}-circle"></i>
${domainData.verified ? 'Doğrulanmış' : 'Doğrulanmamış'}
</span>
${!domainData.verified ? `
<button class="btn btn-sm btn-success" onclick="verifyDomain('${domain}')">
<i class="fas fa-check-circle"></i> Doğrula
</button>
` : ''}
</div>
</div>
${domainData.verified ? `
<div class="detail-item">
<div class="detail-label">
<i class="fas fa-clock"></i>
Doğrulama Tarihi
</div>
<div class="detail-value">
${new Date(domainData.verified_at).toLocaleDateString('tr-TR')}
</div>
</div>
` : ''}
</div>
</div>
<div class="detail-section">
<h4>
<i class="fas fa-user"></i>
Domain Sahibi
</h4>
<div class="detail-grid">
<div class="detail-item">
<div class="detail-label">
<i class="fas fa-key"></i>
Auth Code
</div>
<div class="detail-value user-auth">
${apiDetails.data.user_auth_code || 'Atanmamış'}
${apiDetails.data.user_auth_code ? `
<button class="btn btn-sm btn-danger" onclick="unassignDomain('${domain}')">
<i class="fas fa-user-minus"></i> Atamayı Kaldır
</button>
` : `
<div class="input-group">
<input type="text" id="assignAuthCode" class="form-control"
placeholder="Kullanıcı auth kodunu girin">
<button class="btn btn-primary" onclick="assignDomain('${domain}')">
<i class="fas fa-user-plus"></i> Ata
</button>
</div>
`}
</div>
</div>
</div>
</div>
<div class="detail-section">
<h4>
<i class="fas fa-code"></i>
API Detayları
</h4>
<pre class="api-details">${JSON.stringify(apiDetails, null, 2)}</pre>
</div>
</div>
</div>
`;
// Create and show modal
const modal = document.createElement('div');
modal.className = 'modal active';
modal.id = 'domainModal';
modal.innerHTML = modalContent;
document.body.appendChild(modal);
// Add modal close event
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});
} else {
alert(data.message);
}
} catch (error) {
console.error('Error loading domain details:', error);
alert('Domain detayları yüklenirken bir hata oluştu.');
}
}
function closeModal() {
const domainModal = document.getElementById('domainModal');
const domainsModal = document.getElementById('domainsModal');
if (domainModal) {
domainModal.remove();
}
if (domainsModal) {
domainsModal.remove();
}
}
async function assignDomain(domain) {
const authCode = document.getElementById('assignAuthCode').value.trim();
if (!authCode) {
alert('Lütfen bir auth kodu girin');
return;
}
try {
const response = await fetch(`${API_URL}?action=assignDomain`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ domain, authCode })
});
const data = await response.json();
if (data.success) {
alert('Domain başarıyla atandı');
closeModal();
loadAllDomains();
} else {
alert(data.message);
}
} catch (error) {
console.error('Error assigning domain:', error);
alert('Domain atanırken bir hata oluştu.');
}
}
async function unassignDomain(domain) {
if (!confirm(`${domain} domaininin atamasını kaldırmak istediğinize emin misiniz?`)) {
return;
}
try {
const response = await fetch(`${API_URL}?action=unassignDomain`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ domain })
});
const data = await response.json();
if (data.success) {
alert('Domain ataması kaldırıldı');
closeModal();
loadAllDomains();
} else {
alert(data.message);
}
} catch (error) {
console.error('Error unassigning domain:', error);
alert('Domain ataması kaldırılırken bir hata oluştu.');
}
}
async function deleteDomain(domain) {
if (!confirm(`${domain} domainini silmek istediğinize emin misiniz?`)) {
return;
}
try {
const response = await fetch(`${API_URL}?action=deleteDomain`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ domain })
});
const data = await response.json();
if (data.success) {
loadAllDomains();
} else {
alert(data.message);
}
} catch (error) {
console.error('Error deleting domain:', error);
alert('Domain silinirken bir hata oluştu.');
}
}
function loadSettings() {
// Load current settings
document.getElementById('apiUrl').value = BASE_URL;
document.getElementById('adminUsername').value = localStorage.getItem('adminUsername') || '';
}
async function saveSettings() {
const username = document.getElementById('adminUsername').value;
const password = document.getElementById('newPassword').value;
if (!username) {
alert('Kullanıcı adı gerekli!');
return;
}
if (!password) {
alert('Yeni şifre gerekli!');
return;
}
try {
const response = await fetch(`${API_URL}?action=updateAdminSettings`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ username, password })
});
const data = await response.json();
if (data.success) {
localStorage.setItem('adminUsername', username);
alert('Ayarlar başarıyla güncellendi!');
document.getElementById('newPassword').value = '';
} else {
alert(data.message);
}
} catch (error) {
console.error('Error updating settings:', error);
alert('Ayarlar güncellenirken bir hata oluştu.');
}
}
async function loadAllDomainsFromApi() {
if (!confirm('Tüm domainleri API\'den yüklemek istediğinize emin misiniz?')) {
return;
}
try {
const response = await fetch(`${API_URL}?action=loadAllDomainsFromApi`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (data.success) {
alert(data.message);
loadAllDomains(); // Refresh domain list
} else {
alert(data.message);
}
} catch (error) {
console.error('Error loading domains from API:', error);
alert('Domainler API\'den yüklenirken bir hata oluştu.');
}
}
async function loadPromoCodes() {
try {
const response = await fetch(`${API_URL}?action=listPromoCodes`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (data.success) {
const promoList = document.getElementById('promoList');
promoList.innerHTML = data.data.map(promo => `
<div class="user-card">
<div class="user-header">
<span class="user-auth">
${promo.code}
<button class="btn-icon" onclick="copyPromoCode('${promo.code}')" title="Kodu Kopyala">
<i class="fas fa-copy"></i>
</button>
</span>
<span class="status-badge ${promo.current_uses >= promo.max_uses && promo.max_uses !== 0 ? 'inactive' : 'active'}">
${promo.current_uses >= promo.max_uses && promo.max_uses !== 0 ? 'Tükenmiş' : 'Aktif'}
</span>
</div>
<div class="user-stats">
<div class="stat-item">
<div class="stat-label">Kredi Miktarı</div>
<div class="stat-value">${promo.discount_amount}</div>
</div>
<div class="stat-item">
<div class="stat-label">Kullanım</div>
<div class="stat-value">${promo.current_uses}/${promo.max_uses || '∞'}</div>
</div>
<div class="stat-item">
<div class="stat-label">Oluşturma Tarihi</div>
<div class="stat-value">${new Date(promo.created_at).toLocaleDateString('tr-TR')}</div>
</div>
</div>
<div class="user-actions">
<button class="btn btn-danger" onclick="removePromoCode('${promo.code}')">
<i class="fas fa-trash"></i> Kodu Sil
</button>
</div>
</div>
`).join('');
} else {
alert(data.message);
}
} catch (error) {
console.error('Error loading promo codes:', error);
alert('Promo kodları yüklenirken bir hata oluştu.');
}
}
async function createPromoCode() {
// Create modal for promo code creation
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<h3>Yeni Promo Kodu Oluştur</h3>
<button onclick="this.closest('.modal').remove()">&times;</button>
</div>
<div class="modal-body">
<form id="promoForm" onsubmit="submitPromoCode(event)">
<div class="form-group">
<label>Kredi Miktarı</label>
<input type="number" id="discountAmount" required min="1">
</div>
<div class="form-group">
<label>Maksimum Kullanım (0 = sınırsız)</label>
<input type="number" id="maxUses" required min="0" value="1">
</div>
<button type="submit" class="btn">Oluştur</button>
</form>
</div>
</div>
`;
document.body.appendChild(modal);
}
async function submitPromoCode(event) {
event.preventDefault();
const discountAmount = document.getElementById('discountAmount').value;
const maxUses = document.getElementById('maxUses').value;
try {
const response = await fetch(`${API_URL}?action=createPromoCode`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({
discount_amount: parseInt(discountAmount),
max_uses: parseInt(maxUses)
})
});
const data = await response.json();
if (data.success) {
alert(`Promo kodu başarıyla oluşturuldu: ${data.data.promo_code}`);
document.querySelector('.modal').remove();
loadPromoCodes();
} else {
alert(data.message);
}
} catch (error) {
console.error('Error creating promo code:', error);
alert('Promo kodu oluşturulurken bir hata oluştu.');
}
}
async function removePromoCode(code) {
if (!confirm(`"${code}" promo kodunu silmek istediğinize emin misiniz?`)) {
return;
}
try {
const response = await fetch(`${API_URL}?action=removePromoCode`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ code })
});
const data = await response.json();
if (data.success) {
alert('Promo kodu başarıyla silindi');
loadPromoCodes(); // Refresh the list
} else {
alert(data.message);
}
} catch (error) {
console.error('Error removing promo code:', error);
alert('Promo kodu silinirken bir hata oluştu');
}
}
function searchUsers() {
const searchInput = document.getElementById('userSearch').value.toLowerCase();
const userCards = document.querySelectorAll('#userList .user-card');
userCards.forEach(card => {
const authCode = card.getAttribute('data-auth');
if (authCode.includes(searchInput)) {
card.style.display = 'block';
} else {
card.style.display = 'none';
}
});
}
function searchDomains() {
const searchInput = document.getElementById('domainSearch').value.toLowerCase();
const domainCards = document.querySelectorAll('#domainList .user-card');
domainCards.forEach(card => {
const domainName = card.getAttribute('data-domain');
if (domainName.includes(searchInput)) {
card.style.display = 'block';
} else {
card.style.display = 'none';
}
});
}
// Add CSS for pages
const style = document.createElement('style');
style.textContent = `
.page {
display: none;
}
.page.active {
display: block;
}
.settings-form {
max-width: 600px;
background-color: #1a1a1a;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
`;
document.head.appendChild(style);
async function loginAsUser(authCode) {
// Store admin token temporarily
const currentAdminToken = adminToken;
try {
// Set the auth code in localStorage instead of cookie
localStorage.setItem('authCode', authCode);
// Open panel.html in a new tab
window.open('/panel.html', '_blank');
} catch (error) {
console.error('Error logging in as user:', error);
alert('Kullanıcı olarak giriş yapılırken bir hata oluştu.');
}
}
function copyPromoCode(code) {
try {
// Use the newer clipboard API if available
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(code).then(() => {
showToast('Promo kod kopyalandı', 'success');
}).catch(() => {
showToast('Promo kod kopyalanamadı', 'error');
});
} else {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = code;
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
showToast('Promo kod kopyalandı', 'success');
} catch (err) {
showToast('Promo kod kopyalanamadı', 'error');
}
document.body.removeChild(textArea);
}
} catch (error) {
console.error('Copy error:', error);
showToast('Promo kod kopyalanamadı', 'error');
}
}
async function verifyDomain(domain) {
if (!confirm(`${domain} domainini doğrulamak istediğinize emin misiniz?`)) {
return;
}
try {
const response = await fetch(`${API_URL}?action=verifyDomain`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ domain })
});
const data = await response.json();
if (data.success) {
alert('Domain başarıyla doğrulandı');
loadAllDomains(); // Refresh domain list
} else {
alert(data.message);
}
} catch (error) {
console.error('Error verifying domain:', error);
alert('Domain doğrulanırken bir hata oluştu.');
}
}
async function verifyUserDomains(userId) {
if (!confirm('Bu kullanıcının tüm domainlerini doğrulamak istediğinize emin misiniz?')) {
return;
}
try {
// First get all domains of the user
const response = await fetch(`${API_URL}?action=getUserDomains&userId=${userId}`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (!data.success) {
alert(data.message);
return;
}
let verifiedCount = 0;
let failedCount = 0;
// Verify each domain
for (const domain of data.data) {
try {
const verifyResponse = await fetch(`${API_URL}?action=verifyDomain`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ domain: domain.domain_name })
});
const verifyData = await verifyResponse.json();
if (verifyData.success) {
verifiedCount++;
} else {
failedCount++;
}
} catch (error) {
failedCount++;
console.error(`Error verifying domain ${domain.domain_name}:`, error);
}
}
alert(`Doğrulama tamamlandı!\nBaşarılı: ${verifiedCount}\nBaşarısız: ${failedCount}`);
loadUsers(); // Refresh the user list
} catch (error) {
console.error('Error verifying user domains:', error);
alert('Domainler doğrulanırken bir hata oluştu.');
}
}
async function loadResellers() {
try {
const response = await fetch(`${API_URL}?action=getAllResellers`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (data.success) {
const resellerList = document.getElementById('resellerList');
resellerList.innerHTML = data.data.map(reseller => `
<div class="user-card">
<div class="user-header">
<div class="user-avatar">
<img
src="${reseller.avatar_url}"
alt="${reseller.username}"
onerror="this.src='https://via.placeholder.com/60x60?text=${reseller.username.charAt(0)}'"
>
</div>
<div class="user-info">
<h3>${reseller.username}</h3>
<a href="${reseller.website}" target="_blank">${reseller.website}</a>
<div class="reseller-auth">Auth Code: ${reseller.auth_code}</div>
<div class="reseller-rights">Kalan Kayıt Hakkı: ${reseller.registration_rights}</div>
</div>
<div class="user-actions">
<button class="btn-icon" onclick="editReseller(${reseller.id})" title="Düzenle">
<i class="fas fa-edit"></i>
</button>
<button class="btn-icon" onclick="removeReseller(${reseller.id})" title="Sil">
<i class="fas fa-trash"></i>
</button>
</div>
</div>
<div class="user-description">
${reseller.description}
</div>
</div>
`).join('');
} else {
alert(data.message);
}
} catch (error) {
console.error('Error loading resellers:', error);
alert('Resellerlar yüklenirken bir hata oluştu.');
}
}
function addReseller() {
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<h3>Yeni Reseller Ekle</h3>
<button class="modal-close" onclick="this.closest('.modal').remove()">&times;</button>
</div>
<div class="modal-body">
<form id="resellerForm">
<div class="form-group">
<label>Kullanıcı Adı</label>
<input type="text" id="username" required>
</div>
<div class="form-group">
<label>Auth Code</label>
<input type="text" id="authCode" required>
</div>
<div class="form-group">
<label>Profil Resmi URL</label>
<input type="url" id="avatarUrl" required>
</div>
<div class="form-group">
<label>Website URL</label>
<input type="url" id="website" required>
</div>
<div class="form-group">
<label>Açıklama</label>
<textarea id="description" required
placeholder="Reseller hakkında detaylı açıklama yazın..."
style="width: 100%; min-height: 150px; resize: vertical;"></textarea>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary" onclick="this.closest('.modal').remove()">İptal</button>
<button type="submit" class="btn">Kaydet</button>
</div>
</form>
</div>
</div>
`;
document.body.appendChild(modal);
modal.querySelector('form').addEventListener('submit', async (e) => {
e.preventDefault();
await saveReseller();
});
}
async function saveReseller() {
const username = document.getElementById('username').value;
const authCode = document.getElementById('authCode').value;
const avatarUrl = document.getElementById('avatarUrl').value;
const website = document.getElementById('website').value;
const description = document.getElementById('description').value;
try {
const response = await fetch(`${API_URL}?action=addReseller`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({
username,
authCode,
avatarUrl,
website,
description
})
});
const data = await response.json();
if (data.success) {
alert('Reseller başarıyla eklendi');
document.querySelector('.modal').remove();
loadResellers();
} else {
alert(data.message);
}
} catch (error) {
console.error('Error adding reseller:', error);
alert('Reseller eklenirken bir hata oluştu.');
}
}
async function editReseller(id) {
try {
// First get the current reseller data
const response = await fetch(`${API_URL}?action=getReseller&id=${id}`, {
headers: {
'X-Admin-Token': adminToken
}
});
const data = await response.json();
if (!data.success) {
alert(data.message);
return;
}
const reseller = data.data;
// Create and show edit modal
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<div class="modal-content">
<div class="modal-header">
<h3>Reseller Düzenle</h3>
<button class="modal-close" onclick="this.closest('.modal').remove()">&times;</button>
</div>
<div class="modal-body">
<form id="editResellerForm">
<div class="form-group">
<label>Profil Resmi URL</label>
<input type="url" id="editAvatarUrl" value="${reseller.avatar_url}" required>
</div>
<div class="form-group">
<label>Kullanıcı Adı</label>
<input type="text" id="editUsername" value="${reseller.username}" required>
</div>
<div class="form-group">
<label>Website URL</label>
<input type="url" id="editWebsite" value="${reseller.website}" required>
</div>
<div class="form-group">
<label>Açıklama</label>
<textarea id="editDescription" required
placeholder="Reseller hakkında detaylı açıklama yazın..."
style="width: 100%; min-height: 150px; resize: vertical;">${reseller.description}</textarea>
</div>
<input type="hidden" id="editResellerId" value="${reseller.id}">
<div class="form-actions">
<button type="button" class="btn btn-secondary" onclick="this.closest('.modal').remove()">İptal</button>
<button type="submit" class="btn">Kaydet</button>
</div>
</form>
</div>
</div>
`;
document.body.appendChild(modal);
modal.querySelector('form').addEventListener('submit', async (e) => {
e.preventDefault();
await updateReseller();
});
} catch (error) {
console.error('Error loading reseller details:', error);
alert('Reseller bilgileri yüklenirken bir hata oluştu.');
}
}
async function updateReseller() {
const id = document.getElementById('editResellerId').value;
const avatarUrl = document.getElementById('editAvatarUrl').value;
const username = document.getElementById('editUsername').value;
const website = document.getElementById('editWebsite').value;
const description = document.getElementById('editDescription').value;
try {
const response = await fetch(`${API_URL}?action=editReseller`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({
id,
avatarUrl,
username,
website,
description
})
});
const data = await response.json();
if (data.success) {
alert('Reseller başarıyla güncellendi');
document.querySelector('.modal').remove();
loadResellers(); // Refresh the list
} else {
alert(data.message);
}
} catch (error) {
console.error('Error updating reseller:', error);
alert('Reseller güncellenirken bir hata oluştu.');
}
}
async function removeReseller(id) {
if (!confirm('Bu reseller\'ı silmek istediğinize emin misiniz?')) {
return;
}
try {
const response = await fetch(`${API_URL}?action=removeReseller`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Admin-Token': adminToken
},
body: JSON.stringify({ id })
});
const data = await response.json();
if (data.success) {
alert('Reseller başarıyla silindi');
loadResellers(); // Refresh the list
} else {
alert(data.message);
}
} catch (error) {
console.error('Error removing reseller:', error);
alert('Reseller silinirken bir hata oluştu.');
}
}
function showToast(message, type = 'info') {
// Create toast container if it doesn't exist
let toastContainer = document.getElementById('toastContainer');
if (!toastContainer) {
toastContainer = document.createElement('div');
toastContainer.id = 'toastContainer';
document.body.appendChild(toastContainer);
}
// Create toast element
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
// Add toast to container
toastContainer.appendChild(toast);
// Remove toast after animation
setTimeout(() => {
toast.classList.add('fade-out');
setTimeout(() => {
toastContainer.removeChild(toast);
}, 300);
}, 3000);
}
</script>
</body>
</html>