| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- <?php
- // Αρχείο: /var/www/html/hockey-cms/admin/categories.php
- require_once 'admin_auth.php';
- require_once '../config/database.php';
- // --- Μηχανισμός Αλλαγής Γλώσσας ---
- if (isset($_GET['lang']) && in_array($_GET['lang'], ['el', 'en'])) {
- $_SESSION['lang'] = $_GET['lang'];
- }
- $current_lang = $_SESSION['lang'] ?? 'el';
- $translations = [
- 'el' => [
- 'manage_cats' => 'Διαχείριση Κατηγοριών',
- 'edit_cat' => '✏️ Επεξεργασία Κατηγορίας',
- 'add_cat' => '📁 Προσθήκη Νέας Κατηγορίας',
- 'name_el' => 'Όνομα 🇬🇷 (Ελληνικά) *',
- 'name_en' => 'Όνομα 🇬🇧 (Αγγλικά)',
- 'parent_cat' => 'Ανήκει σε... (Προαιρετικό)',
- 'is_main' => '-- Είναι Κεντρική Κατηγορία --',
- 'attr_group' => 'Ομάδα Χαρακτηριστικών',
- 'no_attr' => '-- Χωρίς Ειδικά Χαρακτηριστικά --',
- 'btn_save' => 'Αποθήκευση Αλλαγών',
- 'btn_add' => 'Προσθήκη Κατηγορίας',
- 'btn_cancel' => 'Ακύρωση',
- 'tree_title' => 'Δέντρο Κατηγοριών (Treeview)',
- 'no_cats' => 'Δεν υπάρχουν κατηγορίες ακόμα.',
- 'msg_add_ok' => 'Η κατηγορία προστέθηκε επιτυχώς!',
- 'msg_edit_ok' => 'Η κατηγορία ενημερώθηκε επιτυχώς!',
- 'msg_err_name' => 'Το Ελληνικό όνομα είναι υποχρεωτικό.',
- 'msg_err_slug' => 'Σφάλμα: (Μήπως το URL/Slug υπάρχει ήδη;)',
- 'msg_del_ok' => 'Η κατηγορία διεγράφη επιτυχώς!',
- 'msg_err_prod' => 'Αδυναμία διαγραφής! Υπάρχουν προϊόντα σε αυτή την κατηγορία.',
- 'msg_err_child' => 'Αδυναμία διαγραφής! Υπάρχουν υποκατηγορίες μέσα σε αυτή την κατηγορία.',
- 'confirm_del' => 'Είστε σίγουρος ότι θέλετε να διαγράψετε αυτή την κατηγορία;'
- ],
- 'en' => [
- 'manage_cats' => 'Manage Categories',
- 'edit_cat' => '✏️ Edit Category',
- 'add_cat' => '📁 Add New Category',
- 'name_el' => 'Name 🇬🇷 (Greek) *',
- 'name_en' => 'Name 🇬🇧 (English)',
- 'parent_cat' => 'Belongs to... (Optional)',
- 'is_main' => '-- Is Main Category --',
- 'attr_group' => 'Attribute Group',
- 'no_attr' => '-- No Special Attributes --',
- 'btn_save' => 'Save Changes',
- 'btn_add' => 'Add Category',
- 'btn_cancel' => 'Cancel',
- 'tree_title' => 'Category Tree (Treeview)',
- 'no_cats' => 'No categories found.',
- 'msg_add_ok' => 'Category added successfully!',
- 'msg_edit_ok' => 'Category updated successfully!',
- 'msg_err_name' => 'The Greek name is required.',
- 'msg_err_slug' => 'Error: (Maybe the URL/Slug already exists?)',
- 'msg_del_ok' => 'Category deleted successfully!',
- 'msg_err_prod' => 'Cannot delete! There are products in this category.',
- 'msg_err_child' => 'Cannot delete! There are subcategories inside this category.',
- 'confirm_del' => 'Are you sure you want to delete this category?'
- ]
- ];
- $t = $translations[$current_lang];
- header('Content-Type: text/html; charset=utf-8');
- $message = '';
- function createSlug($string) {
- $greek = ['α','ά','Α','Ά','β','Β','γ','Γ','δ','Δ','ε','έ','Ε','Έ','ζ','Ζ','η','ή','Η','Ή','θ','Θ','ι','ί','ϊ','ΐ','Ι','Ί','Ϊ','κ','Κ','λ','Λ','μ','Μ','ν','Ν','ξ','Ξ','ο','ό','Ο','Ό','π','Π','ρ','Ρ','σ','ς','Σ','τ','Τ','υ','ύ','ϋ','ΰ','Υ','Ύ','Ϋ','φ','Φ','χ','Χ','ψ','Ψ','ω','ώ','Ω','Ώ'];
- $latin = ['a','a','a','a','b','b','g','g','d','d','e','e','e','e','z','z','i','i','i','i','th','th','i','i','i','i','i','i','i','k','k','l','l','m','m','n','n','x','x','o','o','o','o','p','p','r','r','s','s','s','t','t','y','y','y','y','y','y','y','f','f','ch','ch','ps','ps','o','o','o','o'];
- $string = str_replace($greek, $latin, $string);
- $string = strtolower(trim($string));
- $string = preg_replace('/[^a-z0-9-]/', '-', $string);
- $string = preg_replace('/-+/', "-", $string);
- return trim($string, '-');
- }
- // Χειρισμός Μετακίνησης
- if (isset($_GET['move']) && isset($_GET['id'])) {
- $move_id = (int)$_GET['id'];
- $direction = $_GET['move'];
- $all = $pdo->query("
- SELECT c1.id
- FROM categories c1
- LEFT JOIN categories c2 ON c1.parent_id = c2.id
- ORDER BY c1.sort_order ASC, c2.name_el ASC, c1.name_el ASC
- ")->fetchAll(PDO::FETCH_ASSOC);
-
- $current_index = -1;
- $seq = 1;
- foreach ($all as $idx => $row) {
- $pdo->prepare("UPDATE categories SET sort_order = ? WHERE id = ?")->execute([$seq, $row['id']]);
- $all[$idx]['sort_order'] = $seq;
- if ($row['id'] == $move_id) { $current_index = $idx; }
- $seq++;
- }
- if ($current_index !== -1) {
- if ($direction === 'up' && $current_index > 0) {
- $prev_id = $all[$current_index - 1]['id'];
- $current_order = $all[$current_index]['sort_order'];
- $prev_order = $all[$current_index - 1]['sort_order'];
-
- $pdo->prepare("UPDATE categories SET sort_order = ? WHERE id = ?")->execute([$prev_order, $move_id]);
- $pdo->prepare("UPDATE categories SET sort_order = ? WHERE id = ?")->execute([$current_order, $prev_id]);
-
- } elseif ($direction === 'down' && $current_index < count($all) - 1) {
- $next_id = $all[$current_index + 1]['id'];
- $current_order = $all[$current_index]['sort_order'];
- $next_order = $all[$current_index + 1]['sort_order'];
-
- $pdo->prepare("UPDATE categories SET sort_order = ? WHERE id = ?")->execute([$next_order, $move_id]);
- $pdo->prepare("UPDATE categories SET sort_order = ? WHERE id = ?")->execute([$current_order, $next_id]);
- }
- }
- header("Location: categories.php");
- exit;
- }
- // Χειρισμός POST
- if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
- $action = $_POST['action'];
- $name_el = trim($_POST['name_el']);
- $name_en = trim($_POST['name_en']);
- $parent_id = !empty($_POST['parent_id']) ? $_POST['parent_id'] : null;
- $attribute_group_id = !empty($_POST['attribute_group_id']) ? (int)$_POST['attribute_group_id'] : null;
- if (!empty($name_el)) {
- $slug_source = !empty($name_en) ? $name_en : $name_el;
- $slug = createSlug($slug_source);
-
- try {
- if ($action == 'add') {
- $stmt = $pdo->prepare("INSERT INTO categories (parent_id, name_el, name_en, slug, attribute_group_id, sort_order) VALUES (?, ?, ?, ?, ?, 999)");
- $stmt->execute([$parent_id, $name_el, $name_en, $slug, $attribute_group_id]);
- $message = "<div class='alert success'>{$t['msg_add_ok']}</div>";
- } elseif ($action == 'edit') {
- $category_id = (int)$_POST['category_id'];
- $stmt = $pdo->prepare("UPDATE categories SET parent_id = ?, name_el = ?, name_en = ?, slug = ?, attribute_group_id = ? WHERE id = ?");
- $stmt->execute([$parent_id, $name_el, $name_en, $slug, $attribute_group_id, $category_id]);
- $message = "<div class='alert success'>{$t['msg_edit_ok']}</div>";
- }
- } catch (PDOException $e) {
- $message = "<div class='alert error'>{$t['msg_err_slug']} " . $e->getMessage() . "</div>";
- }
- } else {
- $message = "<div class='alert error'>{$t['msg_err_name']}</div>";
- }
- }
- // Χειρισμός Διαγραφής
- if (isset($_GET['delete'])) {
- $delete_id = (int)$_GET['delete'];
-
- $checkStmt = $pdo->prepare("SELECT COUNT(*) FROM products WHERE category_id = ?");
- $checkStmt->execute([$delete_id]);
- $hasProducts = $checkStmt->fetchColumn();
- $checkChild = $pdo->prepare("SELECT COUNT(*) FROM categories WHERE parent_id = ?");
- $checkChild->execute([$delete_id]);
- $hasChildren = $checkChild->fetchColumn();
- if ($hasProducts > 0) {
- $message = "<div class='alert error'>{$t['msg_err_prod']}</div>";
- } elseif ($hasChildren > 0) {
- $message = "<div class='alert error'>{$t['msg_err_child']}</div>";
- } else {
- try {
- $stmt = $pdo->prepare("DELETE FROM categories WHERE id = ?");
- $stmt->execute([$delete_id]);
- $message = "<div class='alert success'>{$t['msg_del_ok']}</div>";
- } catch (PDOException $e) {
- $message = "<div class='alert error'>Σφάλμα: " . $e->getMessage() . "</div>";
- }
- }
- }
- $edit_category = null;
- if (isset($_GET['edit'])) {
- $edit_id = (int)$_GET['edit'];
- $editStmt = $pdo->prepare("SELECT * FROM categories WHERE id = ?");
- $editStmt->execute([$edit_id]);
- $edit_category = $editStmt->fetch();
- }
- $stmt = $pdo->query("
- SELECT c1.id, c1.parent_id, c1.name_el, c1.name_en, c1.slug, c1.sort_order, ag.name as group_name
- FROM categories c1
- LEFT JOIN attribute_groups ag ON c1.attribute_group_id = ag.id
- ORDER BY c1.sort_order ASC, c1.name_el ASC
- ");
- $all_categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
- function buildCategoryTree($categories, $parentId = null) {
- $branch = [];
- foreach ($categories as $cat) {
- if ($cat['parent_id'] == $parentId) {
- $children = buildCategoryTree($categories, $cat['id']);
- if ($children) {
- $cat['children'] = $children;
- }
- $branch[] = $cat;
- }
- }
- return $branch;
- }
- $categoryTree = buildCategoryTree($all_categories);
- function renderTreeHTML($tree, $level = 0, $t) {
- $html = '<ul class="' . ($level === 0 ? 'tree-root' : 'tree-branch') . '">';
- foreach ($tree as $node) {
- $padding = $level * 35;
- $html .= '<li class="tree-node">';
- $html .= '<div class="tree-row" style="padding-left: ' . ($padding + 15) . 'px;">';
-
- if ($level > 0) {
- $html .= '<span class="tree-line"></span>';
- }
- $html .= '<div class="tree-arrows">';
- $html .= '<a href="categories.php?move=up&id='.$node['id'].'">▲</a>';
- $html .= '<a href="categories.php?move=down&id='.$node['id'].'">▼</a>';
- $html .= '</div>';
- $html .= '<div class="tree-info">';
- $html .= '<strong>' . htmlspecialchars($node['name_el']) . '</strong>';
- if (!empty($node['name_en'])) {
- $html .= ' <span class="tree-en">(' . htmlspecialchars($node['name_en']) . ')</span>';
- }
- $html .= ' <span class="tree-slug">/' . htmlspecialchars($node['slug']) . '</span>';
- if (!empty($node['group_name'])) {
- $html .= ' <span class="tree-badge">' . htmlspecialchars($node['group_name']) . '</span>';
- }
- $html .= '</div>';
- $html .= '<div class="tree-actions">';
- $html .= '<a href="categories.php?edit='.$node['id'].'" class="action-link action-edit">Edit</a>';
- $html .= '<a href="categories.php?delete='.$node['id'].'" class="action-link action-delete" onclick="return confirm(\''.$t['confirm_del'].'\');">Delete</a>';
- $html .= '</div>';
- $html .= '</div>';
- if (!empty($node['children'])) {
- $html .= renderTreeHTML($node['children'], $level + 1, $t);
- }
- $html .= '</li>';
- }
- $html .= '</ul>';
- return $html;
- }
- $stmtParents = $pdo->query("SELECT id, name_el FROM categories WHERE parent_id IS NULL ORDER BY sort_order ASC, name_el ASC");
- $parentCategories = $stmtParents->fetchAll();
- $attrGroups = $pdo->query("SELECT id, name FROM attribute_groups ORDER BY name")->fetchAll();
- ?>
- <!DOCTYPE html>
- <html lang="<?php echo $current_lang; ?>">
- <head>
- <meta charset="UTF-8">
- <title><?php echo $t['manage_cats']; ?> - Hockey CMS</title>
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
- <style>
- :root {
- --primary: #f97316;
- --primary-hover: #ea580c;
- --bg-color: #0b1120;
- --panel-bg: #1e293b;
- --border-color: #334155;
- --text-main: #f8fafc;
- --text-muted: #94a3b8;
- }
- body { font-family: 'Inter', sans-serif; background-color: var(--bg-color); color: var(--text-main); margin: 0; }
- .content { margin-left: 250px; padding: 30px; }
- .content h2 { margin-top: 0; color: var(--primary); font-size: 26px; text-transform: uppercase; letter-spacing: 0.5px; }
-
- .card { background: var(--panel-bg); padding: 25px; border-radius: 8px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.3); border: 1px solid var(--border-color); margin-bottom: 25px; }
- .card h3 { margin-top: 0; color: var(--text-main); border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 15px; font-size: 18px; text-transform: uppercase; letter-spacing: 0.5px; }
-
- .form-group { margin-bottom: 20px; }
- .form-group label { display: block; margin-bottom: 8px; font-weight: 700; font-size: 13px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.5px;}
- .form-group input, .form-group select { width: 100%; padding: 12px; background: #0f172a; border: 1px solid var(--border-color); color: var(--text-main); border-radius: 6px; box-sizing: border-box; font-family: 'Inter', sans-serif; outline: none; transition: 0.2s; }
- .form-group input:focus, .form-group select:focus { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(249, 115, 22, 0.2); }
-
- .btn { padding: 12px 20px; background: var(--primary); color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: 800; font-size: 14px; text-transform: uppercase; transition: 0.2s; }
- .btn:hover { background: var(--primary-hover); transform: translateY(-1px); }
- .btn-cancel { background: rgba(255,255,255,0.05); color: var(--text-main); padding: 12px 20px; text-decoration: none; border-radius: 6px; display: inline-block; font-weight: 700; border: 1px solid var(--border-color); text-transform: uppercase; transition: 0.2s;}
- .btn-cancel:hover { background: rgba(255,255,255,0.1); }
-
- .alert { padding: 15px; border-radius: 6px; margin-bottom: 20px; font-weight: 600; font-size: 14px;}
- .success { background: rgba(16, 185, 129, 0.1); color: #10b981; border: 1px solid rgba(16, 185, 129, 0.2); }
- .error { background: rgba(239, 68, 68, 0.1); color: #ef4444; border: 1px solid rgba(239, 68, 68, 0.2); }
-
- /* --- DARK TREEVIEW STYLES --- */
- .tree-root { list-style: none; padding: 0; margin: 0; border: 1px solid var(--border-color); border-radius: 6px; overflow: hidden; }
- .tree-branch { list-style: none; padding: 0; margin: 0; }
- .tree-node { border-bottom: 1px solid rgba(255,255,255,0.05); }
- .tree-node:last-child { border-bottom: none; }
-
- .tree-row { display: flex; align-items: center; padding: 15px; background: var(--panel-bg); transition: 0.2s; position: relative; }
- .tree-row:hover { background: rgba(255,255,255,0.02); }
-
- .tree-line { display: inline-block; width: 15px; height: 15px; border-left: 2px solid var(--border-color); border-bottom: 2px solid var(--border-color); margin-right: 15px; margin-top: -10px; }
-
- .tree-arrows { display: flex; flex-direction: column; margin-right: 15px; gap: 3px; }
- .tree-arrows a { text-decoration: none; color: var(--text-muted); font-size: 10px; background: #0f172a; padding: 3px 6px; border-radius: 4px; line-height: 1; border: 1px solid var(--border-color); transition: 0.2s;}
- .tree-arrows a:hover { background: var(--primary); color: white; border-color: var(--primary); }
-
- .tree-info { flex-grow: 1; }
- .tree-info strong { color: var(--text-main); font-size: 15px; }
- .tree-en { color: var(--text-muted); font-size: 13px; font-weight: 500;}
- .tree-slug { color: #3b82f6; font-size: 12px; margin-left: 10px; font-family: monospace;}
- .tree-badge { background: rgba(0,0,0,0.3); color: var(--text-muted); padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 700; margin-left: 10px; border: 1px solid var(--border-color); text-transform: uppercase;}
-
- .tree-actions { flex-shrink: 0; }
- .action-link { padding: 6px 12px; text-decoration: none; border-radius: 4px; font-size: 12px; margin-left: 5px; display: inline-block; font-weight: 700; text-transform: uppercase; transition: 0.2s;}
- .action-edit { background-color: rgba(249, 115, 22, 0.1); color: var(--primary); border: 1px solid rgba(249, 115, 22, 0.2); }
- .action-edit:hover { background-color: var(--primary); color: white; }
- .action-delete { background-color: rgba(239, 68, 68, 0.1); color: #ef4444; border: 1px solid rgba(239, 68, 68, 0.2); }
- .action-delete:hover { background-color: #ef4444; color: white; }
- </style>
- </head>
- <body>
-
- <?php include 'sidebar.php'; ?>
- <div class="content">
- <h2><?php echo $t['manage_cats']; ?></h2>
- <?php echo $message; ?>
- <div class="card">
- <h3><?php echo $edit_category ? $t['edit_cat'] : $t['add_cat']; ?></h3>
- <form method="POST" action="categories.php">
- <input type="hidden" name="action" value="<?php echo $edit_category ? 'edit' : 'add'; ?>">
- <?php if ($edit_category): ?>
- <input type="hidden" name="category_id" value="<?php echo $edit_category['id']; ?>">
- <?php endif; ?>
-
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
- <div class="form-group">
- <label><?php echo $t['name_el']; ?></label>
- <input type="text" name="name_el" value="<?php echo $edit_category ? htmlspecialchars($edit_category['name_el']) : ''; ?>" required>
- </div>
- <div class="form-group">
- <label><?php echo $t['name_en']; ?></label>
- <input type="text" name="name_en" value="<?php echo $edit_category ? htmlspecialchars($edit_category['name_en'] ?? '') : ''; ?>">
- </div>
- </div>
-
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
- <div class="form-group">
- <label><?php echo $t['parent_cat']; ?></label>
- <select name="parent_id">
- <option value=""><?php echo $t['is_main']; ?></option>
- <?php foreach($parentCategories as $parent): ?>
- <?php if (!$edit_category || $edit_category['id'] != $parent['id']): ?>
- <option value="<?php echo $parent['id']; ?>" <?php echo ($edit_category && $edit_category['parent_id'] == $parent['id']) ? 'selected' : ''; ?>>
- <?php echo htmlspecialchars($parent['name_el']); ?>
- </option>
- <?php endif; ?>
- <?php endforeach; ?>
- </select>
- </div>
- <div class="form-group">
- <label><?php echo $t['attr_group']; ?></label>
- <select name="attribute_group_id">
- <option value=""><?php echo $t['no_attr']; ?></option>
- <?php foreach($attrGroups as $group): ?>
- <option value="<?php echo $group['id']; ?>" <?php echo ($edit_category && $edit_category['attribute_group_id'] == $group['id']) ? 'selected' : ''; ?>>
- <?php echo htmlspecialchars($group['name']); ?>
- </option>
- <?php endforeach; ?>
- </select>
- </div>
- </div>
-
- <button type="submit" class="btn"><?php echo $edit_category ? $t['btn_save'] : $t['btn_add']; ?></button>
- <?php if ($edit_category): ?>
- <a href="categories.php" class="btn-cancel"><?php echo $t['btn_cancel']; ?></a>
- <?php endif; ?>
- </form>
- </div>
- <div class="card">
- <h3>📂 <?php echo $t['tree_title']; ?></h3>
- <?php
- if (!empty($categoryTree)) {
- echo renderTreeHTML($categoryTree, 0, $t);
- } else {
- echo "<p style='color: var(--text-muted); padding: 20px; text-align: center;'>{$t['no_cats']}</p>";
- }
- ?>
- </div>
- </div>
- </body>
- </html>
|