gitea init

This commit is contained in:
skryper
2025-10-08 21:28:30 +04:00
commit d4651a423d
2518 changed files with 522832 additions and 0 deletions
@@ -0,0 +1,16 @@
<?php
// controllers/create.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
require_once __DIR__ . '/../../../../vendor/autoload.php';
// ბაზის კავშირის გადაცემა მოდელს
ProductModel::setDb($pdo);
// (დროებით არ გვჭირდება dropdown-ებისთვის ცალკე მონაცემები, მაგრამ თუ დაგჭირდება შემიძლია დავამატო)
// გადადი ფორმის ვიუ გვერდზე
require_once __DIR__ . '/../views/create.php';
@@ -0,0 +1,17 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
ProductModel::setDb($pdo);
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
$id = (int) $_GET['id'];
ProductModel::deleteProductById($id);
}
header("Location: dashboard.php?module=product&action=list&deleted=1");
exit;
@@ -0,0 +1,27 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
require_once __DIR__ . '/../../../../vendor/autoload.php';
ProductModel::setDb($pdo);
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
echo "<div class='container-xl mt-4'><div class='alert alert-danger'>ID არ არის სწორი.</div></div>";
exit;
}
$id = (int) $_GET['id'];
$product = ProductModel::getProductById($id);
if (!$product) {
echo "<div class='container-xl mt-4'><div class='alert alert-danger'>პროდუქტი ვერ მოიძებნა.</div></div>";
exit;
}
$tab = $_GET['tab'] ?? 'details';
require_once __DIR__ . '/../views/edit.php';
@@ -0,0 +1,5 @@
<?php
// Product index controller - redirects to list
header("Location: dashboard.php?module=product&action=list");
exit;
?>
@@ -0,0 +1,16 @@
<?php
// controllers/list.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
require_once __DIR__ . '/../../../../vendor/autoload.php';
ProductModel::setDb($pdo);
$products = ProductModel::getAllProducts();
require_once __DIR__ . '/../views/list.php';
@@ -0,0 +1,124 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/producttypesmodel.php';
ProductTypesModel::setDb($pdo);
$message = '';
$messageType = '';
$action = $_GET['subaction'] ?? 'list';
// POST მოთხოვნების მართვა
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$postAction = $_POST['action'] ?? '';
switch ($postAction) {
case 'add':
$data = [
'name' => trim($_POST['name'] ?? ''),
'description' => trim($_POST['description'] ?? ''),
'icon' => $_POST['icon'] ?? 'box',
'sort_order' => (int)($_POST['sort_order'] ?? 0),
'is_active' => isset($_POST['is_active']) ? 1 : 0
];
if (empty($data['name'])) {
$message = 'პროდუქტის ტიპის სახელი სავალდებულოა';
$messageType = 'danger';
} else {
try {
ProductTypesModel::addType($data);
$message = 'პროდუქტის ტიპი წარმატებით დაემატა';
$messageType = 'success';
$action = 'list';
} catch (Exception $e) {
$message = 'შეცდომა: ' . $e->getMessage();
$messageType = 'danger';
}
}
break;
case 'edit':
$id = (int)($_POST['id'] ?? 0);
$data = [
'name' => trim($_POST['name'] ?? ''),
'description' => trim($_POST['description'] ?? ''),
'icon' => $_POST['icon'] ?? 'box',
'sort_order' => (int)($_POST['sort_order'] ?? 0),
'is_active' => isset($_POST['is_active']) ? 1 : 0
];
if (empty($data['name']) || $id <= 0) {
$message = 'არასწორი მონაცემები';
$messageType = 'danger';
} else {
try {
ProductTypesModel::updateType($id, $data);
$message = 'პროდუქტის ტიპი წარმატებით განახლდა';
$messageType = 'success';
$action = 'list';
} catch (Exception $e) {
$message = 'შეცდომა: ' . $e->getMessage();
$messageType = 'danger';
}
}
break;
case 'delete':
$id = (int)($_POST['id'] ?? 0);
if ($id > 0) {
try {
ProductTypesModel::deleteType($id);
$message = 'პროდუქტის ტიპი წარმატებით წაიშალა';
$messageType = 'success';
} catch (Exception $e) {
$message = 'შეცდომა: ' . $e->getMessage();
$messageType = 'danger';
}
}
$action = 'list';
break;
case 'update_order':
$orders = $_POST['orders'] ?? [];
try {
ProductTypesModel::updateSortOrder($orders);
$message = 'რიგითობა წარმატებით განახლდა';
$messageType = 'success';
} catch (Exception $e) {
$message = 'შეცდომა: ' . $e->getMessage();
$messageType = 'danger';
}
$action = 'list';
break;
}
}
// მონაცემების მომზადება view-სთვის
switch ($action) {
case 'add':
case 'edit':
$availableIcons = ProductTypesModel::getAvailableIcons();
if ($action === 'edit') {
$editId = (int)($_GET['id'] ?? 0);
$editType = ProductTypesModel::getTypeById($editId);
if (!$editType) {
$message = 'პროდუქტის ტიპი ვერ მოიძებნა';
$messageType = 'danger';
$action = 'list';
}
}
break;
case 'list':
default:
$productTypes = ProductTypesModel::getAllTypes();
break;
}
require_once __DIR__ . '/../views/product_types.php';
?>
@@ -0,0 +1,33 @@
<?php
// controllers/save.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
ProductModel::setDb($pdo);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$product = [
'name' => trim($_POST['name']),
'group' => trim($_POST['group']),
'type' => trim($_POST['type']),
'url' => trim($_POST['url']),
'module' => trim($_POST['module']),
'hidden' => isset($_POST['hidden']) ? 1 : 0
];
$success = ProductModel::createProduct($product);
if ($success) {
header("Location: dashboard.php?module=product&action=list&added=1");
} else {
header("Location: dashboard.php?module=product&action=create&error=1");
}
exit;
}
header("Location: dashboard.php?module=product&action=create");
exit;
@@ -0,0 +1,38 @@
<?php
// modules/product/controllers/update.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
ProductModel::setDb($pdo);
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['id'])) {
$id = (int) $_POST['id'];
$data = [
'name' => trim($_POST['name']),
'group' => trim($_POST['group']),
'type' => trim($_POST['type']),
'url' => trim($_POST['url']),
'module' => trim($_POST['module']),
'hidden' => isset($_POST['hidden']) ? 1 : 0,
];
$success = ProductModel::updateProduct($id, $data);
if ($success) {
header("Location: dashboard.php?module=product&action=edit&id=$id&updated=1");
} else {
header("Location: dashboard.php?module=product&action=edit&id=$id&updated=0");
}
exit;
} else {
header("Location: dashboard.php?module=product&action=list");
exit;
}
@@ -0,0 +1,80 @@
<?php
class ProductModel
{
private static $db;
public static function setDb($pdo)
{
self::$db = $pdo;
}
/**
* პროდუქტის ტიპების მიღება (dynamic)
*/
public static function getProductTypes()
{
$stmt = self::$db->query("SELECT name, description, icon FROM product_types WHERE is_active = 1 ORDER BY sort_order, name");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
public static function deleteProductById($id)
{
if (!$id || !is_numeric($id)) {
return false;
}
$stmt = self::$db->prepare("DELETE FROM products WHERE id = ?");
return $stmt->execute([$id]);
}
public static function getProductById($id)
{
if (!$id || !is_numeric($id)) {
return null;
}
$stmt = self::$db->prepare("SELECT * FROM products WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch();
}
public static function getAllProducts()
{
$stmt = self::$db->query("SELECT * FROM products ORDER BY id DESC");
return $stmt->fetchAll();
}
public static function createProduct($data)
{
$stmt = self::$db->prepare("INSERT INTO products (name, `group`, type, url, module, hidden) VALUES (?, ?, ?, ?, ?, ?)");
return $stmt->execute([
$data['name'],
$data['group'],
$data['type'],
$data['url'],
$data['module'],
$data['hidden']
]);
}
public static function updateProduct($id, $data)
{
$stmt = self::$db->prepare("
UPDATE products
SET name = ?, `group` = ?, type = ?, url = ?, module = ?, hidden = ?, updated_at = NOW()
WHERE id = ?
");
return $stmt->execute([
$data['name'],
$data['group'],
$data['type'],
$data['url'],
$data['module'],
$data['hidden'],
$id
]);
}
}
@@ -0,0 +1,148 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
class ProductTypesModel
{
protected static $db;
public static function setDb($pdo)
{
self::$db = $pdo;
}
/**
* ყველა აქტიური product type-ის მიღება
*/
public static function getActiveTypes()
{
$stmt = self::$db->query("SELECT * FROM product_types WHERE is_active = 1 ORDER BY sort_order, name");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* ყველა product type-ის მიღება (ადმინისთვის)
*/
public static function getAllTypes()
{
$stmt = self::$db->query("SELECT * FROM product_types ORDER BY sort_order, name");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
/**
* კონკრეტული product type-ის მიღება
*/
public static function getTypeById($id)
{
$stmt = self::$db->prepare("SELECT * FROM product_types WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
/**
* ახალი product type-ის დამატება
*/
public static function addType($data)
{
$stmt = self::$db->prepare("
INSERT INTO product_types (name, description, icon, sort_order, is_active)
VALUES (?, ?, ?, ?, ?)
");
return $stmt->execute([
$data['name'],
$data['description'] ?? '',
$data['icon'] ?? 'box',
$data['sort_order'] ?? 0,
$data['is_active'] ?? 1
]);
}
/**
* Product type-ის განახლება
*/
public static function updateType($id, $data)
{
$stmt = self::$db->prepare("
UPDATE product_types
SET name = ?, description = ?, icon = ?, sort_order = ?, is_active = ?, updated_at = NOW()
WHERE id = ?
");
return $stmt->execute([
$data['name'],
$data['description'] ?? '',
$data['icon'] ?? 'box',
$data['sort_order'] ?? 0,
$data['is_active'] ?? 1,
$id
]);
}
/**
* Product type-ის წაშლა
*/
public static function deleteType($id)
{
// ვამოწმებთ არ არის თუ არა გამოყენებული პროდუქტებში
$stmt = self::$db->prepare("SELECT COUNT(*) FROM products WHERE type = (SELECT name FROM product_types WHERE id = ?)");
$stmt->execute([$id]);
$count = $stmt->fetchColumn();
if ($count > 0) {
throw new Exception("ამ ტიპის პროდუქტები უკვე არსებობს. წაშლა შეუძლებელია.");
}
$stmt = self::$db->prepare("DELETE FROM product_types WHERE id = ?");
return $stmt->execute([$id]);
}
/**
* Sort order-ის განახლება
*/
public static function updateSortOrder($orders)
{
try {
self::$db->beginTransaction();
$stmt = self::$db->prepare("UPDATE product_types SET sort_order = ? WHERE id = ?");
foreach ($orders as $id => $order) {
$stmt->execute([$order, $id]);
}
self::$db->commit();
return true;
} catch (Exception $e) {
self::$db->rollback();
throw $e;
}
}
/**
* ხელმისაწვდომი აიკონების სია
*/
public static function getAvailableIcons()
{
return [
'server' => 'სერვერი',
'server-2' => 'VPS/Dedicated',
'users' => 'მომხმარებლები',
'world' => 'დომენი',
'shield-check' => 'უსაფრთხოება',
'mail' => 'ელ.ფოსტა',
'cloud' => 'ღრუბელი',
'database' => 'ბაზა',
'box' => 'პაკეტი',
'gift' => 'საჩუქარი',
'star' => 'პრემიუმი',
'lightning' => 'სწრაფი',
'globe' => 'გლობალური',
'lock' => 'დაცული',
'dots' => 'სხვა'
];
}
}
?>
+82
View File
@@ -0,0 +1,82 @@
<div class="container-xl mt-4">
<h2 class="mb-4">პროდუქტის რედაქტირება: <?= htmlspecialchars($product['name']) ?></h2>
<div class="tab-content pt-3">
<div class="tab-pane active" id="details">
<form method="POST" action="dashboard.php?module=product&action=update">
<input type="hidden" name="id" value="<?= $product['id'] ?>">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Product Type</label>
<input type="text" name="type" class="form-control" value="<?= htmlspecialchars($product['type']) ?>">
</div>
<div class="mb-3">
<label class="form-label">Product Group</label>
<input type="text" name="group" class="form-control" value="<?= htmlspecialchars($product['group']) ?>">
</div>
<div class="mb-3">
<label class="form-label">Product Name</label>
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($product['name']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Product Tagline</label>
<input type="text" name="tagline" class="form-control" value="<?= htmlspecialchars($product['tagline'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label">URL</label>
<input type="text" name="url" class="form-control" value="<?= htmlspecialchars($product['url']) ?>">
</div>
<div class="mb-3">
<label class="form-label">Short Description</label>
<textarea name="short_description" class="form-control"><?= htmlspecialchars($product['short_description'] ?? '') ?></textarea>
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea name="description" class="form-control" rows="4"><?= htmlspecialchars($product['description'] ?? '') ?></textarea>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Product Color</label>
<input type="color" name="color" class="form-control form-control-color" value="<?= htmlspecialchars($product['color'] ?? '#ffffff') ?>">
</div>
<div class="mb-3">
<label class="form-label">Welcome Email</label>
<input type="text" name="welcome_email" class="form-control" value="<?= htmlspecialchars($product['welcome_email'] ?? '') ?>">
</div>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" name="require_domain" value="1" id="requireDomain" <?= !empty($product['require_domain']) ? 'checked' : '' ?>>
<label class="form-check-label" for="requireDomain">Check to show domain registration options</label>
</div>
<div class="mb-3">
<label class="form-label">Stock Quantity</label>
<input type="number" name="stock_quantity" class="form-control" value="<?= htmlspecialchars($product['stock_quantity'] ?? 0) ?>">
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="apply_tax" value="1" id="applyTax" <?= !empty($product['apply_tax']) ? 'checked' : '' ?>>
<label class="form-check-label" for="applyTax">Check to charge tax for this product</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="featured" value="1" id="featured" <?= !empty($product['featured']) ? 'checked' : '' ?>>
<label class="form-check-label" for="featured">Display this product more prominently</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="hidden" value="1" id="hiddenSwitch" <?= !empty($product['hidden']) ? 'checked' : '' ?>>
<label class="form-check-label" for="hiddenSwitch">Check to hide from order form</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="retired" value="1" id="retired" <?= !empty($product['retired']) ? 'checked' : '' ?>>
<label class="form-check-label" for="retired">Check to hide from dropdown menus</label>
</div>
</div>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">შენახვა</button>
<a href="dashboard.php?module=product&action=list" class="btn btn-secondary">უკან</a>
</div>
</form>
</div>
+62
View File
@@ -0,0 +1,62 @@
<?php
$pageTitle = "პროდუქტის რედაქტირება";
$tab = $_GET['tab'] ?? 'details';
include '../../layout/header.php';
?>
<div class="page-body">
<div class="container-xl">
<div class="card">
<div class="card-body">
<?php if ($tab === 'details') : ?>
<?php include 'tabs/details.php'; ?>
<?php elseif ($tab === 'pricing') : ?>
<h3>Pricing</h3>
<form>
<div class="mb-3">
<label class="form-label">Payment Type</label>
<div>
<label class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="payment_type" value="free"> Free
</label>
<label class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="payment_type" value="onetime"> One Time
</label>
<label class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="payment_type" value="recurring" checked> Recurring
</label>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>Currency</th>
<th>Setup Fee</th>
<th>Price</th>
<th>Enable</th>
</tr>
</thead>
<tbody>
<tr>
<td>GEL</td>
<td><input type="text" class="form-control" value="0.00"></td>
<td><input type="text" class="form-control" value="70.00"></td>
<td><input type="checkbox" checked></td>
</tr>
<tr>
<td>USD</td>
<td><input type="text" class="form-control" value="0.00"></td>
<td><input type="text" class="form-control" value="29.00"></td>
<td><input type="checkbox" checked></td>
</tr>
</tbody>
</table>
</div>
</form>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php include '../../layout/footer.php'; ?>
@@ -0,0 +1,45 @@
<?php
require_once __DIR__ . '/includes/init.php';
?>
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use App\Config;
require_once Config::includePath('head.php');
require_once Config::includePath('navbar.php');
require_once Config::includePath('pageheader.php');
require_once Config::includePath('pagebodystart.php');
?>
<?php
require 'db.php';
$action = $_GET['action'] ?? 'list';
$id = $_GET['id'] ?? null;
switch ($action) {
case 'create':
include __DIR__ . '/product/create.php';
break;
case 'edit':
if ($id) {
include __DIR__ . '/product/edit.php';
} else {
echo "<div class='container-xl mt-4'><div class='alert alert-danger'>ID ვერ მოიძებნა.</div></div>";
}
break;
case 'list':
default:
include __DIR__ . '/product/list.php';
break;
}
?>
<?php require_once Config::includePath('footer.php'); ?>
+122
View File
@@ -0,0 +1,122 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
use App\Config;
// Product types-ების მიღება
ProductModel::setDb($pdo);
$productTypes = ProductModel::getProductTypes();
?>
<?php require_once Config::includePath('head.php'); ?>
<?php require_once Config::includePath('navbar.php'); ?>
<?php require_once Config::includePath('pageheader.php'); ?>
<?php require_once Config::includePath('pagebodystart.php'); ?>
<div class="container-xl mt-4">
<h2 class="mb-4">ახალი პროდუქტის დამატება</h2>
<form method="POST" action="dashboard.php?module=product&action=save">
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">Product Type</label>
<div class="row">
<div class="col">
<select name="type" class="form-select" id="product-type-select" required>
<option value="">აირჩიეთ ტიპი...</option>
<?php foreach ($productTypes as $type): ?>
<option value="<?= htmlspecialchars($type['name']) ?>" data-icon="<?= htmlspecialchars($type['icon']) ?>">
<?= htmlspecialchars($type['name']) ?>
<?php if ($type['description']): ?>
- <?= htmlspecialchars($type['description']) ?>
<?php endif; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-auto">
<a href="dashboard.php?module=product&action=types" class="btn btn-outline-secondary" title="ტიპების მართვა">
<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">
<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.37.996.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>
მართვა
</a>
</div>
</div>
<div class="mt-2" id="type-preview" style="display: none;">
<div class="d-flex align-items-center text-muted">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon me-2" id="type-icon">
</svg>
<span id="type-description"></span>
</div>
</div>
</div>
<div class="mb-3">
<label class="form-label">Product Group</label>
<input type="text" name="group" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">დასახელება</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">URL</label>
<input type="text" name="url" class="form-control">
</div>
<div class="mb-3">
<label class="form-label">მოდული</label>
<input type="text" name="module" class="form-control">
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="hidden" value="1" id="hiddenSwitch">
<label class="form-check-label" for="hiddenSwitch">შექმნა დამალულად</label>
</div>
</div>
</div>
<div class="form-footer mt-3">
<button type="submit" class="btn btn-primary">შენახვა</button>
<a href="dashboard.php?module=product&action=list" class="btn btn-secondary">გაუქმება</a>
</div>
</form>
</div>
<script>
// Product type selection preview
document.addEventListener('DOMContentLoaded', function() {
const typeSelect = document.getElementById('product-type-select');
const typePreview = document.getElementById('type-preview');
const typeIcon = document.getElementById('type-icon');
const typeDescription = document.getElementById('type-description');
typeSelect.addEventListener('change', function() {
const selectedOption = this.options[this.selectedIndex];
if (this.value) {
const iconName = selectedOption.getAttribute('data-icon') || 'box';
const description = selectedOption.text.split(' - ')[1] || '';
// Update icon
typeIcon.className = `icon me-2 icon-tabler icons-tabler-outline icon-tabler-${iconName}`;
// Update description
if (description) {
typeDescription.textContent = description;
typePreview.style.display = 'block';
} else {
typePreview.style.display = 'none';
}
} else {
typePreview.style.display = 'none';
}
});
});
</script>
<?php require_once Config::includePath('footer.php'); ?>
+33
View File
@@ -0,0 +1,33 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
use App\Config;
?>
<?php require_once Config::includePath('head.php'); ?>
<?php require_once Config::includePath('navbar.php'); ?>
<?php require_once Config::includePath('pageheader.php'); ?>
<?php require_once Config::includePath('pagebodystart.php'); ?>
<div class="tab-content mt-4">
<?php
$allowedTabs = ['details', 'pricing'];
if (!in_array($tab, $allowedTabs)) {
$tab = 'details';
}
$tabPath = __DIR__ . '/../tabs/' . $tab . '.php';
if (file_exists($tabPath)) {
include $tabPath;
} else {
echo "<div class='alert alert-danger'>ტაბის ფაილი ვერ მოიძებნა.</div>";
}
?>
</div>
+75
View File
@@ -0,0 +1,75 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../models/productmodels.php';
use App\Config;
?>
<?php require_once Config::includePath('head.php'); ?>
<?php require_once Config::includePath('navbar.php'); ?>
<?php require_once Config::includePath('pageheader.php'); ?>
<?php require_once Config::includePath('pagebodystart.php'); ?>
<?php if (isset($_GET['added']) && $_GET['added'] == 1): ?>
<div class="alert alert-success">პროდუქტი წარმატებით დაემატა.</div>
<?php endif; ?>
<div class="container-xl mt-4">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2>პროდუქტები და სერვისები</h2>
<div class="btn-list">
<a href="dashboard.php?module=product&action=types" class="btn btn-outline-secondary">
<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">
<rect x="3" y="3" width="7" height="7"/>
<rect x="14" y="3" width="7" height="7"/>
<rect x="14" y="14" width="7" height="7"/>
<rect x="3" y="14" width="7" height="7"/>
</svg>
ტიპების მართვა
</a>
<a href="dashboard.php?module=product&action=create" class="btn btn-primary">
<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">
<path d="M12 5l0 14"/>
<path d="M5 12l14 0"/>
</svg>
ახალი პროდუქტი
</a>
</div>
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Product Name</th>
<th>Group</th>
<th>Type</th>
<th>Pay Type</th>
<th>Auto Setup</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($products as $product): ?>
<tr>
<td><?= htmlspecialchars($product['id'] ?? '') ?></td>
<td><?= htmlspecialchars($product['name'] ?? '') ?></td>
<td><?= htmlspecialchars($product['group'] ?? '') ?></td>
<td><?= htmlspecialchars($product['type'] ?? '') ?></td>
<td><?= htmlspecialchars($product['pay_type'] ?? '') ?></td>
<td><?= htmlspecialchars($product['auto_setup'] ?? '') ?></td>
<td>
<a href="dashboard.php?module=product&action=edit&id=<?= $product['id'] ?>" class="btn btn-sm btn-warning">რედ.</a>
<a href="dashboard.php?module=product&action=delete&id=<?= $product['id'] ?>" class="btn btn-sm btn-danger" onclick="return confirm('წაშლა?');">წაშლა</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php require_once Config::includePath('footer.php'); ?>
@@ -0,0 +1,313 @@
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/../../../includes/init.php';
require_once __DIR__ . '/../../../../vendor/autoload.php';
use App\Config;
?>
<?php require_once Config::includePath('head.php'); ?>
<?php require_once Config::includePath('navbar.php'); ?>
<?php require_once Config::includePath('pageheader.php'); ?>
<?php require_once Config::includePath('pagebodystart.php'); ?>
<div class="container-xl mt-4">
<!-- Page header -->
<div class="page-header d-print-none">
<div class="row align-items-center">
<div class="col">
<h2 class="page-title">პროდუქტის ტიპების მართვა</h2>
<div class="text-muted mt-1">პროდუქტების კატეგორიების კონფიგურაცია</div>
</div>
<div class="col-auto">
<div class="btn-list">
<?php if ($action === 'list'): ?>
<a href="dashboard.php?module=product&action=types&subaction=add" class="btn btn-primary">
<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 5l0 14"/>
<path d="M5 12l14 0"/>
</svg>
ახალი ტიპი
</a>
<?php endif; ?>
<a href="dashboard.php?module=product&action=list" class="btn btn-outline-primary">
<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 12l14 0"/>
<path d="M5 12l6 6"/>
<path d="M5 12l6 -6"/>
</svg>
უკან დაბრუნება
</a>
</div>
</div>
</div>
</div>
<!-- Messages -->
<?php if ($message): ?>
<div class="alert alert-<?= $messageType ?> alert-dismissible">
<div class="d-flex">
<div><?= htmlspecialchars($message) ?></div>
</div>
<a class="btn-close" data-bs-dismiss="alert" aria-label="close"></a>
</div>
<?php endif; ?>
<?php if ($action === 'list'): ?>
<!-- Product Types List -->
<div class="card">
<div class="card-header">
<h3 class="card-title">პროდუქტის ტიპები</h3>
<div class="card-actions">
<small class="text-muted">გადაათრიე რიგითობის ცვლილებისთვის</small>
</div>
</div>
<div class="card-body">
<?php if (empty($productTypes)): ?>
<div class="text-center text-muted py-4">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon mb-3">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
<polyline points="3.27,6.96 12,12.01 20.73,6.96"/>
<line x1="12" y1="22.08" x2="12" y2="12"/>
</svg>
<h3>პროდუქტის ტიპები არ არის</h3>
<p class="text-muted">დაამატეთ ახალი პროდუქტის ტიპი</p>
</div>
<?php else: ?>
<div id="sortable-types" class="list-group list-group-flush">
<?php foreach ($productTypes as $type): ?>
<div class="list-group-item" data-id="<?= $type['id'] ?>">
<div class="row align-items-center">
<div class="col-auto">
<span class="handle cursor-move">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon text-muted">
<line x1="8" y1="6" x2="21" y2="6"/>
<line x1="8" y1="12" x2="21" y2="12"/>
<line x1="8" y1="18" x2="21" y2="18"/>
<line x1="3" y1="6" x2="3.01" y2="6"/>
<line x1="3" y1="12" x2="3.01" y2="12"/>
<line x1="3" y1="18" x2="3.01" y2="18"/>
</svg>
</span>
</div>
<div class="col-auto">
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" 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-<?= htmlspecialchars($type['icon']) ?>">
<!-- Icon will be rendered by Tabler -->
</svg>
</div>
<div class="col">
<div class="d-flex align-items-center">
<strong><?= htmlspecialchars($type['name']) ?></strong>
<?php if (!$type['is_active']): ?>
<span class="badge bg-secondary ms-2">უაქტივო</span>
<?php endif; ?>
</div>
<?php if ($type['description']): ?>
<div class="text-muted small"><?= htmlspecialchars($type['description']) ?></div>
<?php endif; ?>
<small class="text-muted">რიგითობა: <?= $type['sort_order'] ?></small>
</div>
<div class="col-auto">
<div class="btn-list">
<a href="dashboard.php?module=product&action=types&subaction=edit&id=<?= $type['id'] ?>" class="btn btn-sm btn-outline-primary">
<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">
<path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"/>
<path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z"/>
<path d="M16 5l3 3"/>
</svg>
რედაქტირება
</a>
<form method="post" style="display: inline;">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" value="<?= $type['id'] ?>">
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('დარწმუნებული ხართ რომ გსურთ ამ ტიპის წაშლა?')">
<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">
<path d="M4 7l16 0"/>
<path d="M10 11l0 6"/>
<path d="M14 11l0 6"/>
<path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"/>
<path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"/>
</svg>
წაშლა
</button>
</form>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<form id="sort-form" method="post" style="display: none;">
<input type="hidden" name="action" value="update_order">
<div id="sort-orders"></div>
</form>
<?php endif; ?>
</div>
</div>
<?php elseif ($action === 'add' || $action === 'edit'): ?>
<!-- Add/Edit Form -->
<div class="card">
<div class="card-header">
<h3 class="card-title">
<?= $action === 'add' ? 'ახალი პროდუქტის ტიპი' : 'პროდუქტის ტიპის რედაქტირება' ?>
</h3>
</div>
<div class="card-body">
<form method="post">
<input type="hidden" name="action" value="<?= $action ?>">
<?php if ($action === 'edit'): ?>
<input type="hidden" name="id" value="<?= $editType['id'] ?>">
<?php endif; ?>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">ტიპის სახელი</label>
<input type="text" name="name" class="form-control"
value="<?= htmlspecialchars($editType['name'] ?? '') ?>"
placeholder="მაგ: Shared Hosting" required>
</div>
<div class="mb-3">
<label class="form-label">აღწერა</label>
<textarea name="description" class="form-control" rows="3"
placeholder="ტიპის დეტალური აღწერა"><?= htmlspecialchars($editType['description'] ?? '') ?></textarea>
</div>
<div class="mb-3">
<label class="form-label">რიგითობა</label>
<input type="number" name="sort_order" class="form-control"
value="<?= $editType['sort_order'] ?? '0' ?>"
placeholder="0">
<small class="form-hint">უფრო პატარა რიცხვი = უფრო ზევით</small>
</div>
<div class="form-check form-switch mb-3">
<input class="form-check-input" type="checkbox" name="is_active"
<?= ($editType['is_active'] ?? 1) ? 'checked' : '' ?>>
<label class="form-check-label">აქტიური</label>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="form-label">აიკონი</label>
<select name="icon" class="form-select" id="icon-select">
<?php foreach ($availableIcons as $iconName => $iconLabel): ?>
<option value="<?= $iconName ?>"
<?= ($editType['icon'] ?? 'box') === $iconName ? 'selected' : '' ?>>
<?= $iconLabel ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">აიკონის გადახედვა</label>
<div class="icon-preview p-4 border rounded text-center">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" 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" id="preview-icon">
<!-- Icon preview -->
</svg>
<div class="mt-2 text-muted" id="preview-text">აიკონის გადახედვა</div>
</div>
</div>
</div>
</div>
<div class="card-actions">
<button type="submit" class="btn btn-primary">
<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">
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
<polyline points="17,21 17,13 7,13 7,21"/>
<polyline points="7,3 7,8 15,8"/>
</svg>
შენახვა
</button>
<a href="dashboard.php?module=product&action=types" class="btn btn-secondary">გაუქმება</a>
</div>
</form>
</div>
</div>
<?php endif; ?>
</div>
<script src="../dist/js/tabler.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Sortable functionality
const sortableEl = document.getElementById('sortable-types');
if (sortableEl) {
const sortable = Sortable.create(sortableEl, {
handle: '.handle',
animation: 150,
onEnd: function() {
const items = sortableEl.querySelectorAll('.list-group-item');
const orders = {};
items.forEach((item, index) => {
const id = item.getAttribute('data-id');
orders[id] = index + 1;
});
// Update hidden form
const sortOrdersDiv = document.getElementById('sort-orders');
sortOrdersDiv.innerHTML = '';
Object.keys(orders).forEach(id => {
const input = document.createElement('input');
input.type = 'hidden';
input.name = `orders[${id}]`;
input.value = orders[id];
sortOrdersDiv.appendChild(input);
});
// Submit form
document.getElementById('sort-form').submit();
}
});
}
// Icon preview
const iconSelect = document.getElementById('icon-select');
const previewIcon = document.getElementById('preview-icon');
const previewText = document.getElementById('preview-text');
if (iconSelect && previewIcon) {
function updateIconPreview() {
const selectedIcon = iconSelect.value;
const selectedText = iconSelect.options[iconSelect.selectedIndex].text;
// Update icon class
previewIcon.className = `icon icon-tabler icons-tabler-outline icon-tabler-${selectedIcon}`;
previewText.textContent = selectedText;
}
// Initialize preview
updateIconPreview();
// Update on change
iconSelect.addEventListener('change', updateIconPreview);
}
// Form validation
const form = document.querySelector('form[method="post"]');
if (form && form.querySelector('input[name="name"]')) {
form.addEventListener('submit', function(e) {
const nameInput = form.querySelector('input[name="name"]');
if (!nameInput.value.trim()) {
alert('ტიპის სახელი სავალდებულოა');
e.preventDefault();
nameInput.focus();
return false;
}
});
}
});
</script>
<?php require_once Config::includePath('footer.php'); ?>