Files
easystream-main/f_modules/m_backend/token_customization.php
SamiAhmed7777 0b7e2d0a5b feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory
- Added PROJECT_OVERVIEW.md with feature highlights and getting started guide
- Added ARCHITECTURE.md with system design and technical details
- Added SECURITY.md with comprehensive security implementation guide
- Added DEVELOPMENT.md with development workflows and best practices
- Added DEPLOYMENT.md with production deployment instructions
- Added API.md with complete REST API documentation
- Added CONTRIBUTING.md with contribution guidelines
- Added CHANGELOG.md with version history and migration notes
- Reorganized all documentation files into docs/ directory for better organization
- Updated README.md with proper documentation links and quick navigation
- Enhanced project structure with professional documentation standards
2025-10-21 00:39:45 -07:00

650 lines
24 KiB
PHP

<?php
/*******************************************************************************************************************
| EasyStream Token Customization System
| Allows platform owners to customize their monetization token branding
|*******************************************************************************************************************/
define('_ISVALID', true);
include_once '../../f_core/config.core.php';
// Check admin permissions
$logged_in = VLogin::checkBackend('token_customization');
$error_message = '';
$success_message = '';
// Handle form submission
if ($_POST && isset($_POST['action'])) {
switch ($_POST['action']) {
case 'update_token_settings':
$result = updateTokenSettings($_POST);
if ($result['success']) {
$success_message = $result['message'];
} else {
$error_message = $result['message'];
}
break;
case 'upload_token_icon':
$result = uploadTokenIcon($_FILES['token_icon']);
if ($result['success']) {
$success_message = $result['message'];
} else {
$error_message = $result['message'];
}
break;
case 'reset_to_defaults':
$result = resetTokenDefaults();
if ($result['success']) {
$success_message = $result['message'];
} else {
$error_message = $result['message'];
}
break;
}
}
// Get current token settings
$token_settings = getTokenSettings();
function getTokenSettings() {
global $class_database;
$defaults = [
'token_name' => 'EasyCoins',
'token_symbol' => 'EC',
'token_plural' => 'EasyCoins',
'token_description' => 'Platform currency for tips and donations',
'token_icon' => '/f_templates/tpl_frontend/img/default-token.png',
'token_color_primary' => '#FFD700',
'token_color_secondary' => '#FFA500',
'exchange_rate' => '1.00',
'min_purchase' => '1.00',
'max_purchase' => '1000.00',
'enabled' => '1'
];
try {
$sql = "SELECT setting_key, setting_value FROM db_settings WHERE setting_key LIKE 'token_%'";
$result = $class_database->execute($sql);
$settings = $defaults;
while (!$result->EOF) {
$key = str_replace('token_', '', $result->fields['setting_key']);
$settings[$key] = $result->fields['setting_value'];
$result->MoveNext();
}
return $settings;
} catch (Exception $e) {
return $defaults;
}
}
function updateTokenSettings($data) {
global $class_database;
try {
$settings = [
'token_name' => $class_filter->clr_str($data['token_name']),
'token_symbol' => strtoupper($class_filter->clr_str($data['token_symbol'])),
'token_plural' => $class_filter->clr_str($data['token_plural']),
'token_description' => $class_filter->clr_str($data['token_description']),
'token_color_primary' => $class_filter->clr_str($data['token_color_primary']),
'token_color_secondary' => $class_filter->clr_str($data['token_color_secondary']),
'exchange_rate' => floatval($data['exchange_rate']),
'min_purchase' => floatval($data['min_purchase']),
'max_purchase' => floatval($data['max_purchase']),
'enabled' => isset($data['enabled']) ? '1' : '0'
];
foreach ($settings as $key => $value) {
$sql = "INSERT INTO db_settings (setting_key, setting_value, setting_description)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE setting_value = ?";
$description = ucfirst(str_replace('_', ' ', $key));
$class_database->execute($sql, ["token_$key", $value, $description, $value]);
}
return ['success' => true, 'message' => 'Token settings updated successfully!'];
} catch (Exception $e) {
return ['success' => false, 'message' => 'Error updating settings: ' . $e->getMessage()];
}
}
function uploadTokenIcon($file) {
if (!isset($file['tmp_name']) || $file['error'] !== UPLOAD_ERR_OK) {
return ['success' => false, 'message' => 'No file uploaded or upload error'];
}
// Validate file type
$allowed_types = ['image/png', 'image/jpeg', 'image/gif', 'image/svg+xml'];
if (!in_array($file['type'], $allowed_types)) {
return ['success' => false, 'message' => 'Invalid file type. Please upload PNG, JPG, GIF, or SVG'];
}
// Validate file size (max 2MB)
if ($file['size'] > 2 * 1024 * 1024) {
return ['success' => false, 'message' => 'File too large. Maximum size is 2MB'];
}
try {
$upload_dir = 'f_templates/tpl_frontend/img/tokens/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
$filename = 'token_icon_' . time() . '.' . $extension;
$filepath = $upload_dir . $filename;
if (move_uploaded_file($file['tmp_name'], $filepath)) {
// Update database
global $class_database;
$sql = "INSERT INTO db_settings (setting_key, setting_value, setting_description)
VALUES ('token_icon', ?, 'Token icon image path')
ON DUPLICATE KEY UPDATE setting_value = ?";
$icon_path = '/' . $filepath;
$class_database->execute($sql, [$icon_path, $icon_path]);
return ['success' => true, 'message' => 'Token icon uploaded successfully!'];
} else {
return ['success' => false, 'message' => 'Failed to upload file'];
}
} catch (Exception $e) {
return ['success' => false, 'message' => 'Upload error: ' . $e->getMessage()];
}
}
function resetTokenDefaults() {
global $class_database;
try {
$sql = "DELETE FROM db_settings WHERE setting_key LIKE 'token_%'";
$class_database->execute($sql);
return ['success' => true, 'message' => 'Token settings reset to defaults!'];
} catch (Exception $e) {
return ['success' => false, 'message' => 'Error resetting settings: ' . $e->getMessage()];
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Token Customization - EasyStream Admin</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0;
background: #f8f9fa;
color: #333;
}
.header {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 20px 0;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 30px 20px;
}
.card {
background: white;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
margin-bottom: 30px;
overflow: hidden;
}
.card-header {
background: #f8f9fa;
padding: 20px 30px;
border-bottom: 1px solid #e9ecef;
font-size: 1.2rem;
font-weight: 600;
display: flex;
align-items: center;
gap: 10px;
}
.card-body {
padding: 30px;
}
.form-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #495057;
}
.form-input {
width: 100%;
padding: 12px;
border: 2px solid #e9ecef;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.2s ease;
box-sizing: border-box;
}
.form-input:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102,126,234,0.1);
}
.color-input {
width: 100px;
height: 50px;
border: none;
border-radius: 8px;
cursor: pointer;
}
.btn {
background: #667eea;
color: white;
border: none;
padding: 12px 24px;
border-radius: 8px;
cursor: pointer;
font-size: 1rem;
font-weight: 500;
transition: all 0.2s ease;
text-decoration: none;
display: inline-block;
}
.btn:hover {
background: #5a6fd8;
transform: translateY(-1px);
}
.btn-secondary {
background: #6c757d;
}
.btn-secondary:hover {
background: #5a6268;
}
.btn-danger {
background: #dc3545;
}
.btn-danger:hover {
background: #c82333;
}
.alert {
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.alert-success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.token-preview {
background: linear-gradient(135deg, var(--token-primary, #FFD700), var(--token-secondary, #FFA500));
color: white;
padding: 20px;
border-radius: 12px;
text-align: center;
margin: 20px 0;
}
.token-icon {
width: 60px;
height: 60px;
border-radius: 50%;
margin: 0 auto 15px;
display: block;
object-fit: cover;
border: 3px solid white;
}
.token-name {
font-size: 1.5rem;
font-weight: 700;
margin-bottom: 5px;
}
.token-symbol {
font-size: 1rem;
opacity: 0.9;
margin-bottom: 10px;
}
.token-description {
font-size: 0.9rem;
opacity: 0.8;
}
.upload-area {
border: 2px dashed #e9ecef;
border-radius: 8px;
padding: 30px;
text-align: center;
transition: border-color 0.2s ease;
}
.upload-area:hover {
border-color: #667eea;
}
.upload-area.dragover {
border-color: #667eea;
background: #f8f9ff;
}
.file-input {
display: none;
}
.current-icon {
max-width: 100px;
max-height: 100px;
border-radius: 8px;
margin: 10px 0;
}
@media (max-width: 768px) {
.form-grid {
grid-template-columns: 1fr;
}
.header-content {
flex-direction: column;
gap: 15px;
}
}
</style>
</head>
<body>
<div class="header">
<div class="header-content">
<h1>🪙 Token Customization</h1>
<div>
<a href="dashboard.php" class="btn btn-secondary">← Back to Dashboard</a>
</div>
</div>
</div>
<div class="container">
<?php if ($error_message): ?>
<div class="alert alert-error">
<?php echo htmlspecialchars($error_message); ?>
</div>
<?php endif; ?>
<?php if ($success_message): ?>
<div class="alert alert-success">
<?php echo htmlspecialchars($success_message); ?>
</div>
<?php endif; ?>
<!-- Token Preview -->
<div class="card">
<div class="card-header">
👁️ Live Preview
</div>
<div class="card-body">
<div class="token-preview" style="--token-primary: <?php echo $token_settings['token_color_primary']; ?>; --token-secondary: <?php echo $token_settings['token_color_secondary']; ?>">
<img src="<?php echo htmlspecialchars($token_settings['token_icon']); ?>" alt="Token Icon" class="token-icon" onerror="this.src='/f_templates/tpl_frontend/img/default-token.png'">
<div class="token-name"><?php echo htmlspecialchars($token_settings['token_name']); ?></div>
<div class="token-symbol"><?php echo htmlspecialchars($token_settings['token_symbol']); ?></div>
<div class="token-description"><?php echo htmlspecialchars($token_settings['token_description']); ?></div>
</div>
</div>
</div>
<!-- Token Settings -->
<div class="card">
<div class="card-header">
⚙️ Token Settings
</div>
<div class="card-body">
<form method="POST" id="token-settings-form">
<input type="hidden" name="action" value="update_token_settings">
<div class="form-grid">
<div class="form-group">
<label class="form-label" for="token_name">Token Name</label>
<input type="text" id="token_name" name="token_name" class="form-input"
value="<?php echo htmlspecialchars($token_settings['token_name']); ?>"
placeholder="e.g., EasyCoins" required>
</div>
<div class="form-group">
<label class="form-label" for="token_symbol">Token Symbol</label>
<input type="text" id="token_symbol" name="token_symbol" class="form-input"
value="<?php echo htmlspecialchars($token_settings['token_symbol']); ?>"
placeholder="e.g., EC" maxlength="5" required>
</div>
<div class="form-group">
<label class="form-label" for="token_plural">Plural Form</label>
<input type="text" id="token_plural" name="token_plural" class="form-input"
value="<?php echo htmlspecialchars($token_settings['token_plural']); ?>"
placeholder="e.g., EasyCoins" required>
</div>
<div class="form-group">
<label class="form-label" for="exchange_rate">Exchange Rate (USD)</label>
<input type="number" id="exchange_rate" name="exchange_rate" class="form-input"
value="<?php echo $token_settings['exchange_rate']; ?>"
step="0.01" min="0.01" placeholder="1.00" required>
</div>
<div class="form-group">
<label class="form-label" for="min_purchase">Minimum Purchase</label>
<input type="number" id="min_purchase" name="min_purchase" class="form-input"
value="<?php echo $token_settings['min_purchase']; ?>"
step="0.01" min="0.01" placeholder="1.00" required>
</div>
<div class="form-group">
<label class="form-label" for="max_purchase">Maximum Purchase</label>
<input type="number" id="max_purchase" name="max_purchase" class="form-input"
value="<?php echo $token_settings['max_purchase']; ?>"
step="0.01" min="1" placeholder="1000.00" required>
</div>
</div>
<div class="form-group">
<label class="form-label" for="token_description">Description</label>
<textarea id="token_description" name="token_description" class="form-input" rows="3"
placeholder="Brief description of your platform currency"><?php echo htmlspecialchars($token_settings['token_description']); ?></textarea>
</div>
<div class="form-grid">
<div class="form-group">
<label class="form-label" for="token_color_primary">Primary Color</label>
<input type="color" id="token_color_primary" name="token_color_primary" class="color-input"
value="<?php echo $token_settings['token_color_primary']; ?>">
</div>
<div class="form-group">
<label class="form-label" for="token_color_secondary">Secondary Color</label>
<input type="color" id="token_color_secondary" name="token_color_secondary" class="color-input"
value="<?php echo $token_settings['token_color_secondary']; ?>">
</div>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="enabled" <?php echo $token_settings['enabled'] ? 'checked' : ''; ?>>
Enable token system
</label>
</div>
<button type="submit" class="btn">💾 Save Settings</button>
</form>
</div>
</div>
<!-- Token Icon Upload -->
<div class="card">
<div class="card-header">
🖼️ Token Icon
</div>
<div class="card-body">
<form method="POST" enctype="multipart/form-data" id="icon-upload-form">
<input type="hidden" name="action" value="upload_token_icon">
<div class="form-group">
<label class="form-label">Current Icon</label>
<div>
<img src="<?php echo htmlspecialchars($token_settings['token_icon']); ?>"
alt="Current Token Icon" class="current-icon"
onerror="this.src='/f_templates/tpl_frontend/img/default-token.png'">
</div>
</div>
<div class="upload-area" onclick="document.getElementById('token_icon').click()">
<div style="font-size: 3rem; margin-bottom: 15px;">📁</div>
<div style="font-size: 1.1rem; margin-bottom: 10px;">Click to upload new token icon</div>
<div style="color: #666; font-size: 0.9rem;">
Supports PNG, JPG, GIF, SVG • Max 2MB • Recommended: 256x256px
</div>
<input type="file" id="token_icon" name="token_icon" class="file-input"
accept="image/png,image/jpeg,image/gif,image/svg+xml"
onchange="handleFileSelect(this)">
</div>
<div style="margin-top: 20px;">
<button type="submit" class="btn">📤 Upload Icon</button>
</div>
</form>
</div>
</div>
<!-- Reset Options -->
<div class="card">
<div class="card-header">
🔄 Reset Options
</div>
<div class="card-body">
<p style="margin-bottom: 20px; color: #666;">
Reset all token settings to default values. This action cannot be undone.
</p>
<form method="POST" onsubmit="return confirm('Are you sure you want to reset all token settings to defaults?')">
<input type="hidden" name="action" value="reset_to_defaults">
<button type="submit" class="btn btn-danger">🔄 Reset to Defaults</button>
</form>
</div>
</div>
</div>
<script>
// Live preview updates
function updatePreview() {
const preview = document.querySelector('.token-preview');
const tokenName = document.getElementById('token_name').value;
const tokenSymbol = document.getElementById('token_symbol').value;
const tokenDescription = document.getElementById('token_description').value;
const primaryColor = document.getElementById('token_color_primary').value;
const secondaryColor = document.getElementById('token_color_secondary').value;
preview.style.setProperty('--token-primary', primaryColor);
preview.style.setProperty('--token-secondary', secondaryColor);
preview.querySelector('.token-name').textContent = tokenName || 'Token Name';
preview.querySelector('.token-symbol').textContent = tokenSymbol || 'SYM';
preview.querySelector('.token-description').textContent = tokenDescription || 'Token description';
}
// Add event listeners for live preview
document.getElementById('token_name').addEventListener('input', updatePreview);
document.getElementById('token_symbol').addEventListener('input', updatePreview);
document.getElementById('token_description').addEventListener('input', updatePreview);
document.getElementById('token_color_primary').addEventListener('change', updatePreview);
document.getElementById('token_color_secondary').addEventListener('change', updatePreview);
// File upload handling
function handleFileSelect(input) {
if (input.files && input.files[0]) {
const file = input.files[0];
const reader = new FileReader();
reader.onload = function(e) {
document.querySelector('.current-icon').src = e.target.result;
document.querySelector('.token-icon').src = e.target.result;
};
reader.readAsDataURL(file);
}
}
// Drag and drop for file upload
const uploadArea = document.querySelector('.upload-area');
uploadArea.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', function(e) {
e.preventDefault();
this.classList.remove('dragover');
});
uploadArea.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('dragover');
const files = e.dataTransfer.files;
if (files.length > 0) {
document.getElementById('token_icon').files = files;
handleFileSelect(document.getElementById('token_icon'));
}
});
</script>
</body>
</html>