gitea init
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
class Config
|
||||
{
|
||||
public static function baseUrl()
|
||||
{
|
||||
return rtrim(dirname(dirname($_SERVER['SCRIPT_NAME'])), '/');
|
||||
}
|
||||
|
||||
public static function basePath()
|
||||
{
|
||||
return realpath(__DIR__ . '/../../');
|
||||
}
|
||||
|
||||
//ფოლდერების ლოკაციების განსაზღვრა
|
||||
public static function dist(string $path): string {
|
||||
return '/admin/dist/' . ltrim($path, '/');
|
||||
}
|
||||
|
||||
public static function libs(string $path): string {
|
||||
return '/admin/libs/' . ltrim($path, '/');
|
||||
}
|
||||
|
||||
public static function preview(string $path): string {
|
||||
return '/admin/preview/' . ltrim($path, '/');
|
||||
}
|
||||
|
||||
public static function static(string $path): string {
|
||||
return '/admin/static/' . ltrim($path, '/');
|
||||
}
|
||||
|
||||
public static function route(string $relativePath, array $query = []): string
|
||||
{
|
||||
// თუ მიწოდებული ბმული აბსოლუტურია (იწყება http-ით ან /-ით), დავაბრუნოთ ისე
|
||||
if (strpos($relativePath, 'http') === 0 || strpos($relativePath, '/') === 0) {
|
||||
return $relativePath;
|
||||
}
|
||||
|
||||
$url = '/admin/' . ltrim($relativePath, '/');
|
||||
|
||||
if (!empty($query)) {
|
||||
$url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($query);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public static function includePath($file)
|
||||
{
|
||||
return self::basePath() . '/admin/includes/' . $file;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
|
||||
class DashboardModel
|
||||
{
|
||||
protected static $db;
|
||||
|
||||
public static function setDb($pdo)
|
||||
{
|
||||
self::$db = $pdo;
|
||||
}
|
||||
|
||||
/**
|
||||
* კლიენტების სტატისტიკა
|
||||
*/
|
||||
public static function getClientStats()
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
try {
|
||||
// სულ კლიენტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM clients");
|
||||
$stats['total'] = $stmt->fetchColumn();
|
||||
|
||||
// აქტიური კლიენტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM clients WHERE status = 'active'");
|
||||
$stats['active'] = $stmt->fetchColumn();
|
||||
|
||||
// ამ თვის ახალი კლიენტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM clients WHERE created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')");
|
||||
$stats['this_month'] = $stmt->fetchColumn();
|
||||
|
||||
// გუშინდელი ახალი კლიენტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM clients WHERE DATE(created_at) = CURDATE() - INTERVAL 1 DAY");
|
||||
$stats['yesterday'] = $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
// თუ clients ცხრილი არ არსებობს
|
||||
$stats = [
|
||||
'total' => 0,
|
||||
'active' => 0,
|
||||
'this_month' => 0,
|
||||
'yesterday' => 0
|
||||
];
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* პროდუქტების სტატისტიკა
|
||||
*/
|
||||
public static function getProductStats()
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
try {
|
||||
// სულ პროდუქტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM products");
|
||||
$stats['total'] = $stmt->fetchColumn();
|
||||
|
||||
// აქტიური პროდუქტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM products WHERE status = 'active'");
|
||||
$stats['active'] = $stmt->fetchColumn();
|
||||
|
||||
// ამ თვის ახალი პროდუქტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM products WHERE created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')");
|
||||
$stats['this_month'] = $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
// თუ products ცხრილი არ არსებობს
|
||||
$stats['total'] = 0;
|
||||
$stats['active'] = 0;
|
||||
$stats['this_month'] = 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// პროდუქტის ტიპები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM product_types WHERE is_active = 1");
|
||||
$stats['types'] = $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
// თუ product_types ცხრილი არ არსებობს
|
||||
$stats['types'] = 0;
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* ბილინგის სტატისტიკა
|
||||
*/
|
||||
public static function getBillingStats()
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
try {
|
||||
// სულ ინვოისები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM invoices");
|
||||
$stats['total_invoices'] = $stmt->fetchColumn();
|
||||
|
||||
// გადახდილი ინვოისები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM invoices WHERE status = 'paid'");
|
||||
$stats['paid_invoices'] = $stmt->fetchColumn();
|
||||
|
||||
// გადაუხდელი ინვოისები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM invoices WHERE status = 'pending'");
|
||||
$stats['pending_invoices'] = $stmt->fetchColumn();
|
||||
|
||||
// სულ ტრანზაქციები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM transactions");
|
||||
$stats['total_transactions'] = $stmt->fetchColumn();
|
||||
|
||||
// ამ თვის შემოსავალი
|
||||
$stmt = self::$db->query("SELECT COALESCE(SUM(amount), 0) FROM transactions WHERE status = 'completed' AND created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')");
|
||||
$stats['monthly_revenue'] = $stmt->fetchColumn();
|
||||
|
||||
// სულ შემოსავალი
|
||||
$stmt = self::$db->query("SELECT COALESCE(SUM(amount), 0) FROM transactions WHERE status = 'completed'");
|
||||
$stats['total_revenue'] = $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
// თუ billing ცხრილები არ არსებობს
|
||||
$stats = [
|
||||
'total_invoices' => 0,
|
||||
'paid_invoices' => 0,
|
||||
'pending_invoices' => 0,
|
||||
'total_transactions' => 0,
|
||||
'monthly_revenue' => 0,
|
||||
'total_revenue' => 0
|
||||
];
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* მომხმარებლების სტატისტიკა
|
||||
*/
|
||||
public static function getUserStats()
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
// სულ მომხმარებლები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM users");
|
||||
$stats['total'] = $stmt->fetchColumn();
|
||||
|
||||
// აქტიური მომხმარებლები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM users WHERE is_active = 1");
|
||||
$stats['active'] = $stmt->fetchColumn();
|
||||
|
||||
// ადმინისტრატორები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM users WHERE role = 'admin'");
|
||||
$stats['admins'] = $stmt->fetchColumn();
|
||||
|
||||
// ამ თვის ახალი მომხმარებლები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM users WHERE created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')");
|
||||
$stats['this_month'] = $stmt->fetchColumn();
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* მარკეტინგის სტატისტიკა
|
||||
*/
|
||||
public static function getMarketingStats()
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
try {
|
||||
// სულ გაგზავნილი ელ.ფოსტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM email_logs");
|
||||
$stats['total_emails'] = $stmt->fetchColumn();
|
||||
|
||||
// წარმატებით გაგზავნილი
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM email_logs WHERE status = 'sent'");
|
||||
$stats['sent_emails'] = $stmt->fetchColumn();
|
||||
|
||||
// ვერ გაგზავნილი
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM email_logs WHERE status = 'failed'");
|
||||
$stats['failed_emails'] = $stmt->fetchColumn();
|
||||
|
||||
// ამ თვის ელ.ფოსტები
|
||||
$stmt = self::$db->query("SELECT COUNT(*) FROM email_logs WHERE created_at >= DATE_FORMAT(NOW(), '%Y-%m-01')");
|
||||
$stats['this_month'] = $stmt->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
// თუ email_logs ცხრილი არ არსებობს
|
||||
$stats = [
|
||||
'total_emails' => 0,
|
||||
'sent_emails' => 0,
|
||||
'failed_emails' => 0,
|
||||
'this_month' => 0
|
||||
];
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* ბოლო აქტივობა
|
||||
*/
|
||||
public static function getRecentActivity()
|
||||
{
|
||||
$activities = [];
|
||||
|
||||
try {
|
||||
// ბოლო კლიენტები
|
||||
$stmt = self::$db->query("
|
||||
SELECT 'client' as type, CONCAT(first_name, ' ', last_name) as title, created_at
|
||||
FROM clients
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$activities = array_merge($activities, $stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
} catch (Exception $e) {
|
||||
// clients ცხრილი არ არსებობს
|
||||
}
|
||||
|
||||
try {
|
||||
// ბოლო ინვოისები
|
||||
$stmt = self::$db->query("
|
||||
SELECT 'invoice' as type, CONCAT('ინვოისი #', id) as title, created_at
|
||||
FROM invoices
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$activities = array_merge($activities, $stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
} catch (Exception $e) {
|
||||
// invoices ცხრილი არ არსებობს
|
||||
}
|
||||
|
||||
try {
|
||||
// ბოლო ტრანზაქციები
|
||||
$stmt = self::$db->query("
|
||||
SELECT 'transaction' as type, CONCAT('ტრანზაქცია ', amount, ' ლარი') as title, created_at
|
||||
FROM transactions
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$activities = array_merge($activities, $stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
} catch (Exception $e) {
|
||||
// transactions ცხრილი არ არსებობს
|
||||
}
|
||||
|
||||
try {
|
||||
// ბოლო მომხმარებლები
|
||||
$stmt = self::$db->query("
|
||||
SELECT 'user' as type, CONCAT(first_name, ' ', last_name, ' - მომხმარებელი') as title, created_at
|
||||
FROM users
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 3
|
||||
");
|
||||
$activities = array_merge($activities, $stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
} catch (Exception $e) {
|
||||
// users ცხრილი არ არსებობს
|
||||
}
|
||||
|
||||
// დალაგება თარიღის მიხედვით
|
||||
if (!empty($activities)) {
|
||||
usort($activities, function($a, $b) {
|
||||
return strtotime($b['created_at']) - strtotime($a['created_at']);
|
||||
});
|
||||
}
|
||||
|
||||
return array_slice($activities, 0, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* სისტემის ზოგადი სტატისტიკა
|
||||
*/
|
||||
public static function getSystemStats()
|
||||
{
|
||||
return [
|
||||
'clients' => self::getClientStats(),
|
||||
'products' => self::getProductStats(),
|
||||
'billing' => self::getBillingStats(),
|
||||
'users' => self::getUserStats(),
|
||||
'marketing' => self::getMarketingStats(),
|
||||
'server' => self::getServerStats(),
|
||||
'recent_activity' => self::getRecentActivity()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* სერვერის სტატისტიკა
|
||||
*/
|
||||
public static function getServerStats()
|
||||
{
|
||||
$stats = [];
|
||||
|
||||
// სერვერის ინფორმაცია
|
||||
$stats['php_version'] = PHP_VERSION;
|
||||
|
||||
try {
|
||||
$stats['mysql_version'] = self::$db->query("SELECT VERSION()")->fetchColumn();
|
||||
} catch (Exception $e) {
|
||||
$stats['mysql_version'] = 'N/A';
|
||||
}
|
||||
|
||||
// მეხსიერება
|
||||
$stats['memory_usage'] = round(memory_get_usage(true) / 1024 / 1024, 2); // MB
|
||||
$stats['memory_limit'] = ini_get('memory_limit');
|
||||
|
||||
// დისკის ადგილი
|
||||
$stats['disk_free'] = disk_free_space('.') ? round(disk_free_space('.') / 1024 / 1024 / 1024, 2) : 0; // GB
|
||||
$stats['disk_total'] = disk_total_space('.') ? round(disk_total_space('.') / 1024 / 1024 / 1024, 2) : 0; // GB
|
||||
|
||||
// პროცესორი (load average) - Linux სისტემისთვის
|
||||
if (is_readable('/proc/loadavg')) {
|
||||
$load = file_get_contents('/proc/loadavg');
|
||||
$load_avg = explode(' ', $load);
|
||||
$stats['cpu_load'] = round(floatval($load_avg[0]), 2);
|
||||
} else {
|
||||
$stats['cpu_load'] = 0;
|
||||
}
|
||||
|
||||
// უფრო ინფორმატიული სტატისტიკა
|
||||
$stats['max_execution_time'] = ini_get('max_execution_time');
|
||||
$stats['upload_max_filesize'] = ini_get('upload_max_filesize');
|
||||
|
||||
return $stats;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
// auth_check.php - ავტორიზაციის შემოწმების ფაილი
|
||||
session_start();
|
||||
|
||||
function checkAuth() {
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
function isLoggedIn() {
|
||||
return isset($_SESSION['user_id']);
|
||||
}
|
||||
|
||||
function getUserId() {
|
||||
return $_SESSION['user_id'] ?? null;
|
||||
}
|
||||
|
||||
function getUserName() {
|
||||
return $_SESSION['user_name'] ?? 'ანონიმი';
|
||||
}
|
||||
|
||||
function logout() {
|
||||
session_destroy();
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
// ვიტვირთავთ კონფიგურაციას ინსტალაციის ვიზარდიდან
|
||||
$configFile = __DIR__ . '/../config.php';
|
||||
|
||||
if (!file_exists($configFile)) {
|
||||
die('კონფიგურაციის ფაილი ვერ მოიძებნა. გთხოვთ ჯერ გაიაროთ ინსტალაციის ვიზარდი: <a href="install/">ინსტალაცია</a>');
|
||||
}
|
||||
|
||||
$config = include $configFile;
|
||||
|
||||
// შევამოწმოთ არის თუ არა სისტემა ინსტალირებული
|
||||
if (isset($config['app']['installed']) && $config['app']['installed'] === false) {
|
||||
die('სისტემა არ არის ინსტალირებული. გთხოვთ გაიაროთ ინსტალაციის ვიზარდი: <a href="install/">ინსტალაცია</a>');
|
||||
}
|
||||
|
||||
// PDO სისტემა config.php-ის მიხედვით
|
||||
$host = $config['host'] ?? $config['db']['host'] ?? 'localhost';
|
||||
$db = $config['dbname'] ?? $config['db']['name'] ?? '';
|
||||
$user = $config['user'] ?? $config['db']['user'] ?? '';
|
||||
$pass = $config['pass'] ?? $config['db']['pass'] ?? '';
|
||||
$charset = $config['charset'] ?? $config['db']['charset'] ?? 'utf8mb4';
|
||||
|
||||
if (empty($db)) {
|
||||
die('მონაცემთა ბაზის კონფიგურაცია არ არის სწორად დაყენებული.');
|
||||
}
|
||||
|
||||
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
|
||||
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Debug-სთვის
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // ასოც. array
|
||||
PDO::ATTR_EMULATE_PREPARES => false, // თავდასხმებისგან დაცვა
|
||||
];
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, $user, $pass, $options);
|
||||
} catch (\PDOException $e) {
|
||||
die("მონაცემთა ბაზის შეცდომა: " . $e->getMessage() . '<br>გთხოვთ შეამოწმოთ კონფიგურაცია.');
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
// ვიტვირთავთ კონფიგურაციას ინსტალაციის ვიზარდიდან
|
||||
$configFile = __DIR__ . '/../config.php';
|
||||
|
||||
if (!file_exists($configFile)) {
|
||||
die('კონფიგურაციის ფაილი ვერ მოიძებნა. გთხოვთ ჯერ გაიაროთ ინსტალაციის ვიზარდი: <a href="install/">ინსტალაცია</a>');
|
||||
}
|
||||
|
||||
$config = include $configFile;
|
||||
|
||||
// შევამოწმოთ არის თუ არა სისტემა ინსტალირებული
|
||||
if (isset($config['app']['installed']) && $config['app']['installed'] === false) {
|
||||
die('სისტემა არ არის ინსტალირებული. გთხოვთ გაიაროთ ინსტალაციის ვიზარდი: <a href="install/">ინსტალაცია</a>');
|
||||
}
|
||||
|
||||
// PDO სისტემა config.php-ის მიხედვით
|
||||
$host = $config['host'] ?? $config['db']['host'] ?? 'localhost';
|
||||
$db = $config['dbname'] ?? $config['db']['name'] ?? '';
|
||||
$user = $config['user'] ?? $config['db']['user'] ?? '';
|
||||
$pass = $config['pass'] ?? $config['db']['pass'] ?? '';
|
||||
$charset = $config['charset'] ?? $config['db']['charset'] ?? 'utf8mb4';
|
||||
|
||||
if (empty($db)) {
|
||||
die('მონაცემთა ბაზის კონფიგურაცია არ არის სწორად დაყენებული.');
|
||||
}
|
||||
|
||||
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
|
||||
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // Debug-სთვის
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, // ასოც. array
|
||||
PDO::ATTR_EMULATE_PREPARES => false, // თავდასხმებისგან დაცვა
|
||||
];
|
||||
|
||||
try {
|
||||
$pdo = new PDO($dsn, $user, $pass, $options);
|
||||
} catch (\PDOException $e) {
|
||||
die("მონაცემთა ბაზის შეცდომა: " . $e->getMessage() . '<br>გთხოვთ შეამოწმოთ კონფიგურაცია.');
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,65 @@
|
||||
</div>
|
||||
<!-- BEGIN FOOTER -->
|
||||
<footer class="footer footer-transparent d-print-none">
|
||||
<div class="container-xl">
|
||||
<div class="row text-center align-items-center flex-row-reverse">
|
||||
<div class="col-lg-auto ms-lg-auto">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item"><a href="https://stack.ge/docs" target="_blank" class="link-secondary" rel="noopener">დოკუმენტაცია</a></li>
|
||||
<li class="list-inline-item"><a href="https://stack.ge/license" class="link-secondary">ლიცენზია</a></li>
|
||||
<li class="list-inline-item">
|
||||
<a href="https://github.com/stackge/billingerp" target="_blank" class="link-secondary" rel="noopener">წყარო კოდი</a>
|
||||
</li>
|
||||
<li class="list-inline-item">
|
||||
<a href="https://stack.ge/support" target="_blank" class="link-secondary" rel="noopener">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/heart -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon text-pink icon-inline icon-4"
|
||||
>
|
||||
<path d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572" />
|
||||
</svg>
|
||||
მხარდაჭერა
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 col-lg-auto mt-3 mt-lg-0">
|
||||
<ul class="list-inline list-inline-dots mb-0">
|
||||
<li class="list-inline-item">
|
||||
Copyright © 2025
|
||||
<a href="https://stack.ge" class="link-secondary">STACK</a>. ყველა უფლება დაცულია.
|
||||
</li>
|
||||
<li class="list-inline-item">
|
||||
<a href="https://stack.ge/changelog" class="link-secondary" rel="noopener"> v1.1.1 </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- END FOOTER -->
|
||||
|
||||
|
||||
<!-- BEGIN PAGE LIBRARIES -->
|
||||
<script src="<?= App\Config::libs('apexcharts/dist/apexcharts.min.js?1740918423') ?>" defer></script>
|
||||
<script src="<?= App\Config::libs('jsvectormap/dist/jsvectormap.min.js?1740918423') ?>" defer></script>
|
||||
<script src="<?= App\Config::libs('jsvectormap/dist/maps/world.js?1740918423') ?>" defer></script>
|
||||
<script src="<?= App\Config::libs('jsvectormap/dist/maps/world-merc.js?1740918423') ?>" defer></script>
|
||||
<!-- END PAGE LIBRARIES -->
|
||||
<!-- BEGIN GLOBAL MANDATORY SCRIPTS -->
|
||||
<script src="<?= App\Config::dist('js/tabler.min.js?1740918423') ?>" defer></script>
|
||||
<!-- END GLOBAL MANDATORY SCRIPTS -->
|
||||
<!-- BEGIN DEMO SCRIPTS -->
|
||||
<script src="<?= App\Config::preview('js/demo.min.js?1740918423') ?>" defer></script>
|
||||
|
||||
<!-- END DEMO SCRIPTS -->
|
||||
<!-- BEGIN PAGE SCRIPTS -->
|
||||
@@ -0,0 +1,43 @@
|
||||
<!doctype html>
|
||||
<!--
|
||||
* STACK - ბილინგისა და მართვის სისტემა stack.ge
|
||||
* @version 1.1.1
|
||||
* @link https://stack.ge
|
||||
* Copyright 2025 Stack.ge
|
||||
* შექმნილია Stack.ge გუნდის მიერ
|
||||
* Licensed under MIT License
|
||||
-->
|
||||
<html lang="ka">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||
<title>Მართვის პანელი</title>
|
||||
<!-- BEGIN PAGE LEVEL STYLES -->
|
||||
<!-- END PAGE LEVEL STYLES -->
|
||||
<!-- BEGIN GLOBAL MANDATORY STYLES -->
|
||||
<!-- <link href="css/tabler.min.css?1740918423" rel="stylesheet" /> -->
|
||||
<link href="<?= App\Config::dist('css/tabler.min.css?1740918423') ?>" rel="stylesheet" />
|
||||
<!-- END GLOBAL MANDATORY STYLES -->
|
||||
<!-- BEGIN PLUGINS STYLES -->
|
||||
<link href="<?= App\Config::dist('css/tabler-flags.min.css?1740918423') ?>" rel="stylesheet" />
|
||||
<link href="<?= App\Config::dist('css/tabler-socials.min.css?1740918423') ?>" rel="stylesheet" />
|
||||
<link href="<?= App\Config::dist('css/tabler-payments.min.css?1740918423') ?>" rel="stylesheet" />
|
||||
<link href="<?= App\Config::dist('css/tabler-vendors.min.css?1740918423') ?>" rel="stylesheet" />
|
||||
<link href="<?= App\Config::dist('css/tabler-marketing.min.css?1740918423') ?>" rel="stylesheet" />
|
||||
|
||||
<!-- END PLUGINS STYLES -->
|
||||
<!-- BEGIN DEMO STYLES -->
|
||||
<link href="<?= App\Config::preview('css/demo.min.css?1740918423') ?>" rel="stylesheet" />
|
||||
<!-- END DEMO STYLES -->
|
||||
<!-- BEGIN CUSTOM FONT -->
|
||||
<style>
|
||||
@import url("https://rsms.me/inter/inter.css");
|
||||
</style>
|
||||
<!-- END CUSTOM FONT -->
|
||||
</head>
|
||||
<body>
|
||||
<!-- BEGIN DEMO THEME SCRIPT -->
|
||||
<script src="<?= App\Config::preview('js/demo-theme.min.js?1740918423') ?>"></script>
|
||||
<!-- END DEMO THEME SCRIPT -->
|
||||
<div class="page">
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
// სესიის გაშვება თუ ჯერ არ არის
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
// ავტორიზაციის შემოწმება
|
||||
if (!isset($_SESSION['user_id']) || !isset($_SESSION['user_name'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// მომხმარებლის მონაცემები
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$user_name = $_SESSION['user_name'];
|
||||
$user_email = $_SESSION['user_email'] ?? '';
|
||||
|
||||
// ბაზასთან კავშირი
|
||||
require_once __DIR__ . '/db.php';
|
||||
@@ -0,0 +1,415 @@
|
||||
|
||||
<?php
|
||||
// menu_items.php ან includes/navbar.php-ის თავში
|
||||
$menuItems = [
|
||||
[
|
||||
'title' => 'მთავარი',
|
||||
'icon' => 'home',
|
||||
'link' => 'dashboard.php'
|
||||
],
|
||||
[
|
||||
'title' => 'კლიენტები',
|
||||
'icon' => 'users',
|
||||
'items' => [
|
||||
['label' => 'მომხმარებლების სია', 'module' => 'clients', 'action' => 'list'],
|
||||
['label' => 'ახალი კლიენტი', 'module' => 'clients', 'action' => 'add'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'title' => 'პროდუქცია',
|
||||
'icon' => 'package',
|
||||
'items' => [
|
||||
['label' => 'პროდუქტების სია', 'module' => 'product', 'action' => 'list'],
|
||||
['label' => 'ახალი პროდუქტი', 'module' => 'product', 'action' => 'create'],
|
||||
['label' => 'პროდუქტის ტიპები', 'module' => 'product', 'action' => 'types'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'title' => 'ბილინგი',
|
||||
'icon' => 'credit-card',
|
||||
'items' => [
|
||||
[
|
||||
'label' => 'ინვოისების სია',
|
||||
'module' => 'billing',
|
||||
'submodule'=> 'invoices',
|
||||
'action' => 'list'
|
||||
],
|
||||
[
|
||||
'label' => 'ინვოისის შექმნა',
|
||||
'module' => 'billing',
|
||||
'submodule'=> 'invoices',
|
||||
'action' => 'create'
|
||||
],
|
||||
[
|
||||
'label' => 'ტრაზაქციები',
|
||||
'module' => 'billing',
|
||||
'submodule'=> 'transactions',
|
||||
'action' => 'list'
|
||||
],
|
||||
[
|
||||
'label' => 'ტრანზაქციის შექმნა',
|
||||
'module' => 'billing',
|
||||
'submodule'=> 'transactions',
|
||||
'action' => 'create'
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'title' => 'სისტემა',
|
||||
'icon' => 'settings',
|
||||
'items' => [
|
||||
['label' => 'მომხმარებლების მართვა', 'module' => 'users', 'action' => 'management'],
|
||||
['label' => 'SMTP სეტინგები', 'link' => 'modules/settings/controllers/smtp_settings.php'],
|
||||
['label' => 'განახლებები', 'link' => 'update/'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'title' => 'მარკეტინგი',
|
||||
'icon' => 'mail',
|
||||
'items' => [
|
||||
['label' => 'ელ.ფოსტის გაგზავნა', 'module' => 'marketing', 'action' => 'broadcast'],
|
||||
['label' => 'ელ.ფოსტის ჩანაწერები', 'module' => 'marketing', 'action' => 'email_logs'],
|
||||
]
|
||||
]
|
||||
];
|
||||
?>
|
||||
<!-- BEGIN NAVBAR -->
|
||||
<header class="navbar navbar-expand-md navbar-overlap d-print-none" data-bs-theme="dark">
|
||||
<div class="container-xl">
|
||||
<!-- BEGIN NAVBAR TOGGLER -->
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbar-menu"
|
||||
aria-controls="navbar-menu"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<!-- END NAVBAR TOGGLER -->
|
||||
<!-- BEGIN NAVBAR LOGO -->
|
||||
<div class="navbar-brand navbar-brand-autodark d-none-navbar-horizontal pe-0 pe-md-3">
|
||||
<a href=".">
|
||||
<h3 style="color: #066fd1; font-weight: bold; margin: 0;">STACK</h3>
|
||||
<small style="color: #6c757d;">stack.ge</small>
|
||||
</a>
|
||||
</div>
|
||||
<!-- END NAVBAR LOGO -->
|
||||
<div class="navbar-nav flex-row order-md-last">
|
||||
<div class="d-none d-md-flex">
|
||||
<div class="nav-item">
|
||||
<a href="?theme=dark" class="nav-link px-0 hide-theme-dark" title="Enable dark mode" data-bs-toggle="tooltip" data-bs-placement="bottom">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/moon -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
|
||||
</svg>
|
||||
</a>
|
||||
<a href="?theme=light" class="nav-link px-0 hide-theme-light" title="Enable light mode" data-bs-toggle="tooltip" data-bs-placement="bottom">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/sun -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M12 12m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0" />
|
||||
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="nav-item dropdown d-none d-md-flex me-3">
|
||||
<a href="#" class="nav-link px-0" data-bs-toggle="dropdown" tabindex="-1" aria-label="Show notifications">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/bell -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3h-16a4 4 0 0 0 2 -3v-3a7 7 0 0 1 4 -6" />
|
||||
<path d="M9 17v1a3 3 0 0 0 6 0v-1" />
|
||||
</svg>
|
||||
<span class="badge bg-red"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-arrow dropdown-menu-end dropdown-menu-card">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Last updates</h3>
|
||||
</div>
|
||||
<div class="list-group list-group-flush list-group-hoverable">
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot status-dot-animated bg-red d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 1</a>
|
||||
<div class="d-block text-secondary text-truncate mt-n1">Change deprecated html tags to text decoration classes (#29604)</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/star -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon text-muted icon-2"
|
||||
>
|
||||
<path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 2</a>
|
||||
<div class="d-block text-secondary text-truncate mt-n1">justify-content:between ⇒ justify-content:space-between (#29734)</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions show">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/star -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon text-yellow icon-2"
|
||||
>
|
||||
<path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 3</a>
|
||||
<div class="d-block text-secondary text-truncate mt-n1">Update change-version.js (#29736)</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/star -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon text-muted icon-2"
|
||||
>
|
||||
<path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto"><span class="status-dot status-dot-animated bg-green d-block"></span></div>
|
||||
<div class="col text-truncate">
|
||||
<a href="#" class="text-body d-block">Example 4</a>
|
||||
<div class="d-block text-secondary text-truncate mt-n1">Regenerate package-lock.json (#29730)</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<a href="#" class="list-group-item-actions">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/star -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon text-muted icon-2"
|
||||
>
|
||||
<path d="M12 17.75l-6.172 3.245l1.179 -6.873l-5 -4.867l6.9 -1l3.086 -6.253l3.086 6.253l6.9 1l-5 4.867l1.179 6.873z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="nav-item dropdown">
|
||||
<a href="#" class="nav-link d-flex lh-1 p-0 px-2" data-bs-toggle="dropdown" aria-label="Open user menu">
|
||||
<span class="avatar avatar-sm" style="background-image: url(<?= App\Config::static('') ?>/avatars/000m.jpg)"></span>
|
||||
<div class="d-none d-xl-block ps-2">
|
||||
<div><?= htmlspecialchars($user_name) ?></div>
|
||||
<div class="mt-1 small text-secondary">ადმინი</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow" data-bs-theme="light">
|
||||
<a href="profile.php" class="dropdown-item">პროფილი</a>
|
||||
<a href="dashboard.php?module=users&action=management" class="dropdown-item">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-users">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M9 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"/>
|
||||
<path d="M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"/>
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
||||
<path d="M21 21v-2a4 4 0 0 0 -3 -3.85"/>
|
||||
</svg>
|
||||
მომხმარებლების მართვა
|
||||
</a>
|
||||
<a href="modules/settings/controllers/smtp_settings.php" class="dropdown-item">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-mail">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"/>
|
||||
<path d="M3 7l9 6l9 -6"/>
|
||||
</svg>
|
||||
SMTP სეტინგები
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a href="logout.php" class="dropdown-item">გასვლა</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="navbar-menu">
|
||||
<div class="d-flex flex-column flex-md-row flex-fill align-items-stretch align-items-md-center">
|
||||
<!-- BEGIN NAVBAR MENU -->
|
||||
<!-- Dinamically Generated NAVBAR -->
|
||||
<ul class="navbar-nav">
|
||||
<?php foreach ($menuItems as $menu): ?>
|
||||
<?php if (isset($menu['items'])): ?>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<?php
|
||||
$iconSvg = '';
|
||||
switch($menu['icon']) {
|
||||
case 'home':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M5 12l-2 0l9 -9l9 9l-2 0"/><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7"/><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"/></svg>';
|
||||
break;
|
||||
case 'users':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M9 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"/><path d="M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/><path d="M21 21v-2a4 4 0 0 0 -3 -3.85"/></svg>';
|
||||
break;
|
||||
case 'package':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5"/><path d="M12 12l8 -4.5"/><path d="M12 12l0 9"/><path d="M12 12l-8 -4.5"/></svg>';
|
||||
break;
|
||||
case 'credit-card':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M3 5m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z"/><path d="M3 10l18 0"/><path d="M7 15l.01 0"/><path d="M11 15l2 0"/></svg>';
|
||||
break;
|
||||
case 'settings':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94-1.543.826-3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065z"/><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"/></svg>';
|
||||
break;
|
||||
case 'mail':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"/><path d="M3 7l9 6l9 -6"/></svg>';
|
||||
break;
|
||||
default:
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><circle cx="12" cy="12" r="1"/></svg>';
|
||||
}
|
||||
echo $iconSvg;
|
||||
?>
|
||||
</span>
|
||||
<span class="nav-link-title"> <?= $menu['title'] ?> </span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<?php foreach ($menu['items'] as $item): ?>
|
||||
<!-- ლინკის სივრცე, ქვე მოდულებისა და მოდულების მარშუტებისთვის -->
|
||||
<?php if (isset($item['module']) && isset($item['action'])): ?>
|
||||
<a class="dropdown-item" href="<?= App\Config::route('dashboard.php?module=' . $item['module']
|
||||
. (isset($item['submodule']) ? '&submodule=' . $item['submodule'] : '')
|
||||
. '&action=' . $item['action']) ?>">
|
||||
<?= $item['label'] ?>
|
||||
</a>
|
||||
<?php elseif (isset($item['link'])): ?>
|
||||
<a class="dropdown-item" href="<?= App\Config::route($item['link']) ?>">
|
||||
<?= $item['label'] ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</li>
|
||||
<?php elseif (isset($menu['link'])): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?= App\Config::route($menu['link']) ?>">
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<?php
|
||||
$iconSvg = '';
|
||||
switch($menu['icon']) {
|
||||
case 'home':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M5 12l-2 0l9 -9l9 9l-2 0"/><path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7"/><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"/></svg>';
|
||||
break;
|
||||
case 'users':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M9 7m-4 0a4 4 0 1 0 8 0a4 4 0 1 0 -8 0"/><path d="M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/><path d="M21 21v-2a4 4 0 0 0 -3 -3.85"/></svg>';
|
||||
break;
|
||||
case 'package':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5"/><path d="M12 12l8 -4.5"/><path d="M12 12l0 9"/><path d="M12 12l-8 -4.5"/></svg>';
|
||||
break;
|
||||
case 'credit-card':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M3 5m0 3a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3z"/><path d="M3 10l18 0"/><path d="M7 15l.01 0"/><path d="M11 15l2 0"/></svg>';
|
||||
break;
|
||||
case 'settings':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94-1.543.826-3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065z"/><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"/></svg>';
|
||||
break;
|
||||
case 'mail':
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"/><path d="M3 7l9 6l9 -6"/></svg>';
|
||||
break;
|
||||
default:
|
||||
$iconSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon"><circle cx="12" cy="12" r="1"/></svg>';
|
||||
}
|
||||
echo $iconSvg;
|
||||
?>
|
||||
</span>
|
||||
<span class="nav-link-title"> <?= $menu['title'] ?> </span>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<!-- END NAVBAR MENU -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<!-- END NAVBAR -->
|
||||
|
||||
<div class="page-wrapper" style="padding-top: 4rem;">
|
||||
@@ -0,0 +1,217 @@
|
||||
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="<?= App\Config::route('dashboard.php') ?>">
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/home -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M5 12l-2 0l9 -9l9 9l-2 0" />
|
||||
<path d="M5 12v7a2 2 0 0 0 2 2h10a2 2 0 0 0 2 -2v-7" />
|
||||
<path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="nav-link-title"> მთავარი </span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#navbar-addons"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/plus -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M12 5l0 14" />
|
||||
<path d="M5 12l14 0" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="nav-link-title"> კლიენტები </span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="<?= App\Config::route('clients_list.php') ?>"> მომხმარებლების სია </a>
|
||||
<a class="dropdown-item" href="<?= App\Config::route('add_client.php') ?>"> ახალი კლიენტი </a>
|
||||
<a class="dropdown-item" href="./flags.html"> პროდუქტები & სერვისები </a>
|
||||
<a class="dropdown-item" href="./illustrations.html"> დომენის რეგისტრაციები </a>
|
||||
<a class="dropdown-item" href="./payment-providers.html"> კლიენტების ძებნა </a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#navbar-addons"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/plus -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M12 5l0 14" />
|
||||
<path d="M5 12l14 0" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="nav-link-title"> შეკვეთები </span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="configproduct.php"> პროდუქტების სია </a>
|
||||
<a class="dropdown-item" href="./emails.html"> Emails </a>
|
||||
<a class="dropdown-item" href="./flags.html"> Flags </a>
|
||||
<a class="dropdown-item" href="./illustrations.html"> Illustrations </a>
|
||||
<a class="dropdown-item" href="./payment-providers.html"> Payment providers </a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#navbar-addons"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/plus -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M12 5l0 14" />
|
||||
<path d="M5 12l14 0" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="nav-link-title"> ბილინგი </span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="<?= App\Config::route('billing/invoices/list.php') ?>"> ინვოისების სია </a>
|
||||
<a class="dropdown-item" href="<?= App\Config::route('billing/invoices/create.php') ?>"> ინვოისის შექმნა </a>
|
||||
<a class="dropdown-item" href="<?= App\Config::route('billing/invoices/list.php') ?>"> გადაუხდელები </a>
|
||||
<a class="dropdown-item" href="<?= App\Config::route('billing/invoices/list.php') ?>"> Illustrations </a>
|
||||
<a class="dropdown-item" href="<?= App\Config::route('billing/invoices/list.php') ?>"> Payment providers </a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#navbar-addons"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/plus -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M12 5l0 14" />
|
||||
<path d="M5 12l14 0" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="nav-link-title"> მხარდაჭერა </span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="./icons.html"> Icons </a>
|
||||
<a class="dropdown-item" href="./emails.html"> Emails </a>
|
||||
<a class="dropdown-item" href="./flags.html"> Flags </a>
|
||||
<a class="dropdown-item" href="./illustrations.html"> Illustrations </a>
|
||||
<a class="dropdown-item" href="./payment-providers.html"> Payment providers </a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="nav-item dropdown">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#navbar-addons"
|
||||
data-bs-toggle="dropdown"
|
||||
data-bs-auto-close="outside"
|
||||
role="button"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<span class="nav-link-icon d-md-none d-lg-inline-block">
|
||||
<!-- Download SVG icon from http://tabler.io/icons/icon/plus -->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="icon icon-1"
|
||||
>
|
||||
<path d="M12 5l0 14" />
|
||||
<path d="M5 12l14 0" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="nav-link-title"> ელ-ფოსტები </span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="<?= App\Config::route('broadcast.php') ?>"> ელ.ფოსტის გაგზავნა </a>
|
||||
<a class="dropdown-item" href="<?= App\Config::route('email_logs_list.php') ?>"> გაგზავნილები </a>
|
||||
<a class="dropdown-item" href="./flags.html"> Flags </a>
|
||||
<a class="dropdown-item" href="./illustrations.html"> Illustrations </a>
|
||||
<a class="dropdown-item" href="./payment-providers.html"> Payment providers </a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,5 @@
|
||||
<!-- BEGIN PAGE BODY -->
|
||||
<div class="page-body">
|
||||
<div class="container-xl mt-4">
|
||||
|
||||
<!-- CONTENT START -->
|
||||
@@ -0,0 +1,11 @@
|
||||
<!-- BEGIN PAGE HEADER -->
|
||||
<div class="page-header d-print-none text-white">
|
||||
<div class="container-xl">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col">
|
||||
<h2 class="page-title">Empty page</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END PAGE HEADER -->
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
// მოდული, ქვე-მოდული და მოქმედება
|
||||
$module = preg_replace('/[^a-zA-Z0-9_]/', '', $_GET['module'] ?? 'dashboard');
|
||||
$submodule = preg_replace('/[^a-zA-Z0-9_]/', '', $_GET['submodule'] ?? '');
|
||||
$action = preg_replace('/[^a-zA-Z0-9_]/', '', $_GET['action'] ?? 'index');
|
||||
$subaction = preg_replace('/[^a-zA-Z0-9_]/', '', $_GET['subaction'] ?? '');
|
||||
|
||||
// სპეციალური ლოგიკა განსაკუთრებული routes-ისთვის
|
||||
if ($module === 'product' && $action === 'types') {
|
||||
$controller_file = __DIR__ . '/../modules/product/controllers/product_types.php';
|
||||
} elseif ($module === 'users' && $action === 'management') {
|
||||
$controller_file = __DIR__ . '/../modules/users/controllers/users_management.php';
|
||||
} else {
|
||||
// ფაილის ლოკაცია – controllers-ში
|
||||
$controller_file = __DIR__ . '/../modules/' . $module . '/controllers/';
|
||||
$controller_file .= $submodule ? $submodule . '/' : '';
|
||||
$controller_file .= $action . '.php';
|
||||
}
|
||||
|
||||
// თუ controller არ არსებობს, აჩვენე 404
|
||||
if (file_exists($controller_file)) {
|
||||
require_once $controller_file;
|
||||
} else {
|
||||
echo "404 - ფაილი ვერ მოიძებნა: " . $controller_file;
|
||||
}
|
||||
Reference in New Issue
Block a user