# RR SHOP 17FEB26 01 - REPOSITORY ================================================================================ Project Name: RR shop 17Feb26 01 Created: 2026-02-17 02:46:11 Last Updated: 2026-02-17 02:47:15 Source ZIP: rrshop.zip Total Files: 42 Total Folders: 7 ================================================================================ ## FILE STRUCTURE ================================================================================ RR shop 17Feb26 01/ ├── affiliate_create.php ├── finance.php ├── demand.php ├── login.php ├── support.php ├── member_view.php ├── supply.php ├── logout.php ├── affiliate_edit.php ├── users.php ├── settings.php ├── client_create.php ├── members.php ├── index.php ├── error-404.html ├── affiliate_view.php ├── client_edit.php ├── clients.php ├── config.php ├── robots.txt ├── maintenance.html ├── generate_hash.php ├── assets/ │ ├── images/ │ │ └── logo.svg │ ├── css/ │ │ ├── member-enhancements.css │ │ ├── dashboard.css │ │ ├── main.css │ │ └── responsive.css │ └── js/ │ ├── dashboard.js │ └── main.js ├── error-500.html ├── README.md ├── member_edit.php ├── panel.php ├── sitemap.xml ├── uploads/ │ └── clients/ │ ├── BD0B267D_1769770697_0.pdf │ ├── A6FB1FDC_1770453927_0.pdf │ ├── BD0B267D_1769743328_0.png │ └── EA89781D_1769740517_0.pdf ├── client_view.php └── includes/ ├── footer.php ├── navigation.php └── header.php ================================================================================ ## FILE CONTENTS ================================================================================ ### FILE 1: affiliate_create.php - Type: PHP - Size: 17.14 KB - Path: . - Name: affiliate_create.php ------------------------------------------------------------ ------------------------------------------------------------ prepare("SELECT id FROM affiliates WHERE affiliate_code = ?"); $checkStmt->execute([$affiliate_code]); } while ($checkStmt->fetch()); // Insert affiliate $stmt = $pdo->prepare(" INSERT INTO affiliates (affiliate_code, type, company_name, incharge_name, state, postal_code, place_name, mobile, email, url, signup_reward, survey_reward, created_by, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'active', NOW()) "); $stmt->execute([ $affiliate_code, $type, $company_name, $incharge_name, $state, $postal_code, $place_name, $mobile, $email, $url, $signup_reward, $survey_reward, $_SESSION['admin_id'] ]); $affiliate_id = $pdo->lastInsertId(); // Handle file uploads if (!empty($_FILES['attachments']['name'][0])) { $upload_dir = 'uploads/affiliates/'; if (!file_exists($upload_dir)) { mkdir($upload_dir, 0755, true); } $allowed_types = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png', 'image/gif']; $max_files = 10; $max_size = 5 * 1024 * 1024; // 5MB for ($i = 0; $i < min(count($_FILES['attachments']['name']), $max_files); $i++) { if ($_FILES['attachments']['error'][$i] === UPLOAD_ERR_OK) { $file_type = $_FILES['attachments']['type'][$i]; $file_size = $_FILES['attachments']['size'][$i]; if (in_array($file_type, $allowed_types) && $file_size <= $max_size) { $file_name = $_FILES['attachments']['name'][$i]; $file_tmp = $_FILES['attachments']['tmp_name'][$i]; // Generate unique filename $extension = pathinfo($file_name, PATHINFO_EXTENSION); $unique_name = $affiliate_code . '_' . time() . '_' . $i . '.' . $extension; $file_path = $upload_dir . $unique_name; if (move_uploaded_file($file_tmp, $file_path)) { $attachStmt = $pdo->prepare(" INSERT INTO affiliate_attachments (affiliate_id, file_name, file_path, file_type, file_size, uploaded_at) VALUES (?, ?, ?, ?, ?, NOW()) "); $attachStmt->execute([ $affiliate_id, $file_name, $file_path, $file_type, $file_size ]); } } } } } logActivity($_SESSION['admin_id'], 'create_affiliate', "Created affiliate: $affiliate_code", 'affiliate', $affiliate_id); header('Location: supply.php?success=created&code=' . $affiliate_code); exit; } catch (Exception $e) { $error = 'An error occurred. Please try again.'; error_log("Create affiliate error: " . $e->getMessage()); } } } include 'includes/header.php'; ?>
₹5 for email verification + rest for mobile verification
Per survey completed by referred members

📑 Click to upload or drag and drop files here

PDF, JPG, PNG, GIF (Max 10 files, 5MB each) Upload GST Certificate, PAN Card, Cancelled Cheque, Business Registration, etc.
Cancel
-------------------- END OF FILE -------------------- ### FILE 2: affiliate_edit.php - Type: PHP - Size: 10.64 KB - Path: . - Name: affiliate_edit.php ------------------------------------------------------------ ------------------------------------------------------------ prepare(" UPDATE affiliates SET type = ?, company_name = ?, incharge_name = ?, state = ?, postal_code = ?, place_name = ?, mobile = ?, email = ?, url = ?, signup_reward = ?, survey_reward = ?, status = ?, updated_at = NOW() WHERE id = ? "); $stmt->execute([ $type, $company_name, $incharge_name, $state, $postal_code, $place_name, $mobile, $email, $url, $signup_reward, $survey_reward, $status, $affiliate_id ]); logActivity($_SESSION['admin_id'], 'update_affiliate', "Updated affiliate #$affiliate_id", 'affiliate', $affiliate_id); $success = 'Affiliate updated successfully!'; } catch (Exception $e) { $error = 'An error occurred. Please try again.'; error_log("Update affiliate error: " . $e->getMessage()); } } } } // Fetch affiliate details try { $pdo = getDBConnection(); $stmt = $pdo->prepare("SELECT * FROM affiliates WHERE id = ?"); $stmt->execute([$affiliate_id]); $affiliate = $stmt->fetch(); if (!$affiliate) { header('Location: supply.php'); exit; } } catch (Exception $e) { error_log("Fetch affiliate error: " . $e->getMessage()); header('Location: supply.php'); exit; } $indian_states = [ 'Andhra Pradesh', 'Arunachal Pradesh', 'Assam', 'Bihar', 'Chhattisgarh', 'Goa', 'Gujarat', 'Haryana', 'Himachal Pradesh', 'Jharkhand', 'Karnataka', 'Kerala', 'Madhya Pradesh', 'Maharashtra', 'Manipur', 'Meghalaya', 'Mizoram', 'Nagaland', 'Odisha', 'Punjab', 'Rajasthan', 'Sikkim', 'Tamil Nadu', 'Telangana', 'Tripura', 'Uttar Pradesh', 'Uttarakhand', 'West Bengal', 'Andaman and Nicobar Islands', 'Chandigarh', 'Dadra and Nagar Haveli and Daman and Diu', 'Delhi', 'Jammu and Kashmir', 'Ladakh', 'Lakshadweep', 'Puducherry' ]; include 'includes/header.php'; ?>
₹5 for email verification + rest for mobile verification
Per survey completed by referred members
-------------------- END OF FILE -------------------- ### FILE 3: affiliate_view.php - Type: PHP - Size: 13.94 KB - Path: . - Name: affiliate_view.php ------------------------------------------------------------ ------------------------------------------------------------ prepare("SELECT * FROM affiliates WHERE id = ?"); $stmt->execute([$affiliate_id]); $affiliate = $stmt->fetch(); if (!$affiliate) { header('Location: supply.php'); exit; } // Fetch attachments $attachStmt = $pdo->prepare("SELECT * FROM affiliate_attachments WHERE affiliate_id = ?"); $attachStmt->execute([$affiliate_id]); $attachments = $attachStmt->fetchAll(); // Fetch signups $signupsStmt = $pdo->prepare(" SELECT * FROM affiliate_signups WHERE affiliate_id = ? ORDER BY clicked_at DESC LIMIT 100 "); $signupsStmt->execute([$affiliate_id]); $signups = $signupsStmt->fetchAll(); } catch (Exception $e) { error_log("View affiliate error: " . $e->getMessage()); header('Location: supply.php'); exit; } $signup_url = 'https://relevantreflex.com/signup.php?ref=' . $affiliate['affiliate_code']; include 'includes/header.php'; ?>

Affiliate Code & Signup Link

Basic Information

Type
Company Name
In-charge Name
State
Location

PIN:
Mobile
Email
Website/URL
Signup Reward
₹5 email + ₹ mobile
Survey Revenue Share
Per survey completed by referred members
Status
Created

Performance Statistics

Total Signups
Verified Signups
Total Rewards Paid
Conversion Rate
0 ? ($affiliate['total_verified_signups'] / $affiliate['total_signups'] * 100) : 0; echo number_format($conversion, 1); ?>%

Attachments ()


KB • Uploaded on
💥 Download

Recent Signups (Last 100)

No signups yet

Email Clicked At Signed Up Verified Reward Status
Not completed'; ?> Pending Not verified Pending Complete Awaiting Verification Clicked Only
-------------------- END OF FILE -------------------- ### FILE 4: client_create.php - Type: PHP - Size: 17.34 KB - Path: . - Name: client_create.php ------------------------------------------------------------ prepare("SELECT COUNT(*) FROM clients WHERE client_code = ?"); $stmt->execute([$client_code]); } while ($stmt->fetchColumn() > 0); $stmt = $pdo->prepare(" INSERT INTO clients (client_code, company_name, industry, contact_person, email, phone, address, city, country, postal_code, website, notes, currency, created_by, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW()) "); $stmt->execute([ $client_code, $company_name, $industry, $contact_person, $email, $phone, $address, $city, $country, $postal_code, $website, $notes, $currency, $_SESSION['admin_id'] ]); $client_id = $pdo->lastInsertId(); // Handle file uploads if (!empty($_FILES['attachments']['name'][0])) { $upload_dir = 'uploads/clients/'; if (!file_exists($upload_dir)) { mkdir($upload_dir, 0755, true); } $allowed_types = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png', 'image/gif']; $max_files = 10; $max_size = 5 * 1024 * 1024; // 5MB for ($i = 0; $i < min(count($_FILES['attachments']['name']), $max_files); $i++) { if ($_FILES['attachments']['error'][$i] === UPLOAD_ERR_OK) { $file_type = $_FILES['attachments']['type'][$i]; $file_size = $_FILES['attachments']['size'][$i]; if (in_array($file_type, $allowed_types) && $file_size <= $max_size) { $file_name = $_FILES['attachments']['name'][$i]; $file_tmp = $_FILES['attachments']['tmp_name'][$i]; $extension = pathinfo($file_name, PATHINFO_EXTENSION); $unique_name = $client_code . '_' . time() . '_' . $i . '.' . $extension; $file_path = $upload_dir . $unique_name; if (move_uploaded_file($file_tmp, $file_path)) { $attachStmt = $pdo->prepare(" INSERT INTO client_attachments (client_id, file_name, file_path, file_type, file_size, uploaded_at) VALUES (?, ?, ?, ?, ?, NOW()) "); $attachStmt->execute([ $client_id, $file_name, $file_path, $file_type, $file_size ]); } } } } } logActivity($_SESSION['admin_id'], 'create_client', "Created client: $client_code", 'client', $client_id); header('Location: clients.php?success=created&code=' . $client_code); exit; } catch (Exception $e) { $error = 'An error occurred. Please try again.'; error_log("Create client error: " . $e->getMessage()); } } } include 'includes/header.php'; ?>
Include country code (e.g., +91 for India, +1 for USA)

📑 Click to upload or drag and drop files here

PDF, JPG, PNG, GIF (Max 10 files, 5MB each) Upload contracts, agreements, proposals, GST certificate, etc.
Cancel
-------------------- END OF FILE -------------------- ### FILE 5: client_edit.php - Type: PHP - Size: 19.31 KB - Path: . - Name: client_edit.php ------------------------------------------------------------ prepare(" UPDATE clients SET company_name = ?, industry = ?, contact_person = ?, email = ?, phone = ?, address = ?, city = ?, country = ?, postal_code = ?, website = ?, notes = ?, status = ?, currency = ?, updated_at = NOW() WHERE id = ? "); $stmt->execute([ $company_name, $industry, $contact_person, $email, $phone, $address, $city, $country, $postal_code, $website, $notes, $status, $currency, $client_id ]); // Handle file uploads if (!empty($_FILES['attachments']['name'][0])) { $upload_dir = 'uploads/clients/'; if (!file_exists($upload_dir)) { mkdir($upload_dir, 0755, true); } $allowed_types = ['application/pdf', 'image/jpeg', 'image/jpg', 'image/png', 'image/gif']; $max_size = 5 * 1024 * 1024; // Get client code $clientStmt = $pdo->prepare("SELECT client_code FROM clients WHERE id = ?"); $clientStmt->execute([$client_id]); $client_code = $clientStmt->fetchColumn(); for ($i = 0; $i < count($_FILES['attachments']['name']); $i++) { if ($_FILES['attachments']['error'][$i] === UPLOAD_ERR_OK) { $file_type = $_FILES['attachments']['type'][$i]; $file_size = $_FILES['attachments']['size'][$i]; if (in_array($file_type, $allowed_types) && $file_size <= $max_size) { $file_name = $_FILES['attachments']['name'][$i]; $file_tmp = $_FILES['attachments']['tmp_name'][$i]; $extension = pathinfo($file_name, PATHINFO_EXTENSION); $unique_name = $client_code . '_' . time() . '_' . $i . '.' . $extension; $file_path = $upload_dir . $unique_name; if (move_uploaded_file($file_tmp, $file_path)) { $attachStmt = $pdo->prepare(" INSERT INTO client_attachments (client_id, file_name, file_path, file_type, file_size, uploaded_at) VALUES (?, ?, ?, ?, ?, NOW()) "); $attachStmt->execute([$client_id, $file_name, $file_path, $file_type, $file_size]); } } } } } logActivity($_SESSION['admin_id'], 'update_client', "Updated client #$client_id", 'client', $client_id); $success = 'Client updated successfully!'; } catch (Exception $e) { $error = 'An error occurred. Please try again.'; error_log("Update client error: " . $e->getMessage()); } } } // Handle attachment deletion - SEPARATE ACTION if ($_POST['action'] === 'delete_attachment') { $attach_id = intval($_POST['attachment_id'] ?? 0); if ($attach_id) { try { $pdo = getDBConnection(); $stmt = $pdo->prepare("SELECT * FROM client_attachments WHERE id = ? AND client_id = ?"); $stmt->execute([$attach_id, $client_id]); $attach = $stmt->fetch(); if ($attach) { if (file_exists($attach['file_path'])) { unlink($attach['file_path']); } $stmt = $pdo->prepare("DELETE FROM client_attachments WHERE id = ?"); $stmt->execute([$attach_id]); $success = 'Attachment deleted successfully!'; } } catch (Exception $e) { $error = 'Error deleting attachment.'; } } } } // Fetch client details try { $pdo = getDBConnection(); $stmt = $pdo->prepare("SELECT * FROM clients WHERE id = ?"); $stmt->execute([$client_id]); $client = $stmt->fetch(); if (!$client) { header('Location: clients.php'); exit; } // Fetch attachments $attachStmt = $pdo->prepare("SELECT * FROM client_attachments WHERE client_id = ?"); $attachStmt->execute([$client_id]); $attachments = $attachStmt->fetchAll(); } catch (Exception $e) { error_log("Fetch client error: " . $e->getMessage()); header('Location: clients.php'); exit; } $industries = [ 'Technology', 'Healthcare', 'Finance', 'Retail', 'Manufacturing', 'Education', 'Real Estate', 'Hospitality', 'Consulting', 'Marketing', 'Construction', 'Transportation', 'Other' ]; $countries = [ 'India', 'United States', 'United Kingdom', 'Canada', 'Australia', 'Germany', 'France', 'Japan', 'China', 'Singapore', 'United Arab Emirates', 'Saudi Arabia', 'Malaysia', 'Thailand', 'Indonesia', 'Philippines', 'Vietnam', 'South Korea', 'Hong Kong', 'Taiwan', 'Bangladesh', 'Pakistan', 'Sri Lanka', 'Nepal', 'Bhutan', 'Afghanistan', 'Maldives', 'Myanmar', 'Cambodia', 'Laos', 'Other' ]; include 'includes/header.php'; ?>

📎 Existing Documents ()

KB
Include country code (e.g., +91 for India, +1 for USA)
PDF, JPG, PNG, GIF (Max 5MB per file)
-------------------- END OF FILE -------------------- ### FILE 6: client_view.php - Type: PHP - Size: 11.71 KB - Path: . - Name: client_view.php ------------------------------------------------------------ prepare("SELECT * FROM clients WHERE id = ?"); $stmt->execute([$client_id]); $client = $stmt->fetch(); if (!$client) { header('Location: clients.php'); exit; } // Fetch attachments $attachStmt = $pdo->prepare("SELECT * FROM client_attachments WHERE client_id = ?"); $attachStmt->execute([$client_id]); $attachments = $attachStmt->fetchAll(); } catch (Exception $e) { error_log("View client error: " . $e->getMessage()); header('Location: clients.php'); exit; } include 'includes/header.php'; ?>

Basic Information

Company Name
Industry
Contact Person

Contact Information

Email Address
Phone Number
Website

Location Information

Address
City
Country
Postal Code

Business Information

Total Projects
Total Revenue
Account Created
Last Updated

Notes

Attachments ()

📎

No documents uploaded yet

KB • Uploaded on
📥 Download
-------------------- END OF FILE -------------------- ### FILE 7: clients.php - Type: PHP - Size: 13.34 KB - Path: . - Name: clients.php ------------------------------------------------------------ prepare("SELECT client_code FROM clients WHERE id = ?"); $stmt->execute([$delete_id]); $client_code = $stmt->fetchColumn(); $stmt = $pdo->prepare("DELETE FROM clients WHERE id = ?"); $stmt->execute([$delete_id]); logActivity($_SESSION['admin_id'], 'delete_client', "Deleted client: $client_code", 'client', $delete_id); $success = 'Client deleted successfully!'; } catch (Exception $e) { $error = 'Error deleting client.'; } } } // Fetch clients try { $pdo = getDBConnection(); $stmt = $pdo->query("SELECT * FROM clients ORDER BY created_at DESC"); $clients = $stmt->fetchAll(); } catch (Exception $e) { $clients = []; } $total_clients = count($clients); $active_clients = count(array_filter($clients, fn($c) => $c['status'] === 'active')); $total_projects = array_sum(array_column($clients, 'total_projects')); $total_revenue = array_sum(array_column($clients, 'total_revenue')); include 'includes/header.php'; ?>
Total Clients
Active Clients
Total Projects
Total Revenue
ID Client Code Company Name Industry Contact Person Location Email & Phone Projects Revenue Status Actions
No clients found. Click "Add New Client" to create one.
#
👁
-------------------- END OF FILE -------------------- ### FILE 8: config.php - Type: PHP - Size: 3.88 KB - Path: . - Name: config.php ------------------------------------------------------------ PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ] ); return $pdo; } catch (PDOException $e) { error_log("Connection failed: " . $e->getMessage()); die("Database connection failed. Please try again later."); } } // Create connection for Panel Database (Customer Portal) function getPanelDBConnection() { try { $pdo = new PDO( "mysql:host=" . DB_HOST . ";dbname=" . PANEL_DB_NAME . ";charset=utf8mb4", PANEL_DB_USER, // Use the panel-specific user DB_PASS, // Assuming same password [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ] ); return $pdo; } catch (PDOException $e) { error_log("Panel DB Connection failed: " . $e->getMessage()); die("Panel database connection failed. Please try again later."); } } // Helper function to check if user is logged in function isLoggedIn() { return isset($_SESSION['admin_id']) && isset($_SESSION['admin_role']); } // Helper function to check if user is admin function isAdmin() { return isset($_SESSION['admin_role']) && $_SESSION['admin_role'] === 'admin'; } // Helper function to check if user can access page function canAccessPage($page) { if (!isLoggedIn()) { return false; } // Admin can access everything if (isAdmin()) { return true; } // Manager cannot access users page if ($page === 'users' && $_SESSION['admin_role'] === 'manager') { return false; } return true; } // Helper function to redirect if not authorized function requireLogin() { if (!isLoggedIn()) { header('Location: index.php'); exit; } } // Helper function to require admin role function requireAdmin() { requireLogin(); if (!isAdmin()) { header('Location: index.php'); exit; } } // Helper function to log admin activity function logActivity($admin_id, $action, $description, $resource_type = null, $resource_id = null) { try { $pdo = getDBConnection(); $stmt = $pdo->prepare(" INSERT INTO admin_activity_log (admin_id, action, resource_type, resource_id, description, ip_address) VALUES (?, ?, ?, ?, ?, ?) "); $stmt->execute([ $admin_id, $action, $resource_type, $resource_id, $description, $_SERVER['REMOTE_ADDR'] ?? null ]); } catch (Exception $e) { error_log("Activity log error: " . $e->getMessage()); } } ?> -------------------- END OF FILE -------------------- ### FILE 9: demand.php - Type: PHP - Size: 10.75 KB - Path: . - Name: demand.php ------------------------------------------------------------ 8.7, 'growth_rate' => 15.3, 'market_score' => 92, 'forecast_accuracy' => 87.5 ]; $demand_trends = [ ['category' => 'Technology Panels', 'demand_level' => 'High', 'growth' => '+23%', 'priority' => 'High'], ['category' => 'Healthcare Surveys', 'demand_level' => 'Medium', 'growth' => '+12%', 'priority' => 'Medium'], ['category' => 'Financial Services', 'demand_level' => 'High', 'growth' => '+18%', 'priority' => 'High'], ['category' => 'Retail Analytics', 'demand_level' => 'Low', 'growth' => '-5%', 'priority' => 'Low'], ['category' => 'Education Research', 'demand_level' => 'Medium', 'growth' => '+8%', 'priority' => 'Medium'] ]; $market_insights = [ ['insight' => 'Technology sector showing strongest demand growth', 'impact' => 'High', 'action' => 'Expand tech panel offerings'], ['insight' => 'Q3 demand exceeded forecasts by 15%', 'impact' => 'Medium', 'action' => 'Adjust Q4 capacity planning'], ['insight' => 'Mobile panel participation up 34%', 'impact' => 'High', 'action' => 'Optimize mobile experience'], ['insight' => 'Weekend response rates declining', 'impact' => 'Low', 'action' => 'Review scheduling strategy'] ]; include 'includes/header.php'; ?>
📈
Demand Index
+0.8 vs last month
🚀
%
Growth Rate
+2.3% vs Q2
🎯
Market Score
Excellent rating
🔮
%
Forecast Accuracy
+5.2% improvement

Demand Trends

Current Demand
Forecast

Category Performance

Key Market Insights

$insight): ?>
Impact

-------------------- END OF FILE -------------------- ### FILE 10: error-404.html - Type: HTML - Size: 6.9 KB - Path: . - Name: error-404.html ------------------------------------------------------------ Page Not Found - Relevant Reflex
404

Page Not Found

Sorry, the page you are looking for doesn't exist or has been moved. Let's get you back on track with our panel management system.

🏠 Back to Dashboard ⬅️ Go Back
-------------------- END OF FILE -------------------- ### FILE 11: error-500.html - Type: HTML - Size: 8.81 KB - Path: . - Name: error-500.html ------------------------------------------------------------ Server Error - Relevant Reflex
500

Internal Server Error

We're experiencing technical difficulties with our panel management system. Our team has been notified and is working to resolve this issue.

What you can try:

🏠 Back to Dashboard 📞 Contact Support

Need Immediate Assistance?

Our technical team is available 24/7 to help resolve system issues.

-------------------- END OF FILE -------------------- ### FILE 12: finance.php - Type: PHP - Size: 1.28 KB - Path: . - Name: finance.php ------------------------------------------------------------
💰

Finance

This section is being set up. Financial management, invoicing and reporting features will be available here soon.

-------------------- END OF FILE -------------------- ### FILE 13: generate_hash.php - Type: PHP - Size: 184 B - Path: . - Name: generate_hash.php ------------------------------------------------------------ php -------------------- END OF FILE -------------------- ### FILE 14: index.php - Type: PHP - Size: 23.24 KB - Path: . - Name: index.php ------------------------------------------------------------ prepare("SELECT * FROM admin_users WHERE username = ? AND status = 'active'"); $stmt->execute([$username]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password'])) { $_SESSION['admin_id'] = $user['id']; $_SESSION['admin_username'] = $user['username']; $_SESSION['admin_email'] = $user['email']; $_SESSION['admin_role'] = $user['role']; $_SESSION['admin_name'] = $user['full_name']; $updateStmt = $pdo->prepare("UPDATE admin_users SET last_login = NOW() WHERE id = ?"); $updateStmt->execute([$user['id']]); logActivity($user['id'], 'login', 'User logged in successfully'); header('Location: index.php'); exit; } else { $error = 'Invalid username or password'; } } catch (Exception $e) { error_log("Login error: " . $e->getMessage()); $error = 'An error occurred. Please try again.'; } } } // ============ SHOW LOGIN FORM ============ ?> Login - Relevant Reflex Admin

Welcome Back

Sign in to your admin account

query("SELECT COUNT(*) as total FROM users"); $total_members = $memberStmt->fetchColumn(); // Active members $activeStmt = $panelPdo->query("SELECT COUNT(*) as total FROM users WHERE status = 'active'"); $active_members = $activeStmt->fetchColumn(); // Email verified members $verifiedStmt = $panelPdo->query("SELECT COUNT(*) as total FROM users WHERE email_verified = 1"); $verified_members = $verifiedStmt->fetchColumn(); // Total points in circulation $pointsStmt = $panelPdo->query("SELECT SUM(points) as total FROM user_points"); $total_points = $pointsStmt->fetchColumn() ?? 0; // Total points earned (lifetime) $earnedStmt = $panelPdo->query("SELECT SUM(total_earned) as total FROM user_points"); $total_earned = $earnedStmt->fetchColumn() ?? 0; // Total redemptions $redeemedStmt = $panelPdo->query("SELECT SUM(total_redeemed) as total FROM user_points"); $total_redeemed = $redeemedStmt->fetchColumn() ?? 0; // Pending redemption requests $pendingRedemptionsStmt = $panelPdo->query("SELECT COUNT(*) as total FROM redemption_requests WHERE status = 'pending'"); $pending_redemptions = $pendingRedemptionsStmt->fetchColumn(); // Open support tickets $openTicketsStmt = $panelPdo->query("SELECT COUNT(*) as total FROM support_tickets WHERE status IN ('open', 'pending')"); $open_tickets = $openTicketsStmt->fetchColumn(); // Admin users $adminStmt = $pdo->query("SELECT COUNT(*) as total FROM admin_users WHERE status = 'active'"); $admin_count = $adminStmt->fetchColumn(); // Affiliates $affiliateStmt = $pdo->query("SELECT COUNT(*) as total FROM affiliates WHERE status = 'active'"); $affiliate_count = $affiliateStmt->fetchColumn(); // Recent members (last 7 days) $recentStmt = $panelPdo->query("SELECT COUNT(*) as total FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)"); $recent_members = $recentStmt->fetchColumn(); // Recent activities $activitiesStmt = $pdo->query(" SELECT al.*, au.full_name, au.username FROM admin_activity_log al LEFT JOIN admin_users au ON al.admin_id = au.id ORDER BY al.created_at DESC LIMIT 10 "); $recent_activities = $activitiesStmt->fetchAll(); } catch (Exception $e) { error_log("Dashboard error: " . $e->getMessage()); $total_members = $active_members = $verified_members = 0; $total_points = $total_earned = $total_redeemed = 0; $pending_redemptions = $open_tickets = 0; $admin_count = $affiliate_count = $recent_members = 0; $recent_activities = []; } include 'includes/header.php'; ?>

👋 Welcome back, !

Here's what's happening with your panel today

📅 👤
👥
Total Members
0): ?> ↑ + this week No new members
Active Members
0 ? round(($active_members / $total_members) * 100) : 0; ?>% of total
💎
Points in Circulation
Available balance
🎁
Pending Redemptions
0): ?> ⚠ Needs attention ✓ All processed
🎫
Open Support Tickets
0): ?> ⚠ Requires response ✓ All resolved
📦
Active Affiliates
Partner network

📜 Recent Activity

View All →
📜
No recent activity
-------------------- END OF FILE -------------------- ### FILE 15: login.php - Type: PHP - Size: 3.92 KB - Path: . - Name: login.php ------------------------------------------------------------ prepare("SELECT * FROM admin_users WHERE username = ? AND status = 'active'"); $stmt->execute([$username]); $user = $stmt->fetch(); if ($user && password_verify($password, $user['password'])) { // Set session $_SESSION['admin_id'] = $user['id']; $_SESSION['admin_username'] = $user['username']; $_SESSION['admin_email'] = $user['email']; $_SESSION['admin_role'] = $user['role']; $_SESSION['admin_name'] = $user['full_name']; // Update last login $updateStmt = $pdo->prepare("UPDATE admin_users SET last_login = NOW() WHERE id = ?"); $updateStmt->execute([$user['id']]); // Log activity logActivity($user['id'], 'login', 'User logged in successfully'); header('Location: index.php'); exit; } else { $error = 'Invalid username or password'; } } catch (Exception $e) { error_log("Login error: " . $e->getMessage()); $error = 'An error occurred. Please try again.'; } } } ?> Login - Relevant Reflex

Welcome Back

Sign in to your admin account

-------------------- END OF FILE -------------------- ### FILE 16: logout.php - Type: PHP - Size: 185 B - Path: . - Name: logout.php ------------------------------------------------------------ -------------------- END OF FILE -------------------- ### FILE 17: maintenance.html - Type: HTML - Size: 0 B - Path: . - Name: maintenance.html ------------------------------------------------------------ -------------------- END OF FILE -------------------- ### FILE 18: member_edit.php - Type: PHP - Size: 13.96 KB - Path: . - Name: member_edit.php ------------------------------------------------------------ prepare(" UPDATE users SET gender = ?, date_of_birth = ?, postcode = ?, status = ?, updated_at = NOW() WHERE id = ? "); $stmt->execute([$gender, $dob, $postcode, $status, $member_id]); logActivity($_SESSION['admin_id'], 'update_member', "Updated member #$member_id basic info", 'member', $member_id); $success = 'Member information updated successfully!'; } catch (Exception $e) { $error = 'An error occurred. Please try again.'; error_log("Update member error: " . $e->getMessage()); } } } if ($_POST['action'] === 'update_mobile') { $mobile = trim($_POST['mobile_number'] ?? ''); if (empty($mobile)) { $error = 'Mobile number is required'; } else { try { $panelPdo = getPanelDBConnection(); // Check if mobile verification record exists $checkStmt = $panelPdo->prepare("SELECT id FROM mobile_verifications WHERE user_id = ?"); $checkStmt->execute([$member_id]); $exists = $checkStmt->fetch(); if ($exists) { $stmt = $panelPdo->prepare(" UPDATE mobile_verifications SET mobile_number = ?, updated_at = NOW() WHERE user_id = ? "); $stmt->execute([$mobile, $member_id]); } else { $stmt = $panelPdo->prepare(" INSERT INTO mobile_verifications (user_id, mobile_number) VALUES (?, ?) "); $stmt->execute([$member_id, $mobile]); } logActivity($_SESSION['admin_id'], 'update_member', "Updated member #$member_id mobile number", 'member', $member_id); $success = 'Mobile number updated successfully!'; } catch (Exception $e) { $error = 'An error occurred. Please try again.'; error_log("Update mobile error: " . $e->getMessage()); } } } } // Fetch member details try { $panelPdo = getPanelDBConnection(); $stmt = $panelPdo->prepare(" SELECT u.*, mv.mobile_number, mv.is_verified as mobile_verified FROM users u LEFT JOIN mobile_verifications mv ON u.id = mv.user_id WHERE u.id = ? "); $stmt->execute([$member_id]); $member = $stmt->fetch(); if (!$member) { header('Location: members.php'); exit; } } catch (Exception $e) { error_log("Fetch member error: " . $e->getMessage()); header('Location: members.php'); exit; } include 'includes/header.php'; ?>

Basic Information

Email address cannot be changed

Mobile Number

✓ Verified Not verified

Account Information

Email Verified
✓ Yes' : '✗ No'; ?>
Onboarding Completed
✓ Yes' : '⏳ No'; ?>
Member Since
Last Updated
-------------------- END OF FILE -------------------- ### FILE 19: member_view.php - Type: PHP - Size: 30.18 KB - Path: . - Name: member_view.php ------------------------------------------------------------ prepare(" SELECT u.*, up.points as current_points, up.total_earned, up.total_redeemed, mv.mobile_number, mv.is_verified as mobile_verified, mv.verified_at as mobile_verified_at FROM users u LEFT JOIN user_points up ON u.id = up.user_id LEFT JOIN mobile_verifications mv ON u.id = mv.user_id WHERE u.id = ? "); $stmt->execute([$member_id]); $member = $stmt->fetch(); if (!$member) { header('Location: panel.php'); exit; } // Fetch profiler completion $completionStmt = $panelPdo->prepare(" SELECT * FROM profiler_completion WHERE user_id = ? "); $completionStmt->execute([$member_id]); $completionData = $completionStmt->fetchAll(); // Fetch point transactions $transactionsStmt = $panelPdo->prepare(" SELECT * FROM point_transactions WHERE user_id = ? ORDER BY created_at DESC LIMIT 50 "); $transactionsStmt->execute([$member_id]); $transactions = $transactionsStmt->fetchAll(); // Fetch redemption requests $redemptionsStmt = $panelPdo->prepare(" SELECT * FROM redemption_requests WHERE user_id = ? ORDER BY created_at DESC "); $redemptionsStmt->execute([$member_id]); $redemptions = $redemptionsStmt->fetchAll(); // Fetch support tickets $ticketsStmt = $panelPdo->prepare(" SELECT * FROM support_tickets WHERE user_id = ? ORDER BY created_at DESC LIMIT 10 "); $ticketsStmt->execute([$member_id]); $tickets = $ticketsStmt->fetchAll(); } catch (Exception $e) { error_log("Member view error: " . $e->getMessage()); header('Location: panel.php'); exit; } include 'includes/header.php'; ?>
💰
Current Points
Available Balance
📈
Total Earned
Lifetime Earnings
💳
Total Redeemed
Lifetime Redemptions
Account Status

Basic Information

📧 Email Address
✓ Verified ✗ Not Verified
👤 Gender
🎂 Date of Birth
diff($dob)->y; echo $dob->format('F j, Y'); ?>
years old
📍 Postcode
📱 Mobile Number
✓ Verified
🔒 Account Status
✅ Email Verified
✓ Yes' : '✗ No'; ?>
🎯 Onboarding Status
✓ Completed ⏳ Pending
📅 Member Since
💐 Last Login

Profiler Completion

%
of questions answered • Completed on
📋
No profiler data available

Points Transaction History

💎
No transaction history available

Redemption Requests

Request ID Points Amount (₹) UPI ID Status Requested Processed
Pending'; ?>
🎁
No redemption requests found

Support Tickets

#
Created:
🎫
No support tickets found
-------------------- END OF FILE -------------------- ### FILE 20: members.php - Type: PHP - Size: 21.92 KB - Path: . - Name: members.php ------------------------------------------------------------ 0) { try { $panelPdo = getPanelDBConnection(); $panelPdo->beginTransaction(); // Delete related records first $panelPdo->prepare("DELETE FROM point_transactions WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM user_points WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM redemption_requests WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM support_tickets WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM support_messages WHERE sender_type = 'user' AND sender_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM user_profiler WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM profiler_completion WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM mobile_verifications WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM email_verifications WHERE user_id = ?")->execute([$member_id]); // Delete the user $panelPdo->prepare("DELETE FROM users WHERE id = ?")->execute([$member_id]); $panelPdo->commit(); logActivity($_SESSION['admin_id'], 'delete_member', "Deleted member #$member_id", 'member', $member_id); $success_message = 'Member deleted successfully!'; } catch (Exception $e) { $panelPdo->rollBack(); error_log("Delete member error: " . $e->getMessage()); $error_message = 'Error deleting member. Please try again.'; } } } // Fetch all panel members with their points try { $panelPdo = getPanelDBConnection(); $stmt = $panelPdo->query(" SELECT u.*, up.points as current_points, up.total_earned, up.total_redeemed, mv.mobile_number, mv.is_verified as mobile_verified FROM users u LEFT JOIN user_points up ON u.id = up.user_id LEFT JOIN mobile_verifications mv ON u.id = mv.user_id ORDER BY u.created_at DESC "); $members = $stmt->fetchAll(); } catch (Exception $e) { $members = []; error_log("Fetch members error: " . $e->getMessage()); } include 'includes/header.php'; ?>
Total Members
$m['status'] === 'active')); ?>
Active Members
$m['email_verified'] == 1)); ?>
Email Verified
$m['mobile_verified'] == 1)); ?>
Mobile Verified
ID Email Gender Date of Birth Postcode Points Status Joined Actions
👥
No panel members found
#
Verified
diff($dob)->y; ?>
format('M j, Y'); ?>
years old
-------------------- END OF FILE -------------------- ### FILE 21: panel.php - Type: PHP - Size: 22 KB - Path: . - Name: panel.php ------------------------------------------------------------ 0) { try { $panelPdo = getPanelDBConnection(); $panelPdo->beginTransaction(); // Delete related records first $panelPdo->prepare("DELETE FROM point_transactions WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM user_points WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM redemption_requests WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM support_tickets WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM support_messages WHERE sender_type = 'user' AND sender_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM user_profiler WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM profiler_completion WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM mobile_verifications WHERE user_id = ?")->execute([$member_id]); $panelPdo->prepare("DELETE FROM email_verifications WHERE user_id = ?")->execute([$member_id]); // Delete the user $panelPdo->prepare("DELETE FROM users WHERE id = ?")->execute([$member_id]); $panelPdo->commit(); logActivity($_SESSION['admin_id'], 'delete_member', "Deleted member #$member_id", 'member', $member_id); $success_message = 'Member deleted successfully!'; } catch (Exception $e) { $panelPdo->rollBack(); error_log("Delete member error: " . $e->getMessage()); $error_message = 'Error deleting member. Please try again.'; } } } try { $panelPdo = getPanelDBConnection(); $stmt = $panelPdo->query(" SELECT u.*, up.points as current_points, up.total_earned, up.total_redeemed, mv.mobile_number, mv.is_verified as mobile_verified FROM users u LEFT JOIN user_points up ON u.id = up.user_id LEFT JOIN mobile_verifications mv ON u.id = mv.user_id ORDER BY u.created_at DESC "); $members = $stmt->fetchAll(); } catch (Exception $e) { $members = []; error_log("Fetch members error: " . $e->getMessage()); } include 'includes/header.php'; ?>
Total Members
$m['status'] === 'active')); ?>
Active Members
$m['email_verified'] == 1)); ?>
Email Verified
$m['mobile_verified'] == 1)); ?>
Mobile Verified
$m['onboarding_completed'] == 1)); ?>
Onboarded
Total Points
ID Email Gender Date of Birth Postcode Points Status Joined Actions
👥
No panel members found
#
Verified
diff($dob)->y; ?>
format('M j, Y'); ?>
years old
-------------------- END OF FILE -------------------- ### FILE 22: README.md - Type: MD - Size: 8.86 KB - Path: . - Name: README.md ------------------------------------------------------------ # Relevant Reflex Panel Management System A comprehensive, mobile-responsive panel management system built with PHP, MySQL, and modern web technologies. Designed for fast loading on shared hosting environments like Hostinger. ## 🚀 Features - **Complete Panel Management**: Create, manage, and analyze survey panels - **User Management**: Role-based access control with admin, manager, and user roles - **Supply Chain Management**: Track inventory, suppliers, and procurement - **Demand Analytics**: Market analysis and forecasting tools - **Financial Management**: Revenue tracking and expense management - **Support System**: Built-in ticketing and help center - **Real-time Dashboard**: Live statistics and performance metrics - **Mobile Responsive**: 100% mobile-friendly design - **SEO Optimized**: Search engine friendly structure - **Fast Loading**: Optimized for shared hosting environments ## 📁 File Structure ``` relevant-reflex/ ├── index.php # Dashboard home page ├── users.php # User management ├── panel.php # Panel management ├── supply.php # Supply management ├── demand.php # Demand analysis ├── finance.php # Financial management ├── support.php # Support center ├── settings.php # System settings ├── config.php # Database configuration ├── .htaccess # Apache configuration ├── database_schema.sql # Database structure ├── robots.txt # Search engine directives ├── sitemap.xml # Site structure for SEO ├── includes/ │ ├── header.php # Site header │ ├── footer.php # SEO footer │ └── navigation.php # Navigation menu ├── assets/ │ ├── css/ │ │ ├── main.css # Main stylesheet │ │ ├── responsive.css # Mobile responsiveness │ │ └── dashboard.css # Dashboard styles │ ├── js/ │ │ ├── main.js # Core JavaScript │ │ └── dashboard.js # Dashboard functionality │ └── images/ │ └── (your images here) └── error-pages/ ├── 404.html # Page not found ├── 500.html # Server error └── maintenance.html # Maintenance mode ``` ## 🛠️ Installation Instructions ### Prerequisites - **Web Hosting**: Shared hosting account (Hostinger, cPanel, etc.) - **PHP**: Version 7.4 or higher - **MySQL**: Version 5.7 or higher - **Apache**: With mod_rewrite enabled ### Step 1: Download and Extract 1. Download all the files provided in the artifacts 2. Create a new folder named `relevant-reflex` on your computer 3. Copy all files into this folder maintaining the directory structure ### Step 2: Database Setup 1. **Login to phpMyAdmin** via your hosting control panel 2. **Create a new database**: - Database name: `relevant_reflex_db` (or your preferred name) - Collation: `utf8mb4_unicode_ci` 3. **Import the schema**: - Click on your database - Go to "Import" tab - Choose the `database_schema.sql` file - Click "Go" to execute ### Step 3: Configuration 1. **Edit config.php**: ```php define('DB_HOST', 'localhost'); define('DB_USER', 'your_db_username'); // From your hosting panel define('DB_PASS', 'your_db_password'); // From your hosting panel define('DB_NAME', 'relevant_reflex_db'); // Your database name define('SITE_URL', 'https://yourdomain.com'); // Your actual domain ``` 2. **Update site settings** in other files if needed ### Step 4: File Upload 1. **Connect via FTP/File Manager**: - Use your hosting panel's file manager or FTP client - Navigate to `public_html` directory (or your domain's root) 2. **Upload files**: - Upload all files maintaining the folder structure - Ensure permissions are set correctly: - Files: 644 - Directories: 755 - config.php: 600 (more secure) ### Step 5: Testing 1. **Visit your website**: `https://yourdomain.com` 2. **Default admin login**: - Username: `admin` - Email: `admin@relevantreflex.com` - Password: `admin123` - **⚠️ Change this immediately after first login!** 3. **Test all features**: - Dashboard loading - User management - Panel creation - Mobile responsiveness ### Step 6: Security Hardening 1. **Change default admin password** 2. **Update config.php** with strong database credentials 3. **Enable SSL certificate** (usually free with hosting) 4. **Uncomment HTTPS redirect** in .htaccess: ```apache RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] ``` ## 🎨 Customization ### Changing Colors and Theme All colors are centralized in `assets/css/main.css` at the top: ```css :root { --primary-color: #0066cc; /* Change main brand color */ --primary-hover: #0052a3; /* Hover state */ --success-color: #28a745; /* Success messages */ --warning-color: #ffc107; /* Warnings */ --danger-color: #dc3545; /* Errors */ /* ... more color variables */ } ``` Simply update these values to match your brand colors. ### Adding Your Logo 1. **Replace the RR logo**: - Update the `.logo` content in `includes/navigation.php` - Or replace with an image: `Your Logo` 2. **Update favicon**: - Add your `favicon.ico` to the root directory - Update the reference in `includes/header.php` ### Custom Styling - **Main styles**: `assets/css/main.css` - **Mobile styles**: `assets/css/responsive.css` - **Dashboard styles**: `assets/css/dashboard.css` ## 📱 Mobile Optimization The system is built mobile-first with: - **Responsive Grid System**: Adapts to all screen sizes - **Touch-Friendly Interface**: 44px minimum touch targets - **Optimized Navigation**: Hamburger menu on mobile - **Fast Loading**: Optimized assets and caching - **Progressive Enhancement**: Works without JavaScript ## 🔧 Maintenance ### Regular Tasks 1. **Database Backups**: Weekly automated backups recommended 2. **Update Dependencies**: Keep PHP and MySQL updated 3. **Monitor Performance**: Check load times and optimize 4. **Security Updates**: Regular security audits 5. **Content Updates**: Keep information current ### Performance Optimization 1. **Enable Gzip Compression** (included in .htaccess) 2. **Optimize Images**: Use WebP format when possible 3. **Monitor Database**: Run `OPTIMIZE TABLE` monthly 4. **Cache Headers**: Properly configured in .htaccess 5. **CDN Integration**: Consider using a CDN for static assets ## 🔐 Security Features - **SQL Injection Protection**: PDO prepared statements - **XSS Prevention**: Input sanitization and CSP headers - **CSRF Protection**: Session-based token validation - **Secure Headers**: Comprehensive security headers - **File Upload Security**: Restricted file types and locations - **Access Control**: Role-based permissions ## 🆘 Troubleshooting ### Common Issues **1. Database Connection Error** ``` Solution: Check config.php credentials and database server status ``` **2. Page Not Found (404)** ``` Solution: Verify .htaccess file is uploaded and mod_rewrite is enabled ``` **3. Slow Loading** ``` Solution: Enable compression, check hosting performance, optimize images ``` **4. Mobile Display Issues** ``` Solution: Clear browser cache, check responsive.css is loaded ``` **5. JavaScript Not Working** ``` Solution: Check browser console for errors, verify JS files are accessible ``` ### Getting Help 1. **Check Error Logs**: In your hosting control panel 2. **Browser Console**: F12 to check for JavaScript errors 3. **PHP Error Display**: Temporarily enable in config.php for debugging 4. **Hosting Support**: Contact your hosting provider for server issues ## 📞 Support For technical support and customization services: - **Email**: support@relevantreflex.com - **Documentation**: Check inline comments in code files - **Updates**: Monitor for system updates and security patches ## 📝 License This system is proprietary software developed for Relevant Reflex. All rights reserved. ## 🚀 Quick Start Checklist - [ ] Create database in phpMyAdmin - [ ] Import database_schema.sql - [ ] Update config.php with database credentials - [ ] Upload all files to web server - [ ] Set correct file permissions - [ ] Test login with admin/admin123 - [ ] Change default admin password - [ ] Customize colors and branding - [ ] Enable SSL and HTTPS redirect - [ ] Test all functionality - [ ] Setup regular backups ## Version Information - **Version**: 1.0.0 - **Release Date**: September 2025 - **PHP Compatibility**: 7.4+ - **MySQL Compatibility**: 5.7+ - **Browser Support**: All modern browsers, IE11+ --- **Important**: Always backup your database and files before making changes or updates. -------------------- END OF FILE -------------------- ### FILE 23: robots.txt - Type: TXT - Size: 2.16 KB - Path: . - Name: robots.txt ------------------------------------------------------------ # Relevant Reflex Panel Management System # Robots.txt file for search engine optimization User-agent: * # Allow access to main pages Allow: / Allow: /index.php Allow: /users.php Allow: /panel.php Allow: /supply.php Allow: /demand.php Allow: /finance.php Allow: /support.php Allow: /settings.php # Allow access to static assets Allow: /assets/css/ Allow: /assets/js/ Allow: /assets/images/ # Disallow sensitive files and directories Disallow: /config.php Disallow: /database_schema.sql Disallow: /.htaccess Disallow: /includes/ Disallow: /logs/ Disallow: /backups/ Disallow: /temp/ Disallow: /cache/ Disallow: /admin/ Disallow: /api/ Disallow: /private/ # Disallow URL parameters that might create duplicate content Disallow: /*?* Disallow: /*&* Disallow: /*/search?* Disallow: /*/filter?* # Disallow error pages Disallow: /error-* Disallow: /404.html Disallow: /500.html Disallow: /maintenance.html # Block access to development and testing files Disallow: /test/ Disallow: /dev/ Disallow: /staging/ Disallow: /*.bak Disallow: /*.tmp Disallow: /*.log # Block common exploits and security probes Disallow: /wp-admin/ Disallow: /wordpress/ Disallow: /wp-content/ Disallow: /admin.php Disallow: /administrator/ Disallow: /phpmyadmin/ Disallow: /phpMyAdmin/ # Block unwanted file types Disallow: /*.sql$ Disallow: /*.zip$ Disallow: /*.tar.gz$ Disallow: /*.bak$ Disallow: /*.conf$ Disallow: /*.ini$ # Sitemap location Sitemap: https://yourdomain.com/sitemap.xml # Crawl delay for respectful crawling (optional) # Crawl-delay: 1 # Specific rules for different bots (optional) # Google Bot - allow everything we want indexed User-agent: Googlebot Allow: / Disallow: /config.php Disallow: /includes/ Disallow: /*?* # Bing Bot User-agent: Bingbot Allow: / Disallow: /config.php Disallow: /includes/ # Block aggressive bots that might overload the server User-agent: AhrefsBot Disallow: / User-agent: MJ12bot Disallow: / User-agent: SemrushBot Disallow: / User-agent: DotBot Disallow: / # Allow social media bots for link previews User-agent: facebookexternalhit Allow: / User-agent: Twitterbot Allow: / User-agent: LinkedInBot Allow: / # Note: Update "yourdomain.com" with your actual domain name -------------------- END OF FILE -------------------- ### FILE 24: settings.php - Type: PHP - Size: 28.4 KB - Path: . - Name: settings.php ------------------------------------------------------------ exec(" CREATE TABLE IF NOT EXISTS company_settings ( id INT AUTO_INCREMENT PRIMARY KEY, setting_key VARCHAR(100) UNIQUE NOT NULL, setting_value TEXT, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) "); } catch (Exception $e) { // Table might already exist } // Handle form submission if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_settings'])) { try { $fields = [ 'company_name', 'company_address', 'company_city', 'company_state', 'company_country', 'company_pincode', 'company_phone', 'company_email', 'company_website', 'tax_gst', 'tax_pan', 'tax_cin', 'tax_sac_code', 'bank_name', 'bank_account_name', 'bank_account_number', 'bank_ifsc', 'bank_branch', 'bank_swift', 'invoice_prefix', 'invoice_terms', 'invoice_notes', 'invoice_footer' ]; $stmt = $pdo->prepare(" INSERT INTO company_settings (setting_key, setting_value, updated_at) VALUES (?, ?, NOW()) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value), updated_at = NOW() "); foreach ($fields as $field) { $value = trim($_POST[$field] ?? ''); $stmt->execute([$field, $value]); } $success = 'Company settings saved successfully!'; $mode = 'view'; logActivity($_SESSION['admin_id'], 'update', 'Updated company invoicing settings', 'settings', null); } catch (Exception $e) { $error = 'Error saving settings: ' . $e->getMessage(); $mode = 'edit'; } } // Load current settings $settings = []; try { $result = $pdo->query("SELECT setting_key, setting_value FROM company_settings"); while ($row = $result->fetch()) { $settings[$row['setting_key']] = $row['setting_value']; } } catch (Exception $e) {} function getSetting($key, $default = '') { global $settings; return $settings[$key] ?? $default; } $hasData = !empty(array_filter($settings)); include 'includes/header.php'; ?>

Company Settings

Manage your company details used in client invoicing

📋

No Company Details Saved Yet

Add your company information for invoicing by switching to Edit mode.

✏ Add Company Details

🏢 Company Information

Basic company details that appear on invoices and official documents.

— Not set

📋 Tax & Registration

Tax identification numbers and registration details.

💳 Bank Details

Banking information displayed on invoices for client payments.

📄 Invoice Preferences

Default text and formatting for generated invoices.

🏢 Company Information

Basic company details that appear on invoices and official documents.

📋 Tax & Registration

Tax identification numbers and registration details for invoicing compliance.

GST Identification Number or equivalent Tax ID
Permanent Account Number
Corporate Identification Number
Service Accounting Code for your services

💳 Bank Details

Banking information displayed on invoices for client payments.

Required for international payments

📄 Invoice Preferences

Default text and formatting preferences for generated invoices.

e.g. RR-INV-001, RR-INV-002 ...
Cancel
-------------------- END OF FILE -------------------- ### FILE 25: sitemap.xml - Type: XML - Size: 5.24 KB - Path: . - Name: sitemap.xml ------------------------------------------------------------ https://yourdomain.com/ 2025-09-03 daily 1.0 https://yourdomain.com/users.php 2025-09-03 weekly 0.8 https://yourdomain.com/panel.php 2025-09-03 weekly 0.9 https://yourdomain.com/supply.php 2025-09-03 weekly 0.7 https://yourdomain.com/demand.php 2025-09-03 monthly 0.7 https://yourdomain.com/finance.php 2025-09-03 weekly 0.8 https://yourdomain.com/support.php 2025-09-03 monthly 0.6 https://yourdomain.com/settings.php 2025-09-03 monthly 0.5 -------------------- END OF FILE -------------------- ### FILE 26: supply.php - Type: PHP - Size: 21.02 KB - Path: . - Name: supply.php ------------------------------------------------------------ prepare("SELECT affiliate_code FROM affiliates WHERE id = ?"); $stmt->execute([$delete_id]); $affiliate_code = $stmt->fetchColumn(); // Delete affiliate (cascade will delete attachments and signups) $stmt = $pdo->prepare("DELETE FROM affiliates WHERE id = ?"); $stmt->execute([$delete_id]); logActivity($_SESSION['admin_id'], 'delete_affiliate', "Deleted affiliate: $affiliate_code", 'affiliate', $delete_id); $success = 'Affiliate deleted successfully!'; } catch (Exception $e) { $error = 'An error occurred while deleting. Please try again.'; error_log("Delete affiliate error: " . $e->getMessage()); } } } } // Fetch all affiliates try { $pdo = getDBConnection(); $stmt = $pdo->query("SELECT * FROM affiliates ORDER BY created_at DESC"); $affiliates = $stmt->fetchAll(); } catch (Exception $e) { $affiliates = []; error_log("Fetch affiliates error: " . $e->getMessage()); } // Calculate statistics $total_affiliates = count($affiliates); $active_affiliates = count(array_filter($affiliates, fn($a) => $a['status'] === 'active')); $total_signups = array_sum(array_column($affiliates, 'total_signups')); $verified_signups = array_sum(array_column($affiliates, 'total_verified_signups')); $company_affiliates = count(array_filter($affiliates, fn($a) => $a['type'] === 'company')); $individual_affiliates = count(array_filter($affiliates, fn($a) => $a['type'] === 'individual')); include 'includes/header.php'; ?>
Total Affiliates
Active Affiliates
Total Signups
Verified Signups
Companies
Individuals
ID Affiliate Code Company/Name Type In-charge Location Contact Signups Verified Status Actions
No affiliates found. Click "Add New Affiliate" to create one.
#
-
👁
-------------------- END OF FILE -------------------- ### FILE 27: support.php - Type: PHP - Size: 2.21 KB - Path: . - Name: support.php ------------------------------------------------------------
🛠

Support Center

Our support portal is available on the main Relevant Reflex website. Submit tickets, track requests, and access help resources all in one place.

Open Support Portal →

Opens in a new window at relevantreflex.com

-------------------- END OF FILE -------------------- ### FILE 28: users.php - Type: PHP - Size: 23.18 KB - Path: . - Name: users.php ------------------------------------------------------------ prepare("INSERT INTO admin_users (username, email, password, full_name, role, created_by) VALUES (?, ?, ?, ?, ?, ?)"); $stmt->execute([$username, $email, $hashedPassword, $full_name, $role, $_SESSION['admin_id']]); logActivity($_SESSION['admin_id'], 'create_admin_user', "Created admin user: $username", 'admin_user', $pdo->lastInsertId()); $success = 'Admin user created successfully!'; } catch (PDOException $e) { if ($e->getCode() == 23000) { $error = 'Username or email already exists'; } else { $error = 'An error occurred. Please try again.'; error_log("Create user error: " . $e->getMessage()); } } } } if ($_POST['action'] === 'toggle_status') { $user_id = intval($_POST['user_id'] ?? 0); $new_status = $_POST['new_status'] ?? 'active'; try { $pdo = getDBConnection(); $stmt = $pdo->prepare("UPDATE admin_users SET status = ? WHERE id = ?"); $stmt->execute([$new_status, $user_id]); logActivity($_SESSION['admin_id'], 'update_admin_user', "Changed user status to: $new_status", 'admin_user', $user_id); $success = 'User status updated successfully!'; } catch (Exception $e) { $error = 'An error occurred. Please try again.'; error_log("Status update error: " . $e->getMessage()); } } if ($_POST['action'] === 'delete_user' && isAdmin()) { $user_id = intval($_POST['user_id'] ?? 0); if ($user_id > 0 && $user_id != $_SESSION['admin_id']) { try { $pdo = getDBConnection(); // Get username for logging $stmt = $pdo->prepare("SELECT username FROM admin_users WHERE id = ?"); $stmt->execute([$user_id]); $username = $stmt->fetchColumn(); // Delete user $stmt = $pdo->prepare("DELETE FROM admin_users WHERE id = ?"); $stmt->execute([$user_id]); logActivity($_SESSION['admin_id'], 'delete_admin_user', "Deleted admin user: $username", 'admin_user', $user_id); $success = 'Admin user deleted successfully!'; } catch (Exception $e) { $error = 'An error occurred while deleting. Please try again.'; error_log("Delete user error: " . $e->getMessage()); } } } } // Fetch all users try { $pdo = getDBConnection(); $stmt = $pdo->query("SELECT * FROM admin_users ORDER BY created_at DESC"); $users = $stmt->fetchAll(); } catch (Exception $e) { $users = []; error_log("Fetch users error: " . $e->getMessage()); } include 'includes/header.php'; ?>
Total Users
$u['status'] === 'active')); ?>
Active Users
$u['role'] === 'admin')); ?>
Admins
$u['role'] === 'manager')); ?>
Managers
ID User Details Email Role Status Last Login Actions
#
Never
Current User
-------------------- END OF FILE -------------------- ### FILE 29: assets/css/dashboard.css - Type: CSS - Size: 28.48 KB - Path: assets/css - Name: dashboard.css ------------------------------------------------------------ /* Dashboard Specific Styles for Relevant Reflex */ /* Dashboard Container */ .dashboard-container { max-width: 1200px; margin: 0 auto; padding: 0 var(--spacing-md); } /* Enhanced Stats Cards for Dashboard */ .dashboard-content .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--spacing-xl); margin-bottom: var(--spacing-2xl); } .dashboard-content .stat-card { background: linear-gradient(135deg, var(--white) 0%, #f8fafc 100%); border: 1px solid var(--gray-100); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); display: flex; align-items: center; gap: var(--spacing-xl); transition: all var(--transition-normal); position: relative; overflow: hidden; } .dashboard-content .stat-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--primary-color), var(--primary-dark)); } .dashboard-content .stat-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--primary-color); } .dashboard-content .stat-icon { font-size: 3rem; width: 70px; height: 70px; background: linear-gradient(135deg, var(--primary-light), rgba(5, 150, 105, 0.1)); border: 2px solid var(--primary-color); border-radius: var(--border-radius-2xl); display: flex; align-items: center; justify-content: center; flex-shrink: 0; position: relative; } .dashboard-content .stat-icon::after { content: ''; position: absolute; inset: 2px; background: linear-gradient(135deg, transparent, rgba(255, 255, 255, 0.1)); border-radius: calc(var(--border-radius-2xl) - 2px); pointer-events: none; } .dashboard-content .stat-content h3 { font-size: var(--font-size-4xl); margin: 0; color: var(--primary-color); font-weight: var(--font-weight-bold); line-height: 1; } .dashboard-content .stat-content p { margin: var(--spacing-sm) 0 0; color: var(--gray-600); font-weight: var(--font-weight-semibold); font-size: var(--font-size-base); } .stat-change { display: inline-flex; align-items: center; gap: var(--spacing-xs); font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); margin-top: var(--spacing-sm); padding: var(--spacing-xs) var(--spacing-sm); border-radius: var(--border-radius-xl); } .stat-change.positive { background: var(--success-light); color: var(--success-color); } .stat-change.negative { background: var(--danger-light); color: var(--danger-color); } .stat-change.neutral { background: var(--gray-100); color: var(--gray-600); } .stat-change::before { content: '↗'; font-size: var(--font-size-sm); } .stat-change.negative::before { content: '↘'; } .stat-change.neutral::before { content: '→'; } /* Dashboard Content Grid */ .dashboard-content { margin-top: var(--spacing-2xl); } .content-grid { display: grid; grid-template-columns: 2fr 1fr; gap: var(--spacing-2xl); margin-bottom: var(--spacing-2xl); } /* Chart Section */ .chart-section { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); } .section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-xl); padding-bottom: var(--spacing-lg); border-bottom: 1px solid var(--gray-200); } .section-header h2 { margin: 0; color: var(--dark-color); font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); } .chart-controls select { padding: var(--spacing-sm) var(--spacing-md); border: 1px solid var(--gray-300); border-radius: var(--border-radius-lg); background: var(--white); font-size: var(--font-size-sm); cursor: pointer; } .chart-container { position: relative; height: 300px; background: var(--gray-50); border-radius: var(--border-radius-lg); display: flex; align-items: center; justify-content: center; border: 1px dashed var(--gray-300); } .chart-placeholder { color: var(--gray-500); font-style: italic; text-align: center; } .chart-legend { display: flex; gap: var(--spacing-lg); margin-top: var(--spacing-lg); justify-content: center; } .legend-item { display: flex; align-items: center; gap: var(--spacing-sm); font-size: var(--font-size-sm); } .legend-color { width: 16px; height: 16px; border-radius: var(--border-radius-sm); } /* Recent Activity */ .recent-activity { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); } .view-all { color: var(--primary-color); text-decoration: none; font-weight: var(--font-weight-medium); font-size: var(--font-size-sm); transition: color var(--transition-normal); } .view-all:hover { color: var(--primary-hover); text-decoration: underline; } .activity-list { display: flex; flex-direction: column; gap: var(--spacing-md); } .activity-item { display: flex; flex-direction: column; gap: var(--spacing-sm); padding: var(--spacing-lg); background: linear-gradient(135deg, var(--gray-50), #f1f5f9); border-radius: var(--border-radius-lg); border-left: 4px solid var(--primary-color); transition: all var(--transition-normal); position: relative; } .activity-item:hover { background: linear-gradient(135deg, var(--primary-light), rgba(5, 150, 105, 0.05)); transform: translateX(4px); box-shadow: var(--shadow-sm); } .activity-time { font-size: var(--font-size-xs); color: var(--gray-500); font-weight: var(--font-weight-medium); text-transform: uppercase; letter-spacing: 0.5px; } .activity-text { color: var(--dark-color); font-weight: var(--font-weight-normal); line-height: 1.5; } .activity-footer { margin-top: var(--spacing-lg); text-align: center; padding-top: var(--spacing-lg); border-top: 1px solid var(--gray-200); } /* Quick Actions Section */ .quick-actions-section { margin-top: var(--spacing-2xl); background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); } .quick-actions-section h2 { margin-bottom: var(--spacing-xl); color: var(--dark-color); font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); text-align: center; } .quick-actions-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-lg); } .quick-action-card { background: linear-gradient(135deg, var(--white) 0%, var(--gray-50) 100%); border: 1px solid var(--gray-200); border-radius: var(--border-radius-xl); padding: var(--spacing-xl); text-align: center; cursor: pointer; transition: all var(--transition-normal); text-decoration: none; color: inherit; } .quick-action-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--primary-color); background: linear-gradient(135deg, var(--primary-light) 0%, rgba(5, 150, 105, 0.05) 100%); } .action-icon { font-size: 2.5rem; margin-bottom: var(--spacing-lg); display: block; } .quick-action-card h3 { margin: 0 0 var(--spacing-md); color: var(--dark-color); font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); } .quick-action-card p { margin: 0; color: var(--gray-600); font-size: var(--font-size-sm); line-height: 1.5; } /* Overview Cards for Other Pages */ .overview-grid, .user-stats .stats-row, .supply-overview .stats-grid, .panel-overview .overview-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--spacing-lg); margin-bottom: var(--spacing-2xl); } .overview-card, .stat-item { background: var(--white); border-radius: var(--border-radius-xl); padding: var(--spacing-lg); text-align: center; box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); transition: all var(--transition-normal); } .overview-card:hover, .stat-item:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .overview-icon { font-size: 2rem; margin-bottom: var(--spacing-md); display: block; } .overview-content h3, .stat-number { font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); color: var(--primary-color); margin: 0 0 var(--spacing-sm); } .overview-content p, .stat-label { color: var(--gray-600); font-weight: var(--font-weight-medium); margin: 0; } /* Login Information Styling */ .login-info { display: flex; flex-direction: column; gap: 2px; } .login-date { font-weight: var(--font-weight-medium); color: var(--dark-color); font-size: var(--font-size-sm); } .login-time { font-size: var(--font-size-xs); color: var(--gray-500); } .never-logged { font-style: italic; color: var(--gray-400); font-size: var(--font-size-sm); } /* Response Information */ .response-info { display: flex; flex-direction: column; gap: var(--spacing-xs); } .response-info strong { color: var(--primary-color); font-size: var(--font-size-lg); } .response-info small { color: var(--gray-500); font-size: var(--font-size-xs); } /* Date Information */ .date-info { display: flex; flex-direction: column; gap: var(--spacing-xs); } .end-date { font-weight: var(--font-weight-medium); color: var(--dark-color); } .days-left { font-size: var(--font-size-xs); color: var(--gray-500); } /* Quantity Badge */ .quantity-badge { background: var(--primary-light); color: var(--primary-color); padding: var(--spacing-xs) var(--spacing-md); border-radius: var(--border-radius-xl); font-weight: var(--font-weight-bold); font-size: var(--font-size-sm); } /* Financial Cards */ .finance-card { position: relative; overflow: hidden; } .finance-card.revenue-card::before { background: linear-gradient(90deg, var(--success-color), #20c997); } .finance-card.expense-card::before { background: linear-gradient(90deg, var(--danger-color), #e74c3c); } .finance-card.profit-card::before { background: linear-gradient(90deg, var(--primary-color), var(--primary-dark)); } .stat-footer { font-size: var(--font-size-xs); color: var(--gray-500); margin-top: var(--spacing-sm); text-align: center; font-weight: var(--font-weight-medium); } /* Trend Indicators */ .trend { display: inline-flex; align-items: center; gap: var(--spacing-xs); font-size: var(--font-size-sm); font-weight: var(--font-weight-bold); padding: var(--spacing-xs) var(--spacing-sm); border-radius: var(--border-radius-xl); margin-top: var(--spacing-sm); } .trend-up { background: var(--success-light); color: var(--success-color); } .trend-down { background: var(--danger-light); color: var(--danger-color); } .trend-up::before { content: '↗'; } .trend-down::before { content: '↘'; } /* Demand Metrics */ .demand-metrics { margin-bottom: var(--spacing-2xl); } .metrics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--spacing-lg); } .metric-card { background: var(--white); border-radius: var(--border-radius-xl); padding: var(--spacing-xl); text-align: center; box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); transition: all var(--transition-normal); } .metric-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .metric-icon { font-size: 2.5rem; margin-bottom: var(--spacing-lg); display: block; } .metric-value { font-size: var(--font-size-4xl); font-weight: var(--font-weight-bold); color: var(--primary-color); line-height: 1; margin-bottom: var(--spacing-sm); } .metric-label { color: var(--gray-600); font-weight: var(--font-weight-medium); margin-bottom: var(--spacing-sm); } .metric-change { font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); padding: var(--spacing-xs) var(--spacing-sm); border-radius: var(--border-radius-xl); } /* Category Performance */ .category-performance { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); } .category-list { display: flex; flex-direction: column; gap: var(--spacing-lg); } .category-item { border: 1px solid var(--gray-200); border-radius: var(--border-radius-lg); padding: var(--spacing-lg); transition: all var(--transition-normal); } .category-item:hover { border-color: var(--primary-color); background: var(--primary-light); } .category-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-md); } .category-header h4 { margin: 0; color: var(--dark-color); font-weight: var(--font-weight-semibold); } .category-metrics { display: flex; justify-content: space-between; align-items: center; } .demand-level { padding: var(--spacing-xs) var(--spacing-md); border-radius: var(--border-radius-xl); font-size: var(--font-size-sm); font-weight: var(--font-weight-bold); } .demand-high { background: var(--success-light); color: var(--success-color); } .demand-medium { background: var(--warning-light); color: #856404; } .demand-low { background: var(--gray-200); color: var(--gray-600); } .category-growth { font-weight: var(--font-weight-bold); } .category-growth.positive { color: var(--success-color); } .category-growth.negative { color: var(--danger-color); } /* Insights Sections */ .insights-section { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); margin-top: var(--spacing-2xl); } .insights-section h2 { margin-bottom: var(--spacing-xl); color: var(--dark-color); font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); text-align: center; } .insights-grid, .insights-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--spacing-lg); } .insight-card { background: linear-gradient(135deg, var(--gray-50) 0%, #f8fafc 100%); border: 1px solid var(--gray-200); border-radius: var(--border-radius-xl); padding: var(--spacing-xl); transition: all var(--transition-normal); } .insight-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--primary-color); } .insight-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-lg); } .insight-number { width: 30px; height: 30px; background: var(--primary-color); color: var(--white); border-radius: var(--border-radius-full); display: flex; align-items: center; justify-content: center; font-weight: var(--font-weight-bold); font-size: var(--font-size-sm); } .insight-impact { padding: var(--spacing-xs) var(--spacing-md); border-radius: var(--border-radius-xl); font-size: var(--font-size-xs); font-weight: var(--font-weight-bold); text-transform: uppercase; letter-spacing: 0.5px; } .impact-high { background: var(--danger-light); color: var(--danger-color); } .impact-medium { background: var(--warning-light); color: #856404; } .impact-low { background: var(--info-light); color: var(--info-color); } .insight-content h4 { margin: 0 0 var(--spacing-md); color: var(--dark-color); font-weight: var(--font-weight-semibold); line-height: 1.3; } .insight-content p { margin: 0 0 var(--spacing-md); color: var(--gray-600); line-height: 1.6; } .recommended-action { margin: 0 !important; padding: var(--spacing-md); background: var(--primary-light); border-radius: var(--border-radius-lg); border-left: 4px solid var(--primary-color); font-size: var(--font-size-sm); } .recommended-action strong { color: var(--primary-color); } /* Transaction Items */ .transactions-section { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); } .transactions-list { display: flex; flex-direction: column; gap: var(--spacing-md); } .transaction-item { display: flex; align-items: center; gap: var(--spacing-lg); padding: var(--spacing-lg); border-radius: var(--border-radius-lg); border: 1px solid var(--gray-200); transition: all var(--transition-normal); } .transaction-item:hover { border-color: var(--primary-color); background: var(--primary-light); } .transaction-item.revenue { border-left: 4px solid var(--success-color); } .transaction-item.expense { border-left: 4px solid var(--danger-color); } .transaction-icon { font-size: 1.5rem; width: 40px; height: 40px; border-radius: var(--border-radius-full); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .transaction-item.revenue .transaction-icon { background: var(--success-light); } .transaction-item.expense .transaction-icon { background: var(--danger-light); } .transaction-details { flex: 1; } .transaction-description { font-weight: var(--font-weight-medium); color: var(--dark-color); margin-bottom: var(--spacing-xs); } .transaction-meta { display: flex; gap: var(--spacing-lg); font-size: var(--font-size-sm); color: var(--gray-500); } .transaction-amount { font-size: var(--font-size-lg); font-weight: var(--font-weight-bold); } .transaction-amount.positive { color: var(--success-color); } .transaction-amount.negative { color: var(--danger-color); } /* Support Specific Styles */ .support-overview { margin-bottom: var(--spacing-2xl); } .support-card .stat-icon { background: linear-gradient(135deg, var(--info-light), rgba(23, 162, 184, 0.1)); border: 2px solid var(--info-color); } .help-resources { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-lg); } .help-item { display: flex; align-items: center; gap: var(--spacing-lg); padding: var(--spacing-xl); background: var(--white); border: 1px solid var(--gray-200); border-radius: var(--border-radius-xl); text-decoration: none; color: inherit; transition: all var(--transition-normal); } .help-item:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--primary-color); background: var(--primary-light); } .help-icon { font-size: 2rem; width: 50px; height: 50px; background: var(--primary-light); border-radius: var(--border-radius-xl); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .help-content h4 { margin: 0 0 var(--spacing-xs); color: var(--dark-color); font-weight: var(--font-weight-semibold); } .help-content p { margin: 0; color: var(--gray-600); font-size: var(--font-size-sm); } /* Tickets Section */ .tickets-section { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); margin-top: var(--spacing-2xl); } .tickets-container { display: flex; flex-direction: column; gap: var(--spacing-lg); } .ticket-item { border: 1px solid var(--gray-200); border-radius: var(--border-radius-lg); padding: var(--spacing-lg); transition: all var(--transition-normal); } .ticket-item:hover { border-color: var(--primary-color); background: var(--primary-light); } .ticket-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-md); } .ticket-id { font-family: var(--font-family-mono); font-weight: var(--font-weight-bold); color: var(--primary-color); background: var(--primary-light); padding: var(--spacing-xs) var(--spacing-md); border-radius: var(--border-radius-lg); } .ticket-content h4 { margin: 0 0 var(--spacing-md); color: var(--dark-color); font-weight: var(--font-weight-medium); } .ticket-meta { display: flex; gap: var(--spacing-lg); align-items: center; margin-bottom: var(--spacing-md); } .ticket-date { font-size: var(--font-size-sm); color: var(--gray-500); } /* FAQ Section */ .faq-section { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); margin-top: var(--spacing-2xl); } .faq-container { display: flex; flex-direction: column; gap: var(--spacing-md); } .faq-item { display: flex; justify-content: space-between; align-items: center; padding: var(--spacing-lg); border: 1px solid var(--gray-200); border-radius: var(--border-radius-lg); transition: all var(--transition-normal); } .faq-item:hover { border-color: var(--primary-color); background: var(--primary-light); } .faq-question h4 { margin: 0 0 var(--spacing-xs); color: var(--dark-color); font-weight: var(--font-weight-medium); } .faq-category { font-size: var(--font-size-xs); color: var(--primary-color); font-weight: var(--font-weight-bold); text-transform: uppercase; letter-spacing: 0.5px; } .faq-toggle { background: var(--primary-color); color: var(--white); border: none; padding: var(--spacing-sm) var(--spacing-md); border-radius: var(--border-radius-lg); font-size: var(--font-size-sm); font-weight: var(--font-weight-medium); cursor: pointer; transition: all var(--transition-normal); flex-shrink: 0; } .faq-toggle:hover { background: var(--primary-hover); transform: scale(1.05); } /* Settings Specific Styles */ .settings-section { background: var(--white); } .settings-section h2 { margin-bottom: var(--spacing-xl); color: var(--dark-color); font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); padding-bottom: var(--spacing-lg); border-bottom: 2px solid var(--primary-color); } .settings-section h3 { margin: var(--spacing-xl) 0 var(--spacing-lg); color: var(--gray-700); font-size: var(--font-size-lg); font-weight: var(--font-weight-semibold); } .notification-group { background: var(--gray-50); border-radius: var(--border-radius-lg); padding: var(--spacing-lg); margin-bottom: var(--spacing-lg); } /* Color Picker */ .color-picker-group { display: flex; gap: var(--spacing-md); align-items: center; } .color-picker-group input[type="color"] { width: 60px; height: 40px; border-radius: var(--border-radius); border: 1px solid var(--gray-300); cursor: pointer; } .color-hex { flex: 1; background: var(--gray-100); font-family: var(--font-family-mono); } /* Integration Cards */ .integrations-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--spacing-lg); } .integration-card { background: var(--white); border: 1px solid var(--gray-200); border-radius: var(--border-radius-xl); padding: var(--spacing-xl); transition: all var(--transition-normal); } .integration-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--primary-color); } .integration-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: var(--spacing-lg); } .integration-header h4 { margin: 0; color: var(--dark-color); font-weight: var(--font-weight-semibold); } .integration-icon { font-size: 1.5rem; width: 40px; height: 40px; background: var(--primary-light); border-radius: var(--border-radius-lg); display: flex; align-items: center; justify-content: center; margin-bottom: var(--spacing-md); } /* Account Management */ .account-section { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); margin-top: var(--spacing-2xl); } .account-section h2 { margin-bottom: var(--spacing-xl); color: var(--dark-color); font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); } .account-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--spacing-lg); } .account-card { background: var(--gray-50); border: 1px solid var(--gray-200); border-radius: var(--border-radius-xl); padding: var(--spacing-xl); transition: all var(--transition-normal); text-align: center; } .account-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); } .account-card.danger-card { border-color: var(--danger-color); background: var(--danger-light); } .account-card.danger-card:hover { background: #f8d7da; } .account-icon { font-size: 2rem; margin-bottom: var(--spacing-lg); display: block; } .account-content h4 { margin: 0 0 var(--spacing-md); color: var(--dark-color); font-weight: var(--font-weight-semibold); } .account-content p { margin: 0 0 var(--spacing-lg); color: var(--gray-600); font-size: var(--font-size-sm); line-height: 1.5; } /* Password Strength Indicator */ .password-strength { margin-top: var(--spacing-md); } .strength-bar { height: 4px; background: var(--gray-200); border-radius: var(--border-radius-sm); overflow: hidden; margin-bottom: var(--spacing-sm); } .strength-fill { height: 100%; border-radius: var(--border-radius-sm); transition: all var(--transition-normal); } .strength-fill.strength-weak { background: var(--danger-color); width: 25%; } .strength-fill.strength-fair { background: var(--warning-color); width: 50%; } .strength-fill.strength-good { background: var(--info-color); width: 75%; } .strength-fill.strength-strong { background: var(--success-color); width: 100%; } .strength-text { font-size: var(--font-size-xs); color: var(--gray-500); } /* Summary Stats */ .summary-section { background: var(--white); border-radius: var(--border-radius-2xl); padding: var(--spacing-xl); box-shadow: var(--shadow-sm); border: 1px solid var(--gray-100); } .summary-stats { display: flex; flex-direction: column; gap: var(--spacing-lg); } .summary-item { text-align: center; padding: var(--spacing-lg); background: var(--gray-50); border-radius: var(--border-radius-lg); border: 1px solid var(--gray-200); } .summary-item h3 { font-size: var(--font-size-2xl); font-weight: var(--font-weight-bold); color: var(--primary-color); margin: 0 0 var(--spacing-sm); } .summary-item p { margin: 0; color: var(--gray-600); font-weight: var(--font-weight-medium); } /* Responsive Adjustments for Dashboard Components */ @media (max-width: 992px) { .content-grid { grid-template-columns: 1fr; } .quick-actions-grid { grid-template-columns: repeat(2, 1fr); } .metrics-grid { grid-template-columns: repeat(2, 1fr); } .insights-grid { grid-template-columns: 1fr; } } @media (max-width: 576px) { .quick-actions-grid { grid-template-columns: 1fr; } .metrics-grid { grid-template-columns: 1fr; } .overview-grid, .account-grid, .integrations-grid { grid-template-columns: 1fr; } .transaction-item { flex-direction: column; text-align: center; gap: var(--spacing-md); } .transaction-meta { justify-content: center; } .help-resources { grid-template-columns: 1fr; } .help-item { flex-direction: column; text-align: center; gap: var(--spacing-md); } } -------------------- END OF FILE -------------------- ### FILE 30: assets/css/main.css - Type: CSS - Size: 18.91 KB - Path: assets/css - Name: main.css ------------------------------------------------------------ /* =================================== CSS Variables =================================== */ :root { /* Colors */ --primary-color: #059669; --primary-hover: #047857; --secondary-color: #6c757d; --success-color: #28a745; --danger-color: #dc3545; --warning-color: #ffc107; --info-color: #17a2b8; --light-color: #f8f9fa; --dark-color: #212529; /* Gray Scale */ --gray-50: #f9fafb; --gray-100: #f3f4f6; --gray-200: #e5e7eb; --gray-300: #d1d5db; --gray-400: #9ca3af; --gray-500: #6b7280; --gray-600: #4b5563; --gray-700: #374151; --gray-800: #1f2937; --gray-900: #111827; /* Spacing */ --spacing-xs: 4px; --spacing-sm: 8px; --spacing-md: 16px; --spacing-lg: 24px; --spacing-xl: 32px; --spacing-2xl: 48px; /* Font Sizes */ --font-size-xs: 12px; --font-size-sm: 14px; --font-size-base: 16px; --font-size-lg: 18px; --font-size-xl: 20px; --font-size-2xl: 24px; --font-size-3xl: 30px; /* Border Radius */ --border-radius-sm: 4px; --border-radius-md: 8px; --border-radius-lg: 12px; --border-radius-xl: 16px; --border-radius-full: 9999px; /* Shadows */ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1); /* Transitions */ --transition-fast: 150ms ease-in-out; --transition-base: 250ms ease-in-out; --transition-slow: 350ms ease-in-out; } /* =================================== Reset & Base Styles =================================== */ * { margin: 0; padding: 0; box-sizing: border-box; } html { font-size: 16px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-size: var(--font-size-base); line-height: 1.5; color: var(--dark-color); background: var(--gray-50); min-height: 100vh; } /* =================================== Header & Navigation =================================== */ .main-header { background: white; border-bottom: 1px solid var(--gray-200); position: sticky; top: 0; z-index: 100; box-shadow: var(--shadow-sm); } .navbar { padding: 0; } .nav-container { max-width: 1400px; margin: 0 auto; padding: 0 var(--spacing-lg); display: flex; align-items: center; justify-content: space-between; min-height: 64px; } .nav-brand { display: flex; align-items: center; gap: var(--spacing-md); font-weight: 700; font-size: var(--font-size-lg); color: var(--dark-color); } .logo { width: 40px; height: 40px; background: linear-gradient(135deg, var(--primary-color), #047857); color: white; border-radius: var(--border-radius-lg); display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 18px; } .nav-menu { display: flex; align-items: center; gap: var(--spacing-sm); flex: 1; justify-content: flex-end; } .nav-link { display: flex; align-items: center; gap: var(--spacing-sm); padding: var(--spacing-sm) var(--spacing-md); color: var(--gray-700); text-decoration: none; border-radius: var(--border-radius-md); transition: all var(--transition-fast); font-size: var(--font-size-sm); font-weight: 500; white-space: nowrap; } .nav-link:hover { background: var(--gray-100); color: var(--primary-color); } .nav-link.active { background: var(--primary-color); color: white; } .nav-icon { font-size: 18px; } .mobile-toggle { display: none; flex-direction: column; gap: 4px; background: none; border: none; padding: var(--spacing-sm); cursor: pointer; } .mobile-toggle span { width: 24px; height: 2px; background: var(--dark-color); transition: var(--transition-fast); } /* =================================== Page Container & Layout =================================== */ .page-container { max-width: 1400px; margin: 0 auto; padding: var(--spacing-2xl) var(--spacing-lg); } .page-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: var(--spacing-2xl); gap: var(--spacing-lg); } .page-header h1 { font-size: var(--font-size-3xl); font-weight: 700; color: var(--dark-color); margin-bottom: var(--spacing-xs); } .page-subtitle { font-size: var(--font-size-base); color: var(--gray-600); margin: 0; } .header-actions { display: flex; gap: var(--spacing-md); } /* =================================== Buttons =================================== */ .btn { display: inline-flex; align-items: center; gap: var(--spacing-sm); padding: 10px 20px; border: none; border-radius: var(--border-radius-md); font-size: var(--font-size-sm); font-weight: 600; cursor: pointer; transition: all var(--transition-fast); text-decoration: none; white-space: nowrap; } .btn-primary { background: var(--primary-color); color: white; } .btn-primary:hover { background: var(--primary-hover); transform: translateY(-1px); box-shadow: var(--shadow-md); } .btn-secondary { background: var(--gray-200); color: var(--gray-700); } .btn-secondary:hover { background: var(--gray-300); } /* =================================== Statistics Cards =================================== */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-lg); margin-bottom: var(--spacing-2xl); } .stat-card { background: white; padding: var(--spacing-xl); border-radius: var(--border-radius-lg); box-shadow: var(--shadow-sm); display: flex; align-items: center; gap: var(--spacing-lg); transition: var(--transition-base); } .stat-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); } .stat-icon { font-size: 48px; opacity: 0.9; } .stat-content h3 { font-size: var(--font-size-3xl); font-weight: 700; color: var(--dark-color); margin-bottom: var(--spacing-xs); } .stat-content p { font-size: var(--font-size-sm); color: var(--gray-600); margin: 0 0 var(--spacing-xs) 0; } .stat-change { font-size: var(--font-size-xs); font-weight: 600; padding: 2px 8px; border-radius: var(--border-radius-sm); } .stat-change.positive { background: #d4edda; color: #155724; } .stat-change.negative { background: #f8d7da; color: #721c24; } .stat-change.neutral { background: var(--gray-100); color: var(--gray-600); } /* =================================== User Stats (Alternative Layout) =================================== */ .user-stats { background: white; padding: var(--spacing-xl); border-radius: var(--border-radius-lg); box-shadow: var(--shadow-sm); margin-bottom: var(--spacing-2xl); } .stats-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--spacing-xl); } .stat-item { text-align: center; } .stat-number { font-size: var(--font-size-3xl); font-weight: 700; color: var(--primary-color); margin-bottom: var(--spacing-xs); } .stat-label { font-size: var(--font-size-sm); color: var(--gray-600); } /* =================================== Table Controls (Search & Filters) =================================== */ .table-controls { display: flex; gap: var(--spacing-md); margin-bottom: var(--spacing-lg); flex-wrap: wrap; } .search-container { flex: 1; min-width: 250px; } .search-input { width: 100%; padding: 10px 16px; border: 1px solid var(--gray-300); border-radius: var(--border-radius-md); font-size: var(--font-size-sm); transition: var(--transition-fast); } .search-input:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.1); } .filter-container { display: flex; gap: var(--spacing-md); flex-wrap: wrap; } .filter-select { padding: 10px 16px; border: 1px solid var(--gray-300); border-radius: var(--border-radius-md); font-size: var(--font-size-sm); background: white; cursor: pointer; transition: var(--transition-fast); } .filter-select:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.1); } /* =================================== Tables - FIXED LAYOUT =================================== */ .table-container { background: white; border-radius: var(--border-radius-lg); box-shadow: var(--shadow-sm); overflow-x: auto; overflow-y: visible; } .data-table { width: 100%; border-collapse: collapse; font-size: var(--font-size-sm); table-layout: fixed; min-width: 100%; } .data-table thead { background: var(--gray-50); border-bottom: 2px solid var(--gray-200); } .data-table th { padding: 16px 12px; text-align: left; font-weight: 600; color: var(--gray-700); text-transform: uppercase; font-size: var(--font-size-xs); letter-spacing: 0.5px; white-space: nowrap; position: sticky; top: 0; background: var(--gray-50); z-index: 10; } .data-table td { padding: 16px 12px; border-bottom: 1px solid var(--gray-100); vertical-align: middle; overflow: hidden; text-overflow: ellipsis; } .data-table tbody tr { transition: var(--transition-fast); } .data-table tbody tr:hover { background: var(--gray-50); } .data-table tbody tr:last-child td { border-bottom: none; } /* =================================== Badges =================================== */ .role-badge, .status-badge { display: inline-block; padding: 4px 12px; border-radius: var(--border-radius-full); font-size: var(--font-size-xs); font-weight: 600; text-transform: uppercase; white-space: nowrap; } /* Role Badges */ .role-badge.role-admin { background: #e3f2fd; color: #1976d2; } .role-badge.role-manager { background: #f3e5f5; color: #7b1fa2; } /* Status Badges */ .status-badge.status-active { background: #d4edda; color: #155724; } .status-badge.status-inactive { background: #f8d7da; color: #721c24; } .status-badge.status-suspended { background: #fff3cd; color: #856404; } .status-badge.status-open { background: #d1ecf1; color: #0c5460; } .status-badge.status-pending { background: #fff3cd; color: #856404; } .status-badge.status-resolved, .status-badge.status-completed { background: #d4edda; color: #155724; } .status-badge.status-closed { background: var(--gray-200); color: var(--gray-700); } /* =================================== Messages =================================== */ .success-message, .error-message { padding: 16px 20px; border-radius: var(--border-radius-md); margin-bottom: var(--spacing-lg); display: flex; align-items: center; gap: var(--spacing-md); font-size: var(--font-size-sm); } .success-message { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; } .error-message { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; } .message-icon { font-size: 20px; } /* =================================== Forms =================================== */ .form-group { margin-bottom: var(--spacing-lg); } .form-group label { display: block; margin-bottom: var(--spacing-sm); color: var(--gray-700); font-weight: 600; font-size: var(--font-size-sm); } .form-group input, .form-group select, .form-group textarea { width: 100%; padding: 10px 16px; border: 1px solid var(--gray-300); border-radius: var(--border-radius-md); font-size: var(--font-size-sm); transition: var(--transition-fast); font-family: inherit; } .form-group input:focus, .form-group select:focus, .form-group textarea:focus { outline: none; border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.1); } .form-group input:disabled, .form-group select:disabled { background: var(--gray-100); cursor: not-allowed; } .form-help { display: block; margin-top: var(--spacing-xs); font-size: var(--font-size-xs); color: var(--gray-600); } .form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--spacing-lg); } .form-actions { display: flex; gap: var(--spacing-md); margin-top: var(--spacing-xl); justify-content: flex-end; } /* =================================== Modal =================================== */ .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 1000; align-items: center; justify-content: center; padding: var(--spacing-lg); } .modal-content { background: white; border-radius: var(--border-radius-xl); padding: var(--spacing-2xl); max-width: 500px; width: 100%; max-height: 90vh; overflow-y: auto; box-shadow: var(--shadow-xl); } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: var(--spacing-xl); } .modal-header h2 { font-size: var(--font-size-2xl); color: var(--dark-color); margin: 0; } .modal-close { background: none; border: none; font-size: 28px; color: var(--gray-500); cursor: pointer; padding: 0; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: var(--border-radius-md); transition: var(--transition-fast); } .modal-close:hover { background: var(--gray-100); color: var(--gray-700); } /* =================================== Dashboard Specific =================================== */ .dashboard-container { /* Dashboard specific styles */ } .quick-actions-section h2 { font-size: var(--font-size-2xl); font-weight: 700; color: var(--dark-color); margin-bottom: var(--spacing-lg); } .quick-actions-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-lg); } .quick-action-card { background: white; padding: var(--spacing-xl); border-radius: var(--border-radius-lg); box-shadow: var(--shadow-sm); transition: var(--transition-base); text-align: center; } .quick-action-card:hover { box-shadow: var(--shadow-lg); transform: translateY(-4px); } .action-icon { font-size: 48px; margin-bottom: var(--spacing-md); } .quick-action-card h3 { font-size: var(--font-size-lg); color: var(--dark-color); margin-bottom: var(--spacing-sm); } .quick-action-card p { font-size: var(--font-size-sm); color: var(--gray-600); margin: 0; } /* =================================== Settings & Tabs =================================== */ .settings-container { display: grid; grid-template-columns: 250px 1fr; gap: var(--spacing-2xl); } .settings-nav { background: white; padding: var(--spacing-lg); border-radius: var(--border-radius-lg); box-shadow: var(--shadow-sm); height: fit-content; position: sticky; top: 80px; } .settings-tabs { list-style: none; } .settings-tabs li { margin-bottom: var(--spacing-xs); } .tab-link { display: block; padding: var(--spacing-md); color: var(--gray-700); text-decoration: none; border-radius: var(--border-radius-md); transition: var(--transition-fast); font-size: var(--font-size-sm); font-weight: 500; } .tab-link:hover { background: var(--gray-100); color: var(--primary-color); } .tab-link.active { background: var(--primary-color); color: white; } .settings-content { background: white; padding: var(--spacing-2xl); border-radius: var(--border-radius-lg); box-shadow: var(--shadow-sm); } .settings-section { margin-bottom: var(--spacing-2xl); } .settings-section:last-child { margin-bottom: 0; } .settings-section h2 { font-size: var(--font-size-2xl); color: var(--dark-color); margin-bottom: var(--spacing-lg); padding-bottom: var(--spacing-md); border-bottom: 2px solid var(--gray-200); } .tab-content { display: none; } .tab-content.active { display: block; } /* =================================== Responsive Design =================================== */ @media (max-width: 1024px) { .settings-container { grid-template-columns: 1fr; } .settings-nav { position: static; } } @media (max-width: 768px) { .page-container { padding: var(--spacing-lg); } .page-header { flex-direction: column; } .header-actions { width: 100%; } .stats-grid, .quick-actions-grid { grid-template-columns: 1fr; } .stats-row { grid-template-columns: repeat(2, 1fr); } .mobile-toggle { display: flex; } .nav-menu { display: none; position: absolute; top: 64px; left: 0; right: 0; background: white; flex-direction: column; padding: var(--spacing-lg); border-top: 1px solid var(--gray-200); box-shadow: var(--shadow-lg); } .nav-menu.active { display: flex; } .nav-link { width: 100%; justify-content: flex-start; } .table-container { overflow-x: scroll; } .form-row { grid-template-columns: 1fr; } } @media (max-width: 480px) { .stats-row { grid-template-columns: 1fr; } .table-controls { flex-direction: column; } .search-container, .filter-container { width: 100%; } .filter-container { flex-direction: column; } .filter-select { width: 100%; } } /* =================================== Utility Classes =================================== */ .text-center { text-align: center; } .text-right { text-align: right; } .mt-0 { margin-top: 0; } .mt-1 { margin-top: var(--spacing-xs); } .mt-2 { margin-top: var(--spacing-sm); } .mt-3 { margin-top: var(--spacing-md); } .mt-4 { margin-top: var(--spacing-lg); } .mt-5 { margin-top: var(--spacing-xl); } .mb-0 { margin-bottom: 0; } .mb-1 { margin-bottom: var(--spacing-xs); } .mb-2 { margin-bottom: var(--spacing-sm); } .mb-3 { margin-bottom: var(--spacing-md); } .mb-4 { margin-bottom: var(--spacing-lg); } .mb-5 { margin-bottom: var(--spacing-xl); } .skip-link { position: absolute; top: -40px; left: 0; background: var(--primary-color); color: white; padding: 8px; text-decoration: none; z-index: 100; } .skip-link:focus { top: 0; } -------------------- END OF FILE -------------------- ### FILE 31: assets/css/member-enhancements.css - Type: CSS - Size: 9.09 KB - Path: assets/css - Name: member-enhancements.css ------------------------------------------------------------ /* MEMBER MANAGEMENT ENHANCEMENTS CSS Add this to your main.css or include separately Improves member_view.php and member_edit.php styling */ /* Navigation Fix - Add to all member pages */ .page-cache-control { /* Prevents caching issues with back button */ } /* Enhanced Page Header */ .page-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 32px; padding-bottom: 24px; border-bottom: 2px solid #e5e7eb; } .page-header h1 { font-size: 32px; font-weight: 700; color: #111827; margin: 0 0 8px 0; } .page-subtitle { font-size: 16px; color: #6b7280; margin: 0; } .header-actions { display: flex; gap: 12px; } /* Enhanced Buttons */ .btn { padding: 10px 20px; border-radius: 8px; border: none; font-size: 14px; font-weight: 600; cursor: pointer; transition: all 0.2s; text-decoration: none; display: inline-flex; align-items: center; gap: 8px; } .btn-primary { background: linear-gradient(135deg, #059669, #047857); color: white; } .btn-primary:hover { background: linear-gradient(135deg, #047857, #047857); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(5,150,105,0.3); } .btn-secondary { background: #f3f4f6; color: #374151; } .btn-secondary:hover { background: #e5e7eb; } /* Statistics Cards - Member View */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin-bottom: 32px; } .stat-card { background: white; border-radius: 12px; padding: 24px; box-shadow: 0 4px 12px rgba(0,0,0,0.08); transition: transform 0.2s; } .stat-card:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0,0,0,0.12); } .stat-icon { width: 48px; height: 48px; background: #059669; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 24px; margin-bottom: 16px; } .stat-content h3 { font-size: 32px; font-weight: 700; color: #111827; margin: 0 0 8px 0; } .stat-content p { font-size: 14px; color: #6b7280; margin: 0 0 8px 0; } .stat-meta { font-size: 12px; color: #9ca3af; } /* Enhanced Tab Navigation */ .settings-container { display: grid; grid-template-columns: 240px 1fr; gap: 24px; margin-top: 24px; } .settings-nav { background: white; border-radius: 12px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); position: sticky; top: 24px; height: fit-content; } .settings-tabs { list-style: none; padding: 0; margin: 0; } .settings-tabs li { margin-bottom: 8px; } .tab-link { display: block; padding: 12px 16px; color: #6b7280; text-decoration: none; border-radius: 8px; font-weight: 500; transition: all 0.2s; } .tab-link:hover { background: #f3f4f6; color: #111827; } .tab-link.active { background: linear-gradient(135deg, #059669, #047857); color: white; } .settings-content { background: white; border-radius: 12px; padding: 32px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); } .tab-content { display: none; } .tab-content.active { display: block; } .settings-section { margin-bottom: 32px; } .settings-section h2 { font-size: 20px; font-weight: 700; color: #111827; margin-bottom: 20px; padding-bottom: 12px; border-bottom: 2px solid #e5e7eb; } /* Enhanced Form Styling */ .form-group { margin-bottom: 20px; } .form-group label { display: block; font-size: 14px; font-weight: 600; color: #374151; margin-bottom: 8px; } .form-group input, .form-group select, .form-group textarea { width: 100%; padding: 12px 16px; border: 2px solid #e5e7eb; border-radius: 8px; font-size: 14px; transition: all 0.2s; font-family: inherit; } .form-group input:focus, .form-group select:focus, .form-group textarea:focus { outline: none; border-color: #059669; box-shadow: 0 0 0 3px rgba(5,150,105,0.1); } .form-group input:disabled { background: #f9fafb; color: #9ca3af; cursor: not-allowed; } .form-help { display: block; font-size: 12px; color: #6b7280; margin-top: 6px; } .form-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; } .form-actions { margin-top: 32px; padding-top: 20px; border-top: 2px solid #e5e7eb; display: flex; gap: 12px; } /* Info Display Styling */ .info-item { margin-bottom: 20px; } .info-item label { display: block; font-size: 12px; font-weight: 600; color: #6b7280; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; } .info-item p { font-size: 16px; color: #111827; margin: 0; } /* Progress Bar */ .progress-container { display: flex; align-items: center; gap: 12px; } .progress-bar { flex: 1; height: 8px; background: #e5e7eb; border-radius: 4px; overflow: hidden; } .progress-fill { height: 100%; background: linear-gradient(to right, #059669, #047857); transition: width 0.3s ease; } .progress-text { font-size: 14px; font-weight: 600; color: #6b7280; min-width: 48px; } /* Transaction Item Styling */ .transactions-list { display: flex; flex-direction: column; gap: 16px; } .transaction-item { display: flex; align-items: center; gap: 16px; padding: 16px; border-radius: 12px; background: #f9fafb; border-left: 4px solid #e5e7eb; } .transaction-item.revenue { background: #ecfdf5; border-left-color: #059669; } .transaction-item.expense { background: #fef2f2; border-left-color: #dc2626; } .transaction-icon { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; font-size: 20px; border-radius: 50%; background: white; } .transaction-details { flex: 1; } .transaction-description { font-size: 14px; font-weight: 600; color: #111827; margin-bottom: 4px; } .transaction-meta { display: flex; gap: 12px; flex-wrap: wrap; } .transaction-date, .transaction-category { font-size: 12px; color: #6b7280; } .transaction-amount { font-size: 18px; font-weight: 700; } .transaction-amount.positive { color: #059669; } .transaction-amount.negative { color: #dc2626; } /* Ticket Item Styling */ .tickets-container { display: grid; gap: 16px; } .ticket-item { background: white; border: 2px solid #e5e7eb; border-radius: 12px; padding: 20px; transition: all 0.2s; } .ticket-item:hover { border-color: #059669; box-shadow: 0 4px 12px rgba(5,150,105,0.1); } .ticket-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .ticket-id { font-family: monospace; font-weight: 700; color: #6b7280; font-size: 14px; } .ticket-content h4 { font-size: 16px; font-weight: 600; color: #111827; margin: 0 0 12px 0; } .ticket-meta { display: flex; gap: 12px; align-items: center; } .priority-badge { padding: 4px 12px; border-radius: 12px; font-size: 11px; font-weight: 700; text-transform: uppercase; } .priority-low { background: #dbeafe; color: #1e40af; } .priority-medium { background: #fef3c7; color: #92400e; } .priority-high { background: #fee2e2; color: #991b1b; } .priority-critical { background: #047857; color: white; } .ticket-date { font-size: 12px; color: #6b7280; } /* Responsive Adjustments */ @media (max-width: 1024px) { .settings-container { grid-template-columns: 1fr; } .settings-nav { position: static; } .form-row { grid-template-columns: 1fr; } } @media (max-width: 768px) { .page-header { flex-direction: column; align-items: flex-start; gap: 16px; } .stats-grid { grid-template-columns: repeat(2, 1fr); } .transaction-item { flex-direction: column; align-items: flex-start; } } @media (max-width: 480px) { .stats-grid { grid-template-columns: 1fr; } .header-actions { width: 100%; flex-direction: column; } .btn { width: 100%; justify-content: center; } } /* Back Button Prevention - Add this JavaScript */ /* */ -------------------- END OF FILE -------------------- ### FILE 32: assets/css/responsive.css - Type: CSS - Size: 18.5 KB - Path: assets/css - Name: responsive.css ------------------------------------------------------------ /* Mobile First Responsive Design for Relevant Reflex */ /* Base Mobile Styles (up to 576px) */ @media (max-width: 576px) { :root { --font-size-base: 14px; --font-size-lg: 16px; --font-size-xl: 18px; --font-size-2xl: 20px; --font-size-3xl: 24px; --spacing-md: 0.75rem; --spacing-lg: 1rem; --spacing-xl: 1.5rem; } .nav-container { padding: 0 var(--spacing-md); height: 60px; } .brand-name { display: none; } .logo { width: 35px; height: 35px; font-size: var(--font-size-base); } .nav-menu { position: fixed; top: 60px; left: -100%; width: 100%; height: calc(100vh - 60px); background: var(--white); flex-direction: column; padding: var(--spacing-xl); gap: var(--spacing-md); transition: left var(--transition-normal); box-shadow: var(--shadow-xl); z-index: var(--z-modal); overflow-y: auto; } .nav-menu.active { left: 0; } .mobile-toggle { display: flex !important; } .nav-link { justify-content: flex-start; padding: var(--spacing-lg); border-radius: var(--border-radius-xl); font-size: var(--font-size-base); width: 100%; } .nav-link::before { display: none; } .nav-icon { font-size: var(--font-size-lg); } .page-container { padding: 0 var(--spacing-md); } .page-header { flex-direction: column; align-items: flex-start; gap: var(--spacing-md); margin-bottom: var(--spacing-xl); } .page-header h1 { font-size: var(--font-size-3xl); } .header-actions { width: 100%; justify-content: flex-start; flex-wrap: wrap; } .btn { font-size: var(--font-size-sm); padding: var(--spacing-md); min-height: 40px; } .btn-small { padding: var(--spacing-sm) var(--spacing-md); font-size: var(--font-size-xs); min-height: 32px; } .stats-grid { grid-template-columns: 1fr; gap: var(--spacing-md); } .stat-card { padding: var(--spacing-lg); flex-direction: row; gap: var(--spacing-md); } .stat-icon { width: 50px; height: 50px; font-size: 2rem; } .stat-content h3 { font-size: var(--font-size-xl); } .table-container { overflow-x: auto; border-radius: var(--border-radius-lg); } .data-table { min-width: 700px; } .data-table th, .data-table td { padding: var(--spacing-sm) var(--spacing-md); font-size: var(--font-size-xs); } .user-info, .item-info, .panel-info { gap: var(--spacing-sm); } .user-avatar { width: 32px; height: 32px; font-size: var(--font-size-xs); } .action-buttons { flex-direction: column; gap: 2px; } .btn-edit, .btn-delete, .btn-view, .btn-analytics, .btn-track, .btn-launch { min-width: 28px; height: 28px; padding: 2px; } .form-row { grid-template-columns: 1fr; gap: var(--spacing-md); } .table-controls { flex-direction: column; align-items: stretch; gap: var(--spacing-md); } .filter-container { flex-direction: column; gap: var(--spacing-sm); } .search-container { max-width: none; } .modal { padding: var(--spacing-md); } .modal-content { max-height: 95vh; } .modal-form, .settings-form, .support-form { padding: var(--spacing-lg); } } /* Mobile Landscape and Small Tablets (577px - 768px) */ @media (min-width: 577px) and (max-width: 768px) { .nav-menu { position: fixed; top: 70px; left: -100%; width: 100%; height: calc(100vh - 70px); background: var(--white); flex-direction: column; padding: var(--spacing-xl); gap: var(--spacing-md); transition: left var(--transition-normal); box-shadow: var(--shadow-xl); z-index: var(--z-modal); } .nav-menu.active { left: 0; } .mobile-toggle { display: flex; } .nav-link { justify-content: flex-start; padding: var(--spacing-lg); border-radius: var(--border-radius-xl); width: 100%; } .stats-grid { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-lg); } .page-header { flex-direction: column; align-items: flex-start; gap: var(--spacing-md); } .form-row { grid-template-columns: 1fr; gap: var(--spacing-md); } .table-controls { flex-direction: row; flex-wrap: wrap; } .filter-container { flex-direction: row; gap: var(--spacing-md); } } /* Tablets (769px - 992px) */ @media (min-width: 769px) and (max-width: 992px) { .nav-container { padding: 0 var(--spacing-lg); } .page-container { padding: 0 var(--spacing-lg); } .stats-grid { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-lg); } .content-grid { grid-template-columns: 1fr; gap: var(--spacing-xl); } .dashboard-content .content-grid { grid-template-columns: 2fr 1fr; } .footer-grid { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-xl); } .nav-link { padding: var(--spacing-md); font-size: var(--font-size-sm); } .nav-icon { font-size: var(--font-size-sm); } .nav-label { font-size: var(--font-size-sm); } } /* Desktop (993px - 1199px) */ @media (min-width: 993px) and (max-width: 1199px) { .nav-container, .page-container, .footer-container { max-width: 960px; } .stats-grid { grid-template-columns: repeat(4, 1fr); } .content-grid { grid-template-columns: 2fr 1fr; } .footer-grid { grid-template-columns: repeat(4, 1fr); } } /* Large Desktop (1200px and up) */ @media (min-width: 1200px) { .nav-container, .page-container, .footer-container { max-width: 1200px; } .stats-grid { grid-template-columns: repeat(4, 1fr); } .content-grid { grid-template-columns: 2fr 1fr; gap: var(--spacing-2xl); } } /* Extra Large Screens (1400px and up) */ @media (min-width: 1400px) { .nav-container, .page-container, .footer-container { max-width: 1400px; } :root { --spacing-md: 1.25rem; --spacing-lg: 2rem; --spacing-xl: 2.5rem; --spacing-2xl: 3.5rem; } } /* Settings Page Responsive */ .settings-container { display: grid; grid-template-columns: 250px 1fr; gap: var(--spacing-2xl); margin-top: var(--spacing-xl); } .settings-nav { background: var(--white); border-radius: var(--border-radius-xl); padding: var(--spacing-lg); box-shadow: var(--shadow-sm); height: fit-content; position: sticky; top: calc(70px + var(--spacing-lg)); } .settings-tabs { list-style: none; display: flex; flex-direction: column; gap: var(--spacing-sm); } .tab-link { display: block; padding: var(--spacing-md); text-decoration: none; color: var(--gray-600); border-radius: var(--border-radius-lg); transition: all var(--transition-normal); font-weight: var(--font-weight-medium); } .tab-link:hover { background: var(--primary-light); color: var(--primary-color); } .tab-link.active { background: var(--primary-color); color: var(--white); } .settings-content { background: var(--white); border-radius: var(--border-radius-xl); box-shadow: var(--shadow-sm); } .tab-content { display: none; padding: var(--spacing-2xl); } .tab-content.active { display: block; } @media (max-width: 768px) { .settings-container { grid-template-columns: 1fr; gap: var(--spacing-lg); } .settings-nav { position: static; order: -1; } .settings-tabs { flex-direction: row; overflow-x: auto; gap: var(--spacing-xs); padding-bottom: var(--spacing-sm); } .tab-link { white-space: nowrap; padding: var(--spacing-sm) var(--spacing-md); font-size: var(--font-size-sm); } } /* Dashboard Responsive Specific */ .dashboard-container { max-width: 1200px; margin: 0 auto; padding: 0 var(--spacing-md); } @media (max-width: 768px) { .dashboard-container { padding: 0 var(--spacing-md); } .content-grid { grid-template-columns: 1fr; gap: var(--spacing-lg); } .quick-actions-grid { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-md); } } @media (max-width: 480px) { .quick-actions-grid { grid-template-columns: 1fr; } } /* Table Responsive Behavior */ @media (max-width: 768px) { .table-container { border-radius: var(--border-radius-lg); } .data-table th:first-child, .data-table td:first-child { position: sticky; left: 0; background: var(--white); z-index: 10; } .data-table th { background: var(--gray-50); } .data-table tbody tr:hover th:first-child, .data-table tbody tr:hover td:first-child { background: var(--gray-50); } } /* Modal Responsive */ @media (max-width: 768px) { .modal { padding: var(--spacing-md); align-items: flex-start; padding-top: 10vh; } .modal-content { max-height: 85vh; width: 100%; margin: 0; } .modal-header { padding: var(--spacing-lg); } .modal-form, .settings-form, .support-form { padding: var(--spacing-lg); } .modal-large { max-width: none; } } /* Form Responsive */ @media (max-width: 576px) { .form-row { grid-template-columns: 1fr; gap: var(--spacing-md); } .form-actions { flex-direction: column; gap: var(--spacing-md); } .form-actions .btn { width: 100%; justify-content: center; } .table-controls { flex-direction: column; align-items: stretch; } .filter-container { flex-direction: column; gap: var(--spacing-sm); } .search-input, .filter-select { width: 100%; } } /* Stats Grid Responsive */ @media (max-width: 1200px) { .stats-grid { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 768px) { .stats-grid { grid-template-columns: 1fr; } } /* Footer Responsive */ @media (max-width: 992px) { .footer-grid { grid-template-columns: repeat(2, 1fr); gap: var(--spacing-xl); } } @media (max-width: 576px) { .footer-container { padding: var(--spacing-xl) var(--spacing-md) var(--spacing-md); } .footer-grid { grid-template-columns: 1fr; gap: var(--spacing-lg); } .footer-bottom { flex-direction: column; text-align: center; gap: var(--spacing-md); } .legal-links { flex-direction: column; align-items: center; gap: var(--spacing-sm); } .social-links { justify-content: center; } } /* Chart Responsive */ @media (max-width: 768px) { .chart-container canvas { max-width: 100%; height: auto; } .chart-section { padding: var(--spacing-md); } } /* Touch Device Optimizations */ @media (hover: none) and (pointer: coarse) { .btn { min-height: 44px; /* Apple's recommended minimum */ padding: var(--spacing-md) var(--spacing-lg); } .btn-edit, .btn-delete, .btn-view, .btn-analytics { min-width: 44px; min-height: 44px; padding: var(--spacing-md); } .nav-link { min-height: 44px; padding: var(--spacing-md) var(--spacing-lg); } .mobile-toggle { min-width: 44px; min-height: 44px; } /* Remove hover effects on touch devices */ .stat-card:hover { transform: none; box-shadow: var(--shadow-sm); } .btn-primary:hover { transform: none; } } /* High DPI Displays */ @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { .logo { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } } /* Landscape Phone Orientation */ @media (max-height: 500px) and (orientation: landscape) { .nav-menu { height: calc(100vh - 70px); padding: var(--spacing-lg); } .modal { padding-top: 2vh; } .page-header { margin-bottom: var(--spacing-lg); } main { padding: var(--spacing-lg) 0; } } /* Print Optimizations */ @media print { .main-header, .main-footer, .btn, .mobile-toggle, .action-buttons, .search-input, .filter-select, .modal { display: none !important; } .page-container { max-width: none; padding: 0; margin: 0; } .stats-grid { grid-template-columns: repeat(4, 1fr); gap: var(--spacing-md); break-inside: avoid; } .stat-card { border: 1px solid var(--gray-300); box-shadow: none; break-inside: avoid; } .table-container { border: 1px solid var(--gray-300); box-shadow: none; } .data-table th { background: var(--gray-100) !important; color: var(--dark-color) !important; } body { font-size: 11pt; line-height: 1.4; color: black !important; background: white !important; } h1, h2, h3, h4 { color: black !important; } .page-header h1 { font-size: 18pt; margin-bottom: 12pt; } } /* High Contrast Mode Support */ @media (prefers-contrast: high) { :root { --primary-color: #047857; --secondary-color: #495057; --gray-300: #999999; --gray-600: #333333; } .nav-link { border: 1px solid transparent; } .nav-link.active { border-color: var(--white); } .btn { border: 2px solid currentColor; } .stat-card { border: 1px solid var(--gray-300); } } /* Reduced Motion Support */ @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } .modal-content { animation: none; } } /* Dark Mode Support */ @media (prefers-color-scheme: dark) { :root { --white: #1a1d20; --light-color: #212529; --gray-50: #2d3436; --gray-100: #495057; --gray-200: #6c757d; --gray-300: #adb5bd; --gray-400: #ced4da; --gray-500: #dee2e6; --gray-600: #e9ecef; --gray-700: #f1f3f4; --gray-800: #f8f9fa; --dark-color: #ffffff; --primary-light: rgba(5, 150, 105, 0.1); } body { background-color: #0d1117; color: var(--dark-color); } .main-header { background: #161b22; border-bottom: 1px solid var(--gray-700); } .nav-link:hover { background: rgba(5, 150, 105, 0.1); } .table-container, .stat-card, .modal-content, .settings-content { background: #161b22; border: 1px solid var(--gray-700); } .data-table th { background: var(--gray-800); } .search-input, .filter-select, input, textarea, select { background: #0d1117; border-color: var(--gray-700); color: var(--dark-color); } .search-input:focus, input:focus, textarea:focus, select:focus { border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(5, 150, 105, 0.1); } } /* Pagination Responsive */ .pagination-container { display: flex; justify-content: space-between; align-items: center; margin-top: var(--spacing-lg); padding: var(--spacing-lg); background: var(--white); border-radius: var(--border-radius-lg); box-shadow: var(--shadow-sm); } .pagination-controls { display: flex; gap: var(--spacing-sm); align-items: center; } .page-number { padding: var(--spacing-sm) var(--spacing-md); border-radius: var(--border-radius); background: var(--gray-100); color: var(--gray-700); font-weight: var(--font-weight-medium); } .page-number.active { background: var(--primary-color); color: var(--white); } @media (max-width: 576px) { .pagination-container { flex-direction: column; gap: var(--spacing-md); text-align: center; } .pagination-info { order: 2; font-size: var(--font-size-sm); } .pagination-controls { order: 1; } } /* Loading States Responsive */ @media (max-width: 576px) { .loading::after { animation-duration: 2s; } } /* Support Page Responsive */ .support-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-2xl); margin-bottom: var(--spacing-2xl); } @media (max-width: 992px) { .support-grid { grid-template-columns: 1fr; gap: var(--spacing-xl); } } .help-resources { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-lg); } @media (max-width: 576px) { .help-resources { grid-template-columns: 1fr; } } /* Finance Page Responsive */ .finance-overview { margin-bottom: var(--spacing-2xl); } .finance-content .content-grid { display: grid; grid-template-columns: 2fr 1fr; gap: var(--spacing-2xl); } @media (max-width: 992px) { .finance-content .content-grid { grid-template-columns: 1fr; gap: var(--spacing-xl); } } -------------------- END OF FILE -------------------- ### FILE 33: assets/images/logo.svg - Type: SVG - Size: 0 B - Path: assets/images - Name: logo.svg ------------------------------------------------------------ [IMAGE FILE: SVG - Content not displayed] -------------------- END OF FILE -------------------- ### FILE 34: assets/js/dashboard.js - Type: JS - Size: 26.44 KB - Path: assets/js - Name: dashboard.js ------------------------------------------------------------ // Dashboard specific functionality for Relevant Reflex (function() { 'use strict'; // Dashboard module window.RR = window.RR || {}; RR.dashboard = { charts: {}, updateInterval: null, refreshRate: 30000, // 30 seconds init: function() { this.initializeCharts(); this.setupQuickActions(); this.setupRealTimeUpdates(); this.setupInteractions(); this.loadDashboardData(); }, initializeCharts: function() { // Performance Chart const performanceCanvas = document.getElementById('performanceChart'); if (performanceCanvas) { this.charts.performance = this.createPerformanceChart(performanceCanvas); } // Revenue Chart (for finance page) const revenueCanvas = document.getElementById('revenueChart'); if (revenueCanvas) { this.charts.revenue = this.createRevenueChart(revenueCanvas); } // Demand Chart (for demand page) const demandCanvas = document.getElementById('demandChart'); if (demandCanvas) { this.charts.demand = this.createDemandChart(demandCanvas); } // Setup chart period controls this.setupChartControls(); }, createPerformanceChart: function(canvas) { const ctx = canvas.getContext('2d'); // Sample performance data - replace with real API data const data = { labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5', 'Week 6'], datasets: [{ label: 'Panel Responses', data: [320, 450, 380, 520, 430, 580], borderColor: getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(), backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim() + '20', borderWidth: 3, tension: 0.4, fill: true }, { label: 'Active Users', data: [280, 390, 420, 480, 510, 540], borderColor: getComputedStyle(document.documentElement).getPropertyValue('--success-color').trim(), backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--success-color').trim() + '20', borderWidth: 3, tension: 0.4, fill: true }] }; return this.drawChart(ctx, canvas, data, 'line'); }, createRevenueChart: function(canvas) { const ctx = canvas.getContext('2d'); // Sample revenue data for last 12 months const data = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], datasets: [{ label: 'Revenue', data: [28500, 31200, 29800, 33500, 35200, 38900, 42100, 39800, 43500, 45230, 41800, 44600], backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(), borderColor: getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(), borderWidth: 1 }] }; return this.drawChart(ctx, canvas, data, 'bar'); }, createDemandChart: function(canvas) { const ctx = canvas.getContext('2d'); // Sample demand trend data const currentData = [6.2, 6.8, 7.1, 7.5, 8.2, 8.0, 8.5, 8.7, 9.1, 8.9, 8.7, 9.2]; const forecastData = [9.0, 9.2, 9.5, 9.7, 9.9, 10.2]; const data = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan+', 'Feb+', 'Mar+', 'Apr+', 'May+', 'Jun+'], datasets: [{ label: 'Current Demand', data: [...currentData, ...Array(6).fill(null)], borderColor: getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim(), backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--primary-color').trim() + '30', borderWidth: 3, tension: 0.4, fill: false }, { label: 'Forecast', data: [...Array(11).fill(null), currentData[11], ...forecastData], borderColor: getComputedStyle(document.documentElement).getPropertyValue('--success-color').trim(), backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--success-color').trim() + '30', borderWidth: 2, borderDash: [5, 5], tension: 0.4, fill: false }] }; return this.drawChart(ctx, canvas, data, 'line'); }, drawChart: function(ctx, canvas, data, type) { // Simple chart implementation (replace with Chart.js for production) const chart = { data: data, type: type, canvas: canvas, ctx: ctx }; this.renderChart(chart); return chart; }, renderChart: function(chart) { const { ctx, canvas, data, type } = chart; const padding = 40; const chartWidth = canvas.width - 2 * padding; const chartHeight = canvas.height - 2 * padding; // Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height); if (type === 'line') { this.renderLineChart(ctx, canvas, data, padding, chartWidth, chartHeight); } else if (type === 'bar') { this.renderBarChart(ctx, canvas, data, padding, chartWidth, chartHeight); } }, renderLineChart: function(ctx, canvas, data, padding, chartWidth, chartHeight) { const datasets = data.datasets; const labels = data.labels; // Find max and min values const allValues = datasets.flatMap(d => d.data.filter(v => v !== null)); const maxValue = Math.max(...allValues); const minValue = Math.min(...allValues); const range = maxValue - minValue || 1; // Draw axes ctx.strokeStyle = '#e9ecef'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(padding, padding); ctx.lineTo(padding, canvas.height - padding); ctx.lineTo(canvas.width - padding, canvas.height - padding); ctx.stroke(); // Draw grid lines ctx.strokeStyle = '#f1f3f4'; ctx.lineWidth = 1; for (let i = 1; i < 5; i++) { const y = padding + (i / 5) * chartHeight; ctx.beginPath(); ctx.moveTo(padding, y); ctx.lineTo(canvas.width - padding, y); ctx.stroke(); } // Draw labels ctx.fillStyle = '#666'; ctx.font = '12px Arial'; ctx.textAlign = 'center'; labels.forEach((label, index) => { const x = padding + (index / (labels.length - 1)) * chartWidth; ctx.fillText(label, x, canvas.height - padding + 20); }); // Draw datasets datasets.forEach(dataset => { ctx.strokeStyle = dataset.borderColor; ctx.lineWidth = dataset.borderWidth || 2; if (dataset.borderDash) { ctx.setLineDash(dataset.borderDash); } else { ctx.setLineDash([]); } ctx.beginPath(); let firstPoint = true; dataset.data.forEach((value, index) => { if (value !== null) { const x = padding + (index / (labels.length - 1)) * chartWidth; const y = canvas.height - padding - ((value - minValue) / range) * chartHeight; if (firstPoint) { ctx.moveTo(x, y); firstPoint = false; } else { ctx.lineTo(x, y); } // Draw data points ctx.save(); ctx.fillStyle = dataset.borderColor; ctx.beginPath(); ctx.arc(x, y, 3, 0, 2 * Math.PI); ctx.fill(); ctx.restore(); } }); ctx.stroke(); }); }, renderBarChart: function(ctx, canvas, data, padding, chartWidth, chartHeight) { const dataset = data.datasets[0]; const labels = data.labels; const values = dataset.data; const maxValue = Math.max(...values); const barWidth = chartWidth / values.length * 0.8; // Draw axes ctx.strokeStyle = '#e9ecef'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(padding, padding); ctx.lineTo(padding, canvas.height - padding); ctx.lineTo(canvas.width - padding, canvas.height - padding); ctx.stroke(); // Draw bars ctx.fillStyle = dataset.backgroundColor; values.forEach((value, index) => { const barHeight = (value / maxValue) * chartHeight; const x = padding + (index / values.length) * chartWidth + (chartWidth / values.length - barWidth) / 2; const y = canvas.height - padding - barHeight; ctx.fillRect(x, y, barWidth, barHeight); // Draw value labels ctx.fillStyle = '#666'; ctx.font = '12px Arial'; ctx.textAlign = 'center'; ctx.fillText('$' + (value / 1000).toFixed(0) + 'k', x + barWidth / 2, y - 5); // Draw month labels ctx.fillText(labels[index], x + barWidth / 2, canvas.height - padding + 15); ctx.fillStyle = dataset.backgroundColor; }); }, setupChartControls: function() { // Chart period selectors const periodSelects = document.querySelectorAll('#chartPeriod, #trendPeriod, #revenuePeriod'); periodSelects.forEach(select => { select.addEventListener('change', function() { const chartId = this.id.replace('Period', 'Chart'); RR.dashboard.updateChartPeriod(chartId, this.value); }); }); }, updateChartPeriod: function(chartId, period) { const chart = this.charts[chartId.replace('Chart', '')]; if (!chart) return; // Update chart data based on period // This would typically fetch new data from API console.log(`Updating ${chartId} for period: ${period}`); // Show loading state const canvas = chart.canvas; const ctx = chart.ctx; ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = '#666'; ctx.font = '16px Arial'; ctx.textAlign = 'center'; ctx.fillText('Loading...', canvas.width / 2, canvas.height / 2); // Simulate API call setTimeout(() => { this.renderChart(chart); RR.toast.show('Chart updated successfully', 'success'); }, 800); }, setupQuickActions: function() { // Quick action buttons const quickActions = { createPanel: () => { window.location.href = 'panel.php?action=create'; }, manageUsers: () => { window.location.href = 'users.php'; }, viewReports: () => { window.location.href = 'finance.php?tab=reports'; }, systemSettings: () => { window.location.href = 'settings.php'; } }; // Expose to global scope window.quickActions = quickActions; // Setup quick action cards document.querySelectorAll('.quick-action-card').forEach(card => { card.addEventListener('click', function() { const action = this.getAttribute('data-action'); if (action && quickActions[action]) { quickActions[action](); } }); }); // Setup header action buttons document.getElementById('addUserBtn')?.addEventListener('click', function() { RR.modals.open('addUserModal'); }); document.getElementById('createPanelBtn')?.addEventListener('click', function() { RR.modals.open('createPanelModal'); }); document.getElementById('addSupplyBtn')?.addEventListener('click', function() { RR.modals.open('addSupplyModal'); }); document.getElementById('addTransactionBtn')?.addEventListener('click', function() { RR.modals.open('addTransactionModal'); }); }, setupRealTimeUpdates: function() { // Auto-refresh dashboard data this.updateInterval = setInterval(() => { this.updateRealTimeData(); }, this.refreshRate); // Pause updates when page is not visible document.addEventListener('visibilitychange', () => { if (document.hidden) { clearInterval(this.updateInterval); } else { this.updateInterval = setInterval(() => { this.updateRealTimeData(); }, this.refreshRate); } }); }, updateRealTimeData: function() { // Update stat cards with simulated real-time data const statCards = document.querySelectorAll('.stat-card'); statCards.forEach(card => { const valueElement = card.querySelector('h3'); if (!valueElement) return; const currentText = valueElement.textContent; // Update revenue values if (currentText.includes('$')) { const currentValue = parseInt(currentText.replace(/[^0-9]/g, '')); const variation = Math.floor(Math.random() * 200) - 100; // -100 to +100 const newValue = Math.max(0, currentValue + variation); valueElement.textContent = '$' + RR.utils.formatNumber(newValue); // Add pulse animation card.style.transform = 'scale(1.02)'; setTimeout(() => { card.style.transform = ''; }, 200); } // Update numeric values else if (/^\d+$/.test(currentText)) { const currentValue = parseInt(currentText); const variation = Math.floor(Math.random() * 6) - 3; // -3 to +3 const newValue = Math.max(0, currentValue + variation); valueElement.textContent = newValue.toString(); // Add subtle highlight card.classList.add('updated'); setTimeout(() => { card.classList.remove('updated'); }, 1000); } }); // Update charts Object.keys(this.charts).forEach(chartKey => { if (Math.random() > 0.7) { // 30% chance to update each chart this.updateChartData(this.charts[chartKey]); } }); }, updateChartData: function(chart) { if (!chart || !chart.data) return; // Add new data point and remove oldest chart.data.datasets.forEach(dataset => { if (dataset.data.length > 0) { // Generate new data point based on last value const lastValue = dataset.data[dataset.data.length - 1]; const variation = (Math.random() - 0.5) * (lastValue * 0.1); const newValue = Math.max(0, lastValue + variation); dataset.data.push(Math.round(newValue)); // Remove oldest point if we have too many if (dataset.data.length > 12) { dataset.data.shift(); } } }); this.renderChart(chart); }, setupInteractions: function() { // Activity item interactions document.querySelectorAll('.activity-item').forEach(item => { item.addEventListener('click', function() { this.classList.toggle('expanded'); }); }); // Stat card interactions document.querySelectorAll('.stat-card').forEach(card => { card.addEventListener('click', function() { const cardType = this.querySelector('p').textContent.toLowerCase(); RR.dashboard.navigateToDetails(cardType); }); }); // Export functionality document.querySelectorAll('[id$="ExportBtn"], [id$="exportBtn"]').forEach(btn => { btn.addEventListener('click', function() { RR.dashboard.exportData(this.id); }); }); // Generate report functionality document.getElementById('generateReportBtn')?.addEventListener('click', function() { RR.dashboard.generateReport(); }); }, navigateToDetails: function(cardType) { const navigationMap = { 'total users': 'users.php', 'active panels': 'panel.php', 'pending supplies': 'supply.php', 'monthly revenue': 'finance.php', 'total revenue': 'finance.php', 'net profit': 'finance.php' }; const url = navigationMap[cardType]; if (url) { window.location.href = url; } }, exportData: function(buttonId) { const button = document.getElementById(buttonId); if (!button) return; // Show loading state const originalText = button.textContent; button.textContent = 'Exporting...'; button.disabled = true; // Simulate export process setTimeout(() => { // Reset button button.textContent = originalText; button.disabled = false; // Show success message RR.toast.show('Data exported successfully!', 'success'); // Simulate file download const link = document.createElement('a'); link.href = 'data:text/csv;charset=utf-8,Sample Export Data\nColumn1,Column2,Column3\nValue1,Value2,Value3'; link.download = `export-${new Date().toISOString().split('T')[0]}.csv`; document.body.appendChild(link); link.click(); document.body.removeChild(link); }, 2000); }, generateReport: function() { const button = document.getElementById('generateReportBtn'); if (!button) return; // Show loading state button.innerHTML = ' Generating...'; button.disabled = true; // Simulate report generation setTimeout(() => { // Reset button button.innerHTML = '📊 Generate Report'; button.disabled = false; // Show success and open modal with report preview RR.toast.show('Report generated successfully!', 'success'); // Create and show report preview modal RR.dashboard.showReportPreview(); }, 3000); }, showReportPreview: function() { const modal = document.createElement('div'); modal.className = 'modal'; modal.id = 'reportPreviewModal'; modal.innerHTML = ` `; document.body.appendChild(modal); RR.modals.open('reportPreviewModal'); }, loadDashboardData: function() { // Load initial dashboard data console.log('Loading dashboard data...'); // This would typically make API calls to load real data // For now, we'll simulate data loading with a timeout setTimeout(() => { console.log('Dashboard data loaded successfully'); }, 1000); }, // Keyboard shortcuts setupKeyboardShortcuts: function() { document.addEventListener('keydown', function(e) { // Only trigger shortcuts if not typing in input fields if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') { return; } if (e.ctrlKey || e.metaKey) { switch(e.key) { case '1': e.preventDefault(); window.location.href = 'users.php'; break; case '2': e.preventDefault(); window.location.href = 'panel.php'; break; case '3': e.preventDefault(); window.location.href = 'supply.php'; break; case '4': e.preventDefault(); window.location.href = 'demand.php'; break; case '5': e.preventDefault(); window.location.href = 'finance.php'; break; case 'h': e.preventDefault(); window.location.href = 'index.php'; break; } } }); }, // Cleanup function destroy: function() { if (this.updateInterval) { clearInterval(this.updateInterval); } } }; // Initialize dashboard when DOM is ready document.addEventListener('DOMContentLoaded', function() { // Only initialize on dashboard-related pages const isDashboardPage = document.querySelector('.dashboard-container, .stats-grid, .chart-section'); if (isDashboardPage) { RR.dashboard.init(); RR.dashboard.setupKeyboardShortcuts(); } }); // Initialize dashboard function for other pages to call window.initDashboard = function() { if (RR.dashboard) { RR.dashboard.init(); } }; // Cleanup on page unload window.addEventListener('beforeunload', function() { if (RR.dashboard) { RR.dashboard.destroy(); } }); // Add CSS for updated state const style = document.createElement('style'); style.textContent = ` .stat-card.updated { background: linear-gradient(135deg, var(--primary-light) 0%, rgba(5, 150, 105, 0.05) 100%); border-color: var(--primary-color); transform: translateY(-1px); } .report-preview h3 { color: var(--primary-color); margin-bottom: var(--spacing-lg); } .report-preview h4 { color: var(--gray-700); margin: var(--spacing-lg) 0 var(--spacing-md); } .report-preview ul { list-style: none; padding-left: 0; } .report-preview li { padding: var(--spacing-sm) 0; border-bottom: 1px solid var(--gray-200); } .report-preview li:last-child { border-bottom: none; } `; document.head.appendChild(style); })(); -------------------- END OF FILE -------------------- ### FILE 35: assets/js/main.js - Type: JS - Size: 33.12 KB - Path: assets/js - Name: main.js ------------------------------------------------------------ // Relevant Reflex - Main JavaScript (function() { 'use strict'; // Global app object window.RR = window.RR || {}; // App configuration RR.config = { version: '1.0.0', apiUrl: '/api/', debounceDelay: 300, toastDuration: 3000, animationDuration: 300 }; // Initialize app when DOM is ready document.addEventListener('DOMContentLoaded', function() { RR.init(); }); // Main initialization RR.init = function() { console.log(`Relevant Reflex Panel Management System v${RR.config.version} initialized`); // Initialize core modules RR.navigation.init(); RR.forms.init(); RR.tables.init(); RR.modals.init(); RR.tooltips.init(); RR.lazyLoad.init(); RR.performance.init(); // Initialize page-specific modules if (typeof window.initDashboard === 'function') { window.initDashboard(); } }; // Navigation Module RR.navigation = { init: function() { this.setupMobileToggle(); this.setupSmoothScrolling(); this.setupActiveLinks(); }, setupMobileToggle: function() { const mobileToggle = document.querySelector('.mobile-toggle'); const navMenu = document.querySelector('.nav-menu'); if (!mobileToggle || !navMenu) return; // Toggle mobile menu mobileToggle.addEventListener('click', function(e) { e.preventDefault(); const isActive = mobileToggle.classList.contains('active'); if (isActive) { RR.navigation.closeMobileMenu(); } else { RR.navigation.openMobileMenu(); } }); // Close menu when clicking nav links navMenu.querySelectorAll('.nav-link').forEach(link => { link.addEventListener('click', function() { RR.navigation.closeMobileMenu(); }); }); // Close menu when clicking outside document.addEventListener('click', function(e) { const isClickInsideNav = navMenu.contains(e.target) || mobileToggle.contains(e.target); if (!isClickInsideNav && mobileToggle.classList.contains('active')) { RR.navigation.closeMobileMenu(); } }); // Close menu on escape key document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && mobileToggle.classList.contains('active')) { RR.navigation.closeMobileMenu(); } }); }, openMobileMenu: function() { const mobileToggle = document.querySelector('.mobile-toggle'); const navMenu = document.querySelector('.nav-menu'); mobileToggle.classList.add('active'); navMenu.classList.add('active'); mobileToggle.setAttribute('aria-expanded', 'true'); // Prevent body scroll document.body.style.overflow = 'hidden'; }, closeMobileMenu: function() { const mobileToggle = document.querySelector('.mobile-toggle'); const navMenu = document.querySelector('.nav-menu'); mobileToggle.classList.remove('active'); navMenu.classList.remove('active'); mobileToggle.setAttribute('aria-expanded', 'false'); // Restore body scroll document.body.style.overflow = ''; }, setupSmoothScrolling: function() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { const href = this.getAttribute('href'); if (href === '#') { e.preventDefault(); return; } const target = document.querySelector(href); if (target) { e.preventDefault(); const headerHeight = document.querySelector('.main-header')?.offsetHeight || 0; const targetPosition = target.offsetTop - headerHeight - 20; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } }); }); }, setupActiveLinks: function() { const currentPage = window.location.pathname; const navLinks = document.querySelectorAll('.nav-link'); navLinks.forEach(link => { const linkPath = new URL(link.href).pathname; if (linkPath === currentPage) { link.classList.add('active'); } else { link.classList.remove('active'); } }); } }; // Forms Module RR.forms = { init: function() { this.setupValidation(); this.setupFileUploads(); this.setupFormSubmissions(); this.setupRealTimeValidation(); }, setupValidation: function() { const forms = document.querySelectorAll('form[data-validate]'); forms.forEach(form => { form.addEventListener('submit', function(e) { if (!RR.forms.validateForm(this)) { e.preventDefault(); } }); }); }, validateForm: function(form) { const requiredFields = form.querySelectorAll('[required]'); let isValid = true; // Clear previous errors form.querySelectorAll('.error').forEach(el => el.classList.remove('error')); form.querySelectorAll('.error-message').forEach(el => el.remove()); requiredFields.forEach(field => { if (!this.validateField(field)) { isValid = false; } }); // Email validation const emailFields = form.querySelectorAll('input[type="email"]'); emailFields.forEach(field => { if (field.value && !this.isValidEmail(field.value)) { this.showFieldError(field, 'Please enter a valid email address'); isValid = false; } }); // Password confirmation const passwordField = form.querySelector('input[name="password"]'); const confirmField = form.querySelector('input[name="confirm_password"]'); if (passwordField && confirmField && passwordField.value !== confirmField.value) { this.showFieldError(confirmField, 'Passwords do not match'); isValid = false; } return isValid; }, validateField: function(field) { const value = field.value.trim(); if (!value) { this.showFieldError(field, 'This field is required'); return false; } // Minimum length validation const minLength = field.getAttribute('minlength'); if (minLength && value.length < parseInt(minLength)) { this.showFieldError(field, `Minimum ${minLength} characters required`); return false; } field.classList.remove('error'); return true; }, showFieldError: function(field, message) { field.classList.add('error'); // Remove existing error message const existingError = field.parentNode.querySelector('.error-message'); if (existingError) { existingError.remove(); } // Add new error message const errorEl = document.createElement('small'); errorEl.className = 'error-message'; errorEl.textContent = message; errorEl.style.color = 'var(--danger-color)'; errorEl.style.display = 'block'; errorEl.style.marginTop = 'var(--spacing-xs)'; field.parentNode.insertBefore(errorEl, field.nextSibling); }, isValidEmail: function(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); }, setupFileUploads: function() { const fileInputs = document.querySelectorAll('input[type="file"]'); fileInputs.forEach(input => { input.addEventListener('change', function() { const file = this.files[0]; if (file) { // Validate file size (5MB limit) if (file.size > 5 * 1024 * 1024) { RR.toast.show('File size must be less than 5MB', 'error'); this.value = ''; return; } // Show file name const label = this.nextElementSibling; if (label) { label.textContent = file.name; } } }); }); }, setupFormSubmissions: function() { const submitButtons = document.querySelectorAll('.btn[type="submit"], .btn-primary'); submitButtons.forEach(btn => { btn.addEventListener('click', function(e) { const form = this.closest('form'); if (form && this.type === 'submit') { RR.forms.addLoadingState(this); // Remove loading state after form submission setTimeout(() => { RR.forms.removeLoadingState(this); }, 2000); } }); }); }, setupRealTimeValidation: function() { const inputs = document.querySelectorAll('input[required], textarea[required]'); inputs.forEach(input => { input.addEventListener('blur', function() { if (this.value.trim()) { RR.forms.validateField(this); } }); input.addEventListener('input', function() { if (this.classList.contains('error') && this.value.trim()) { RR.forms.validateField(this); } }); }); }, addLoadingState: function(button) { if (button.classList.contains('loading')) return; const originalText = button.textContent; button.setAttribute('data-original-text', originalText); button.textContent = 'Loading...'; button.disabled = true; button.classList.add('loading'); }, removeLoadingState: function(button) { const originalText = button.getAttribute('data-original-text'); if (originalText) { button.textContent = originalText; button.removeAttribute('data-original-text'); } button.disabled = false; button.classList.remove('loading'); } }; // Tables Module RR.tables = { init: function() { this.setupSearch(); this.setupSorting(); this.setupActions(); this.setupFilters(); }, setupSearch: function() { const searchInputs = document.querySelectorAll('.search-input'); searchInputs.forEach(input => { let timeout; input.addEventListener('input', function() { clearTimeout(timeout); timeout = setTimeout(() => { const query = this.value.toLowerCase().trim(); RR.tables.filterTable(query); }, RR.config.debounceDelay); }); }); }, filterTable: function(query) { const table = document.querySelector('.data-table'); if (!table) return; const rows = table.querySelectorAll('tbody tr'); let visibleCount = 0; rows.forEach(row => { const text = row.textContent.toLowerCase(); const shouldShow = !query || text.includes(query); row.style.display = shouldShow ? '' : 'none'; if (shouldShow) visibleCount++; }); // Update pagination info if exists const paginationInfo = document.querySelector('.pagination-info'); if (paginationInfo && query) { paginationInfo.textContent = `Showing ${visibleCount} of ${rows.length} results`; } }, setupSorting: function() { const headers = document.querySelectorAll('.data-table th[data-sort]'); headers.forEach(header => { header.style.cursor = 'pointer'; header.addEventListener('click', function() { const sortKey = this.getAttribute('data-sort'); const isAscending = !this.classList.contains('sort-asc'); // Remove sort classes from all headers headers.forEach(h => h.classList.remove('sort-asc', 'sort-desc')); // Add sort class to current header this.classList.add(isAscending ? 'sort-asc' : 'sort-desc'); RR.tables.sortTable(sortKey, isAscending); }); }); }, sortTable: function(sortKey, ascending) { const table = document.querySelector('.data-table tbody'); if (!table) return; const rows = Array.from(table.querySelectorAll('tr')); const sortIndex = Array.from(table.parentNode.querySelectorAll('th')).findIndex(th => th.getAttribute('data-sort') === sortKey ); if (sortIndex === -1) return; rows.sort((a, b) => { const aText = a.cells[sortIndex]?.textContent.trim() || ''; const bText = b.cells[sortIndex]?.textContent.trim() || ''; // Try numeric sort first const aNum = parseFloat(aText.replace(/[^0-9.-]/g, '')); const bNum = parseFloat(bText.replace(/[^0-9.-]/g, '')); if (!isNaN(aNum) && !isNaN(bNum)) { return ascending ? aNum - bNum : bNum - aNum; } // Fall back to string sort return ascending ? aText.localeCompare(bText) : bText.localeCompare(aText); }); // Re-append sorted rows rows.forEach(row => table.appendChild(row)); }, setupActions: function() { // Edit buttons document.addEventListener('click', function(e) { if (e.target.closest('.btn-edit')) { e.preventDefault(); const id = e.target.closest('.btn-edit').getAttribute('data-id'); RR.tables.handleEdit(id); } if (e.target.closest('.btn-delete')) { e.preventDefault(); const id = e.target.closest('.btn-delete').getAttribute('data-id'); RR.tables.handleDelete(id); } if (e.target.closest('.btn-view')) { e.preventDefault(); const id = e.target.closest('.btn-view').getAttribute('data-id'); RR.tables.handleView(id); } }); }, handleEdit: function(id) { RR.toast.show(`Edit functionality for ID: ${id}`, 'info'); // Implement edit modal or redirect }, handleDelete: function(id) { if (confirm('Are you sure you want to delete this item? This action cannot be undone.')) { // Show loading state const button = document.querySelector(`[data-id="${id}"].btn-delete`); if (button) { button.disabled = true; button.innerHTML = ''; } // Simulate API call setTimeout(() => { const row = button?.closest('tr'); if (row) { row.style.transition = 'all 0.3s ease'; row.style.opacity = '0'; row.style.transform = 'translateX(-20px)'; setTimeout(() => { row.remove(); RR.toast.show('Item deleted successfully', 'success'); }, 300); } }, 1000); } }, handleView: function(id) { RR.toast.show(`View details for ID: ${id}`, 'info'); // Implement view modal or redirect }, setupFilters: function() { const filterSelects = document.querySelectorAll('.filter-select'); filterSelects.forEach(select => { select.addEventListener('change', function() { RR.tables.applyFilters(); }); }); }, applyFilters: function() { const table = document.querySelector('.data-table'); if (!table) return; const rows = table.querySelectorAll('tbody tr'); const filters = {}; // Get all filter values document.querySelectorAll('.filter-select').forEach(select => { if (select.value) { filters[select.id] = select.value.toLowerCase(); } }); // Apply filters rows.forEach(row => { let shouldShow = true; Object.keys(filters).forEach(filterId => { const filterValue = filters[filterId]; let cellText = ''; // Get cell text based on filter type if (filterId.includes('role')) { const roleElement = row.querySelector('.role-badge'); cellText = roleElement ? roleElement.textContent.toLowerCase() : ''; } else if (filterId.includes('status')) { const statusElement = row.querySelector('.status-badge'); cellText = statusElement ? statusElement.textContent.toLowerCase() : ''; } if (cellText && !cellText.includes(filterValue)) { shouldShow = false; } }); row.style.display = shouldShow ? '' : 'none'; }); } }; // Modals Module RR.modals = { init: function() { this.setupModalTriggers(); this.setupModalClosing(); this.setupKeyboardNavigation(); }, setupModalTriggers: function() { // Generic modal triggers document.addEventListener('click', function(e) { const trigger = e.target.closest('[data-modal]'); if (trigger) { e.preventDefault(); const modalId = trigger.getAttribute('data-modal'); RR.modals.open(modalId); } }); }, setupModalClosing: function() { document.addEventListener('click', function(e) { // Close button if (e.target.closest('.modal-close')) { const modal = e.target.closest('.modal'); if (modal) RR.modals.close(modal.id); } // Backdrop click if (e.target.classList.contains('modal')) { RR.modals.close(e.target.id); } }); }, setupKeyboardNavigation: function() { document.addEventListener('keydown', function(e) { if (e.key === 'Escape') { const openModal = document.querySelector('.modal[style*="flex"]'); if (openModal) { RR.modals.close(openModal.id); } } }); }, open: function(modalId) { const modal = document.getElementById(modalId); if (!modal) return; modal.style.display = 'flex'; document.body.style.overflow = 'hidden'; // Focus first input const firstInput = modal.querySelector('input, textarea, select'); if (firstInput) { setTimeout(() => firstInput.focus(), 100); } // Add animation class if needed const modalContent = modal.querySelector('.modal-content'); if (modalContent) { modalContent.style.animation = 'modalAppear 0.3s ease-out'; } }, close: function(modalId) { const modal = document.getElementById(modalId); if (!modal) return; modal.style.display = 'none'; document.body.style.overflow = ''; // Reset form if exists const form = modal.querySelector('form'); if (form) { form.reset(); form.querySelectorAll('.error').forEach(el => el.classList.remove('error')); form.querySelectorAll('.error-message').forEach(el => el.remove()); } } }; // Toast Notifications RR.toast = { show: function(message, type = 'info') { // Remove existing toasts document.querySelectorAll('.toast').forEach(toast => toast.remove()); const toast = document.createElement('div'); toast.className = `toast toast-${type}`; toast.textContent = message; toast.setAttribute('role', 'alert'); toast.setAttribute('aria-live', 'assertive'); document.body.appendChild(toast); // Show with animation setTimeout(() => toast.classList.add('show'), 100); // Auto hide setTimeout(() => { toast.classList.remove('show'); setTimeout(() => { if (toast.parentNode) { toast.parentNode.removeChild(toast); } }, RR.config.animationDuration); }, RR.config.toastDuration); } }; // Tooltips Module RR.tooltips = { init: function() { this.createTooltips(); }, createTooltips: function() { const elements = document.querySelectorAll('[title]'); elements.forEach(el => { const title = el.getAttribute('title'); el.removeAttribute('title'); // Prevent default tooltip el.addEventListener('mouseenter', () => { RR.tooltips.show(el, title); }); el.addEventListener('mouseleave', () => { RR.tooltips.hide(); }); }); }, show: function(element, text) { const tooltip = document.createElement('div'); tooltip.className = 'tooltip'; tooltip.textContent = text; tooltip.style.cssText = ` position: absolute; background: var(--dark-color); color: var(--white); padding: var(--spacing-sm) var(--spacing-md); border-radius: var(--border-radius); font-size: var(--font-size-sm); z-index: var(--z-tooltip); pointer-events: none; opacity: 0; transition: opacity 0.2s ease; white-space: nowrap; `; document.body.appendChild(tooltip); const rect = element.getBoundingClientRect(); const tooltipRect = tooltip.getBoundingClientRect(); tooltip.style.left = rect.left + (rect.width - tooltipRect.width) / 2 + 'px'; tooltip.style.top = rect.top - tooltipRect.height - 8 + 'px'; setTimeout(() => tooltip.style.opacity = '1', 10); }, hide: function() { const tooltips = document.querySelectorAll('.tooltip'); tooltips.forEach(tooltip => { tooltip.style.opacity = '0'; setTimeout(() => { if (tooltip.parentNode) { tooltip.parentNode.removeChild(tooltip); } }, 200); }); } }; // Lazy Loading Module RR.lazyLoad = { init: function() { if ('IntersectionObserver' in window) { this.setupImageLazyLoading(); this.setupContentLazyLoading(); } }, setupImageLazyLoading: function() { const images = document.querySelectorAll('img[data-src]'); if (images.length === 0) return; const imageObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.remove('lazy'); imageObserver.unobserve(img); } }); }); images.forEach(img => imageObserver.observe(img)); }, setupContentLazyLoading: function() { const lazyElements = document.querySelectorAll('.lazy-load'); if (lazyElements.length === 0) return; const contentObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('loaded'); contentObserver.unobserve(entry.target); } }); }); lazyElements.forEach(el => contentObserver.observe(el)); } }; // Performance Module RR.performance = { init: function() { this.monitorPageLoad(); this.setupLinkPrefetching(); }, monitorPageLoad: function() { window.addEventListener('load', function() { if ('performance' in window) { const loadTime = Math.round(performance.now()); console.log(`Page loaded in ${loadTime}ms`); // Warn if load time is slow if (loadTime > 3000) { console.warn('Page load time is above 3 seconds. Consider optimization.'); } // Send to analytics if available if (typeof gtag !== 'undefined') { gtag('event', 'timing_complete', { name: 'load', value: loadTime }); } } }); }, setupLinkPrefetching: function() { // Prefetch important pages on hover const importantLinks = document.querySelectorAll('.nav-link, .btn-primary'); importantLinks.forEach(link => { link.addEventListener('mouseenter', function() { const url = this.href; if (url && url.startsWith(window.location.origin)) { RR.performance.prefetchPage(url); } }); }); }, prefetchPage: function(url) { // Check if already prefetched if (document.querySelector(`link[href="${url}"]`)) return; const link = document.createElement('link'); link.rel = 'prefetch'; link.href = url; document.head.appendChild(link); } }; // Utility Functions RR.utils = { // Debounce function debounce: function(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }, // Throttle function throttle: function(func, limit) { let inThrottle; return function() { const args = arguments; const context = this; if (!inThrottle) { func.apply(context, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }, // Format numbers with commas formatNumber: function(num) { return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); }, // Format currency formatCurrency: function(amount, currency = 'USD') { return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency }).format(amount); }, // Format date formatDate: function(date, options = {}) { const defaultOptions = { year: 'numeric', month: 'short', day: 'numeric' }; return new Date(date).toLocaleDateString('en-US', { ...defaultOptions, ...options }); }, // Get relative time getRelativeTime: function(date) { const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); const now = new Date(); const targetDate = new Date(date); const diffInMs = targetDate - now; const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24)); if (Math.abs(diffInDays) < 1) { const diffInHours = Math.floor(diffInMs / (1000 * 60 * 60)); return rtf.format(diffInHours, 'hour'); } else { return rtf.format(diffInDays, 'day'); } }, // API helper api: async function(url, options = {}) { const defaultOptions = { headers: { 'Content-Type': 'application/json', 'X-Requested-With': 'XMLHttpRequest' } }; try { const response = await fetch(RR.config.apiUrl + url, { ...defaultOptions, ...options, headers: { ...defaultOptions.headers, ...options.headers } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); return data; } catch (error) { console.error('API call failed:', error); RR.toast.show('An error occurred. Please try again.', 'error'); throw error; } }, // Local storage helpers (with fallbacks) storage: { get: function(key) { try { return JSON.parse(localStorage.getItem(key)); } catch { return null; } }, set: function(key, value) { try { localStorage.setItem(key, JSON.stringify(value)); return true; } catch { return false; } }, remove: function(key) { try { localStorage.removeItem(key); return true; } catch { return false; } } } }; // Expose utilities globally window.utils = RR.utils; window.showToast = RR.toast.show; })(); -------------------- END OF FILE -------------------- ### FILE 36: includes/footer.php - Type: PHP - Size: 3.88 KB - Path: includes - Name: footer.php ------------------------------------------------------------ -------------------- END OF FILE -------------------- ### FILE 37: includes/header.php - Type: PHP - Size: 9.56 KB - Path: includes - Name: header.php ------------------------------------------------------------ <?php echo isset($page_title) ? htmlspecialchars($page_title) . ' - ' . SITE_NAME : SITE_NAME . ' - Professional Panel Management System'; ?>
RR
Relevant Reflex Admin Panel
-------------------- END OF FILE -------------------- ### FILE 38: includes/navigation.php - Type: PHP - Size: 1.37 KB - Path: includes - Name: navigation.php ------------------------------------------------------------ -------------------- END OF FILE -------------------- ### FILE 39: uploads/clients/A6FB1FDC_1770453927_0.pdf - Type: PDF - Size: 358.78 KB - Path: uploads/clients - Name: A6FB1FDC_1770453927_0.pdf ------------------------------------------------------------ [BINARY/UNKNOWN FILE: PDF - Content not displayed] -------------------- END OF FILE -------------------- ### FILE 40: uploads/clients/BD0B267D_1769743328_0.png - Type: PNG - Size: 151.42 KB - Path: uploads/clients - Name: BD0B267D_1769743328_0.png ------------------------------------------------------------ [IMAGE FILE: PNG - Content not displayed] -------------------- END OF FILE -------------------- ### FILE 41: uploads/clients/BD0B267D_1769770697_0.pdf - Type: PDF - Size: 358.78 KB - Path: uploads/clients - Name: BD0B267D_1769770697_0.pdf ------------------------------------------------------------ [BINARY/UNKNOWN FILE: PDF - Content not displayed] -------------------- END OF FILE -------------------- ### FILE 42: uploads/clients/EA89781D_1769740517_0.pdf - Type: PDF - Size: 358.78 KB - Path: uploads/clients - Name: EA89781D_1769740517_0.pdf ------------------------------------------------------------ [BINARY/UNKNOWN FILE: PDF - Content not displayed] -------------------- END OF FILE -------------------- ================================================================================ ## SUMMARY ================================================================================ Repository contains 42 files total. All file contents have been extracted and are shown above. This repository snapshot was generated on: 2026-02-17 22:38:02 ================================================================================ ## END OF REPOSITORY ================================================================================