From 8a93cf86572799a6c765b685e7ff765a41e64ea8 Mon Sep 17 00:00:00 2001 From: "kirill.khorkov" Date: Tue, 16 Dec 2025 19:18:03 +0300 Subject: [PATCH] Delete comment --- admin/index.php | 1399 ++++++------- api/add_to_cart.php | 226 +- api/auth.php | 127 +- api/cart.php | 57 +- api/get_cart.php | 121 +- api/get_cart_count.php | 42 +- api/get_product.php | 63 +- api/process_order.php | 256 ++- api/register_handler.php | 331 ++- assets/img/стили_оформления.css | 123 +- assets/js/checkout.js | 652 +++--- assets/js/profile.js | 732 ++++--- assets/less/checkout.less | 277 ++- assets/less/mixins.less | 1 - config/check_auth.js | 221 +- config/database.php | 62 +- includes/auth.php | 55 +- includes/footer.php | 1 - includes/functions.php | 45 +- includes/header.php | 18 +- migrations/grant_admin.php | 13 +- migrations/migrate.php | 28 +- public/admin/index.php | 1611 +++++++------- public/api/add_to_cart.php | 226 +- public/api/auth.php | 137 +- public/api/cart.php | 57 +- public/api/get_cart.php | 121 +- public/api/get_cart_count.php | 42 +- public/api/get_product.php | 63 +- public/api/process_order.php | 256 ++- public/api/register_handler.php | 335 ++- public/assets/img/стили_оформления.css | 123 +- public/assets/js/checkout.js | 652 +++--- public/assets/js/profile.js | 732 ++++--- public/assets/less/checkout.less | 277 ++- public/assets/less/mixins.less | 1 - public/catalog.php | 2647 ++++++++++++------------ public/check_auth.js | 221 +- public/checkout.php | 999 +++++---- public/config/check_auth.js | 221 +- public/config/database.php | 62 +- public/delivery.php | 346 ++-- public/footer.php | 1 - public/header_common.php | 18 +- public/img/стили_оформления.css | 123 +- public/img2/стили_оформления.css | 123 +- public/includes/auth.php | 55 +- public/includes/footer.php | 1 - public/includes/functions.php | 45 +- public/includes/header.php | 18 +- public/index.php | 1532 +++++++------- public/login.php | 593 +++--- public/logout.php | 5 - public/product.php | 974 +++++---- public/register.php | 1517 +++++++------- public/services.php | 223 +- public/warranty.php | 409 ++-- public/стили_оформления.less | 277 ++- стили_оформления.less | 277 ++- 59 files changed, 9767 insertions(+), 10403 deletions(-) diff --git a/admin/index.php b/admin/index.php index 25d2877..b0a9aa4 100644 --- a/admin/index.php +++ b/admin/index.php @@ -1,710 +1,691 @@ -alert('Требуется авторизация администратора'); window.location.href = 'login.php';"; - exit(); -} - -$db = Database::getInstance()->getConnection(); - -// Обработка действий -$action = $_GET['action'] ?? 'dashboard'; -$message = $_GET['message'] ?? ''; -$error = $_GET['error'] ?? ''; - -// Обработка POST запросов - ДОБАВЛЕНО ПРОСТОЕ И РАБОТАЮЩЕЕ! -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $post_action = $_POST['action'] ?? ''; - - try { - if ($post_action === 'add_category') { - $name = trim($_POST['name'] ?? ''); - $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); - $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL; - $description = trim($_POST['description'] ?? ''); - $sort_order = (int)($_POST['sort_order'] ?? 0); - $is_active = isset($_POST['is_active']) ? 1 : 0; - - if (empty($name)) { - throw new Exception('Название категории обязательно'); - } - - $stmt = $db->prepare(" - INSERT INTO categories (name, slug, parent_id, description, sort_order, is_active) - VALUES (?, ?, ?, ?, ?, ?) - "); - - $result = $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active]); - - if ($result) { - header('Location: admin_panel.php?action=categories&message=Категория+успешно+добавлена'); - exit(); - } - } - - // ИСПРАВЬТЕ БЛОК edit_category или добавьте его если его нет: - if ($post_action === 'edit_category' && isset($_POST['category_id'])) { - $category_id = (int)$_POST['category_id']; - $name = trim($_POST['name'] ?? ''); - $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL; - $description = trim($_POST['description'] ?? ''); - $sort_order = (int)($_POST['sort_order'] ?? 0); - $is_active = isset($_POST['is_active']) ? 1 : 0; - - if (empty($name)) { - throw new Exception('Название категории обязательно'); - } - - $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); - - $stmt = $db->prepare(" - UPDATE categories SET - name = ?, - slug = ?, - parent_id = ?, - description = ?, - sort_order = ?, - is_active = ?, - updated_at = CURRENT_TIMESTAMP - WHERE category_id = ? - "); - - $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active, $category_id]); - - header('Location: admin_panel.php?action=categories&message=Категория+обновлена'); - exit(); - } - - if ($post_action === 'add_product') { - $name = trim($_POST['name'] ?? ''); - $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); - $category_id = (int)($_POST['category_id'] ?? 0); - $description = trim($_POST['description'] ?? ''); - $price = (float)($_POST['price'] ?? 0); - $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL; - $sku = trim($_POST['sku'] ?? ''); - $stock_quantity = (int)($_POST['stock_quantity'] ?? 0); - $is_available = isset($_POST['is_available']) ? 1 : 0; - $is_featured = isset($_POST['is_featured']) ? 1 : 0; - $image_url = trim($_POST['image_url'] ?? ''); - $color = trim($_POST['color'] ?? ''); - $material = trim($_POST['material'] ?? ''); - $card_size = trim($_POST['card_size'] ?? 'small'); - - - // ВАЖНО: Проверяем category_id - if ($category_id <= 0) { - $_SESSION['error'] = 'Выберите корректную категорию'; - header('Location: admin_panel.php?action=add_product'); - exit(); - } - - // Проверяем существование категории - $check_category = $db->prepare("SELECT COUNT(*) FROM categories WHERE category_id = ?"); - $check_category->execute([$category_id]); - if ($check_category->fetchColumn() == 0) { - $_SESSION['error'] = 'Выбранная категория не существует'; - header('Location: admin_panel.php?action=add_product'); - exit(); - } - - if (empty($name)) throw new Exception('Название товара обязательно'); - if ($price <= 0) throw new Exception('Цена должна быть больше 0'); - - // Генерируем SKU если пустой - if (empty($sku)) { - $sku = 'PROD-' . strtoupper(substr(preg_replace('/[^a-z0-9]/i', '', $name), 0, 6)) . '-' . rand(100, 999); - } - - $stmt = $db->prepare(" - INSERT INTO products ( - category_id, name, slug, description, price, old_price, - sku, stock_quantity, is_available, is_featured, image_url, - color, material, card_size - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - "); - - $result = $stmt->execute([ - $category_id, $name, $slug, $description, $price, $old_price, - $sku, $stock_quantity, $is_available, $is_featured, $image_url, - $color, $material, $card_size - ]); - - if ($result) { - $_SESSION['message'] = 'Товар успешно добавлен'; - header('Location: admin_panel.php?action=products'); - exit(); - } - } - - // ИСПРАВЛЕННЫЙ КОД для edit_product в admin_panel.php: - if ($post_action === 'edit_product' && isset($_POST['product_id'])) { - $product_id = (int)$_POST['product_id']; - $name = trim($_POST['name'] ?? ''); - $category_id = (int)($_POST['category_id'] ?? 1); // ПО УМОЛЧАНИЮ 1, чтобы избежать 0 - $description = trim($_POST['description'] ?? ''); - $price = (float)($_POST['price'] ?? 0); - $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL; - $stock_quantity = (int)($_POST['stock_quantity'] ?? 0); - $is_available = isset($_POST['is_available']) ? 1 : 0; - $image_url = trim($_POST['image_url'] ?? ''); - $color = trim($_POST['color'] ?? ''); - $material = trim($_POST['material'] ?? ''); - - // ВАЖНО: Проверяем category_id - if ($category_id <= 0) { - // Если category_id = 0, устанавливаем первую доступную категорию - $firstCat = $db->query("SELECT category_id FROM categories LIMIT 1")->fetchColumn(); - $category_id = $firstCat ?: 1; - } - - $stmt = $db->prepare(" - UPDATE products SET - name = ?, - category_id = ?, - description = ?, - price = ?, - old_price = ?, - stock_quantity = ?, - is_available = ?, - image_url = ?, - color = ?, - material = ?, - updated_at = CURRENT_TIMESTAMP - WHERE product_id = ? - "); - - $stmt->execute([ - $name, $category_id, $description, $price, $old_price, - $stock_quantity, $is_available, $image_url, $color, $material, $product_id - ]); - - header('Location: admin_panel.php?action=products&message=Товар+обновлен'); - exit(); - } - - if ($post_action === 'delete_category' && isset($_POST['category_id'])) { - $categoryId = intval($_POST['category_id']); - - // 1. Проверяем, есть ли товары в этой категории - $checkProducts = $db->prepare("SELECT COUNT(*) FROM products WHERE category_id = ?"); - $checkProducts->execute([$categoryId]); - $productCount = $checkProducts->fetchColumn(); - - // 2. Проверяем, есть ли дочерние категории - $checkChildren = $db->prepare("SELECT COUNT(*) FROM categories WHERE parent_id = ?"); - $checkChildren->execute([$categoryId]); - $childCount = $checkChildren->fetchColumn(); - - if ($productCount > 0) { - // Если есть товары, делаем категорию неактивной вместо удаления - $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?"); - $stmt->execute([$categoryId]); - - header('Location: admin_panel.php?action=categories&message=Категория+скрыта+(содержит+товары)'); - exit(); - } elseif ($childCount > 0) { - // Если есть дочерние категории, делаем неактивной - $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?"); - $stmt->execute([$categoryId]); - - header('Location: admin_panel.php?action=categories&message=Категория+скрыта+(имеет+дочерние+категории)'); - exit(); - } else { - // Если нет товаров и дочерних категорий, удаляем - $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?"); - $stmt->execute([$categoryId]); - - header('Location: admin_panel.php?action=categories&message=Категория+удалена'); - exit(); - } - } - } catch (PDOException $e) { - header('Location: admin_panel.php?action=' . $action . '&error=' . urlencode('Ошибка БД: ' . $e->getMessage())); - exit(); - } catch (Exception $e) { - header('Location: admin_panel.php?action=' . $action . '&error=' . urlencode($e->getMessage())); - exit(); - } - } - - -// Получение данных для отображения -try { - // Статистика - $stats = [ - 'total_products' => $db->query("SELECT COUNT(*) FROM products")->fetchColumn(), - 'active_products' => $db->query("SELECT COUNT(*) FROM products WHERE is_available = TRUE")->fetchColumn(), - 'total_orders' => $db->query("SELECT COUNT(*) FROM orders")->fetchColumn(), - 'total_users' => $db->query("SELECT COUNT(*) FROM users")->fetchColumn(), - 'revenue' => $db->query("SELECT COALESCE(SUM(final_amount), 0) FROM orders WHERE status = 'completed'")->fetchColumn() - ]; - - // Получаем все категории - $allCategories = $db->query("SELECT * FROM categories WHERE is_active = TRUE ORDER BY name")->fetchAll(); - - // Получаем родительские категории - $parentCategories = $db->query("SELECT * FROM categories WHERE parent_id IS NULL AND is_active = TRUE ORDER BY name")->fetchAll(); - - switch ($action) { - case 'products': - $showAll = isset($_GET['show_all']) && $_GET['show_all'] == '1'; - $sql = $showAll - ? "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id ORDER BY p.created_at DESC" - : "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id WHERE p.is_available = TRUE ORDER BY p.created_at DESC"; - $data = $db->query($sql)->fetchAll(); - break; - - case 'categories': - $data = $db->query(" - SELECT c1.*, c2.name as parent_name, - (SELECT COUNT(*) FROM products p WHERE p.category_id = c1.category_id) as product_count - FROM categories c1 - LEFT JOIN categories c2 ON c1.parent_id = c2.category_id - ORDER BY c1.sort_order, c1.name - ")->fetchAll(); - break; - - case 'orders': - $data = $db->query(" - SELECT o.*, u.email as user_email - FROM orders o - LEFT JOIN users u ON o.user_id = u.user_id - ORDER BY o.created_at DESC - LIMIT 50 - ")->fetchAll(); - break; - - case 'users': - $data = $db->query("SELECT * FROM users ORDER BY created_at DESC LIMIT 50")->fetchAll(); - break; - - case 'add_product': - case 'edit_product': - if ($action === 'edit_product' && isset($_GET['id'])) { - $productId = (int)$_GET['id']; - $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?"); - $stmt->execute([$productId]); - $edit_data = $stmt->fetch(); - } - break; - - case 'add_category': - case 'edit_category': - if ($action === 'edit_category' && isset($_GET['id'])) { - $categoryId = (int)$_GET['id']; - $stmt = $db->prepare("SELECT * FROM categories WHERE category_id = ?"); - $stmt->execute([$categoryId]); - $edit_data = $stmt->fetch(); - } - break; - - } - -} catch (PDOException $e) { - $error = "Ошибка базы данных: " . $e->getMessage(); -} -?> - - - - - - AETERNA - Админ-панель - - - - -
-

Админ-панель AETERNA

-
- - В каталог - Выйти -
-
- -
- - Дашборд - - - Товары - - - Категории - - - Заказы - - - Пользователи - -
- -
- -
- -
- - - -
- -
- - - - -

Статистика

-
-
-

-

Всего товаров

-
-
-

-

Активных товаров

-
-
-

-

Заказов

-
-
-

-

Пользователей

-
-
- -
- - Добавить новый товар - - - Добавить категорию - -
- - - -
-

Управление товарами

-
- - Добавить товар - - - Только активные - - Показать все - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
IDНазваниеКатегорияЦенаНа складеСтатусДействия
- 0): ?> - ✓ Доступен - - ✗ Недоступен - - ⚠ Нет на складе - - - - - - -
- - - - -
- -
- - - - -
- -
- - - -
-

Управление категориями

- - Добавить категорию - -
- - - - - - - - - - - - - - - - - - - - - - - - -
IDНазваниеSlugРодительскаяТоваровДействия
- - - Редактировать - - - - -
- - - -
-

- -
- - - - - - -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- -
- - - Отмена -
-
- - - -

Заказы

- - - - - - - - - - - - - - - - - - - - - - - -
№ заказаКлиентСуммаСтатусДатаДействия
- - - -
- - - -

Пользователи

- - - - - - - - - - - - - - - - - - - - - -
IDEmailФИОДата регистрацииСтатус
- - ✓ Активен - - ✗ Неактивен - -
- - -
- - +alert('Требуется авторизация администратора'); window.location.href = 'login.php';"; + exit(); +} + +$db = Database::getInstance()->getConnection(); + +$action = $_GET['action'] ?? 'dashboard'; +$message = $_GET['message'] ?? ''; +$error = $_GET['error'] ?? ''; + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $post_action = $_POST['action'] ?? ''; + + try { + if ($post_action === 'add_category') { + $name = trim($_POST['name'] ?? ''); + $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); + $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL; + $description = trim($_POST['description'] ?? ''); + $sort_order = (int)($_POST['sort_order'] ?? 0); + $is_active = isset($_POST['is_active']) ? 1 : 0; + + if (empty($name)) { + throw new Exception('Название категории обязательно'); + } + + $stmt = $db->prepare(" + INSERT INTO categories (name, slug, parent_id, description, sort_order, is_active) + VALUES (?, ?, ?, ?, ?, ?) + "); + + $result = $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active]); + + if ($result) { + header('Location: admin_panel.php?action=categories&message=Категория+успешно+добавлена'); + exit(); + } + } + + if ($post_action === 'edit_category' && isset($_POST['category_id'])) { + $category_id = (int)$_POST['category_id']; + $name = trim($_POST['name'] ?? ''); + $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL; + $description = trim($_POST['description'] ?? ''); + $sort_order = (int)($_POST['sort_order'] ?? 0); + $is_active = isset($_POST['is_active']) ? 1 : 0; + + if (empty($name)) { + throw new Exception('Название категории обязательно'); + } + + $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); + + $stmt = $db->prepare(" + UPDATE categories SET + name = ?, + slug = ?, + parent_id = ?, + description = ?, + sort_order = ?, + is_active = ?, + updated_at = CURRENT_TIMESTAMP + WHERE category_id = ? + "); + + $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active, $category_id]); + + header('Location: admin_panel.php?action=categories&message=Категория+обновлена'); + exit(); + } + + if ($post_action === 'add_product') { + $name = trim($_POST['name'] ?? ''); + $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); + $category_id = (int)($_POST['category_id'] ?? 0); + $description = trim($_POST['description'] ?? ''); + $price = (float)($_POST['price'] ?? 0); + $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL; + $sku = trim($_POST['sku'] ?? ''); + $stock_quantity = (int)($_POST['stock_quantity'] ?? 0); + $is_available = isset($_POST['is_available']) ? 1 : 0; + $is_featured = isset($_POST['is_featured']) ? 1 : 0; + $image_url = trim($_POST['image_url'] ?? ''); + $color = trim($_POST['color'] ?? ''); + $material = trim($_POST['material'] ?? ''); + $card_size = trim($_POST['card_size'] ?? 'small'); + + if ($category_id <= 0) { + $_SESSION['error'] = 'Выберите корректную категорию'; + header('Location: admin_panel.php?action=add_product'); + exit(); + } + + $check_category = $db->prepare("SELECT COUNT(*) FROM categories WHERE category_id = ?"); + $check_category->execute([$category_id]); + if ($check_category->fetchColumn() == 0) { + $_SESSION['error'] = 'Выбранная категория не существует'; + header('Location: admin_panel.php?action=add_product'); + exit(); + } + + if (empty($name)) throw new Exception('Название товара обязательно'); + if ($price <= 0) throw new Exception('Цена должна быть больше 0'); + + if (empty($sku)) { + $sku = 'PROD-' . strtoupper(substr(preg_replace('/[^a-z0-9]/i', '', $name), 0, 6)) . '-' . rand(100, 999); + } + + $stmt = $db->prepare(" + INSERT INTO products ( + category_id, name, slug, description, price, old_price, + sku, stock_quantity, is_available, is_featured, image_url, + color, material, card_size + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "); + + $result = $stmt->execute([ + $category_id, $name, $slug, $description, $price, $old_price, + $sku, $stock_quantity, $is_available, $is_featured, $image_url, + $color, $material, $card_size + ]); + + if ($result) { + $_SESSION['message'] = 'Товар успешно добавлен'; + header('Location: admin_panel.php?action=products'); + exit(); + } + } + + if ($post_action === 'edit_product' && isset($_POST['product_id'])) { + $product_id = (int)$_POST['product_id']; + $name = trim($_POST['name'] ?? ''); + $category_id = (int)($_POST['category_id'] ?? 1); + $description = trim($_POST['description'] ?? ''); + $price = (float)($_POST['price'] ?? 0); + $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL; + $stock_quantity = (int)($_POST['stock_quantity'] ?? 0); + $is_available = isset($_POST['is_available']) ? 1 : 0; + $image_url = trim($_POST['image_url'] ?? ''); + $color = trim($_POST['color'] ?? ''); + $material = trim($_POST['material'] ?? ''); + + if ($category_id <= 0) { + + $firstCat = $db->query("SELECT category_id FROM categories LIMIT 1")->fetchColumn(); + $category_id = $firstCat ?: 1; + } + + $stmt = $db->prepare(" + UPDATE products SET + name = ?, + category_id = ?, + description = ?, + price = ?, + old_price = ?, + stock_quantity = ?, + is_available = ?, + image_url = ?, + color = ?, + material = ?, + updated_at = CURRENT_TIMESTAMP + WHERE product_id = ? + "); + + $stmt->execute([ + $name, $category_id, $description, $price, $old_price, + $stock_quantity, $is_available, $image_url, $color, $material, $product_id + ]); + + header('Location: admin_panel.php?action=products&message=Товар+обновлен'); + exit(); + } + + if ($post_action === 'delete_category' && isset($_POST['category_id'])) { + $categoryId = intval($_POST['category_id']); + + $checkProducts = $db->prepare("SELECT COUNT(*) FROM products WHERE category_id = ?"); + $checkProducts->execute([$categoryId]); + $productCount = $checkProducts->fetchColumn(); + + $checkChildren = $db->prepare("SELECT COUNT(*) FROM categories WHERE parent_id = ?"); + $checkChildren->execute([$categoryId]); + $childCount = $checkChildren->fetchColumn(); + + if ($productCount > 0) { + + $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?"); + $stmt->execute([$categoryId]); + + header('Location: admin_panel.php?action=categories&message=Категория+скрыта+(содержит+товары)'); + exit(); + } elseif ($childCount > 0) { + + $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?"); + $stmt->execute([$categoryId]); + + header('Location: admin_panel.php?action=categories&message=Категория+скрыта+(имеет+дочерние+категории)'); + exit(); + } else { + + $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?"); + $stmt->execute([$categoryId]); + + header('Location: admin_panel.php?action=categories&message=Категория+удалена'); + exit(); + } + } + } catch (PDOException $e) { + header('Location: admin_panel.php?action=' . $action . '&error=' . urlencode('Ошибка БД: ' . $e->getMessage())); + exit(); + } catch (Exception $e) { + header('Location: admin_panel.php?action=' . $action . '&error=' . urlencode($e->getMessage())); + exit(); + } + } + +try { + + $stats = [ + 'total_products' => $db->query("SELECT COUNT(*) FROM products")->fetchColumn(), + 'active_products' => $db->query("SELECT COUNT(*) FROM products WHERE is_available = TRUE")->fetchColumn(), + 'total_orders' => $db->query("SELECT COUNT(*) FROM orders")->fetchColumn(), + 'total_users' => $db->query("SELECT COUNT(*) FROM users")->fetchColumn(), + 'revenue' => $db->query("SELECT COALESCE(SUM(final_amount), 0) FROM orders WHERE status = 'completed'")->fetchColumn() + ]; + + $allCategories = $db->query("SELECT * FROM categories WHERE is_active = TRUE ORDER BY name")->fetchAll(); + + $parentCategories = $db->query("SELECT * FROM categories WHERE parent_id IS NULL AND is_active = TRUE ORDER BY name")->fetchAll(); + + switch ($action) { + case 'products': + $showAll = isset($_GET['show_all']) && $_GET['show_all'] == '1'; + $sql = $showAll + ? "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id ORDER BY p.created_at DESC" + : "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id WHERE p.is_available = TRUE ORDER BY p.created_at DESC"; + $data = $db->query($sql)->fetchAll(); + break; + + case 'categories': + $data = $db->query(" + SELECT c1.*, c2.name as parent_name, + (SELECT COUNT(*) FROM products p WHERE p.category_id = c1.category_id) as product_count + FROM categories c1 + LEFT JOIN categories c2 ON c1.parent_id = c2.category_id + ORDER BY c1.sort_order, c1.name + ")->fetchAll(); + break; + + case 'orders': + $data = $db->query(" + SELECT o.*, u.email as user_email + FROM orders o + LEFT JOIN users u ON o.user_id = u.user_id + ORDER BY o.created_at DESC + LIMIT 50 + ")->fetchAll(); + break; + + case 'users': + $data = $db->query("SELECT * FROM users ORDER BY created_at DESC LIMIT 50")->fetchAll(); + break; + + case 'add_product': + case 'edit_product': + if ($action === 'edit_product' && isset($_GET['id'])) { + $productId = (int)$_GET['id']; + $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?"); + $stmt->execute([$productId]); + $edit_data = $stmt->fetch(); + } + break; + + case 'add_category': + case 'edit_category': + if ($action === 'edit_category' && isset($_GET['id'])) { + $categoryId = (int)$_GET['id']; + $stmt = $db->prepare("SELECT * FROM categories WHERE category_id = ?"); + $stmt->execute([$categoryId]); + $edit_data = $stmt->fetch(); + } + break; + + } + +} catch (PDOException $e) { + $error = "Ошибка базы данных: " . $e->getMessage(); +} +?> + + + + + + AETERNA - Админ-панель + + + + +
+

Админ-панель AETERNA

+
+ + В каталог + Выйти +
+
+ +
+ + Дашборд + + + Товары + + + Категории + + + Заказы + + + Пользователи + +
+ +
+ +
+ +
+ + + +
+ +
+ + + + +

Статистика

+
+
+

+

Всего товаров

+
+
+

+

Активных товаров

+
+
+

+

Заказов

+
+
+

+

Пользователей

+
+
+ +
+ + Добавить новый товар + + + Добавить категорию + +
+ + + +
+

Управление товарами

+
+ + Добавить товар + + + Только активные + + Показать все + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
IDНазваниеКатегорияЦенаНа складеСтатусДействия
+ 0): ?> + ✓ Доступен + + ✗ Недоступен + + ⚠ Нет на складе + + + + + + +
+ + + + +
+ +
+ + + + +
+ +
+ + + +
+

Управление категориями

+ + Добавить категорию + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
IDНазваниеSlugРодительскаяТоваровДействия
+ + + Редактировать + + + +
+ + + +
+

+ +
+ + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + Отмена +
+
+ + + +

Заказы

+ + + + + + + + + + + + + + + + + + + + + + + +
№ заказаКлиентСуммаСтатусДатаДействия
+ + + +
+ + + +

Пользователи

+ + + + + + + + + + + + + + + + + + + + + +
IDEmailФИОДата регистрацииСтатус
+ + ✓ Активен + + ✗ Неактивен + +
+ + +
+ + \ No newline at end of file diff --git a/api/add_to_cart.php b/api/add_to_cart.php index bed64de..a452dcc 100644 --- a/api/add_to_cart.php +++ b/api/add_to_cart.php @@ -1,116 +1,112 @@ - false, 'message' => 'Требуется авторизация']); - exit(); -} - -if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['product_id'])) { - $product_id = intval($_POST['product_id']); - $quantity = intval($_POST['quantity'] ?? 1); - $user_id = $_SESSION['user_id'] ?? 0; - - if ($user_id == 0) { - echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); - exit(); - } - - $db = Database::getInstance()->getConnection(); - - try { - // Проверяем наличие товара на складе - $checkStock = $db->prepare(" - SELECT stock_quantity, name, price - FROM products - WHERE product_id = ? AND is_available = TRUE - "); - $checkStock->execute([$product_id]); - $product = $checkStock->fetch(); - - if (!$product) { - echo json_encode(['success' => false, 'message' => 'Товар не найден']); - exit(); - } - - if ($product['stock_quantity'] < $quantity) { - echo json_encode(['success' => false, 'message' => 'Недостаточно товара на складе']); - exit(); - } - - // Проверяем, есть ли товар уже в корзине пользователя - $checkCart = $db->prepare(" - SELECT cart_id, quantity - FROM cart - WHERE user_id = ? AND product_id = ? - "); - $checkCart->execute([$user_id, $product_id]); - $cartItem = $checkCart->fetch(); - - if ($cartItem) { - // Обновляем количество - $newQuantity = $cartItem['quantity'] + $quantity; - - // Проверяем общее количество - if ($newQuantity > $product['stock_quantity']) { - echo json_encode(['success' => false, 'message' => 'Превышено доступное количество']); - exit(); - } - - $updateStmt = $db->prepare(" - UPDATE cart - SET quantity = ?, updated_at = CURRENT_TIMESTAMP - WHERE cart_id = ? - "); - $updateStmt->execute([$newQuantity, $cartItem['cart_id']]); - } else { - // Добавляем новый товар - $insertStmt = $db->prepare(" - INSERT INTO cart (user_id, product_id, quantity) - VALUES (?, ?, ?) - "); - $insertStmt->execute([$user_id, $product_id, $quantity]); - } - - // Обновляем сессию - if (!isset($_SESSION['cart'])) { - $_SESSION['cart'] = []; - } - - if (isset($_SESSION['cart'][$product_id])) { - $_SESSION['cart'][$product_id]['quantity'] += $quantity; - } else { - $_SESSION['cart'][$product_id] = [ - 'quantity' => $quantity, - 'name' => $product['name'], - 'price' => $product['price'], - 'added_at' => time() - ]; - } - - // Получаем общее количество товаров в корзине - $cartCountStmt = $db->prepare(" - SELECT SUM(quantity) as total - FROM cart - WHERE user_id = ? - "); - $cartCountStmt->execute([$user_id]); - $cart_count = $cartCountStmt->fetchColumn() ?: 0; - - echo json_encode([ - 'success' => true, - 'cart_count' => $cart_count, - 'message' => 'Товар добавлен в корзину' - ]); - - } catch (PDOException $e) { - echo json_encode([ - 'success' => false, - 'message' => 'Ошибка базы данных: ' . $e->getMessage() - ]); - } -} else { - echo json_encode(['success' => false, 'message' => 'Неверный запрос']); -} + false, 'message' => 'Требуется авторизация']); + exit(); +} + +if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['product_id'])) { + $product_id = intval($_POST['product_id']); + $quantity = intval($_POST['quantity'] ?? 1); + $user_id = $_SESSION['user_id'] ?? 0; + + if ($user_id == 0) { + echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); + exit(); + } + + $db = Database::getInstance()->getConnection(); + + try { + + $checkStock = $db->prepare(" + SELECT stock_quantity, name, price + FROM products + WHERE product_id = ? AND is_available = TRUE + "); + $checkStock->execute([$product_id]); + $product = $checkStock->fetch(); + + if (!$product) { + echo json_encode(['success' => false, 'message' => 'Товар не найден']); + exit(); + } + + if ($product['stock_quantity'] < $quantity) { + echo json_encode(['success' => false, 'message' => 'Недостаточно товара на складе']); + exit(); + } + + $checkCart = $db->prepare(" + SELECT cart_id, quantity + FROM cart + WHERE user_id = ? AND product_id = ? + "); + $checkCart->execute([$user_id, $product_id]); + $cartItem = $checkCart->fetch(); + + if ($cartItem) { + + $newQuantity = $cartItem['quantity'] + $quantity; + + if ($newQuantity > $product['stock_quantity']) { + echo json_encode(['success' => false, 'message' => 'Превышено доступное количество']); + exit(); + } + + $updateStmt = $db->prepare(" + UPDATE cart + SET quantity = ?, updated_at = CURRENT_TIMESTAMP + WHERE cart_id = ? + "); + $updateStmt->execute([$newQuantity, $cartItem['cart_id']]); + } else { + + $insertStmt = $db->prepare(" + INSERT INTO cart (user_id, product_id, quantity) + VALUES (?, ?, ?) + "); + $insertStmt->execute([$user_id, $product_id, $quantity]); + } + + if (!isset($_SESSION['cart'])) { + $_SESSION['cart'] = []; + } + + if (isset($_SESSION['cart'][$product_id])) { + $_SESSION['cart'][$product_id]['quantity'] += $quantity; + } else { + $_SESSION['cart'][$product_id] = [ + 'quantity' => $quantity, + 'name' => $product['name'], + 'price' => $product['price'], + 'added_at' => time() + ]; + } + + $cartCountStmt = $db->prepare(" + SELECT SUM(quantity) as total + FROM cart + WHERE user_id = ? + "); + $cartCountStmt->execute([$user_id]); + $cart_count = $cartCountStmt->fetchColumn() ?: 0; + + echo json_encode([ + 'success' => true, + 'cart_count' => $cart_count, + 'message' => 'Товар добавлен в корзину' + ]); + + } catch (PDOException $e) { + echo json_encode([ + 'success' => false, + 'message' => 'Ошибка базы данных: ' . $e->getMessage() + ]); + } +} else { + echo json_encode(['success' => false, 'message' => 'Неверный запрос']); +} ?> \ No newline at end of file diff --git a/api/auth.php b/api/auth.php index e37ce6a..41f8cd7 100644 --- a/api/auth.php +++ b/api/auth.php @@ -1,66 +1,63 @@ - false, 'message' => 'Заполните все поля']); - exit(); - } - - $db = Database::getInstance()->getConnection(); - - try { - // Проверяем пользователя в базе данных - $stmt = $db->prepare(" - SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active - FROM users - WHERE email = ? - "); - $stmt->execute([$email]); - $user = $stmt->fetch(); - - if (!$user) { - echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); - exit(); - } - - if (!$user['is_active']) { - echo json_encode(['success' => false, 'message' => 'Аккаунт заблокирован']); - exit(); - } - - // Проверяем пароль - if (!password_verify($password, $user['password_hash'])) { - echo json_encode(['success' => false, 'message' => 'Неверный пароль']); - exit(); - } - - // Сохраняем в сессию - $_SESSION['user_id'] = $user['user_id']; - $_SESSION['user_email'] = $user['email']; - $_SESSION['full_name'] = $user['full_name']; - $_SESSION['user_phone'] = $user['phone'] ?? ''; - $_SESSION['user_city'] = $user['city'] ?? ''; - $_SESSION['isLoggedIn'] = true; - $_SESSION['isAdmin'] = (bool)$user['is_admin']; - $_SESSION['login_time'] = time(); - - // Обновляем время последнего входа - $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); - $updateStmt->execute([$user['user_id']]); - - echo json_encode(['success' => true, 'redirect' => 'catalog.php']); - - } catch (PDOException $e) { - echo json_encode(['success' => false, 'message' => 'Ошибка базы данных']); - } - -} else { - echo json_encode(['success' => false, 'message' => 'Неверный запрос']); -} + false, 'message' => 'Заполните все поля']); + exit(); + } + + $db = Database::getInstance()->getConnection(); + + try { + + $stmt = $db->prepare(" + SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active + FROM users + WHERE email = ? + "); + $stmt->execute([$email]); + $user = $stmt->fetch(); + + if (!$user) { + echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); + exit(); + } + + if (!$user['is_active']) { + echo json_encode(['success' => false, 'message' => 'Аккаунт заблокирован']); + exit(); + } + + if (!password_verify($password, $user['password_hash'])) { + echo json_encode(['success' => false, 'message' => 'Неверный пароль']); + exit(); + } + + $_SESSION['user_id'] = $user['user_id']; + $_SESSION['user_email'] = $user['email']; + $_SESSION['full_name'] = $user['full_name']; + $_SESSION['user_phone'] = $user['phone'] ?? ''; + $_SESSION['user_city'] = $user['city'] ?? ''; + $_SESSION['isLoggedIn'] = true; + $_SESSION['isAdmin'] = (bool)$user['is_admin']; + $_SESSION['login_time'] = time(); + + $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); + $updateStmt->execute([$user['user_id']]); + + echo json_encode(['success' => true, 'redirect' => 'catalog.php']); + + } catch (PDOException $e) { + echo json_encode(['success' => false, 'message' => 'Ошибка базы данных']); + } + +} else { + echo json_encode(['success' => false, 'message' => 'Неверный запрос']); +} ?> \ No newline at end of file diff --git a/api/cart.php b/api/cart.php index 030fd9d..cd68d7b 100644 --- a/api/cart.php +++ b/api/cart.php @@ -1,14 +1,10 @@ false, 'message' => 'Требуется авторизация']); exit(); @@ -24,66 +20,64 @@ try { case 'add': $productId = (int)($_POST['product_id'] ?? 0); $quantity = (int)($_POST['quantity'] ?? 1); - + if ($productId <= 0) { echo json_encode(['success' => false, 'message' => 'Неверный ID товара']); exit(); } - - // Проверяем существование товара + $checkProduct = $db->prepare("SELECT product_id, stock_quantity FROM products WHERE product_id = ? AND is_available = TRUE"); $checkProduct->execute([$productId]); $product = $checkProduct->fetch(); - + if (!$product) { echo json_encode(['success' => false, 'message' => 'Товар не найден']); exit(); } - - // Проверяем, есть ли товар уже в корзине + $checkCart = $db->prepare("SELECT cart_id, quantity FROM cart WHERE user_id = ? AND product_id = ?"); $checkCart->execute([$userId, $productId]); $cartItem = $checkCart->fetch(); - + if ($cartItem) { - // Обновляем количество + $newQuantity = $cartItem['quantity'] + $quantity; $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE cart_id = ?"); $stmt->execute([$newQuantity, $cartItem['cart_id']]); } else { - // Добавляем новый товар + $stmt = $db->prepare("INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)"); $stmt->execute([$userId, $productId, $quantity]); } - + echo json_encode(['success' => true, 'message' => 'Товар добавлен в корзину']); break; - + case 'update': $productId = (int)($_POST['product_id'] ?? 0); $quantity = (int)($_POST['quantity'] ?? 1); - + if ($quantity <= 0) { - // Удаляем товар если количество 0 + $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?"); $stmt->execute([$userId, $productId]); } else { $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE user_id = ? AND product_id = ?"); $stmt->execute([$quantity, $userId, $productId]); } - + echo json_encode(['success' => true, 'message' => 'Корзина обновлена']); break; - + case 'remove': $productId = (int)($_POST['product_id'] ?? 0); - + $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?"); $stmt->execute([$userId, $productId]); - + echo json_encode(['success' => true, 'message' => 'Товар удален из корзины']); break; - + case 'get': $stmt = $db->prepare(" SELECT c.cart_id, c.product_id, c.quantity, p.name, p.price, p.image_url, p.stock_quantity @@ -94,13 +88,13 @@ try { "); $stmt->execute([$userId]); $items = $stmt->fetchAll(); - + $total = 0; foreach ($items as &$item) { $item['subtotal'] = $item['price'] * $item['quantity']; $total += $item['subtotal']; } - + echo json_encode([ 'success' => true, 'items' => $items, @@ -108,27 +102,26 @@ try { 'count' => array_sum(array_column($items, 'quantity')) ]); break; - + case 'count': $stmt = $db->prepare("SELECT COALESCE(SUM(quantity), 0) FROM cart WHERE user_id = ?"); $stmt->execute([$userId]); $count = $stmt->fetchColumn(); - + echo json_encode(['success' => true, 'count' => (int)$count]); break; - + case 'clear': $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ?"); $stmt->execute([$userId]); - + echo json_encode(['success' => true, 'message' => 'Корзина очищена']); break; - + default: echo json_encode(['success' => false, 'message' => 'Неизвестное действие']); } - + } catch (PDOException $e) { echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]); } - diff --git a/api/get_cart.php b/api/get_cart.php index c5d2a3c..2d43ea4 100644 --- a/api/get_cart.php +++ b/api/get_cart.php @@ -1,62 +1,61 @@ - false, 'message' => 'Требуется авторизация']); - exit(); -} - -$user_id = $_SESSION['user_id'] ?? 0; - -if ($user_id == 0) { - echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); - exit(); -} - -$db = Database::getInstance()->getConnection(); - -try { - // Получаем корзину из БД - $stmt = $db->prepare(" - SELECT - c.cart_id, - c.product_id, - c.quantity, - p.name, - p.price, - p.image_url, - p.stock_quantity - FROM cart c - JOIN products p ON c.product_id = p.product_id - WHERE c.user_id = ? AND p.is_available = TRUE - ORDER BY c.created_at DESC - "); - $stmt->execute([$user_id]); - $cart_items = $stmt->fetchAll(); - - // Обновляем сессию - $_SESSION['cart'] = []; - foreach ($cart_items as $item) { - $_SESSION['cart'][$item['product_id']] = [ - 'quantity' => $item['quantity'], - 'name' => $item['name'], - 'price' => $item['price'], - 'added_at' => time() - ]; - } - - echo json_encode([ - 'success' => true, - 'cart_items' => $cart_items, - 'total_items' => count($cart_items) - ]); - -} catch (PDOException $e) { - echo json_encode([ - 'success' => false, - 'message' => 'Ошибка базы данных: ' . $e->getMessage() - ]); -} + false, 'message' => 'Требуется авторизация']); + exit(); +} + +$user_id = $_SESSION['user_id'] ?? 0; + +if ($user_id == 0) { + echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); + exit(); +} + +$db = Database::getInstance()->getConnection(); + +try { + + $stmt = $db->prepare(" + SELECT + c.cart_id, + c.product_id, + c.quantity, + p.name, + p.price, + p.image_url, + p.stock_quantity + FROM cart c + JOIN products p ON c.product_id = p.product_id + WHERE c.user_id = ? AND p.is_available = TRUE + ORDER BY c.created_at DESC + "); + $stmt->execute([$user_id]); + $cart_items = $stmt->fetchAll(); + + $_SESSION['cart'] = []; + foreach ($cart_items as $item) { + $_SESSION['cart'][$item['product_id']] = [ + 'quantity' => $item['quantity'], + 'name' => $item['name'], + 'price' => $item['price'], + 'added_at' => time() + ]; + } + + echo json_encode([ + 'success' => true, + 'cart_items' => $cart_items, + 'total_items' => count($cart_items) + ]); + +} catch (PDOException $e) { + echo json_encode([ + 'success' => false, + 'message' => 'Ошибка базы данных: ' . $e->getMessage() + ]); +} ?> \ No newline at end of file diff --git a/api/get_cart_count.php b/api/get_cart_count.php index eacc4d5..f1d59c2 100644 --- a/api/get_cart_count.php +++ b/api/get_cart_count.php @@ -1,22 +1,22 @@ - false, 'cart_count' => 0]); - exit(); -} - -$user_id = $_SESSION['user_id'] ?? 0; -$db = Database::getInstance()->getConnection(); - -try { - $stmt = $db->prepare("SELECT SUM(quantity) as total FROM cart WHERE user_id = ?"); - $stmt->execute([$user_id]); - $cart_count = $stmt->fetchColumn() ?: 0; - - echo json_encode(['success' => true, 'cart_count' => $cart_count]); -} catch (PDOException $e) { - echo json_encode(['success' => false, 'cart_count' => 0]); + false, 'cart_count' => 0]); + exit(); +} + +$user_id = $_SESSION['user_id'] ?? 0; +$db = Database::getInstance()->getConnection(); + +try { + $stmt = $db->prepare("SELECT SUM(quantity) as total FROM cart WHERE user_id = ?"); + $stmt->execute([$user_id]); + $cart_count = $stmt->fetchColumn() ?: 0; + + echo json_encode(['success' => true, 'cart_count' => $cart_count]); +} catch (PDOException $e) { + echo json_encode(['success' => false, 'cart_count' => 0]); } \ No newline at end of file diff --git a/api/get_product.php b/api/get_product.php index e548112..0cd3ca6 100644 --- a/api/get_product.php +++ b/api/get_product.php @@ -1,33 +1,32 @@ - false, 'message' => 'Доступ запрещен']); - exit(); -} - -if (!isset($_GET['id'])) { - echo json_encode(['success' => false, 'message' => 'ID не указан']); - exit(); -} - -try { - $db = Database::getInstance()->getConnection(); - $product_id = $_GET['id']; - - $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?"); - $stmt->execute([$product_id]); - $product = $stmt->fetch(); - - if ($product) { - echo json_encode($product); - } else { - echo json_encode(['success' => false, 'message' => 'Товар не найден']); - } - -} catch (PDOException $e) { - echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]); -} + false, 'message' => 'Доступ запрещен']); + exit(); +} + +if (!isset($_GET['id'])) { + echo json_encode(['success' => false, 'message' => 'ID не указан']); + exit(); +} + +try { + $db = Database::getInstance()->getConnection(); + $product_id = $_GET['id']; + + $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?"); + $stmt->execute([$product_id]); + $product = $stmt->fetch(); + + if ($product) { + echo json_encode($product); + } else { + echo json_encode(['success' => false, 'message' => 'Товар не найден']); + } + +} catch (PDOException $e) { + echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]); +} ?> \ No newline at end of file diff --git a/api/process_order.php b/api/process_order.php index 92d34e0..8c94036 100644 --- a/api/process_order.php +++ b/api/process_order.php @@ -1,134 +1,124 @@ -getConnection(); - - try { - $db->beginTransaction(); - - // Получаем данные из формы - $customer_name = $_POST['full_name'] ?? ''; - $customer_email = $_POST['email'] ?? ''; - $customer_phone = $_POST['phone'] ?? ''; - $delivery_address = $_POST['address'] ?? ''; - $region = $_POST['region'] ?? ''; - $payment_method = $_POST['payment'] ?? 'card'; - $delivery_method = $_POST['delivery'] ?? 'courier'; - $notes = $_POST['notes'] ?? ''; - $discount_amount = floatval($_POST['discount'] ?? 0); - $delivery_cost = floatval($_POST['delivery_price'] ?? 2000); - - // Генерируем номер заказа - $order_number = 'ORD-' . date('Ymd-His') . '-' . rand(1000, 9999); - - // Получаем корзину пользователя - $cartStmt = $db->prepare(" - SELECT - c.product_id, - c.quantity, - p.name, - p.price, - p.stock_quantity - FROM cart c - JOIN products p ON c.product_id = p.product_id - WHERE c.user_id = ? - "); - $cartStmt->execute([$user_id]); - $cart_items = $cartStmt->fetchAll(); - - if (empty($cart_items)) { - throw new Exception('Корзина пуста'); - } - - // Рассчитываем итоги - $total_amount = 0; - foreach ($cart_items as $item) { - $total_amount += $item['price'] * $item['quantity']; - } - - $final_amount = $total_amount - $discount_amount + $delivery_cost; - - // Создаем заказ - $orderStmt = $db->prepare(" - INSERT INTO orders ( - user_id, order_number, total_amount, discount_amount, - delivery_cost, final_amount, status, payment_method, - delivery_method, delivery_address, customer_name, - customer_email, customer_phone, notes - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - RETURNING order_id - "); - - $orderStmt->execute([ - $user_id, $order_number, $total_amount, $discount_amount, - $delivery_cost, $final_amount, 'pending', $payment_method, - $delivery_method, $delivery_address, $customer_name, - $customer_email, $customer_phone, $notes - ]); - - $order_id = $orderStmt->fetchColumn(); - - // Добавляем товары в заказ и обновляем остатки - foreach ($cart_items as $item) { - // Добавляем в order_items - $itemStmt = $db->prepare(" - INSERT INTO order_items ( - order_id, product_id, product_name, - quantity, unit_price, total_price - ) VALUES (?, ?, ?, ?, ?, ?) - "); - - $item_total = $item['price'] * $item['quantity']; - $itemStmt->execute([ - $order_id, $item['product_id'], $item['name'], - $item['quantity'], $item['price'], $item_total - ]); - - // Обновляем остатки на складе - $updateStmt = $db->prepare(" - UPDATE products - SET stock_quantity = stock_quantity - ?, - updated_at = CURRENT_TIMESTAMP - WHERE product_id = ? - "); - $updateStmt->execute([$item['quantity'], $item['product_id']]); - } - - // Очищаем корзину - $clearCartStmt = $db->prepare("DELETE FROM cart WHERE user_id = ?"); - $clearCartStmt->execute([$user_id]); - - // Очищаем сессию - unset($_SESSION['cart']); - - $db->commit(); - - // Перенаправляем на страницу успеха - header('Location: order_success.php?id=' . $order_id); - exit(); - - } catch (Exception $e) { - $db->rollBack(); - header('Location: checkout.php?error=' . urlencode($e->getMessage())); - exit(); - } -} else { - header('Location: checkout.php'); - exit(); -} +getConnection(); + + try { + $db->beginTransaction(); + + $customer_name = $_POST['full_name'] ?? ''; + $customer_email = $_POST['email'] ?? ''; + $customer_phone = $_POST['phone'] ?? ''; + $delivery_address = $_POST['address'] ?? ''; + $region = $_POST['region'] ?? ''; + $payment_method = $_POST['payment'] ?? 'card'; + $delivery_method = $_POST['delivery'] ?? 'courier'; + $notes = $_POST['notes'] ?? ''; + $discount_amount = floatval($_POST['discount'] ?? 0); + $delivery_cost = floatval($_POST['delivery_price'] ?? 2000); + + $order_number = 'ORD-' . date('Ymd-His') . '-' . rand(1000, 9999); + + $cartStmt = $db->prepare(" + SELECT + c.product_id, + c.quantity, + p.name, + p.price, + p.stock_quantity + FROM cart c + JOIN products p ON c.product_id = p.product_id + WHERE c.user_id = ? + "); + $cartStmt->execute([$user_id]); + $cart_items = $cartStmt->fetchAll(); + + if (empty($cart_items)) { + throw new Exception('Корзина пуста'); + } + + $total_amount = 0; + foreach ($cart_items as $item) { + $total_amount += $item['price'] * $item['quantity']; + } + + $final_amount = $total_amount - $discount_amount + $delivery_cost; + + $orderStmt = $db->prepare(" + INSERT INTO orders ( + user_id, order_number, total_amount, discount_amount, + delivery_cost, final_amount, status, payment_method, + delivery_method, delivery_address, customer_name, + customer_email, customer_phone, notes + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + RETURNING order_id + "); + + $orderStmt->execute([ + $user_id, $order_number, $total_amount, $discount_amount, + $delivery_cost, $final_amount, 'pending', $payment_method, + $delivery_method, $delivery_address, $customer_name, + $customer_email, $customer_phone, $notes + ]); + + $order_id = $orderStmt->fetchColumn(); + + foreach ($cart_items as $item) { + + $itemStmt = $db->prepare(" + INSERT INTO order_items ( + order_id, product_id, product_name, + quantity, unit_price, total_price + ) VALUES (?, ?, ?, ?, ?, ?) + "); + + $item_total = $item['price'] * $item['quantity']; + $itemStmt->execute([ + $order_id, $item['product_id'], $item['name'], + $item['quantity'], $item['price'], $item_total + ]); + + $updateStmt = $db->prepare(" + UPDATE products + SET stock_quantity = stock_quantity - ?, + updated_at = CURRENT_TIMESTAMP + WHERE product_id = ? + "); + $updateStmt->execute([$item['quantity'], $item['product_id']]); + } + + $clearCartStmt = $db->prepare("DELETE FROM cart WHERE user_id = ?"); + $clearCartStmt->execute([$user_id]); + + unset($_SESSION['cart']); + + $db->commit(); + + header('Location: order_success.php?id=' . $order_id); + exit(); + + } catch (Exception $e) { + $db->rollBack(); + header('Location: checkout.php?error=' . urlencode($e->getMessage())); + exit(); + } +} else { + header('Location: checkout.php'); + exit(); +} ?> \ No newline at end of file diff --git a/api/register_handler.php b/api/register_handler.php index 002dfad..3bbb0cb 100644 --- a/api/register_handler.php +++ b/api/register_handler.php @@ -1,182 +1,151 @@ - $full_name, - 'city' => $city, - 'email' => $email, - 'phone' => $phone - ]; - header('Location: register.php'); - exit(); - } - - // Подключаемся к базе данных - $db = Database::getInstance()->getConnection(); - - try { - // Проверяем, существует ли пользователь с таким email - $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?"); - $checkStmt->execute([$email]); - - if ($checkStmt->fetch()) { - $_SESSION['registration_errors'] = ['Пользователь с таким email уже существует']; - $_SESSION['old_data'] = [ - 'fio' => $full_name, - 'city' => $city, - 'email' => $email, - 'phone' => $phone - ]; - header('Location: register.php'); - exit(); - } - - // Хэшируем пароль - $password_hash = password_hash($password, PASSWORD_DEFAULT); - - // Определяем, является ли пользователь администратором - $is_admin = false; - $admin_emails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; - if (in_array(strtolower($email), $admin_emails)) { - $is_admin = true; - } - - // РАЗНЫЕ ВАРИАНТЫ ДЛЯ ТЕСТИРОВАНИЯ - РАСКОММЕНТИРУЙТЕ НУЖНЫЙ - - // Вариант 1: С явным преобразованием boolean (самый надежный) - $stmt = $db->prepare(" - INSERT INTO users (email, password_hash, full_name, phone, city, is_admin) - VALUES (?, ?, ?, ?, ?, ?) - RETURNING user_id - "); - - // Преобразуем boolean в integer для PostgreSQL - $stmt->execute([ - $email, - $password_hash, - $full_name, - $phone, - $city, - $is_admin ? 1 : 0 // Преобразуем в integer (1 или 0) - ]); - - // Вариант 2: С использованием CAST в SQL (альтернатива) - /* - $stmt = $db->prepare(" - INSERT INTO users (email, password_hash, full_name, phone, city, is_admin) - VALUES (?, ?, ?, ?, ?, CAST(? AS boolean)) - RETURNING user_id - "); - - $stmt->execute([ - $email, - $password_hash, - $full_name, - $phone, - $city, - $is_admin ? 'true' : 'false' // Строковые значения true/false - ]); - */ - - $user_id = $stmt->fetchColumn(); - - if ($user_id) { - // Автоматически авторизуем пользователя - $_SESSION['user_id'] = $user_id; - $_SESSION['user_email'] = $email; - $_SESSION['full_name'] = $full_name; - $_SESSION['user_phone'] = $phone; - $_SESSION['user_city'] = $city; - $_SESSION['isLoggedIn'] = true; - $_SESSION['isAdmin'] = $is_admin; - $_SESSION['login_time'] = time(); - - // Обновляем время последнего входа - $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); - $updateStmt->execute([$user_id]); - - // Перенаправляем на главную или каталог - $_SESSION['registration_success'] = 'Регистрация прошла успешно! ' . - ($is_admin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!'); - - header('Location: catalog.php'); - exit(); - } else { - throw new Exception('Ошибка при создании пользователя'); - } - - } catch (PDOException $e) { - // Логируем полную ошибку для отладки - error_log("Registration DB Error: " . $e->getMessage()); - error_log("SQL State: " . $e->getCode()); - error_log("Email: " . $email); - - $_SESSION['registration_errors'] = ['Ошибка базы данных: ' . $e->getMessage()]; - $_SESSION['old_data'] = [ - 'fio' => $full_name, - 'city' => $city, - 'email' => $email, - 'phone' => $phone - ]; - header('Location: register.php'); - exit(); - } catch (Exception $e) { - error_log("Registration Error: " . $e->getMessage()); - - $_SESSION['registration_errors'] = [$e->getMessage()]; - header('Location: register.php'); - exit(); - } - -} else { - // Если запрос не POST, перенаправляем на форму регистрации - header('Location: register.php'); - exit(); -} + $full_name, + 'city' => $city, + 'email' => $email, + 'phone' => $phone + ]; + header('Location: register.php'); + exit(); + } + + $db = Database::getInstance()->getConnection(); + + try { + + $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?"); + $checkStmt->execute([$email]); + + if ($checkStmt->fetch()) { + $_SESSION['registration_errors'] = ['Пользователь с таким email уже существует']; + $_SESSION['old_data'] = [ + 'fio' => $full_name, + 'city' => $city, + 'email' => $email, + 'phone' => $phone + ]; + header('Location: register.php'); + exit(); + } + + $password_hash = password_hash($password, PASSWORD_DEFAULT); + + $is_admin = false; + $admin_emails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; + if (in_array(strtolower($email), $admin_emails)) { + $is_admin = true; + } + + $stmt = $db->prepare(" + INSERT INTO users (email, password_hash, full_name, phone, city, is_admin) + VALUES (?, ?, ?, ?, ?, ?) + RETURNING user_id + "); + + $stmt->execute([ + $email, + $password_hash, + $full_name, + $phone, + $city, + $is_admin ? 1 : 0 + ]); + + $user_id = $stmt->fetchColumn(); + + if ($user_id) { + + $_SESSION['user_id'] = $user_id; + $_SESSION['user_email'] = $email; + $_SESSION['full_name'] = $full_name; + $_SESSION['user_phone'] = $phone; + $_SESSION['user_city'] = $city; + $_SESSION['isLoggedIn'] = true; + $_SESSION['isAdmin'] = $is_admin; + $_SESSION['login_time'] = time(); + + $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); + $updateStmt->execute([$user_id]); + + $_SESSION['registration_success'] = 'Регистрация прошла успешно! ' . + ($is_admin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!'); + + header('Location: catalog.php'); + exit(); + } else { + throw new Exception('Ошибка при создании пользователя'); + } + + } catch (PDOException $e) { + + error_log("Registration DB Error: " . $e->getMessage()); + error_log("SQL State: " . $e->getCode()); + error_log("Email: " . $email); + + $_SESSION['registration_errors'] = ['Ошибка базы данных: ' . $e->getMessage()]; + $_SESSION['old_data'] = [ + 'fio' => $full_name, + 'city' => $city, + 'email' => $email, + 'phone' => $phone + ]; + header('Location: register.php'); + exit(); + } catch (Exception $e) { + error_log("Registration Error: " . $e->getMessage()); + + $_SESSION['registration_errors'] = [$e->getMessage()]; + header('Location: register.php'); + exit(); + } + +} else { + + header('Location: register.php'); + exit(); +} ?> \ No newline at end of file diff --git a/assets/img/стили_оформления.css b/assets/img/стили_оформления.css index 581822b..2e1d09c 100644 --- a/assets/img/стили_оформления.css +++ b/assets/img/стили_оформления.css @@ -1,62 +1,61 @@ - -.error-message { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; -} - -.form__input.error { - border-color: #ff0000; -} - -.form__group { - position: relative; - margin-bottom: 15px; -} - -/* Стили для сообщений внизу страницы */ -.page-messages { - position: fixed; - bottom: 20px; - left: 50%; - transform: translateX(-50%); - z-index: 1000; - width: 90%; - max-width: 500px; -} - -.message { - padding: 15px; - margin: 10px 0; - border-radius: 5px; - text-align: center; - font-weight: bold; - display: none; -} - -.message.error { - background-color: #ffebee; - color: #c62828; - border: 1px solid #ffcdd2; -} - -.message.success { - background-color: #e8f5e9; - color: #453227; - border: 1px solid #c8e6c9; -} - -.message.warning { - background-color: #fff3e0; - color: #ef6c00; - border: 1px solid #ffe0b2; -} - -.privacy-error { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; - text-align: center; -} + +.error-message { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; +} + +.form__input.error { + border-color: #ff0000; +} + +.form__group { + position: relative; + margin-bottom: 15px; +} + +.page-messages { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + width: 90%; + max-width: 500px; +} + +.message { + padding: 15px; + margin: 10px 0; + border-radius: 5px; + text-align: center; + font-weight: bold; + display: none; +} + +.message.error { + background-color: #ffebee; + color: #c62828; + border: 1px solid #ffcdd2; +} + +.message.success { + background-color: #e8f5e9; + color: #453227; + border: 1px solid #c8e6c9; +} + +.message.warning { + background-color: #fff3e0; + color: #ef6c00; + border: 1px solid #ffe0b2; +} + +.privacy-error { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; + text-align: center; +} diff --git a/assets/js/checkout.js b/assets/js/checkout.js index 74e8305..45a09f5 100644 --- a/assets/js/checkout.js +++ b/assets/js/checkout.js @@ -1,346 +1,306 @@ -// script.js - -$(document).ready(function() { - // Инициализация корзины - let cart = { - items: [ - { id: 1, name: 'Кресло OPPORTUNITY', price: 16999, quantity: 1 }, - { id: 2, name: 'Кресло GOLDEN', price: 19999, quantity: 1 }, - { id: 3, name: 'Светильник POLET', price: 7999, quantity: 1 } - ], - delivery: 2000, - discount: 0 - }; - - // Функция обновления общей суммы - function updateTotal() { - let productsTotal = 0; - let totalCount = 0; - - // Пересчитываем товары - $('.products__item').each(function() { - const $item = $(this); - const price = parseInt($item.data('price')); - const quantity = parseInt($item.find('.products__qty-value').text()); - - productsTotal += price * quantity; - totalCount += quantity; - }); - - // Обновляем отображение - $('.products-total').text(productsTotal + ' ₽'); - $('.summary-count').text(totalCount); - $('.total-count').text(totalCount + ' шт.'); - $('.cart-count').text(totalCount); - - // Обновляем итоговую сумму - const finalTotal = productsTotal + cart.delivery - cart.discount; - $('.final-total').text(finalTotal + ' ₽'); - } - - // Функция валидации email - function validateEmail(email) { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); - } - - // Функция валидации имени (ФИО) - function validateFullName(name) { - // Проверяем, что имя содержит только буквы, пробелы, дефисы и апострофы - const nameRegex = /^[a-zA-Zа-яА-ЯёЁ\s\-']+$/; - - // Проверяем, что имя состоит минимум из 2 слов - const words = name.trim().split(/\s+/); - - return nameRegex.test(name) && words.length >= 2; - } - - // Функция валидации телефона - function validatePhone(phone) { - // Российский формат телефона: +7XXXXXXXXXX - const phoneRegex = /^\+7\d{10}$/; - return phoneRegex.test(phone); - } - - // Функция отображения сообщения - function showMessage(messageId, duration = 5000) { - // Скрываем все сообщения - $('.message').hide(); - - // Показываем нужное сообщение - $(messageId).fadeIn(300); - - // Автоматически скрываем через указанное время - if (duration > 0) { - setTimeout(() => { - $(messageId).fadeOut(300); - }, duration); - } - } - - // Функция показа ошибки приватности - function showPrivacyError(show) { - if (show) { - $('#privacy-error').show(); - } else { - $('#privacy-error').hide(); - } - } - - // Функция отображения ошибки конкретного поля - function showFieldError(fieldId, message) { - // Убираем старые ошибки - $(fieldId).removeClass('error-input'); - $(fieldId + '-error').remove(); - - if (message) { - $(fieldId).addClass('error-input'); - $(fieldId).after('
' + message + '
'); - } - } - - // Валидация поля при потере фокуса с указанием конкретной ошибки - $('#fullname').on('blur', function() { - const value = $(this).val().trim(); - if (value) { - if (!validateFullName(value)) { - showFieldError('#fullname', 'ФИО должно содержать только буквы и состоять минимум из 2 слов'); - } else { - showFieldError('#fullname', ''); - } - } else { - showFieldError('#fullname', ''); - } - }); - - $('#email').on('blur', function() { - const value = $(this).val().trim(); - if (value) { - if (!validateEmail(value)) { - showFieldError('#email', 'Введите корректный email адрес (например: example@mail.ru)'); - } else { - showFieldError('#email', ''); - } - } else { - showFieldError('#email', ''); - } - }); - - $('#phone').on('blur', function() { - const value = $(this).val().trim(); - if (value) { - if (!validatePhone(value)) { - showFieldError('#phone', 'Введите номер в формате +7XXXXXXXXXX (10 цифр после +7)'); - } else { - showFieldError('#phone', ''); - } - } else { - showFieldError('#phone', ''); - } - }); - - // Валидация обязательных полей - $('#region').on('blur', function() { - const value = $(this).val().trim(); - if (!value) { - showFieldError('#region', 'Укажите регион доставки'); - } else { - showFieldError('#region', ''); - } - }); - - $('#address').on('blur', function() { - const value = $(this).val().trim(); - if (!value) { - showFieldError('#address', 'Укажите адрес доставки (улица, дом, квартира)'); - } else { - showFieldError('#address', ''); - } - }); - - // Очистка ошибки при начале ввода - $('.form__input').on('input', function() { - const fieldId = '#' + $(this).attr('id'); - showFieldError(fieldId, ''); - }); - - // Обработчик увеличения количества - $('.products__qty-btn.plus').click(function() { - const $qtyValue = $(this).siblings('.products__qty-value'); - let quantity = parseInt($qtyValue.text()); - $qtyValue.text(quantity + 1); - updateTotal(); - }); - - // Обработчик уменьшения количества - $('.products__qty-btn.minus').click(function() { - const $qtyValue = $(this).siblings('.products__qty-value'); - let quantity = parseInt($qtyValue.text()); - if (quantity > 1) { - $qtyValue.text(quantity - 1); - updateTotal(); - } - }); - - // Обработчик удаления товара - $('.remove-from-cart').click(function() { - const $productItem = $(this).closest('.products__item'); - $productItem.fadeOut(300, function() { - $(this).remove(); - updateTotal(); - - // Показываем сообщение, если корзина пуста - if ($('.products__item').length === 0) { - $('.products__list').html('
Корзина пуста
'); - } - }); - }); - - // Обработчик применения промокода - $('.promo__btn').click(function() { - const promoCode = $('.promo__input').val().toUpperCase(); - - if (promoCode === 'SALE10') { - cart.discount = Math.round(parseInt($('.products-total').text()) * 0.1); - $('.discount-total').text(cart.discount + ' ₽'); - showMessage('#form-error', 3000); - $('#form-error').text('Промокод применен! Скидка 10%').removeClass('error').addClass('success'); - } else if (promoCode === 'FREE') { - cart.delivery = 0; - $('.delivery-price').text('0 ₽'); - showMessage('#form-error', 3000); - $('#form-error').text('Промокод применен! Бесплатная доставка').removeClass('error').addClass('success'); - } else if (promoCode) { - showMessage('#form-error', 3000); - $('#form-error').text('Промокод недействителен').removeClass('success').addClass('error'); - } - - updateTotal(); - }); - - // Обработчик выбора доставки - $('input[name="delivery"]').change(function() { - if ($(this).val() === 'pickup') { - cart.delivery = 0; - $('.delivery-price').text('0 ₽'); - } else { - cart.delivery = 2000; - $('.delivery-price').text('2000 ₽'); - } - updateTotal(); - }); - - // Функция проверки всех полей формы - function validateForm() { - let isValid = true; - let errorMessages = []; - - // Очищаем все старые ошибки - $('.field-error').remove(); - $('.form__input').removeClass('error-input'); - - // Проверка обязательных полей - const requiredFields = [ - { - id: '#fullname', - value: $('#fullname').val().trim(), - validator: validateFullName, - required: true, - message: 'ФИО должно содержать только буквы и состоять минимум из 2 слов' - }, - { - id: '#phone', - value: $('#phone').val().trim(), - validator: validatePhone, - required: true, - message: 'Введите корректный номер телефона в формате +7XXXXXXXXXX' - }, - { - id: '#email', - value: $('#email').val().trim(), - validator: validateEmail, - required: true, - message: 'Введите корректный email адрес' - }, - { - id: '#region', - value: $('#region').val().trim(), - validator: (val) => val.length > 0, - required: true, - message: 'Поле "Регион" обязательно для заполнения' - }, - { - id: '#address', - value: $('#address').val().trim(), - validator: (val) => val.length > 0, - required: true, - message: 'Поле "Адрес" обязательно для заполнения' - } - ]; - - // Проверяем каждое поле - requiredFields.forEach(field => { - if (field.required && (!field.value || !field.validator(field.value))) { - isValid = false; - errorMessages.push(field.message); - showFieldError(field.id, field.message); - } - }); - - // Проверка согласия на обработку данных - if (!$('#privacy-checkbox').is(':checked')) { - isValid = false; - showPrivacyError(true); - errorMessages.push('Необходимо согласие на обработку персональных данных'); - } else { - showPrivacyError(false); - } - - // Показываем общее сообщение, если есть ошибки - if (!isValid && errorMessages.length > 0) { - showMessage('#form-error', 5000); - $('#form-error').text('Исправьте следующие ошибки: ' + errorMessages.join('; ')).removeClass('success').addClass('error'); - - // Прокручиваем к первой ошибке - $('html, body').animate({ - scrollTop: $('.error-input').first().offset().top - 100 - }, 500); - } - - return isValid; - } - - // Обработчик оформления заказа - $('#submit-order').click(function() { - // Проверка валидации всех полей - if (!validateForm()) { - return; - } - - // Симуляция отправки заказа - $(this).prop('disabled', true).text('ОБРАБОТКА...'); - - setTimeout(() => { - showMessage('#order-success', 5000); - $(this).prop('disabled', false).text('ОФОРМИТЬ ЗАКАЗ'); - - // Здесь можно добавить редирект на страницу благодарности - // window.location.href = 'спасибо.html'; - }, 2000); - }); - - // Маска для телефона - $('#phone').on('input', function() { - let phone = $(this).val().replace(/\D/g, ''); - if (phone.length > 0) { - if (phone[0] !== '7' && phone[0] !== '8') { - phone = '7' + phone; - } - phone = '+7' + phone.substring(1, 11); - $(this).val(phone); - } - }); - - // Инициализация при загрузке - updateTotal(); -}); \ No newline at end of file + +$(document).ready(function() { + + let cart = { + items: [ + { id: 1, name: 'Кресло OPPORTUNITY', price: 16999, quantity: 1 }, + { id: 2, name: 'Кресло GOLDEN', price: 19999, quantity: 1 }, + { id: 3, name: 'Светильник POLET', price: 7999, quantity: 1 } + ], + delivery: 2000, + discount: 0 + }; + + function updateTotal() { + let productsTotal = 0; + let totalCount = 0; + + $('.products__item').each(function() { + const $item = $(this); + const price = parseInt($item.data('price')); + const quantity = parseInt($item.find('.products__qty-value').text()); + + productsTotal += price * quantity; + totalCount += quantity; + }); + + $('.products-total').text(productsTotal + ' ₽'); + $('.summary-count').text(totalCount); + $('.total-count').text(totalCount + ' шт.'); + $('.cart-count').text(totalCount); + + const finalTotal = productsTotal + cart.delivery - cart.discount; + $('.final-total').text(finalTotal + ' ₽'); + } + + function validateEmail(email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + } + + function validateFullName(name) { + + const nameRegex = /^[a-zA-Zа-яА-ЯёЁ\s\-']+$/; + + const words = name.trim().split(/\s+/); + + return nameRegex.test(name) && words.length >= 2; + } + + function validatePhone(phone) { + const phoneRegex = /^\+7\d{10}$/; + return phoneRegex.test(phone); + } + + function showMessage(messageId, duration = 5000) { + $('.message').hide(); + + $(messageId).fadeIn(300); + + if (duration > 0) { + setTimeout(() => { + $(messageId).fadeOut(300); + }, duration); + } + } + + function showPrivacyError(show) { + if (show) { + $('#privacy-error').show(); + } else { + $('#privacy-error').hide(); + } + } + + function showFieldError(fieldId, message) { + $(fieldId).removeClass('error-input'); + $(fieldId + '-error').remove(); + + if (message) { + $(fieldId).addClass('error-input'); + $(fieldId).after('
' + message + '
'); + } + } + + $('#fullname').on('blur', function() { + const value = $(this).val().trim(); + if (value) { + if (!validateFullName(value)) { + showFieldError('#fullname', 'ФИО должно содержать только буквы и состоять минимум из 2 слов'); + } else { + showFieldError('#fullname', ''); + } + } else { + showFieldError('#fullname', ''); + } + }); + + $('#email').on('blur', function() { + const value = $(this).val().trim(); + if (value) { + if (!validateEmail(value)) { + showFieldError('#email', 'Введите корректный email адрес (например: example@mail.ru)'); + } else { + showFieldError('#email', ''); + } + } else { + showFieldError('#email', ''); + } + }); + + $('#phone').on('blur', function() { + const value = $(this).val().trim(); + if (value) { + if (!validatePhone(value)) { + showFieldError('#phone', 'Введите номер в формате +7XXXXXXXXXX (10 цифр после +7)'); + } else { + showFieldError('#phone', ''); + } + } else { + showFieldError('#phone', ''); + } + }); + + $('#region').on('blur', function() { + const value = $(this).val().trim(); + if (!value) { + showFieldError('#region', 'Укажите регион доставки'); + } else { + showFieldError('#region', ''); + } + }); + + $('#address').on('blur', function() { + const value = $(this).val().trim(); + if (!value) { + showFieldError('#address', 'Укажите адрес доставки (улица, дом, квартира)'); + } else { + showFieldError('#address', ''); + } + }); + + $('.form__input').on('input', function() { + const fieldId = '#' + $(this).attr('id'); + showFieldError(fieldId, ''); + }); + + $('.products__qty-btn.plus').click(function() { + const $qtyValue = $(this).siblings('.products__qty-value'); + let quantity = parseInt($qtyValue.text()); + $qtyValue.text(quantity + 1); + updateTotal(); + }); + + $('.products__qty-btn.minus').click(function() { + const $qtyValue = $(this).siblings('.products__qty-value'); + let quantity = parseInt($qtyValue.text()); + if (quantity > 1) { + $qtyValue.text(quantity - 1); + updateTotal(); + } + }); + + $('.remove-from-cart').click(function() { + const $productItem = $(this).closest('.products__item'); + $productItem.fadeOut(300, function() { + $(this).remove(); + updateTotal(); + + if ($('.products__item').length === 0) { + $('.products__list').html('
Корзина пуста
'); + } + }); + }); + + $('.promo__btn').click(function() { + const promoCode = $('.promo__input').val().toUpperCase(); + + if (promoCode === 'SALE10') { + cart.discount = Math.round(parseInt($('.products-total').text()) * 0.1); + $('.discount-total').text(cart.discount + ' ₽'); + showMessage('#form-error', 3000); + $('#form-error').text('Промокод применен! Скидка 10%').removeClass('error').addClass('success'); + } else if (promoCode === 'FREE') { + cart.delivery = 0; + $('.delivery-price').text('0 ₽'); + showMessage('#form-error', 3000); + $('#form-error').text('Промокод применен! Бесплатная доставка').removeClass('error').addClass('success'); + } else if (promoCode) { + showMessage('#form-error', 3000); + $('#form-error').text('Промокод недействителен').removeClass('success').addClass('error'); + } + + updateTotal(); + }); + + $('input[name="delivery"]').change(function() { + if ($(this).val() === 'pickup') { + cart.delivery = 0; + $('.delivery-price').text('0 ₽'); + } else { + cart.delivery = 2000; + $('.delivery-price').text('2000 ₽'); + } + updateTotal(); + }); + + function validateForm() { + let isValid = true; + let errorMessages = []; + + $('.field-error').remove(); + $('.form__input').removeClass('error-input'); + + const requiredFields = [ + { + id: '#fullname', + value: $('#fullname').val().trim(), + validator: validateFullName, + required: true, + message: 'ФИО должно содержать только буквы и состоять минимум из 2 слов' + }, + { + id: '#phone', + value: $('#phone').val().trim(), + validator: validatePhone, + required: true, + message: 'Введите корректный номер телефона в формате +7XXXXXXXXXX' + }, + { + id: '#email', + value: $('#email').val().trim(), + validator: validateEmail, + required: true, + message: 'Введите корректный email адрес' + }, + { + id: '#region', + value: $('#region').val().trim(), + validator: (val) => val.length > 0, + required: true, + message: 'Поле "Регион" обязательно для заполнения' + }, + { + id: '#address', + value: $('#address').val().trim(), + validator: (val) => val.length > 0, + required: true, + message: 'Поле "Адрес" обязательно для заполнения' + } + ]; + + requiredFields.forEach(field => { + if (field.required && (!field.value || !field.validator(field.value))) { + isValid = false; + errorMessages.push(field.message); + showFieldError(field.id, field.message); + } + }); + + if (!$('#privacy-checkbox').is(':checked')) { + isValid = false; + showPrivacyError(true); + errorMessages.push('Необходимо согласие на обработку персональных данных'); + } else { + showPrivacyError(false); + } + + if (!isValid && errorMessages.length > 0) { + showMessage('#form-error', 5000); + $('#form-error').text('Исправьте следующие ошибки: ' + errorMessages.join('; ')).removeClass('success').addClass('error'); + + $('html, body').animate({ + scrollTop: $('.error-input').first().offset().top - 100 + }, 500); + } + + return isValid; + } + + $('#submit-order').click(function() { + if (!validateForm()) { + return; + } + + $(this).prop('disabled', true).text('ОБРАБОТКА...'); + + setTimeout(() => { + showMessage('#order-success', 5000); + $(this).prop('disabled', false).text('ОФОРМИТЬ ЗАКАЗ'); + + }, 2000); + }); + + $('#phone').on('input', function() { + let phone = $(this).val().replace(/\D/g, ''); + if (phone.length > 0) { + if (phone[0] !== '7' && phone[0] !== '8') { + phone = '7' + phone; + } + phone = '+7' + phone.substring(1, 11); + $(this).val(phone); + } + }); + + updateTotal(); +}); diff --git a/assets/js/profile.js b/assets/js/profile.js index 4aa7ff1..0224b62 100644 --- a/assets/js/profile.js +++ b/assets/js/profile.js @@ -1,384 +1,348 @@ -$(document).ready(function() { - // Функции для отображения сообщений - function showMessage(type, text) { - const messageId = type + 'Message'; - const $message = $('#' + messageId); - $message.text(text).fadeIn(300); - setTimeout(() => { - $message.fadeOut(300); - }, 5000); - } - - // Проверка, является ли email администратора - function isAdminEmail(email) { - const adminEmails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; - return adminEmails.includes(email.toLowerCase()); - } - - // Валидация ФИО (без цифр) - function validateFIO(fio) { - const words = fio.trim().split(/\s+/); - // Проверяем, что минимум 2 слова и нет цифр - const hasNoDigits = !/\d/.test(fio); - return words.length >= 2 && words.every(word => word.length >= 2) && hasNoDigits; - } - - // Валидация города - function validateCity(city) { - return city.trim().length >= 2 && /^[а-яА-ЯёЁ\s-]+$/.test(city); - } - - // Валидация email - function validateEmail(email) { - const localPart = email.split('@')[0]; - - // Проверка на кириллические символы перед @ - if (/[а-яА-ЯёЁ]/.test(localPart)) { - showError('email', 'В тексте перед знаком "@" не должно быть кириллических символов'); - return false; - } - - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(email)) { - showError('email', 'Введите корректный email адрес'); - return false; - } - - hideError('email'); - return true; - } - - // Валидация телефона - function validatePhone(phone) { - const phoneRegex = /^(\+7|8)[\s-]?\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}$/; - return phoneRegex.test(phone.replace(/\s/g, '')); - } - - // Валидация пароля - function validatePassword(password) { - return password.length >= 6; - } - - // Показать/скрыть ошибку - function showError(fieldId, message) { - $('#' + fieldId).addClass('error'); - $('#' + fieldId + '-error').text(message).show(); - } - - function hideError(fieldId) { - $('#' + fieldId).removeClass('error'); - $('#' + fieldId + '-error').hide(); - } - - // Валидация формы - function validateForm() { - let isValid = true; - - // Валидация ФИО - const fio = $('#fio').val(); - if (!validateFIO(fio)) { - if (/\d/.test(fio)) { - showError('fio', 'ФИО не должно содержать цифры'); - } else { - showError('fio', 'ФИО должно содержать минимум 2 слова (каждое от 2 символов)'); - } - isValid = false; - } else { - hideError('fio'); - } - - // Валидация города - const city = $('#city').val(); - if (!validateCity(city)) { - showError('city', 'Укажите корректное название города (только русские буквы)'); - isValid = false; - } else { - hideError('city'); - } - - // Валидация email - const email = $('#email').val(); - if (!validateEmail(email)) { - showError('email', 'Введите корректный email адрес'); - isValid = false; - } else { - hideError('email'); - } - - // Валидация телефона - const phone = $('#phone').val(); - if (!validatePhone(phone)) { - showError('phone', 'Введите номер в формате: +7(912)999-12-23'); - isValid = false; - } else { - hideError('phone'); - } - - // Валидация пароля - const password = $('#password').val(); - if (!validatePassword(password)) { - showError('password', 'Пароль должен содержать минимум 6 символов'); - isValid = false; - } else { - hideError('password'); - } - - // Проверка совпадения паролей - const confirmPassword = $('#confirm-password').val(); - if (password !== confirmPassword) { - showError('confirm-password', 'Пароли не совпадают'); - isValid = false; - } else { - hideError('confirm-password'); - } - - // Проверка согласия с условиями - if (!$('#privacy').is(':checked')) { - $('#privacy-error').show(); - isValid = false; - } else { - $('#privacy-error').hide(); - } - - return isValid; - } - - // Реальная валидация при вводе - $('input').on('blur', function() { - const fieldId = $(this).attr('id'); - const value = $(this).val(); - - switch(fieldId) { - case 'fio': - if (!validateFIO(value)) { - if (/\d/.test(value)) { - showError(fieldId, 'ФИО не должно содержать цифры'); - } else { - showError(fieldId, 'ФИО должно содержать минимум 2 слова'); - } - } else { - hideError(fieldId); - } - break; - case 'city': - if (!validateCity(value)) { - showError(fieldId, 'Укажите корректное название города'); - } else { - hideError(fieldId); - } - break; - case 'email': - if (!validateEmail(value)) { - showError(fieldId, 'Введите корректный email адрес'); - } else { - hideError(fieldId); - } - break; - case 'phone': - if (!validatePhone(value)) { - showError(fieldId, 'Введите номер в формате: +7(912)999-12-23'); - } else { - hideError(fieldId); - } - break; - case 'password': - if (!validatePassword(value)) { - showError(fieldId, 'Пароль должен содержать минимум 6 символов'); - } else { - hideError(fieldId); - } - break; - case 'confirm-password': - const password = $('#password').val(); - if (value !== password) { - showError(fieldId, 'Пароли не совпадают'); - } else { - hideError(fieldId); - } - break; - } - }); - - // Обработка отправки формы - $('#registrationForm').on('submit', function(e) { - e.preventDefault(); - - if (validateForm()) { - const email = $('#email').val(); - const isAdmin = isAdminEmail(email); - - // Сохраняем данные пользователя в localStorage - const userData = { - email: email, - fio: $('#fio').val(), - phone: $('#phone').val(), - isAdmin: isAdmin, - registered: new Date().toISOString() - }; - - localStorage.setItem('userData', JSON.stringify(userData)); - localStorage.setItem('isLoggedIn', 'true'); - localStorage.setItem('isAdmin', isAdmin.toString()); - - // Эмуляция успешной регистрации - showMessage('success', 'Регистрация прошла успешно! ' + - (isAdmin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!')); - - setTimeout(() => { - // Перенаправление на главную страницу - window.location.href = 'cite_mebel.php'; - }, 2000); - } else { - showMessage('error', 'Пожалуйста, исправьте ошибки в форме'); - } - }); - - // Плавная прокрутка к якорям - $('a[href^="#"]').on('click', function(event) { - var target = $(this.getAttribute('href')); - if (target.length) { - event.preventDefault(); - $('html, body').stop().animate({ - scrollTop: target.offset().top - }, 1000); - } - }); - - // Переключение между регистрацией и входом - $('.login-btn').on('click', function() { - showMessage('warning', 'Переход к форме входа...'); - setTimeout(() => { - window.location.href = 'вход.php'; - }, 1000); - }); - - // Обработка ссылки "Сменить пароль" - $('.password-link').on('click', function(e) { - e.preventDefault(); - showMessage('warning', 'Функция смены пароля будет доступна после регистрации'); - }); - - // Маска для телефона - $('#phone').on('input', function() { - let value = $(this).val().replace(/\D/g, ''); - if (value.startsWith('7') || value.startsWith('8')) { - value = value.substring(1); - } - if (value.length > 0) { - value = '+7(' + value; - if (value.length > 6) value = value.substring(0, 6) + ')' + value.substring(6); - if (value.length > 10) value = value.substring(0, 10) + '-' + value.substring(10); - if (value.length > 13) value = value.substring(0, 13) + '-' + value.substring(13); - if (value.length > 16) value = value.substring(0, 16); - } - $(this).val(value); - }); - - // Запрет ввода цифр в поле ФИО - $('#fio').on('input', function() { - let value = $(this).val(); - // Удаляем цифры из значения - value = value.replace(/\d/g, ''); - $(this).val(value); - }); -}); - -// Для входа (файл вход.html) -$(document).ready(function() { - // Проверяем, если пользователь уже вошел - if (localStorage.getItem('isLoggedIn') === 'true') { - const userData = JSON.parse(localStorage.getItem('userData') || '{}'); - if (userData.email) { - $('#login-email').val(userData.email); - } - } - - // Функция проверки пароля администратора - function checkAdminPassword(email, password) { - // Административные аккаунты - const adminAccounts = { - 'admin@aeterna.ru': 'admin123', - 'administrator@aeterna.ru': 'admin123', - 'aeterna@mail.ru': 'admin123' - }; - - return adminAccounts[email.toLowerCase()] === password; - } - - // Валидация формы входа - $('#loginForm').on('submit', function(e) { - e.preventDefault(); - - let isValid = true; - const email = $('#login-email').val(); - const password = $('#login-password').val(); - - // Валидация email - if (!isValidEmail(email)) { - $('#email-error').show(); - isValid = false; - } else { - $('#email-error').hide(); - } - - // Валидация пароля - if (password.length < 6) { - $('#password-error').show(); - isValid = false; - } else { - $('#password-error').hide(); - } - - if (isValid) { - // Здесь обычно отправка данных на сервер - showMessage('success', 'Вы успешно вошли в систему!'); - - // Перенаправление на главную страницу через 1.5 секунды - setTimeout(function() { - window.location.href = 'cite_mebel.php'; - }, 1500); - } - }); - - // Функция показа сообщений - function showMessage(type, text) { - const messageId = type + 'Message'; - const $message = $('#' + messageId); - - $message.text(text).show(); - - setTimeout(function() { - $message.fadeOut(); - }, 3000); - } - - // Скрываем сообщения об ошибках при фокусе на полях - $('input').on('focus', function() { - $(this).next('.error-message').hide(); - }); - - // Обработка чекбокса "Запомнить меня" - $('#remember').on('change', function() { - if ($(this).is(':checked')) { - const email = $('#login-email').val(); - if (email) { - localStorage.setItem('rememberedEmail', email); - } - } else { - localStorage.removeItem('rememberedEmail'); - } - }); - - // Автозаполнение email, если пользователь выбрал "Запомнить меня" - const rememberedEmail = localStorage.getItem('rememberedEmail'); - if (rememberedEmail) { - $('#login-email').val(rememberedEmail); - $('#remember').prop('checked', true); - } - - // Обработка ссылки "Забыли пароль?" - $('.forgot-password').on('click', function(e) { - e.preventDefault(); - showMessage('info', 'Для восстановления пароля обратитесь к администратору'); - }); -}); \ No newline at end of file +$(document).ready(function() { + + function showMessage(type, text) { + const messageId = type + 'Message'; + const $message = $('#' + messageId); + $message.text(text).fadeIn(300); + setTimeout(() => { + $message.fadeOut(300); + }, 5000); + } + + function isAdminEmail(email) { + const adminEmails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; + return adminEmails.includes(email.toLowerCase()); + } + + function validateFIO(fio) { + const words = fio.trim().split(/\s+/); + + const hasNoDigits = !/\d/.test(fio); + return words.length >= 2 && words.every(word => word.length >= 2) && hasNoDigits; + } + + function validateCity(city) { + return city.trim().length >= 2 && /^[а-яА-ЯёЁ\s-]+$/.test(city); + } + + function validateEmail(email) { + const localPart = email.split('@')[0]; + + if (/[а-яА-ЯёЁ]/.test(localPart)) { + showError('email', 'В тексте перед знаком "@" не должно быть кириллических символов'); + return false; + } + + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + showError('email', 'Введите корректный email адрес'); + return false; + } + + hideError('email'); + return true; + } + + function validatePhone(phone) { + const phoneRegex = /^(\+7|8)[\s-]?\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}$/; + return phoneRegex.test(phone.replace(/\s/g, '')); + } + + function validatePassword(password) { + return password.length >= 6; + } + + function showError(fieldId, message) { + $('#' + fieldId).addClass('error'); + $('#' + fieldId + '-error').text(message).show(); + } + + function hideError(fieldId) { + $('#' + fieldId).removeClass('error'); + $('#' + fieldId + '-error').hide(); + } + + function validateForm() { + let isValid = true; + + const fio = $('#fio').val(); + if (!validateFIO(fio)) { + if (/\d/.test(fio)) { + showError('fio', 'ФИО не должно содержать цифры'); + } else { + showError('fio', 'ФИО должно содержать минимум 2 слова (каждое от 2 символов)'); + } + isValid = false; + } else { + hideError('fio'); + } + + const city = $('#city').val(); + if (!validateCity(city)) { + showError('city', 'Укажите корректное название города (только русские буквы)'); + isValid = false; + } else { + hideError('city'); + } + + const email = $('#email').val(); + if (!validateEmail(email)) { + showError('email', 'Введите корректный email адрес'); + isValid = false; + } else { + hideError('email'); + } + + const phone = $('#phone').val(); + if (!validatePhone(phone)) { + showError('phone', 'Введите номер в формате: +7(912)999-12-23'); + isValid = false; + } else { + hideError('phone'); + } + + const password = $('#password').val(); + if (!validatePassword(password)) { + showError('password', 'Пароль должен содержать минимум 6 символов'); + isValid = false; + } else { + hideError('password'); + } + + const confirmPassword = $('#confirm-password').val(); + if (password !== confirmPassword) { + showError('confirm-password', 'Пароли не совпадают'); + isValid = false; + } else { + hideError('confirm-password'); + } + + if (!$('#privacy').is(':checked')) { + $('#privacy-error').show(); + isValid = false; + } else { + $('#privacy-error').hide(); + } + + return isValid; + } + + $('input').on('blur', function() { + const fieldId = $(this).attr('id'); + const value = $(this).val(); + + switch(fieldId) { + case 'fio': + if (!validateFIO(value)) { + if (/\d/.test(value)) { + showError(fieldId, 'ФИО не должно содержать цифры'); + } else { + showError(fieldId, 'ФИО должно содержать минимум 2 слова'); + } + } else { + hideError(fieldId); + } + break; + case 'city': + if (!validateCity(value)) { + showError(fieldId, 'Укажите корректное название города'); + } else { + hideError(fieldId); + } + break; + case 'email': + if (!validateEmail(value)) { + showError(fieldId, 'Введите корректный email адрес'); + } else { + hideError(fieldId); + } + break; + case 'phone': + if (!validatePhone(value)) { + showError(fieldId, 'Введите номер в формате: +7(912)999-12-23'); + } else { + hideError(fieldId); + } + break; + case 'password': + if (!validatePassword(value)) { + showError(fieldId, 'Пароль должен содержать минимум 6 символов'); + } else { + hideError(fieldId); + } + break; + case 'confirm-password': + const password = $('#password').val(); + if (value !== password) { + showError(fieldId, 'Пароли не совпадают'); + } else { + hideError(fieldId); + } + break; + } + }); + + $('#registrationForm').on('submit', function(e) { + e.preventDefault(); + + if (validateForm()) { + const email = $('#email').val(); + const isAdmin = isAdminEmail(email); + + const userData = { + email: email, + fio: $('#fio').val(), + phone: $('#phone').val(), + isAdmin: isAdmin, + registered: new Date().toISOString() + }; + + localStorage.setItem('userData', JSON.stringify(userData)); + localStorage.setItem('isLoggedIn', 'true'); + localStorage.setItem('isAdmin', isAdmin.toString()); + + showMessage('success', 'Регистрация прошла успешно! ' + + (isAdmin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!')); + + setTimeout(() => { + + window.location.href = 'cite_mebel.php'; + }, 2000); + } else { + showMessage('error', 'Пожалуйста, исправьте ошибки в форме'); + } + }); + + $('a[href^="#"]').on('click', function(event) { + var target = $(this.getAttribute('href')); + if (target.length) { + event.preventDefault(); + $('html, body').stop().animate({ + scrollTop: target.offset().top + }, 1000); + } + }); + + $('.login-btn').on('click', function() { + showMessage('warning', 'Переход к форме входа...'); + setTimeout(() => { + window.location.href = 'вход.php'; + }, 1000); + }); + + $('.password-link').on('click', function(e) { + e.preventDefault(); + showMessage('warning', 'Функция смены пароля будет доступна после регистрации'); + }); + + $('#phone').on('input', function() { + let value = $(this).val().replace(/\D/g, ''); + if (value.startsWith('7') || value.startsWith('8')) { + value = value.substring(1); + } + if (value.length > 0) { + value = '+7(' + value; + if (value.length > 6) value = value.substring(0, 6) + ')' + value.substring(6); + if (value.length > 10) value = value.substring(0, 10) + '-' + value.substring(10); + if (value.length > 13) value = value.substring(0, 13) + '-' + value.substring(13); + if (value.length > 16) value = value.substring(0, 16); + } + $(this).val(value); + }); + + $('#fio').on('input', function() { + let value = $(this).val(); + + value = value.replace(/\d/g, ''); + $(this).val(value); + }); +}); + +$(document).ready(function() { + + if (localStorage.getItem('isLoggedIn') === 'true') { + const userData = JSON.parse(localStorage.getItem('userData') || '{}'); + if (userData.email) { + $('#login-email').val(userData.email); + } + } + + function checkAdminPassword(email, password) { + + const adminAccounts = { + 'admin@aeterna.ru': 'admin123', + 'administrator@aeterna.ru': 'admin123', + 'aeterna@mail.ru': 'admin123' + }; + + return adminAccounts[email.toLowerCase()] === password; + } + + $('#loginForm').on('submit', function(e) { + e.preventDefault(); + + let isValid = true; + const email = $('#login-email').val(); + const password = $('#login-password').val(); + + if (!isValidEmail(email)) { + $('#email-error').show(); + isValid = false; + } else { + $('#email-error').hide(); + } + + if (password.length < 6) { + $('#password-error').show(); + isValid = false; + } else { + $('#password-error').hide(); + } + + if (isValid) { + + showMessage('success', 'Вы успешно вошли в систему!'); + + setTimeout(function() { + window.location.href = 'cite_mebel.php'; + }, 1500); + } + }); + + function showMessage(type, text) { + const messageId = type + 'Message'; + const $message = $('#' + messageId); + + $message.text(text).show(); + + setTimeout(function() { + $message.fadeOut(); + }, 3000); + } + + $('input').on('focus', function() { + $(this).next('.error-message').hide(); + }); + + $('#remember').on('change', function() { + if ($(this).is(':checked')) { + const email = $('#login-email').val(); + if (email) { + localStorage.setItem('rememberedEmail', email); + } + } else { + localStorage.removeItem('rememberedEmail'); + } + }); + + const rememberedEmail = localStorage.getItem('rememberedEmail'); + if (rememberedEmail) { + $('#login-email').val(rememberedEmail); + $('#remember').prop('checked', true); + } + + $('.forgot-password').on('click', function(e) { + e.preventDefault(); + showMessage('info', 'Для восстановления пароля обратитесь к администратору'); + }); +}); diff --git a/assets/less/checkout.less b/assets/less/checkout.less index fb07c54..a6fe073 100644 --- a/assets/less/checkout.less +++ b/assets/less/checkout.less @@ -1,142 +1,137 @@ -.error-message { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; -} - -.form__input.error { - border-color: #ff0000; -} - -.form__group { - position: relative; - margin-bottom: 15px; -} - -/* Стили для сообщений внизу страницы */ -.page-messages { - position: fixed; - bottom: 20px; - left: 50%; - transform: translateX(-50%); - z-index: 1000; - width: 90%; - max-width: 500px; -} - -.message { - padding: 15px; - margin: 10px 0; - border-radius: 5px; - text-align: center; - font-weight: bold; - display: none; -} - -.message.error { - background-color: #ffebee; - color: #c62828; - border: 1px solid #ffcdd2; -} - -.message.success { - background-color: #e8f5e9; - color: #453227; - border: 1px solid #c8e6c9; -} - -.message.warning { - background-color: #fff3e0; - color: #ef6c00; - border: 1px solid #ffe0b2; -} - -.privacy-error { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; - text-align: center; -} - -/* Дополнительные стили для формы регистрации */ -.input-group { - position: relative; - margin-bottom: 20px; -} - -.profile-form input.error { - border-color: #ff0000; - background-color: #fff5f5; -} - -.privacy-checkbox { - margin: 20px 0; - text-align: center; -} - -.privacy-checkbox label { - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - cursor: pointer; - font-size: 14px; -} - -.privacy-checkbox input[type="checkbox"] { - margin: 0; -} - -/* Исправление отступов для страницы регистрации */ -.profile-page-main { - padding: 40px 0; - min-height: calc(100vh - 200px); -} - -/* Убедимся, что контейнер не перекрывает шапку и футер */ -.profile-container { - margin: 0 auto; - position: relative; - z-index: 1; -} - -.input-hint { - font-size: 12px; - color: #666; - margin-top: 5px; -} - -/* Стили для страницы входа */ -.form-options { - display: flex; - justify-content: space-between; - align-items: center; - margin: 20px 0; -} - -.remember-me { - display: flex; - align-items: center; - gap: 8px; - font-size: 14px; - color: #453227; -} - -.remember-me input[type="checkbox"] { - width: 16px; - height: 16px; - cursor: pointer; -} - -.forgot-password { - font-size: 14px; - color: #453227; - text-decoration: underline; -} - -.forgot-password:hover { - color: #617365; - text-decoration: none; +.error-message { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; +} + +.form__input.error { + border-color: #ff0000; +} + +.form__group { + position: relative; + margin-bottom: 15px; +} + +.page-messages { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + width: 90%; + max-width: 500px; +} + +.message { + padding: 15px; + margin: 10px 0; + border-radius: 5px; + text-align: center; + font-weight: bold; + display: none; +} + +.message.error { + background-color: #ffebee; + color: #c62828; + border: 1px solid #ffcdd2; +} + +.message.success { + background-color: #e8f5e9; + color: #453227; + border: 1px solid #c8e6c9; +} + +.message.warning { + background-color: #fff3e0; + color: #ef6c00; + border: 1px solid #ffe0b2; +} + +.privacy-error { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; + text-align: center; +} + +.input-group { + position: relative; + margin-bottom: 20px; +} + +.profile-form input.error { + border-color: #ff0000; + background-color: #fff5f5; +} + +.privacy-checkbox { + margin: 20px 0; + text-align: center; +} + +.privacy-checkbox label { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + cursor: pointer; + font-size: 14px; +} + +.privacy-checkbox input[type="checkbox"] { + margin: 0; +} + +.profile-page-main { + padding: 40px 0; + min-height: calc(100vh - 200px); +} + +.profile-container { + margin: 0 auto; + position: relative; + z-index: 1; +} + +.input-hint { + font-size: 12px; + color: #666; + margin-top: 5px; +} + +.form-options { + display: flex; + justify-content: space-between; + align-items: center; + margin: 20px 0; +} + +.remember-me { + display: flex; + align-items: center; + gap: 8px; + font-size: 14px; + color: #453227; +} + +.remember-me input[type="checkbox"] { + width: 16px; + height: 16px; + cursor: pointer; +} + +.forgot-password { + font-size: 14px; + color: #453227; + text-decoration: underline; +} + +.forgot-password:hover { + color: #617365; + text-decoration: none; } \ No newline at end of file diff --git a/assets/less/mixins.less b/assets/less/mixins.less index 630b7bd..10638f0 100644 --- a/assets/less/mixins.less +++ b/assets/less/mixins.less @@ -83,4 +83,3 @@ border-color: @color-primary; } } - diff --git a/config/check_auth.js b/config/check_auth.js index e67bbe1..a4e0551 100644 --- a/config/check_auth.js +++ b/config/check_auth.js @@ -1,114 +1,107 @@ -// check_auth.js -$(document).ready(function() { - // Проверка авторизации при загрузке страницы - checkAuthStatus(); - - // Обработка формы входа - $('#loginForm').on('submit', function(e) { - e.preventDefault(); - - const email = $('#login-email').val(); - const password = $('#login-password').val(); - const remember = $('#remember').is(':checked'); - - $.ajax({ - url: 'login_handler.php', - method: 'POST', - data: { - email: email, - password: password - }, - success: function(response) { - try { - const result = JSON.parse(response); - if (result.success) { - // Сохраняем в localStorage если выбрано "Запомнить меня" - if (remember) { - localStorage.setItem('rememberedEmail', email); - } else { - localStorage.removeItem('rememberedEmail'); - } - - // Перенаправляем - window.location.href = result.redirect || 'catalog.php'; - } else { - showMessage('error', result.message || 'Ошибка авторизации'); - } - } catch(e) { - showMessage('error', 'Ошибка обработки ответа'); - } - }, - error: function() { - showMessage('error', 'Ошибка сервера'); - } - }); - }); - - // Проверка статуса авторизации - function checkAuthStatus() { - $.ajax({ - url: 'check_auth_status.php', - method: 'GET', - success: function(response) { - try { - const result = JSON.parse(response); - if (result.loggedIn) { - updateUserProfile(result.user); - } - } catch(e) { - console.error('Ошибка проверки авторизации', e); - } - } - }); - } - - // Обновление профиля пользователя - function updateUserProfile(user) { - // Обновляем шапку, если есть элементы для профиля - if ($('#userEmail').length) { - $('#userEmail').text(user.email); - } - if ($('#userName').length) { - $('#userName').text(user.full_name); - } - } - - // Показать сообщение - function showMessage(type, text) { - const $message = $('#' + type + 'Message'); - if ($message.length) { - $message.text(text).fadeIn(); - setTimeout(() => $message.fadeOut(), 5000); - } else { - alert(text); - } - } - - // Проверка авторизации для ссылок - function checkAuth(redirectUrl) { - $.ajax({ - url: 'check_auth_status.php', - method: 'GET', - success: function(response) { - try { - const result = JSON.parse(response); - if (result.loggedIn) { - window.location.href = redirectUrl; - } else { - // Показываем модальное окно или перенаправляем на вход - showLoginModal(redirectUrl); - } - } catch(e) { - showLoginModal(redirectUrl); - } - } - }); - return false; - } - - // Показать модальное окно входа - function showLoginModal(redirectUrl) { - // Можно реализовать модальное окно или перенаправить на страницу входа - window.location.href = 'вход.php?redirect=' + encodeURIComponent(redirectUrl); - } -}); \ No newline at end of file + +$(document).ready(function() { + + checkAuthStatus(); + + $('#loginForm').on('submit', function(e) { + e.preventDefault(); + + const email = $('#login-email').val(); + const password = $('#login-password').val(); + const remember = $('#remember').is(':checked'); + + $.ajax({ + url: 'login_handler.php', + method: 'POST', + data: { + email: email, + password: password + }, + success: function(response) { + try { + const result = JSON.parse(response); + if (result.success) { + + if (remember) { + localStorage.setItem('rememberedEmail', email); + } else { + localStorage.removeItem('rememberedEmail'); + } + + window.location.href = result.redirect || 'catalog.php'; + } else { + showMessage('error', result.message || 'Ошибка авторизации'); + } + } catch(e) { + showMessage('error', 'Ошибка обработки ответа'); + } + }, + error: function() { + showMessage('error', 'Ошибка сервера'); + } + }); + }); + + function checkAuthStatus() { + $.ajax({ + url: 'check_auth_status.php', + method: 'GET', + success: function(response) { + try { + const result = JSON.parse(response); + if (result.loggedIn) { + updateUserProfile(result.user); + } + } catch(e) { + console.error('Ошибка проверки авторизации', e); + } + } + }); + } + + function updateUserProfile(user) { + + if ($('#userEmail').length) { + $('#userEmail').text(user.email); + } + if ($('#userName').length) { + $('#userName').text(user.full_name); + } + } + + function showMessage(type, text) { + const $message = $('#' + type + 'Message'); + if ($message.length) { + $message.text(text).fadeIn(); + setTimeout(() => $message.fadeOut(), 5000); + } else { + alert(text); + } + } + + function checkAuth(redirectUrl) { + $.ajax({ + url: 'check_auth_status.php', + method: 'GET', + success: function(response) { + try { + const result = JSON.parse(response); + if (result.loggedIn) { + window.location.href = redirectUrl; + } else { + + showLoginModal(redirectUrl); + } + } catch(e) { + showLoginModal(redirectUrl); + } + } + }); + return false; + } + + function showLoginModal(redirectUrl) { + + window.location.href = 'вход.php?redirect=' + encodeURIComponent(redirectUrl); + } +}); diff --git a/config/database.php b/config/database.php index 762cdec..7e3062f 100644 --- a/config/database.php +++ b/config/database.php @@ -1,32 +1,32 @@ -connection = new PDO( - "pgsql:host=185.130.224.177;port=5481;dbname=postgres", - "admin", - "38feaad2840ccfda0e71243a6faaecfd" - ); - $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $this->connection->exec("SET NAMES 'utf8'"); - } catch(PDOException $e) { - die("Ошибка подключения: " . $e->getMessage()); - } - } - - public static function getInstance() { - if (self::$instance == null) { - self::$instance = new Database(); - } - return self::$instance; - } - - public function getConnection() { - return $this->connection; - } -} +connection = new PDO( + "pgsql:host=185.130.224.177;port=5481;dbname=postgres", + "admin", + "38feaad2840ccfda0e71243a6faaecfd" + ); + $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->connection->exec("SET NAMES 'utf8'"); + } catch(PDOException $e) { + die("Ошибка подключения: " . $e->getMessage()); + } + } + + public static function getInstance() { + if (self::$instance == null) { + self::$instance = new Database(); + } + return self::$instance; + } + + public function getConnection() { + return $this->connection; + } +} ?> \ No newline at end of file diff --git a/includes/auth.php b/includes/auth.php index 4c625ef..5326642 100644 --- a/includes/auth.php +++ b/includes/auth.php @@ -1,16 +1,10 @@ getConnection(); - + try { $stmt = $db->prepare(" SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active @@ -31,7 +25,6 @@ function loginUser(string $email, string $password): array { return ['success' => false, 'message' => 'Неверный пароль']; } - // Сохраняем в сессию $_SESSION['user_id'] = $user['user_id']; $_SESSION['user_email'] = $user['email']; $_SESSION['full_name'] = $user['full_name']; @@ -41,7 +34,6 @@ function loginUser(string $email, string $password): array { $_SESSION['isAdmin'] = (bool)$user['is_admin']; $_SESSION['login_time'] = time(); - // Обновляем время последнего входа $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); $updateStmt->execute([$user['user_id']]); @@ -52,43 +44,38 @@ function loginUser(string $email, string $password): array { } } -/** - * Регистрация нового пользователя - */ function registerUser(array $data): array { $db = Database::getInstance()->getConnection(); - + $email = trim($data['email'] ?? ''); $password = $data['password'] ?? ''; $fullName = trim($data['full_name'] ?? ''); $phone = trim($data['phone'] ?? ''); $city = trim($data['city'] ?? ''); - - // Валидация + if (empty($email) || empty($password) || empty($fullName)) { return ['success' => false, 'message' => 'Заполните все обязательные поля']; } - + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { return ['success' => false, 'message' => 'Некорректный email']; } - + if (strlen($password) < 6) { return ['success' => false, 'message' => 'Пароль должен содержать минимум 6 символов']; } - + try { - // Проверяем существование пользователя + $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?"); $checkStmt->execute([$email]); - + if ($checkStmt->fetch()) { return ['success' => false, 'message' => 'Пользователь с таким email уже существует']; } - - // Создаем пользователя + $passwordHash = password_hash($password, PASSWORD_DEFAULT); - + $stmt = $db->prepare(" INSERT INTO users (email, password_hash, full_name, phone, city, is_active) VALUES (?, ?, ?, ?, ?, TRUE) @@ -96,8 +83,7 @@ function registerUser(array $data): array { "); $stmt->execute([$email, $passwordHash, $fullName, $phone, $city]); $userId = $stmt->fetchColumn(); - - // Автоматически авторизуем + $_SESSION['user_id'] = $userId; $_SESSION['user_email'] = $email; $_SESSION['full_name'] = $fullName; @@ -106,20 +92,17 @@ function registerUser(array $data): array { $_SESSION['isLoggedIn'] = true; $_SESSION['isAdmin'] = false; $_SESSION['login_time'] = time(); - + return ['success' => true, 'user_id' => $userId]; - + } catch (PDOException $e) { return ['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]; } } -/** - * Выход пользователя - */ function logoutUser(): void { $_SESSION = []; - + if (ini_get("session.use_cookies")) { $params = session_get_cookie_params(); setcookie(session_name(), '', time() - 42000, @@ -127,22 +110,18 @@ function logoutUser(): void { $params["secure"], $params["httponly"] ); } - + session_destroy(); } -/** - * Проверка является ли пользователь администратором - */ function checkAdminAccess(): bool { if (!isset($_SESSION['isLoggedIn']) || $_SESSION['isLoggedIn'] !== true) { return false; } - + if (!isset($_SESSION['isAdmin']) || $_SESSION['isAdmin'] !== true) { return false; } - + return true; } - diff --git a/includes/footer.php b/includes/footer.php index 439cf70..98e1481 100644 --- a/includes/footer.php +++ b/includes/footer.php @@ -47,4 +47,3 @@ - diff --git a/includes/functions.php b/includes/functions.php index ccfca10..58d16bb 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1,25 +1,13 @@ $_SESSION['user_id'] ?? 0, 'email' => $_SESSION['user_email'] ?? '', @@ -53,38 +35,23 @@ function getCurrentUser(): ?array { ]; } -/** - * Форматирование цены - */ function formatPrice(float $price): string { return number_format($price, 0, '', ' ') . ' ₽'; } -/** - * Безопасный вывод HTML - */ function e(string $str): string { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); } -/** - * Генерация номера заказа - */ function generateOrderNumber(): string { return 'AET-' . date('Ymd') . '-' . strtoupper(substr(uniqid(), -6)); } -/** - * Генерация SKU для товара - */ function generateSKU(string $productName): string { $prefix = strtoupper(substr(preg_replace('/[^a-zA-Z0-9]/', '', transliterate($productName)), 0, 6)); return $prefix . '-' . rand(100, 999); } -/** - * Транслитерация кириллицы в латиницу - */ function transliterate(string $str): string { $converter = [ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', @@ -105,9 +72,6 @@ function transliterate(string $str): string { return strtr($str, $converter); } -/** - * Создание slug из строки - */ function createSlug(string $str): string { $slug = transliterate($str); $slug = strtolower($slug); @@ -116,9 +80,6 @@ function createSlug(string $str): string { return $slug; } -/** - * Показать flash-сообщение - */ function setFlashMessage(string $type, string $message): void { $_SESSION['flash_message'] = [ 'type' => $type, @@ -126,9 +87,6 @@ function setFlashMessage(string $type, string $message): void { ]; } -/** - * Получить и удалить flash-сообщение - */ function getFlashMessage(): ?array { if (isset($_SESSION['flash_message'])) { $message = $_SESSION['flash_message']; @@ -137,4 +95,3 @@ function getFlashMessage(): ?array { } return null; } - diff --git a/includes/header.php b/includes/header.php index 1b76d9e..3f0ac92 100644 --- a/includes/header.php +++ b/includes/header.php @@ -1,18 +1,11 @@ - - -
-

Админ-панель AETERNA

-
- - В каталог - Выйти -
-
- -
- - Дашборд - - - Товары - - - Категории - - - Заказы - - - Пользователи - -
- -
- -
- -
- - - -
- -
- - - - -

Статистика

-
-
-

-

Всего товаров

-
-
-

-

Активных товаров

-
-
-

-

Заказов

-
-
-

-

Пользователей

-
-
- -
- - Добавить новый товар - - - Добавить категорию - -
- - - -
-

Управление товарами

-
- - Добавить товар - - - Только активные - - Показать все - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
IDНазваниеКатегорияЦенаНа складеСтатусДействия
- 0): ?> - ✓ Доступен - - ✗ Недоступен - - ⚠ Нет на складе - - - - - - -
- - - - -
- -
- - - - -
- -
- - - -
-

Управление категориями

- - Добавить категорию - -
- - - - - - - - - - - - - - - - - - - - - - - - -
IDНазваниеSlugРодительскаяТоваровДействия
- - - Редактировать - - - - -
- - - -
-

- -
- - - - - - -
- - -
- -
- - -
- -
- - -
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- -
- - -
- -
-
- - -
-
- - -
-
- -
- -
- -
- -
- - - Отмена -
-
- - - -
-

- -
- - - - - - -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- -
- - - Отмена -
-
- - - -

Заказы

- - - - - - - - - - - - - - - - - - - - - - - -
№ заказаКлиентСуммаСтатусДатаДействия
- - - -
- - - -

Пользователи

- - - - - - - - - - - - - - - - - - - - - -
IDEmailФИОДата регистрацииСтатус
- - ✓ Активен - - ✗ Неактивен - -
- - -
- - +alert('Требуется авторизация администратора'); window.location.href = '../login.php';"; + exit(); +} + +$db = Database::getInstance()->getConnection(); + +$action = $_GET['action'] ?? 'dashboard'; +$message = $_GET['message'] ?? ''; +$error = $_GET['error'] ?? ''; + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $post_action = $_POST['action'] ?? ''; + + try { + if ($post_action === 'add_category') { + $name = trim($_POST['name'] ?? ''); + $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); + $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL; + $description = trim($_POST['description'] ?? ''); + $sort_order = (int)($_POST['sort_order'] ?? 0); + $is_active = isset($_POST['is_active']) ? 1 : 0; + + if (empty($name)) { + throw new Exception('Название категории обязательно'); + } + + $stmt = $db->prepare(" + INSERT INTO categories (name, slug, parent_id, description, sort_order, is_active) + VALUES (?, ?, ?, ?, ?, ?) + "); + + $result = $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active]); + + if ($result) { + header('Location: index.php?action=categories&message=Категория+успешно+добавлена'); + exit(); + } + } + + if ($post_action === 'edit_category' && isset($_POST['category_id'])) { + $category_id = (int)$_POST['category_id']; + $name = trim($_POST['name'] ?? ''); + $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL; + $description = trim($_POST['description'] ?? ''); + $sort_order = (int)($_POST['sort_order'] ?? 0); + $is_active = isset($_POST['is_active']) ? 1 : 0; + + if (empty($name)) { + throw new Exception('Название категории обязательно'); + } + + $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); + + $stmt = $db->prepare(" + UPDATE categories SET + name = ?, + slug = ?, + parent_id = ?, + description = ?, + sort_order = ?, + is_active = ?, + updated_at = CURRENT_TIMESTAMP + WHERE category_id = ? + "); + + $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active, $category_id]); + + header('Location: index.php?action=categories&message=Категория+обновлена'); + exit(); + } + + if ($post_action === 'add_product') { + $name = trim($_POST['name'] ?? ''); + $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name)); + $category_id = (int)($_POST['category_id'] ?? 0); + $description = trim($_POST['description'] ?? ''); + $price = (float)($_POST['price'] ?? 0); + $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL; + $sku = trim($_POST['sku'] ?? ''); + $stock_quantity = (int)($_POST['stock_quantity'] ?? 0); + $is_available = isset($_POST['is_available']) ? 1 : 0; + $is_featured = isset($_POST['is_featured']) ? 1 : 0; + $image_url = trim($_POST['image_url'] ?? ''); + $color = trim($_POST['color'] ?? ''); + $material = trim($_POST['material'] ?? ''); + $card_size = trim($_POST['card_size'] ?? 'small'); + + if ($category_id <= 0) { + $_SESSION['error'] = 'Выберите корректную категорию'; + header('Location: index.php?action=add_product'); + exit(); + } + + $check_category = $db->prepare("SELECT COUNT(*) FROM categories WHERE category_id = ?"); + $check_category->execute([$category_id]); + if ($check_category->fetchColumn() == 0) { + $_SESSION['error'] = 'Выбранная категория не существует'; + header('Location: index.php?action=add_product'); + exit(); + } + + if (empty($name)) throw new Exception('Название товара обязательно'); + if ($price <= 0) throw new Exception('Цена должна быть больше 0'); + + if (empty($sku)) { + $sku = 'PROD-' . strtoupper(substr(preg_replace('/[^a-z0-9]/i', '', $name), 0, 6)) . '-' . rand(100, 999); + } + + $stmt = $db->prepare(" + INSERT INTO products ( + category_id, name, slug, description, price, old_price, + sku, stock_quantity, is_available, is_featured, image_url, + color, material, card_size + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + "); + + $result = $stmt->execute([ + $category_id, $name, $slug, $description, $price, $old_price, + $sku, $stock_quantity, $is_available, $is_featured, $image_url, + $color, $material, $card_size + ]); + + if ($result) { + $_SESSION['message'] = 'Товар успешно добавлен'; + header('Location: index.php?action=products'); + exit(); + } + } + + if ($post_action === 'edit_product' && isset($_POST['product_id'])) { + $product_id = (int)$_POST['product_id']; + $name = trim($_POST['name'] ?? ''); + $category_id = (int)($_POST['category_id'] ?? 1); + $description = trim($_POST['description'] ?? ''); + $price = (float)($_POST['price'] ?? 0); + $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL; + $stock_quantity = (int)($_POST['stock_quantity'] ?? 0); + $is_available = isset($_POST['is_available']) ? 1 : 0; + $image_url = trim($_POST['image_url'] ?? ''); + $color = trim($_POST['color'] ?? ''); + $material = trim($_POST['material'] ?? ''); + + if ($category_id <= 0) { + + $firstCat = $db->query("SELECT category_id FROM categories LIMIT 1")->fetchColumn(); + $category_id = $firstCat ?: 1; + } + + $stmt = $db->prepare(" + UPDATE products SET + name = ?, + category_id = ?, + description = ?, + price = ?, + old_price = ?, + stock_quantity = ?, + is_available = ?, + image_url = ?, + color = ?, + material = ?, + updated_at = CURRENT_TIMESTAMP + WHERE product_id = ? + "); + + $stmt->execute([ + $name, $category_id, $description, $price, $old_price, + $stock_quantity, $is_available, $image_url, $color, $material, $product_id + ]); + + header('Location: index.php?action=products&message=Товар+обновлен'); + exit(); + } + + if ($post_action === 'delete_category' && isset($_POST['category_id'])) { + $categoryId = intval($_POST['category_id']); + + $checkProducts = $db->prepare("SELECT COUNT(*) FROM products WHERE category_id = ?"); + $checkProducts->execute([$categoryId]); + $productCount = $checkProducts->fetchColumn(); + + $checkChildren = $db->prepare("SELECT COUNT(*) FROM categories WHERE parent_id = ?"); + $checkChildren->execute([$categoryId]); + $childCount = $checkChildren->fetchColumn(); + + if ($productCount > 0) { + + $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?"); + $stmt->execute([$categoryId]); + + header('Location: index.php?action=categories&message=Категория+скрыта+(содержит+товары)'); + exit(); + } elseif ($childCount > 0) { + + $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?"); + $stmt->execute([$categoryId]); + + header('Location: index.php?action=categories&message=Категория+скрыта+(имеет+дочерние+категории)'); + exit(); + } else { + + $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?"); + $stmt->execute([$categoryId]); + + header('Location: index.php?action=categories&message=Категория+удалена'); + exit(); + } + } + } catch (PDOException $e) { + header('Location: index.php?action=' . $action . '&error=' . urlencode('Ошибка БД: ' . $e->getMessage())); + exit(); + } catch (Exception $e) { + header('Location: index.php?action=' . $action . '&error=' . urlencode($e->getMessage())); + exit(); + } + } + +try { + + $stats = [ + 'total_products' => $db->query("SELECT COUNT(*) FROM products")->fetchColumn(), + 'active_products' => $db->query("SELECT COUNT(*) FROM products WHERE is_available = TRUE")->fetchColumn(), + 'total_orders' => $db->query("SELECT COUNT(*) FROM orders")->fetchColumn(), + 'total_users' => $db->query("SELECT COUNT(*) FROM users")->fetchColumn(), + 'revenue' => $db->query("SELECT COALESCE(SUM(final_amount), 0) FROM orders WHERE status = 'completed'")->fetchColumn() + ]; + + $allCategories = $db->query("SELECT * FROM categories WHERE is_active = TRUE ORDER BY name")->fetchAll(); + + $parentCategories = $db->query("SELECT * FROM categories WHERE parent_id IS NULL AND is_active = TRUE ORDER BY name")->fetchAll(); + + switch ($action) { + case 'products': + $showAll = isset($_GET['show_all']) && $_GET['show_all'] == '1'; + $sql = $showAll + ? "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id ORDER BY p.created_at DESC" + : "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id WHERE p.is_available = TRUE ORDER BY p.created_at DESC"; + $data = $db->query($sql)->fetchAll(); + break; + + case 'categories': + $data = $db->query(" + SELECT c1.*, c2.name as parent_name, + (SELECT COUNT(*) FROM products p WHERE p.category_id = c1.category_id) as product_count + FROM categories c1 + LEFT JOIN categories c2 ON c1.parent_id = c2.category_id + ORDER BY c1.sort_order, c1.name + ")->fetchAll(); + break; + + case 'orders': + $data = $db->query(" + SELECT o.*, u.email as user_email + FROM orders o + LEFT JOIN users u ON o.user_id = u.user_id + ORDER BY o.created_at DESC + LIMIT 50 + ")->fetchAll(); + break; + + case 'users': + $data = $db->query("SELECT * FROM users ORDER BY created_at DESC LIMIT 50")->fetchAll(); + break; + + case 'add_product': + case 'edit_product': + if ($action === 'edit_product' && isset($_GET['id'])) { + $productId = (int)$_GET['id']; + $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?"); + $stmt->execute([$productId]); + $edit_data = $stmt->fetch(); + } + break; + + case 'add_category': + case 'edit_category': + if ($action === 'edit_category' && isset($_GET['id'])) { + $categoryId = (int)$_GET['id']; + $stmt = $db->prepare("SELECT * FROM categories WHERE category_id = ?"); + $stmt->execute([$categoryId]); + $edit_data = $stmt->fetch(); + } + break; + + } + +} catch (PDOException $e) { + $error = "Ошибка базы данных: " . $e->getMessage(); +} +?> + + + + + + AETERNA - Админ-панель + + + + +
+

Админ-панель AETERNA

+
+ + В каталог + Выйти +
+
+ +
+ + Дашборд + + + Товары + + + Категории + + + Заказы + + + Пользователи + +
+ +
+ +
+ +
+ + + +
+ +
+ + + + +

Статистика

+
+
+

+

Всего товаров

+
+
+

+

Активных товаров

+
+
+

+

Заказов

+
+
+

+

Пользователей

+
+
+ +
+ + Добавить новый товар + + + Добавить категорию + +
+ + + +
+

Управление товарами

+
+ + Добавить товар + + + Только активные + + Показать все + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
IDНазваниеКатегорияЦенаНа складеСтатусДействия
+ 0): ?> + ✓ Доступен + + ✗ Недоступен + + ⚠ Нет на складе + + + + + + +
+ + + + +
+ +
+ + + + +
+ +
+ + + +
+

Управление категориями

+ + Добавить категорию + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
IDНазваниеSlugРодительскаяТоваровДействия
+ + + Редактировать + + + +
+ + + +
+

+ +
+ + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ +
+ +
+ +
+ + + Отмена +
+
+ + + +
+

+ +
+ + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + + Отмена +
+
+ + + +

Заказы

+ + + + + + + + + + + + + + + + + + + + + + + +
№ заказаКлиентСуммаСтатусДатаДействия
+ + + +
+ + + +

Пользователи

+ + + + + + + + + + + + + + + + + + + + + +
IDEmailФИОДата регистрацииСтатус
+ + ✓ Активен + + ✗ Неактивен + +
+ + +
+ + \ No newline at end of file diff --git a/public/api/add_to_cart.php b/public/api/add_to_cart.php index bed64de..a452dcc 100644 --- a/public/api/add_to_cart.php +++ b/public/api/add_to_cart.php @@ -1,116 +1,112 @@ - false, 'message' => 'Требуется авторизация']); - exit(); -} - -if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['product_id'])) { - $product_id = intval($_POST['product_id']); - $quantity = intval($_POST['quantity'] ?? 1); - $user_id = $_SESSION['user_id'] ?? 0; - - if ($user_id == 0) { - echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); - exit(); - } - - $db = Database::getInstance()->getConnection(); - - try { - // Проверяем наличие товара на складе - $checkStock = $db->prepare(" - SELECT stock_quantity, name, price - FROM products - WHERE product_id = ? AND is_available = TRUE - "); - $checkStock->execute([$product_id]); - $product = $checkStock->fetch(); - - if (!$product) { - echo json_encode(['success' => false, 'message' => 'Товар не найден']); - exit(); - } - - if ($product['stock_quantity'] < $quantity) { - echo json_encode(['success' => false, 'message' => 'Недостаточно товара на складе']); - exit(); - } - - // Проверяем, есть ли товар уже в корзине пользователя - $checkCart = $db->prepare(" - SELECT cart_id, quantity - FROM cart - WHERE user_id = ? AND product_id = ? - "); - $checkCart->execute([$user_id, $product_id]); - $cartItem = $checkCart->fetch(); - - if ($cartItem) { - // Обновляем количество - $newQuantity = $cartItem['quantity'] + $quantity; - - // Проверяем общее количество - if ($newQuantity > $product['stock_quantity']) { - echo json_encode(['success' => false, 'message' => 'Превышено доступное количество']); - exit(); - } - - $updateStmt = $db->prepare(" - UPDATE cart - SET quantity = ?, updated_at = CURRENT_TIMESTAMP - WHERE cart_id = ? - "); - $updateStmt->execute([$newQuantity, $cartItem['cart_id']]); - } else { - // Добавляем новый товар - $insertStmt = $db->prepare(" - INSERT INTO cart (user_id, product_id, quantity) - VALUES (?, ?, ?) - "); - $insertStmt->execute([$user_id, $product_id, $quantity]); - } - - // Обновляем сессию - if (!isset($_SESSION['cart'])) { - $_SESSION['cart'] = []; - } - - if (isset($_SESSION['cart'][$product_id])) { - $_SESSION['cart'][$product_id]['quantity'] += $quantity; - } else { - $_SESSION['cart'][$product_id] = [ - 'quantity' => $quantity, - 'name' => $product['name'], - 'price' => $product['price'], - 'added_at' => time() - ]; - } - - // Получаем общее количество товаров в корзине - $cartCountStmt = $db->prepare(" - SELECT SUM(quantity) as total - FROM cart - WHERE user_id = ? - "); - $cartCountStmt->execute([$user_id]); - $cart_count = $cartCountStmt->fetchColumn() ?: 0; - - echo json_encode([ - 'success' => true, - 'cart_count' => $cart_count, - 'message' => 'Товар добавлен в корзину' - ]); - - } catch (PDOException $e) { - echo json_encode([ - 'success' => false, - 'message' => 'Ошибка базы данных: ' . $e->getMessage() - ]); - } -} else { - echo json_encode(['success' => false, 'message' => 'Неверный запрос']); -} + false, 'message' => 'Требуется авторизация']); + exit(); +} + +if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['product_id'])) { + $product_id = intval($_POST['product_id']); + $quantity = intval($_POST['quantity'] ?? 1); + $user_id = $_SESSION['user_id'] ?? 0; + + if ($user_id == 0) { + echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); + exit(); + } + + $db = Database::getInstance()->getConnection(); + + try { + + $checkStock = $db->prepare(" + SELECT stock_quantity, name, price + FROM products + WHERE product_id = ? AND is_available = TRUE + "); + $checkStock->execute([$product_id]); + $product = $checkStock->fetch(); + + if (!$product) { + echo json_encode(['success' => false, 'message' => 'Товар не найден']); + exit(); + } + + if ($product['stock_quantity'] < $quantity) { + echo json_encode(['success' => false, 'message' => 'Недостаточно товара на складе']); + exit(); + } + + $checkCart = $db->prepare(" + SELECT cart_id, quantity + FROM cart + WHERE user_id = ? AND product_id = ? + "); + $checkCart->execute([$user_id, $product_id]); + $cartItem = $checkCart->fetch(); + + if ($cartItem) { + + $newQuantity = $cartItem['quantity'] + $quantity; + + if ($newQuantity > $product['stock_quantity']) { + echo json_encode(['success' => false, 'message' => 'Превышено доступное количество']); + exit(); + } + + $updateStmt = $db->prepare(" + UPDATE cart + SET quantity = ?, updated_at = CURRENT_TIMESTAMP + WHERE cart_id = ? + "); + $updateStmt->execute([$newQuantity, $cartItem['cart_id']]); + } else { + + $insertStmt = $db->prepare(" + INSERT INTO cart (user_id, product_id, quantity) + VALUES (?, ?, ?) + "); + $insertStmt->execute([$user_id, $product_id, $quantity]); + } + + if (!isset($_SESSION['cart'])) { + $_SESSION['cart'] = []; + } + + if (isset($_SESSION['cart'][$product_id])) { + $_SESSION['cart'][$product_id]['quantity'] += $quantity; + } else { + $_SESSION['cart'][$product_id] = [ + 'quantity' => $quantity, + 'name' => $product['name'], + 'price' => $product['price'], + 'added_at' => time() + ]; + } + + $cartCountStmt = $db->prepare(" + SELECT SUM(quantity) as total + FROM cart + WHERE user_id = ? + "); + $cartCountStmt->execute([$user_id]); + $cart_count = $cartCountStmt->fetchColumn() ?: 0; + + echo json_encode([ + 'success' => true, + 'cart_count' => $cart_count, + 'message' => 'Товар добавлен в корзину' + ]); + + } catch (PDOException $e) { + echo json_encode([ + 'success' => false, + 'message' => 'Ошибка базы данных: ' . $e->getMessage() + ]); + } +} else { + echo json_encode(['success' => false, 'message' => 'Неверный запрос']); +} ?> \ No newline at end of file diff --git a/public/api/auth.php b/public/api/auth.php index cc2f70c..4aac5e4 100644 --- a/public/api/auth.php +++ b/public/api/auth.php @@ -1,71 +1,68 @@ - false, 'message' => 'Заполните все поля']); - exit(); - } - - $db = Database::getInstance()->getConnection(); - - try { - // Проверяем пользователя в базе данных - $stmt = $db->prepare(" - SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active - FROM users - WHERE email = ? - "); - $stmt->execute([$email]); - $user = $stmt->fetch(PDO::FETCH_ASSOC); - - if (!$user) { - echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); - exit(); - } - - if (!$user['is_active']) { - echo json_encode(['success' => false, 'message' => 'Аккаунт заблокирован']); - exit(); - } - - // Проверяем пароль - if (empty($user['password_hash'])) { - echo json_encode(['success' => false, 'message' => 'Ошибка: пароль не найден в базе данных']); - exit(); - } - - if (!password_verify($password, $user['password_hash'])) { - echo json_encode(['success' => false, 'message' => 'Неверный пароль']); - exit(); - } - - // Сохраняем в сессию - $_SESSION['user_id'] = $user['user_id']; - $_SESSION['user_email'] = $user['email']; - $_SESSION['full_name'] = $user['full_name']; - $_SESSION['user_phone'] = $user['phone'] ?? ''; - $_SESSION['user_city'] = $user['city'] ?? ''; - $_SESSION['isLoggedIn'] = true; - $_SESSION['isAdmin'] = (bool)$user['is_admin']; - $_SESSION['login_time'] = time(); - - // Обновляем время последнего входа - $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); - $updateStmt->execute([$user['user_id']]); - - echo json_encode(['success' => true, 'redirect' => 'catalog.php']); - - } catch (PDOException $e) { - echo json_encode(['success' => false, 'message' => 'Ошибка базы данных']); - } - -} else { - echo json_encode(['success' => false, 'message' => 'Неверный запрос']); -} + false, 'message' => 'Заполните все поля']); + exit(); + } + + $db = Database::getInstance()->getConnection(); + + try { + + $stmt = $db->prepare(" + SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active + FROM users + WHERE email = ? + "); + $stmt->execute([$email]); + $user = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$user) { + echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); + exit(); + } + + if (!$user['is_active']) { + echo json_encode(['success' => false, 'message' => 'Аккаунт заблокирован']); + exit(); + } + + if (empty($user['password_hash'])) { + echo json_encode(['success' => false, 'message' => 'Ошибка: пароль не найден в базе данных']); + exit(); + } + + if (!password_verify($password, $user['password_hash'])) { + echo json_encode(['success' => false, 'message' => 'Неверный пароль']); + exit(); + } + + $_SESSION['user_id'] = $user['user_id']; + $_SESSION['user_email'] = $user['email']; + $_SESSION['full_name'] = $user['full_name']; + $_SESSION['user_phone'] = $user['phone'] ?? ''; + $_SESSION['user_city'] = $user['city'] ?? ''; + $_SESSION['isLoggedIn'] = true; + $_SESSION['isAdmin'] = (bool)$user['is_admin']; + $_SESSION['login_time'] = time(); + + $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); + $updateStmt->execute([$user['user_id']]); + + echo json_encode(['success' => true, 'redirect' => 'catalog.php']); + + } catch (PDOException $e) { + echo json_encode(['success' => false, 'message' => 'Ошибка базы данных']); + } + +} else { + echo json_encode(['success' => false, 'message' => 'Неверный запрос']); +} ?> \ No newline at end of file diff --git a/public/api/cart.php b/public/api/cart.php index 030fd9d..cd68d7b 100644 --- a/public/api/cart.php +++ b/public/api/cart.php @@ -1,14 +1,10 @@ false, 'message' => 'Требуется авторизация']); exit(); @@ -24,66 +20,64 @@ try { case 'add': $productId = (int)($_POST['product_id'] ?? 0); $quantity = (int)($_POST['quantity'] ?? 1); - + if ($productId <= 0) { echo json_encode(['success' => false, 'message' => 'Неверный ID товара']); exit(); } - - // Проверяем существование товара + $checkProduct = $db->prepare("SELECT product_id, stock_quantity FROM products WHERE product_id = ? AND is_available = TRUE"); $checkProduct->execute([$productId]); $product = $checkProduct->fetch(); - + if (!$product) { echo json_encode(['success' => false, 'message' => 'Товар не найден']); exit(); } - - // Проверяем, есть ли товар уже в корзине + $checkCart = $db->prepare("SELECT cart_id, quantity FROM cart WHERE user_id = ? AND product_id = ?"); $checkCart->execute([$userId, $productId]); $cartItem = $checkCart->fetch(); - + if ($cartItem) { - // Обновляем количество + $newQuantity = $cartItem['quantity'] + $quantity; $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE cart_id = ?"); $stmt->execute([$newQuantity, $cartItem['cart_id']]); } else { - // Добавляем новый товар + $stmt = $db->prepare("INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)"); $stmt->execute([$userId, $productId, $quantity]); } - + echo json_encode(['success' => true, 'message' => 'Товар добавлен в корзину']); break; - + case 'update': $productId = (int)($_POST['product_id'] ?? 0); $quantity = (int)($_POST['quantity'] ?? 1); - + if ($quantity <= 0) { - // Удаляем товар если количество 0 + $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?"); $stmt->execute([$userId, $productId]); } else { $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE user_id = ? AND product_id = ?"); $stmt->execute([$quantity, $userId, $productId]); } - + echo json_encode(['success' => true, 'message' => 'Корзина обновлена']); break; - + case 'remove': $productId = (int)($_POST['product_id'] ?? 0); - + $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?"); $stmt->execute([$userId, $productId]); - + echo json_encode(['success' => true, 'message' => 'Товар удален из корзины']); break; - + case 'get': $stmt = $db->prepare(" SELECT c.cart_id, c.product_id, c.quantity, p.name, p.price, p.image_url, p.stock_quantity @@ -94,13 +88,13 @@ try { "); $stmt->execute([$userId]); $items = $stmt->fetchAll(); - + $total = 0; foreach ($items as &$item) { $item['subtotal'] = $item['price'] * $item['quantity']; $total += $item['subtotal']; } - + echo json_encode([ 'success' => true, 'items' => $items, @@ -108,27 +102,26 @@ try { 'count' => array_sum(array_column($items, 'quantity')) ]); break; - + case 'count': $stmt = $db->prepare("SELECT COALESCE(SUM(quantity), 0) FROM cart WHERE user_id = ?"); $stmt->execute([$userId]); $count = $stmt->fetchColumn(); - + echo json_encode(['success' => true, 'count' => (int)$count]); break; - + case 'clear': $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ?"); $stmt->execute([$userId]); - + echo json_encode(['success' => true, 'message' => 'Корзина очищена']); break; - + default: echo json_encode(['success' => false, 'message' => 'Неизвестное действие']); } - + } catch (PDOException $e) { echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]); } - diff --git a/public/api/get_cart.php b/public/api/get_cart.php index c5d2a3c..2d43ea4 100644 --- a/public/api/get_cart.php +++ b/public/api/get_cart.php @@ -1,62 +1,61 @@ - false, 'message' => 'Требуется авторизация']); - exit(); -} - -$user_id = $_SESSION['user_id'] ?? 0; - -if ($user_id == 0) { - echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); - exit(); -} - -$db = Database::getInstance()->getConnection(); - -try { - // Получаем корзину из БД - $stmt = $db->prepare(" - SELECT - c.cart_id, - c.product_id, - c.quantity, - p.name, - p.price, - p.image_url, - p.stock_quantity - FROM cart c - JOIN products p ON c.product_id = p.product_id - WHERE c.user_id = ? AND p.is_available = TRUE - ORDER BY c.created_at DESC - "); - $stmt->execute([$user_id]); - $cart_items = $stmt->fetchAll(); - - // Обновляем сессию - $_SESSION['cart'] = []; - foreach ($cart_items as $item) { - $_SESSION['cart'][$item['product_id']] = [ - 'quantity' => $item['quantity'], - 'name' => $item['name'], - 'price' => $item['price'], - 'added_at' => time() - ]; - } - - echo json_encode([ - 'success' => true, - 'cart_items' => $cart_items, - 'total_items' => count($cart_items) - ]); - -} catch (PDOException $e) { - echo json_encode([ - 'success' => false, - 'message' => 'Ошибка базы данных: ' . $e->getMessage() - ]); -} + false, 'message' => 'Требуется авторизация']); + exit(); +} + +$user_id = $_SESSION['user_id'] ?? 0; + +if ($user_id == 0) { + echo json_encode(['success' => false, 'message' => 'Пользователь не найден']); + exit(); +} + +$db = Database::getInstance()->getConnection(); + +try { + + $stmt = $db->prepare(" + SELECT + c.cart_id, + c.product_id, + c.quantity, + p.name, + p.price, + p.image_url, + p.stock_quantity + FROM cart c + JOIN products p ON c.product_id = p.product_id + WHERE c.user_id = ? AND p.is_available = TRUE + ORDER BY c.created_at DESC + "); + $stmt->execute([$user_id]); + $cart_items = $stmt->fetchAll(); + + $_SESSION['cart'] = []; + foreach ($cart_items as $item) { + $_SESSION['cart'][$item['product_id']] = [ + 'quantity' => $item['quantity'], + 'name' => $item['name'], + 'price' => $item['price'], + 'added_at' => time() + ]; + } + + echo json_encode([ + 'success' => true, + 'cart_items' => $cart_items, + 'total_items' => count($cart_items) + ]); + +} catch (PDOException $e) { + echo json_encode([ + 'success' => false, + 'message' => 'Ошибка базы данных: ' . $e->getMessage() + ]); +} ?> \ No newline at end of file diff --git a/public/api/get_cart_count.php b/public/api/get_cart_count.php index eacc4d5..f1d59c2 100644 --- a/public/api/get_cart_count.php +++ b/public/api/get_cart_count.php @@ -1,22 +1,22 @@ - false, 'cart_count' => 0]); - exit(); -} - -$user_id = $_SESSION['user_id'] ?? 0; -$db = Database::getInstance()->getConnection(); - -try { - $stmt = $db->prepare("SELECT SUM(quantity) as total FROM cart WHERE user_id = ?"); - $stmt->execute([$user_id]); - $cart_count = $stmt->fetchColumn() ?: 0; - - echo json_encode(['success' => true, 'cart_count' => $cart_count]); -} catch (PDOException $e) { - echo json_encode(['success' => false, 'cart_count' => 0]); + false, 'cart_count' => 0]); + exit(); +} + +$user_id = $_SESSION['user_id'] ?? 0; +$db = Database::getInstance()->getConnection(); + +try { + $stmt = $db->prepare("SELECT SUM(quantity) as total FROM cart WHERE user_id = ?"); + $stmt->execute([$user_id]); + $cart_count = $stmt->fetchColumn() ?: 0; + + echo json_encode(['success' => true, 'cart_count' => $cart_count]); +} catch (PDOException $e) { + echo json_encode(['success' => false, 'cart_count' => 0]); } \ No newline at end of file diff --git a/public/api/get_product.php b/public/api/get_product.php index e548112..0cd3ca6 100644 --- a/public/api/get_product.php +++ b/public/api/get_product.php @@ -1,33 +1,32 @@ - false, 'message' => 'Доступ запрещен']); - exit(); -} - -if (!isset($_GET['id'])) { - echo json_encode(['success' => false, 'message' => 'ID не указан']); - exit(); -} - -try { - $db = Database::getInstance()->getConnection(); - $product_id = $_GET['id']; - - $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?"); - $stmt->execute([$product_id]); - $product = $stmt->fetch(); - - if ($product) { - echo json_encode($product); - } else { - echo json_encode(['success' => false, 'message' => 'Товар не найден']); - } - -} catch (PDOException $e) { - echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]); -} + false, 'message' => 'Доступ запрещен']); + exit(); +} + +if (!isset($_GET['id'])) { + echo json_encode(['success' => false, 'message' => 'ID не указан']); + exit(); +} + +try { + $db = Database::getInstance()->getConnection(); + $product_id = $_GET['id']; + + $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?"); + $stmt->execute([$product_id]); + $product = $stmt->fetch(); + + if ($product) { + echo json_encode($product); + } else { + echo json_encode(['success' => false, 'message' => 'Товар не найден']); + } + +} catch (PDOException $e) { + echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]); +} ?> \ No newline at end of file diff --git a/public/api/process_order.php b/public/api/process_order.php index 92d34e0..8c94036 100644 --- a/public/api/process_order.php +++ b/public/api/process_order.php @@ -1,134 +1,124 @@ -getConnection(); - - try { - $db->beginTransaction(); - - // Получаем данные из формы - $customer_name = $_POST['full_name'] ?? ''; - $customer_email = $_POST['email'] ?? ''; - $customer_phone = $_POST['phone'] ?? ''; - $delivery_address = $_POST['address'] ?? ''; - $region = $_POST['region'] ?? ''; - $payment_method = $_POST['payment'] ?? 'card'; - $delivery_method = $_POST['delivery'] ?? 'courier'; - $notes = $_POST['notes'] ?? ''; - $discount_amount = floatval($_POST['discount'] ?? 0); - $delivery_cost = floatval($_POST['delivery_price'] ?? 2000); - - // Генерируем номер заказа - $order_number = 'ORD-' . date('Ymd-His') . '-' . rand(1000, 9999); - - // Получаем корзину пользователя - $cartStmt = $db->prepare(" - SELECT - c.product_id, - c.quantity, - p.name, - p.price, - p.stock_quantity - FROM cart c - JOIN products p ON c.product_id = p.product_id - WHERE c.user_id = ? - "); - $cartStmt->execute([$user_id]); - $cart_items = $cartStmt->fetchAll(); - - if (empty($cart_items)) { - throw new Exception('Корзина пуста'); - } - - // Рассчитываем итоги - $total_amount = 0; - foreach ($cart_items as $item) { - $total_amount += $item['price'] * $item['quantity']; - } - - $final_amount = $total_amount - $discount_amount + $delivery_cost; - - // Создаем заказ - $orderStmt = $db->prepare(" - INSERT INTO orders ( - user_id, order_number, total_amount, discount_amount, - delivery_cost, final_amount, status, payment_method, - delivery_method, delivery_address, customer_name, - customer_email, customer_phone, notes - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - RETURNING order_id - "); - - $orderStmt->execute([ - $user_id, $order_number, $total_amount, $discount_amount, - $delivery_cost, $final_amount, 'pending', $payment_method, - $delivery_method, $delivery_address, $customer_name, - $customer_email, $customer_phone, $notes - ]); - - $order_id = $orderStmt->fetchColumn(); - - // Добавляем товары в заказ и обновляем остатки - foreach ($cart_items as $item) { - // Добавляем в order_items - $itemStmt = $db->prepare(" - INSERT INTO order_items ( - order_id, product_id, product_name, - quantity, unit_price, total_price - ) VALUES (?, ?, ?, ?, ?, ?) - "); - - $item_total = $item['price'] * $item['quantity']; - $itemStmt->execute([ - $order_id, $item['product_id'], $item['name'], - $item['quantity'], $item['price'], $item_total - ]); - - // Обновляем остатки на складе - $updateStmt = $db->prepare(" - UPDATE products - SET stock_quantity = stock_quantity - ?, - updated_at = CURRENT_TIMESTAMP - WHERE product_id = ? - "); - $updateStmt->execute([$item['quantity'], $item['product_id']]); - } - - // Очищаем корзину - $clearCartStmt = $db->prepare("DELETE FROM cart WHERE user_id = ?"); - $clearCartStmt->execute([$user_id]); - - // Очищаем сессию - unset($_SESSION['cart']); - - $db->commit(); - - // Перенаправляем на страницу успеха - header('Location: order_success.php?id=' . $order_id); - exit(); - - } catch (Exception $e) { - $db->rollBack(); - header('Location: checkout.php?error=' . urlencode($e->getMessage())); - exit(); - } -} else { - header('Location: checkout.php'); - exit(); -} +getConnection(); + + try { + $db->beginTransaction(); + + $customer_name = $_POST['full_name'] ?? ''; + $customer_email = $_POST['email'] ?? ''; + $customer_phone = $_POST['phone'] ?? ''; + $delivery_address = $_POST['address'] ?? ''; + $region = $_POST['region'] ?? ''; + $payment_method = $_POST['payment'] ?? 'card'; + $delivery_method = $_POST['delivery'] ?? 'courier'; + $notes = $_POST['notes'] ?? ''; + $discount_amount = floatval($_POST['discount'] ?? 0); + $delivery_cost = floatval($_POST['delivery_price'] ?? 2000); + + $order_number = 'ORD-' . date('Ymd-His') . '-' . rand(1000, 9999); + + $cartStmt = $db->prepare(" + SELECT + c.product_id, + c.quantity, + p.name, + p.price, + p.stock_quantity + FROM cart c + JOIN products p ON c.product_id = p.product_id + WHERE c.user_id = ? + "); + $cartStmt->execute([$user_id]); + $cart_items = $cartStmt->fetchAll(); + + if (empty($cart_items)) { + throw new Exception('Корзина пуста'); + } + + $total_amount = 0; + foreach ($cart_items as $item) { + $total_amount += $item['price'] * $item['quantity']; + } + + $final_amount = $total_amount - $discount_amount + $delivery_cost; + + $orderStmt = $db->prepare(" + INSERT INTO orders ( + user_id, order_number, total_amount, discount_amount, + delivery_cost, final_amount, status, payment_method, + delivery_method, delivery_address, customer_name, + customer_email, customer_phone, notes + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + RETURNING order_id + "); + + $orderStmt->execute([ + $user_id, $order_number, $total_amount, $discount_amount, + $delivery_cost, $final_amount, 'pending', $payment_method, + $delivery_method, $delivery_address, $customer_name, + $customer_email, $customer_phone, $notes + ]); + + $order_id = $orderStmt->fetchColumn(); + + foreach ($cart_items as $item) { + + $itemStmt = $db->prepare(" + INSERT INTO order_items ( + order_id, product_id, product_name, + quantity, unit_price, total_price + ) VALUES (?, ?, ?, ?, ?, ?) + "); + + $item_total = $item['price'] * $item['quantity']; + $itemStmt->execute([ + $order_id, $item['product_id'], $item['name'], + $item['quantity'], $item['price'], $item_total + ]); + + $updateStmt = $db->prepare(" + UPDATE products + SET stock_quantity = stock_quantity - ?, + updated_at = CURRENT_TIMESTAMP + WHERE product_id = ? + "); + $updateStmt->execute([$item['quantity'], $item['product_id']]); + } + + $clearCartStmt = $db->prepare("DELETE FROM cart WHERE user_id = ?"); + $clearCartStmt->execute([$user_id]); + + unset($_SESSION['cart']); + + $db->commit(); + + header('Location: order_success.php?id=' . $order_id); + exit(); + + } catch (Exception $e) { + $db->rollBack(); + header('Location: checkout.php?error=' . urlencode($e->getMessage())); + exit(); + } +} else { + header('Location: checkout.php'); + exit(); +} ?> \ No newline at end of file diff --git a/public/api/register_handler.php b/public/api/register_handler.php index 91efb70..d1cfb81 100644 --- a/public/api/register_handler.php +++ b/public/api/register_handler.php @@ -1,175 +1,162 @@ - $full_name, - 'city' => $city, - 'email' => $email, - 'phone' => $phone - ]; - header('Location: ../register.php'); - exit(); - } - - // Подключаемся к базе данных - $db = Database::getInstance()->getConnection(); - - try { - // Проверяем, существует ли пользователь с таким email - $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?"); - $checkStmt->execute([$email]); - - if ($checkStmt->fetch()) { - $_SESSION['registration_errors'] = ['Пользователь с таким email уже существует']; - $_SESSION['old_data'] = [ - 'fio' => $full_name, - 'city' => $city, - 'email' => $email, - 'phone' => $phone - ]; - header('Location: ../register.php'); - exit(); - } - - // Хэшируем пароль - $password_hash = password_hash($password, PASSWORD_DEFAULT); - - // Определяем, является ли пользователь администратором - $is_admin = false; - $admin_emails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; - if (in_array(strtolower($email), $admin_emails)) { - $is_admin = true; - } - - // Используем CAST для правильной передачи boolean в PostgreSQL - $stmt = $db->prepare(" - INSERT INTO users (email, password_hash, full_name, phone, city, is_admin, is_active) - VALUES (?, ?, ?, ?, ?, CAST(? AS boolean), TRUE) - RETURNING user_id - "); - - $stmt->execute([ - $email, - $password_hash, - $full_name, - $phone, - $city, - $is_admin ? 'true' : 'false' // Строковые значения true/false для CAST - ]); - - $user_id = $stmt->fetchColumn(); - - if (!$user_id) { - throw new Exception('Ошибка при создании пользователя: user_id не получен'); - } - - // Проверяем, что пользователь действительно создался - $verifyStmt = $db->prepare("SELECT user_id, email, password_hash FROM users WHERE user_id = ?"); - $verifyStmt->execute([$user_id]); - $verifyUser = $verifyStmt->fetch(PDO::FETCH_ASSOC); - - if (!$verifyUser) { - throw new Exception('Ошибка: пользователь не найден после создания'); - } - - // Проверяем, что пароль сохранился правильно - if (empty($verifyUser['password_hash'])) { - throw new Exception('Ошибка: пароль не сохранен'); - } - - // Автоматически авторизуем пользователя - $_SESSION['user_id'] = $user_id; - $_SESSION['user_email'] = $email; - $_SESSION['full_name'] = $full_name; - $_SESSION['user_phone'] = $phone; - $_SESSION['user_city'] = $city; - $_SESSION['isLoggedIn'] = true; - $_SESSION['isAdmin'] = (bool)$is_admin; - $_SESSION['login_time'] = time(); - - // Обновляем время последнего входа - $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); - $updateStmt->execute([$user_id]); - - // Перенаправляем на главную или каталог - $_SESSION['registration_success'] = 'Регистрация прошла успешно! ' . - ($is_admin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!'); - - header('Location: ../catalog.php'); - exit(); - - } catch (PDOException $e) { - // Логируем полную ошибку для отладки - error_log("Registration DB Error: " . $e->getMessage()); - error_log("SQL State: " . $e->getCode()); - error_log("Email: " . $email); - - $_SESSION['registration_errors'] = ['Ошибка базы данных: ' . $e->getMessage()]; - $_SESSION['old_data'] = [ - 'fio' => $full_name, - 'city' => $city, - 'email' => $email, - 'phone' => $phone - ]; - header('Location: ../register.php'); - exit(); - } catch (Exception $e) { - error_log("Registration Error: " . $e->getMessage()); - - $_SESSION['registration_errors'] = [$e->getMessage()]; - header('Location: ../register.php'); - exit(); - } - -} else { - // Если запрос не POST, перенаправляем на форму регистрации - header('Location: register.php'); - exit(); -} + $full_name, + 'city' => $city, + 'email' => $email, + 'phone' => $phone + ]; + header('Location: ../register.php'); + exit(); + } + + $db = Database::getInstance()->getConnection(); + + try { + + $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?"); + $checkStmt->execute([$email]); + + if ($checkStmt->fetch()) { + $_SESSION['registration_errors'] = ['Пользователь с таким email уже существует']; + $_SESSION['old_data'] = [ + 'fio' => $full_name, + 'city' => $city, + 'email' => $email, + 'phone' => $phone + ]; + header('Location: ../register.php'); + exit(); + } + + $password_hash = password_hash($password, PASSWORD_DEFAULT); + + $is_admin = false; + $admin_emails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; + if (in_array(strtolower($email), $admin_emails)) { + $is_admin = true; + } + + $stmt = $db->prepare(" + INSERT INTO users (email, password_hash, full_name, phone, city, is_admin, is_active) + VALUES (?, ?, ?, ?, ?, CAST(? AS boolean), TRUE) + RETURNING user_id + "); + + $stmt->execute([ + $email, + $password_hash, + $full_name, + $phone, + $city, + $is_admin ? 'true' : 'false' + ]); + + $user_id = $stmt->fetchColumn(); + + if (!$user_id) { + throw new Exception('Ошибка при создании пользователя: user_id не получен'); + } + + $verifyStmt = $db->prepare("SELECT user_id, email, password_hash FROM users WHERE user_id = ?"); + $verifyStmt->execute([$user_id]); + $verifyUser = $verifyStmt->fetch(PDO::FETCH_ASSOC); + + if (!$verifyUser) { + throw new Exception('Ошибка: пользователь не найден после создания'); + } + + if (empty($verifyUser['password_hash'])) { + throw new Exception('Ошибка: пароль не сохранен'); + } + + $_SESSION['user_id'] = $user_id; + $_SESSION['user_email'] = $email; + $_SESSION['full_name'] = $full_name; + $_SESSION['user_phone'] = $phone; + $_SESSION['user_city'] = $city; + $_SESSION['isLoggedIn'] = true; + $_SESSION['isAdmin'] = (bool)$is_admin; + $_SESSION['login_time'] = time(); + + $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?"); + $updateStmt->execute([$user_id]); + + $_SESSION['registration_success'] = 'Регистрация прошла успешно! ' . + ($is_admin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!'); + + header('Location: ../catalog.php'); + exit(); + + } catch (PDOException $e) { + + error_log("Registration DB Error: " . $e->getMessage()); + error_log("SQL State: " . $e->getCode()); + error_log("Email: " . $email); + + $_SESSION['registration_errors'] = ['Ошибка базы данных: ' . $e->getMessage()]; + $_SESSION['old_data'] = [ + 'fio' => $full_name, + 'city' => $city, + 'email' => $email, + 'phone' => $phone + ]; + header('Location: ../register.php'); + exit(); + } catch (Exception $e) { + error_log("Registration Error: " . $e->getMessage()); + + $_SESSION['registration_errors'] = [$e->getMessage()]; + header('Location: ../register.php'); + exit(); + } + +} else { + + header('Location: register.php'); + exit(); +} ?> \ No newline at end of file diff --git a/public/assets/img/стили_оформления.css b/public/assets/img/стили_оформления.css index 581822b..2e1d09c 100644 --- a/public/assets/img/стили_оформления.css +++ b/public/assets/img/стили_оформления.css @@ -1,62 +1,61 @@ - -.error-message { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; -} - -.form__input.error { - border-color: #ff0000; -} - -.form__group { - position: relative; - margin-bottom: 15px; -} - -/* Стили для сообщений внизу страницы */ -.page-messages { - position: fixed; - bottom: 20px; - left: 50%; - transform: translateX(-50%); - z-index: 1000; - width: 90%; - max-width: 500px; -} - -.message { - padding: 15px; - margin: 10px 0; - border-radius: 5px; - text-align: center; - font-weight: bold; - display: none; -} - -.message.error { - background-color: #ffebee; - color: #c62828; - border: 1px solid #ffcdd2; -} - -.message.success { - background-color: #e8f5e9; - color: #453227; - border: 1px solid #c8e6c9; -} - -.message.warning { - background-color: #fff3e0; - color: #ef6c00; - border: 1px solid #ffe0b2; -} - -.privacy-error { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; - text-align: center; -} + +.error-message { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; +} + +.form__input.error { + border-color: #ff0000; +} + +.form__group { + position: relative; + margin-bottom: 15px; +} + +.page-messages { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + width: 90%; + max-width: 500px; +} + +.message { + padding: 15px; + margin: 10px 0; + border-radius: 5px; + text-align: center; + font-weight: bold; + display: none; +} + +.message.error { + background-color: #ffebee; + color: #c62828; + border: 1px solid #ffcdd2; +} + +.message.success { + background-color: #e8f5e9; + color: #453227; + border: 1px solid #c8e6c9; +} + +.message.warning { + background-color: #fff3e0; + color: #ef6c00; + border: 1px solid #ffe0b2; +} + +.privacy-error { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; + text-align: center; +} diff --git a/public/assets/js/checkout.js b/public/assets/js/checkout.js index 74e8305..45a09f5 100644 --- a/public/assets/js/checkout.js +++ b/public/assets/js/checkout.js @@ -1,346 +1,306 @@ -// script.js - -$(document).ready(function() { - // Инициализация корзины - let cart = { - items: [ - { id: 1, name: 'Кресло OPPORTUNITY', price: 16999, quantity: 1 }, - { id: 2, name: 'Кресло GOLDEN', price: 19999, quantity: 1 }, - { id: 3, name: 'Светильник POLET', price: 7999, quantity: 1 } - ], - delivery: 2000, - discount: 0 - }; - - // Функция обновления общей суммы - function updateTotal() { - let productsTotal = 0; - let totalCount = 0; - - // Пересчитываем товары - $('.products__item').each(function() { - const $item = $(this); - const price = parseInt($item.data('price')); - const quantity = parseInt($item.find('.products__qty-value').text()); - - productsTotal += price * quantity; - totalCount += quantity; - }); - - // Обновляем отображение - $('.products-total').text(productsTotal + ' ₽'); - $('.summary-count').text(totalCount); - $('.total-count').text(totalCount + ' шт.'); - $('.cart-count').text(totalCount); - - // Обновляем итоговую сумму - const finalTotal = productsTotal + cart.delivery - cart.discount; - $('.final-total').text(finalTotal + ' ₽'); - } - - // Функция валидации email - function validateEmail(email) { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); - } - - // Функция валидации имени (ФИО) - function validateFullName(name) { - // Проверяем, что имя содержит только буквы, пробелы, дефисы и апострофы - const nameRegex = /^[a-zA-Zа-яА-ЯёЁ\s\-']+$/; - - // Проверяем, что имя состоит минимум из 2 слов - const words = name.trim().split(/\s+/); - - return nameRegex.test(name) && words.length >= 2; - } - - // Функция валидации телефона - function validatePhone(phone) { - // Российский формат телефона: +7XXXXXXXXXX - const phoneRegex = /^\+7\d{10}$/; - return phoneRegex.test(phone); - } - - // Функция отображения сообщения - function showMessage(messageId, duration = 5000) { - // Скрываем все сообщения - $('.message').hide(); - - // Показываем нужное сообщение - $(messageId).fadeIn(300); - - // Автоматически скрываем через указанное время - if (duration > 0) { - setTimeout(() => { - $(messageId).fadeOut(300); - }, duration); - } - } - - // Функция показа ошибки приватности - function showPrivacyError(show) { - if (show) { - $('#privacy-error').show(); - } else { - $('#privacy-error').hide(); - } - } - - // Функция отображения ошибки конкретного поля - function showFieldError(fieldId, message) { - // Убираем старые ошибки - $(fieldId).removeClass('error-input'); - $(fieldId + '-error').remove(); - - if (message) { - $(fieldId).addClass('error-input'); - $(fieldId).after('
' + message + '
'); - } - } - - // Валидация поля при потере фокуса с указанием конкретной ошибки - $('#fullname').on('blur', function() { - const value = $(this).val().trim(); - if (value) { - if (!validateFullName(value)) { - showFieldError('#fullname', 'ФИО должно содержать только буквы и состоять минимум из 2 слов'); - } else { - showFieldError('#fullname', ''); - } - } else { - showFieldError('#fullname', ''); - } - }); - - $('#email').on('blur', function() { - const value = $(this).val().trim(); - if (value) { - if (!validateEmail(value)) { - showFieldError('#email', 'Введите корректный email адрес (например: example@mail.ru)'); - } else { - showFieldError('#email', ''); - } - } else { - showFieldError('#email', ''); - } - }); - - $('#phone').on('blur', function() { - const value = $(this).val().trim(); - if (value) { - if (!validatePhone(value)) { - showFieldError('#phone', 'Введите номер в формате +7XXXXXXXXXX (10 цифр после +7)'); - } else { - showFieldError('#phone', ''); - } - } else { - showFieldError('#phone', ''); - } - }); - - // Валидация обязательных полей - $('#region').on('blur', function() { - const value = $(this).val().trim(); - if (!value) { - showFieldError('#region', 'Укажите регион доставки'); - } else { - showFieldError('#region', ''); - } - }); - - $('#address').on('blur', function() { - const value = $(this).val().trim(); - if (!value) { - showFieldError('#address', 'Укажите адрес доставки (улица, дом, квартира)'); - } else { - showFieldError('#address', ''); - } - }); - - // Очистка ошибки при начале ввода - $('.form__input').on('input', function() { - const fieldId = '#' + $(this).attr('id'); - showFieldError(fieldId, ''); - }); - - // Обработчик увеличения количества - $('.products__qty-btn.plus').click(function() { - const $qtyValue = $(this).siblings('.products__qty-value'); - let quantity = parseInt($qtyValue.text()); - $qtyValue.text(quantity + 1); - updateTotal(); - }); - - // Обработчик уменьшения количества - $('.products__qty-btn.minus').click(function() { - const $qtyValue = $(this).siblings('.products__qty-value'); - let quantity = parseInt($qtyValue.text()); - if (quantity > 1) { - $qtyValue.text(quantity - 1); - updateTotal(); - } - }); - - // Обработчик удаления товара - $('.remove-from-cart').click(function() { - const $productItem = $(this).closest('.products__item'); - $productItem.fadeOut(300, function() { - $(this).remove(); - updateTotal(); - - // Показываем сообщение, если корзина пуста - if ($('.products__item').length === 0) { - $('.products__list').html('
Корзина пуста
'); - } - }); - }); - - // Обработчик применения промокода - $('.promo__btn').click(function() { - const promoCode = $('.promo__input').val().toUpperCase(); - - if (promoCode === 'SALE10') { - cart.discount = Math.round(parseInt($('.products-total').text()) * 0.1); - $('.discount-total').text(cart.discount + ' ₽'); - showMessage('#form-error', 3000); - $('#form-error').text('Промокод применен! Скидка 10%').removeClass('error').addClass('success'); - } else if (promoCode === 'FREE') { - cart.delivery = 0; - $('.delivery-price').text('0 ₽'); - showMessage('#form-error', 3000); - $('#form-error').text('Промокод применен! Бесплатная доставка').removeClass('error').addClass('success'); - } else if (promoCode) { - showMessage('#form-error', 3000); - $('#form-error').text('Промокод недействителен').removeClass('success').addClass('error'); - } - - updateTotal(); - }); - - // Обработчик выбора доставки - $('input[name="delivery"]').change(function() { - if ($(this).val() === 'pickup') { - cart.delivery = 0; - $('.delivery-price').text('0 ₽'); - } else { - cart.delivery = 2000; - $('.delivery-price').text('2000 ₽'); - } - updateTotal(); - }); - - // Функция проверки всех полей формы - function validateForm() { - let isValid = true; - let errorMessages = []; - - // Очищаем все старые ошибки - $('.field-error').remove(); - $('.form__input').removeClass('error-input'); - - // Проверка обязательных полей - const requiredFields = [ - { - id: '#fullname', - value: $('#fullname').val().trim(), - validator: validateFullName, - required: true, - message: 'ФИО должно содержать только буквы и состоять минимум из 2 слов' - }, - { - id: '#phone', - value: $('#phone').val().trim(), - validator: validatePhone, - required: true, - message: 'Введите корректный номер телефона в формате +7XXXXXXXXXX' - }, - { - id: '#email', - value: $('#email').val().trim(), - validator: validateEmail, - required: true, - message: 'Введите корректный email адрес' - }, - { - id: '#region', - value: $('#region').val().trim(), - validator: (val) => val.length > 0, - required: true, - message: 'Поле "Регион" обязательно для заполнения' - }, - { - id: '#address', - value: $('#address').val().trim(), - validator: (val) => val.length > 0, - required: true, - message: 'Поле "Адрес" обязательно для заполнения' - } - ]; - - // Проверяем каждое поле - requiredFields.forEach(field => { - if (field.required && (!field.value || !field.validator(field.value))) { - isValid = false; - errorMessages.push(field.message); - showFieldError(field.id, field.message); - } - }); - - // Проверка согласия на обработку данных - if (!$('#privacy-checkbox').is(':checked')) { - isValid = false; - showPrivacyError(true); - errorMessages.push('Необходимо согласие на обработку персональных данных'); - } else { - showPrivacyError(false); - } - - // Показываем общее сообщение, если есть ошибки - if (!isValid && errorMessages.length > 0) { - showMessage('#form-error', 5000); - $('#form-error').text('Исправьте следующие ошибки: ' + errorMessages.join('; ')).removeClass('success').addClass('error'); - - // Прокручиваем к первой ошибке - $('html, body').animate({ - scrollTop: $('.error-input').first().offset().top - 100 - }, 500); - } - - return isValid; - } - - // Обработчик оформления заказа - $('#submit-order').click(function() { - // Проверка валидации всех полей - if (!validateForm()) { - return; - } - - // Симуляция отправки заказа - $(this).prop('disabled', true).text('ОБРАБОТКА...'); - - setTimeout(() => { - showMessage('#order-success', 5000); - $(this).prop('disabled', false).text('ОФОРМИТЬ ЗАКАЗ'); - - // Здесь можно добавить редирект на страницу благодарности - // window.location.href = 'спасибо.html'; - }, 2000); - }); - - // Маска для телефона - $('#phone').on('input', function() { - let phone = $(this).val().replace(/\D/g, ''); - if (phone.length > 0) { - if (phone[0] !== '7' && phone[0] !== '8') { - phone = '7' + phone; - } - phone = '+7' + phone.substring(1, 11); - $(this).val(phone); - } - }); - - // Инициализация при загрузке - updateTotal(); -}); \ No newline at end of file + +$(document).ready(function() { + + let cart = { + items: [ + { id: 1, name: 'Кресло OPPORTUNITY', price: 16999, quantity: 1 }, + { id: 2, name: 'Кресло GOLDEN', price: 19999, quantity: 1 }, + { id: 3, name: 'Светильник POLET', price: 7999, quantity: 1 } + ], + delivery: 2000, + discount: 0 + }; + + function updateTotal() { + let productsTotal = 0; + let totalCount = 0; + + $('.products__item').each(function() { + const $item = $(this); + const price = parseInt($item.data('price')); + const quantity = parseInt($item.find('.products__qty-value').text()); + + productsTotal += price * quantity; + totalCount += quantity; + }); + + $('.products-total').text(productsTotal + ' ₽'); + $('.summary-count').text(totalCount); + $('.total-count').text(totalCount + ' шт.'); + $('.cart-count').text(totalCount); + + const finalTotal = productsTotal + cart.delivery - cart.discount; + $('.final-total').text(finalTotal + ' ₽'); + } + + function validateEmail(email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); + } + + function validateFullName(name) { + + const nameRegex = /^[a-zA-Zа-яА-ЯёЁ\s\-']+$/; + + const words = name.trim().split(/\s+/); + + return nameRegex.test(name) && words.length >= 2; + } + + function validatePhone(phone) { + const phoneRegex = /^\+7\d{10}$/; + return phoneRegex.test(phone); + } + + function showMessage(messageId, duration = 5000) { + $('.message').hide(); + + $(messageId).fadeIn(300); + + if (duration > 0) { + setTimeout(() => { + $(messageId).fadeOut(300); + }, duration); + } + } + + function showPrivacyError(show) { + if (show) { + $('#privacy-error').show(); + } else { + $('#privacy-error').hide(); + } + } + + function showFieldError(fieldId, message) { + $(fieldId).removeClass('error-input'); + $(fieldId + '-error').remove(); + + if (message) { + $(fieldId).addClass('error-input'); + $(fieldId).after('
' + message + '
'); + } + } + + $('#fullname').on('blur', function() { + const value = $(this).val().trim(); + if (value) { + if (!validateFullName(value)) { + showFieldError('#fullname', 'ФИО должно содержать только буквы и состоять минимум из 2 слов'); + } else { + showFieldError('#fullname', ''); + } + } else { + showFieldError('#fullname', ''); + } + }); + + $('#email').on('blur', function() { + const value = $(this).val().trim(); + if (value) { + if (!validateEmail(value)) { + showFieldError('#email', 'Введите корректный email адрес (например: example@mail.ru)'); + } else { + showFieldError('#email', ''); + } + } else { + showFieldError('#email', ''); + } + }); + + $('#phone').on('blur', function() { + const value = $(this).val().trim(); + if (value) { + if (!validatePhone(value)) { + showFieldError('#phone', 'Введите номер в формате +7XXXXXXXXXX (10 цифр после +7)'); + } else { + showFieldError('#phone', ''); + } + } else { + showFieldError('#phone', ''); + } + }); + + $('#region').on('blur', function() { + const value = $(this).val().trim(); + if (!value) { + showFieldError('#region', 'Укажите регион доставки'); + } else { + showFieldError('#region', ''); + } + }); + + $('#address').on('blur', function() { + const value = $(this).val().trim(); + if (!value) { + showFieldError('#address', 'Укажите адрес доставки (улица, дом, квартира)'); + } else { + showFieldError('#address', ''); + } + }); + + $('.form__input').on('input', function() { + const fieldId = '#' + $(this).attr('id'); + showFieldError(fieldId, ''); + }); + + $('.products__qty-btn.plus').click(function() { + const $qtyValue = $(this).siblings('.products__qty-value'); + let quantity = parseInt($qtyValue.text()); + $qtyValue.text(quantity + 1); + updateTotal(); + }); + + $('.products__qty-btn.minus').click(function() { + const $qtyValue = $(this).siblings('.products__qty-value'); + let quantity = parseInt($qtyValue.text()); + if (quantity > 1) { + $qtyValue.text(quantity - 1); + updateTotal(); + } + }); + + $('.remove-from-cart').click(function() { + const $productItem = $(this).closest('.products__item'); + $productItem.fadeOut(300, function() { + $(this).remove(); + updateTotal(); + + if ($('.products__item').length === 0) { + $('.products__list').html('
Корзина пуста
'); + } + }); + }); + + $('.promo__btn').click(function() { + const promoCode = $('.promo__input').val().toUpperCase(); + + if (promoCode === 'SALE10') { + cart.discount = Math.round(parseInt($('.products-total').text()) * 0.1); + $('.discount-total').text(cart.discount + ' ₽'); + showMessage('#form-error', 3000); + $('#form-error').text('Промокод применен! Скидка 10%').removeClass('error').addClass('success'); + } else if (promoCode === 'FREE') { + cart.delivery = 0; + $('.delivery-price').text('0 ₽'); + showMessage('#form-error', 3000); + $('#form-error').text('Промокод применен! Бесплатная доставка').removeClass('error').addClass('success'); + } else if (promoCode) { + showMessage('#form-error', 3000); + $('#form-error').text('Промокод недействителен').removeClass('success').addClass('error'); + } + + updateTotal(); + }); + + $('input[name="delivery"]').change(function() { + if ($(this).val() === 'pickup') { + cart.delivery = 0; + $('.delivery-price').text('0 ₽'); + } else { + cart.delivery = 2000; + $('.delivery-price').text('2000 ₽'); + } + updateTotal(); + }); + + function validateForm() { + let isValid = true; + let errorMessages = []; + + $('.field-error').remove(); + $('.form__input').removeClass('error-input'); + + const requiredFields = [ + { + id: '#fullname', + value: $('#fullname').val().trim(), + validator: validateFullName, + required: true, + message: 'ФИО должно содержать только буквы и состоять минимум из 2 слов' + }, + { + id: '#phone', + value: $('#phone').val().trim(), + validator: validatePhone, + required: true, + message: 'Введите корректный номер телефона в формате +7XXXXXXXXXX' + }, + { + id: '#email', + value: $('#email').val().trim(), + validator: validateEmail, + required: true, + message: 'Введите корректный email адрес' + }, + { + id: '#region', + value: $('#region').val().trim(), + validator: (val) => val.length > 0, + required: true, + message: 'Поле "Регион" обязательно для заполнения' + }, + { + id: '#address', + value: $('#address').val().trim(), + validator: (val) => val.length > 0, + required: true, + message: 'Поле "Адрес" обязательно для заполнения' + } + ]; + + requiredFields.forEach(field => { + if (field.required && (!field.value || !field.validator(field.value))) { + isValid = false; + errorMessages.push(field.message); + showFieldError(field.id, field.message); + } + }); + + if (!$('#privacy-checkbox').is(':checked')) { + isValid = false; + showPrivacyError(true); + errorMessages.push('Необходимо согласие на обработку персональных данных'); + } else { + showPrivacyError(false); + } + + if (!isValid && errorMessages.length > 0) { + showMessage('#form-error', 5000); + $('#form-error').text('Исправьте следующие ошибки: ' + errorMessages.join('; ')).removeClass('success').addClass('error'); + + $('html, body').animate({ + scrollTop: $('.error-input').first().offset().top - 100 + }, 500); + } + + return isValid; + } + + $('#submit-order').click(function() { + if (!validateForm()) { + return; + } + + $(this).prop('disabled', true).text('ОБРАБОТКА...'); + + setTimeout(() => { + showMessage('#order-success', 5000); + $(this).prop('disabled', false).text('ОФОРМИТЬ ЗАКАЗ'); + + }, 2000); + }); + + $('#phone').on('input', function() { + let phone = $(this).val().replace(/\D/g, ''); + if (phone.length > 0) { + if (phone[0] !== '7' && phone[0] !== '8') { + phone = '7' + phone; + } + phone = '+7' + phone.substring(1, 11); + $(this).val(phone); + } + }); + + updateTotal(); +}); diff --git a/public/assets/js/profile.js b/public/assets/js/profile.js index 4aa7ff1..0224b62 100644 --- a/public/assets/js/profile.js +++ b/public/assets/js/profile.js @@ -1,384 +1,348 @@ -$(document).ready(function() { - // Функции для отображения сообщений - function showMessage(type, text) { - const messageId = type + 'Message'; - const $message = $('#' + messageId); - $message.text(text).fadeIn(300); - setTimeout(() => { - $message.fadeOut(300); - }, 5000); - } - - // Проверка, является ли email администратора - function isAdminEmail(email) { - const adminEmails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; - return adminEmails.includes(email.toLowerCase()); - } - - // Валидация ФИО (без цифр) - function validateFIO(fio) { - const words = fio.trim().split(/\s+/); - // Проверяем, что минимум 2 слова и нет цифр - const hasNoDigits = !/\d/.test(fio); - return words.length >= 2 && words.every(word => word.length >= 2) && hasNoDigits; - } - - // Валидация города - function validateCity(city) { - return city.trim().length >= 2 && /^[а-яА-ЯёЁ\s-]+$/.test(city); - } - - // Валидация email - function validateEmail(email) { - const localPart = email.split('@')[0]; - - // Проверка на кириллические символы перед @ - if (/[а-яА-ЯёЁ]/.test(localPart)) { - showError('email', 'В тексте перед знаком "@" не должно быть кириллических символов'); - return false; - } - - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(email)) { - showError('email', 'Введите корректный email адрес'); - return false; - } - - hideError('email'); - return true; - } - - // Валидация телефона - function validatePhone(phone) { - const phoneRegex = /^(\+7|8)[\s-]?\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}$/; - return phoneRegex.test(phone.replace(/\s/g, '')); - } - - // Валидация пароля - function validatePassword(password) { - return password.length >= 6; - } - - // Показать/скрыть ошибку - function showError(fieldId, message) { - $('#' + fieldId).addClass('error'); - $('#' + fieldId + '-error').text(message).show(); - } - - function hideError(fieldId) { - $('#' + fieldId).removeClass('error'); - $('#' + fieldId + '-error').hide(); - } - - // Валидация формы - function validateForm() { - let isValid = true; - - // Валидация ФИО - const fio = $('#fio').val(); - if (!validateFIO(fio)) { - if (/\d/.test(fio)) { - showError('fio', 'ФИО не должно содержать цифры'); - } else { - showError('fio', 'ФИО должно содержать минимум 2 слова (каждое от 2 символов)'); - } - isValid = false; - } else { - hideError('fio'); - } - - // Валидация города - const city = $('#city').val(); - if (!validateCity(city)) { - showError('city', 'Укажите корректное название города (только русские буквы)'); - isValid = false; - } else { - hideError('city'); - } - - // Валидация email - const email = $('#email').val(); - if (!validateEmail(email)) { - showError('email', 'Введите корректный email адрес'); - isValid = false; - } else { - hideError('email'); - } - - // Валидация телефона - const phone = $('#phone').val(); - if (!validatePhone(phone)) { - showError('phone', 'Введите номер в формате: +7(912)999-12-23'); - isValid = false; - } else { - hideError('phone'); - } - - // Валидация пароля - const password = $('#password').val(); - if (!validatePassword(password)) { - showError('password', 'Пароль должен содержать минимум 6 символов'); - isValid = false; - } else { - hideError('password'); - } - - // Проверка совпадения паролей - const confirmPassword = $('#confirm-password').val(); - if (password !== confirmPassword) { - showError('confirm-password', 'Пароли не совпадают'); - isValid = false; - } else { - hideError('confirm-password'); - } - - // Проверка согласия с условиями - if (!$('#privacy').is(':checked')) { - $('#privacy-error').show(); - isValid = false; - } else { - $('#privacy-error').hide(); - } - - return isValid; - } - - // Реальная валидация при вводе - $('input').on('blur', function() { - const fieldId = $(this).attr('id'); - const value = $(this).val(); - - switch(fieldId) { - case 'fio': - if (!validateFIO(value)) { - if (/\d/.test(value)) { - showError(fieldId, 'ФИО не должно содержать цифры'); - } else { - showError(fieldId, 'ФИО должно содержать минимум 2 слова'); - } - } else { - hideError(fieldId); - } - break; - case 'city': - if (!validateCity(value)) { - showError(fieldId, 'Укажите корректное название города'); - } else { - hideError(fieldId); - } - break; - case 'email': - if (!validateEmail(value)) { - showError(fieldId, 'Введите корректный email адрес'); - } else { - hideError(fieldId); - } - break; - case 'phone': - if (!validatePhone(value)) { - showError(fieldId, 'Введите номер в формате: +7(912)999-12-23'); - } else { - hideError(fieldId); - } - break; - case 'password': - if (!validatePassword(value)) { - showError(fieldId, 'Пароль должен содержать минимум 6 символов'); - } else { - hideError(fieldId); - } - break; - case 'confirm-password': - const password = $('#password').val(); - if (value !== password) { - showError(fieldId, 'Пароли не совпадают'); - } else { - hideError(fieldId); - } - break; - } - }); - - // Обработка отправки формы - $('#registrationForm').on('submit', function(e) { - e.preventDefault(); - - if (validateForm()) { - const email = $('#email').val(); - const isAdmin = isAdminEmail(email); - - // Сохраняем данные пользователя в localStorage - const userData = { - email: email, - fio: $('#fio').val(), - phone: $('#phone').val(), - isAdmin: isAdmin, - registered: new Date().toISOString() - }; - - localStorage.setItem('userData', JSON.stringify(userData)); - localStorage.setItem('isLoggedIn', 'true'); - localStorage.setItem('isAdmin', isAdmin.toString()); - - // Эмуляция успешной регистрации - showMessage('success', 'Регистрация прошла успешно! ' + - (isAdmin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!')); - - setTimeout(() => { - // Перенаправление на главную страницу - window.location.href = 'cite_mebel.php'; - }, 2000); - } else { - showMessage('error', 'Пожалуйста, исправьте ошибки в форме'); - } - }); - - // Плавная прокрутка к якорям - $('a[href^="#"]').on('click', function(event) { - var target = $(this.getAttribute('href')); - if (target.length) { - event.preventDefault(); - $('html, body').stop().animate({ - scrollTop: target.offset().top - }, 1000); - } - }); - - // Переключение между регистрацией и входом - $('.login-btn').on('click', function() { - showMessage('warning', 'Переход к форме входа...'); - setTimeout(() => { - window.location.href = 'вход.php'; - }, 1000); - }); - - // Обработка ссылки "Сменить пароль" - $('.password-link').on('click', function(e) { - e.preventDefault(); - showMessage('warning', 'Функция смены пароля будет доступна после регистрации'); - }); - - // Маска для телефона - $('#phone').on('input', function() { - let value = $(this).val().replace(/\D/g, ''); - if (value.startsWith('7') || value.startsWith('8')) { - value = value.substring(1); - } - if (value.length > 0) { - value = '+7(' + value; - if (value.length > 6) value = value.substring(0, 6) + ')' + value.substring(6); - if (value.length > 10) value = value.substring(0, 10) + '-' + value.substring(10); - if (value.length > 13) value = value.substring(0, 13) + '-' + value.substring(13); - if (value.length > 16) value = value.substring(0, 16); - } - $(this).val(value); - }); - - // Запрет ввода цифр в поле ФИО - $('#fio').on('input', function() { - let value = $(this).val(); - // Удаляем цифры из значения - value = value.replace(/\d/g, ''); - $(this).val(value); - }); -}); - -// Для входа (файл вход.html) -$(document).ready(function() { - // Проверяем, если пользователь уже вошел - if (localStorage.getItem('isLoggedIn') === 'true') { - const userData = JSON.parse(localStorage.getItem('userData') || '{}'); - if (userData.email) { - $('#login-email').val(userData.email); - } - } - - // Функция проверки пароля администратора - function checkAdminPassword(email, password) { - // Административные аккаунты - const adminAccounts = { - 'admin@aeterna.ru': 'admin123', - 'administrator@aeterna.ru': 'admin123', - 'aeterna@mail.ru': 'admin123' - }; - - return adminAccounts[email.toLowerCase()] === password; - } - - // Валидация формы входа - $('#loginForm').on('submit', function(e) { - e.preventDefault(); - - let isValid = true; - const email = $('#login-email').val(); - const password = $('#login-password').val(); - - // Валидация email - if (!isValidEmail(email)) { - $('#email-error').show(); - isValid = false; - } else { - $('#email-error').hide(); - } - - // Валидация пароля - if (password.length < 6) { - $('#password-error').show(); - isValid = false; - } else { - $('#password-error').hide(); - } - - if (isValid) { - // Здесь обычно отправка данных на сервер - showMessage('success', 'Вы успешно вошли в систему!'); - - // Перенаправление на главную страницу через 1.5 секунды - setTimeout(function() { - window.location.href = 'cite_mebel.php'; - }, 1500); - } - }); - - // Функция показа сообщений - function showMessage(type, text) { - const messageId = type + 'Message'; - const $message = $('#' + messageId); - - $message.text(text).show(); - - setTimeout(function() { - $message.fadeOut(); - }, 3000); - } - - // Скрываем сообщения об ошибках при фокусе на полях - $('input').on('focus', function() { - $(this).next('.error-message').hide(); - }); - - // Обработка чекбокса "Запомнить меня" - $('#remember').on('change', function() { - if ($(this).is(':checked')) { - const email = $('#login-email').val(); - if (email) { - localStorage.setItem('rememberedEmail', email); - } - } else { - localStorage.removeItem('rememberedEmail'); - } - }); - - // Автозаполнение email, если пользователь выбрал "Запомнить меня" - const rememberedEmail = localStorage.getItem('rememberedEmail'); - if (rememberedEmail) { - $('#login-email').val(rememberedEmail); - $('#remember').prop('checked', true); - } - - // Обработка ссылки "Забыли пароль?" - $('.forgot-password').on('click', function(e) { - e.preventDefault(); - showMessage('info', 'Для восстановления пароля обратитесь к администратору'); - }); -}); \ No newline at end of file +$(document).ready(function() { + + function showMessage(type, text) { + const messageId = type + 'Message'; + const $message = $('#' + messageId); + $message.text(text).fadeIn(300); + setTimeout(() => { + $message.fadeOut(300); + }, 5000); + } + + function isAdminEmail(email) { + const adminEmails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru']; + return adminEmails.includes(email.toLowerCase()); + } + + function validateFIO(fio) { + const words = fio.trim().split(/\s+/); + + const hasNoDigits = !/\d/.test(fio); + return words.length >= 2 && words.every(word => word.length >= 2) && hasNoDigits; + } + + function validateCity(city) { + return city.trim().length >= 2 && /^[а-яА-ЯёЁ\s-]+$/.test(city); + } + + function validateEmail(email) { + const localPart = email.split('@')[0]; + + if (/[а-яА-ЯёЁ]/.test(localPart)) { + showError('email', 'В тексте перед знаком "@" не должно быть кириллических символов'); + return false; + } + + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + showError('email', 'Введите корректный email адрес'); + return false; + } + + hideError('email'); + return true; + } + + function validatePhone(phone) { + const phoneRegex = /^(\+7|8)[\s-]?\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}$/; + return phoneRegex.test(phone.replace(/\s/g, '')); + } + + function validatePassword(password) { + return password.length >= 6; + } + + function showError(fieldId, message) { + $('#' + fieldId).addClass('error'); + $('#' + fieldId + '-error').text(message).show(); + } + + function hideError(fieldId) { + $('#' + fieldId).removeClass('error'); + $('#' + fieldId + '-error').hide(); + } + + function validateForm() { + let isValid = true; + + const fio = $('#fio').val(); + if (!validateFIO(fio)) { + if (/\d/.test(fio)) { + showError('fio', 'ФИО не должно содержать цифры'); + } else { + showError('fio', 'ФИО должно содержать минимум 2 слова (каждое от 2 символов)'); + } + isValid = false; + } else { + hideError('fio'); + } + + const city = $('#city').val(); + if (!validateCity(city)) { + showError('city', 'Укажите корректное название города (только русские буквы)'); + isValid = false; + } else { + hideError('city'); + } + + const email = $('#email').val(); + if (!validateEmail(email)) { + showError('email', 'Введите корректный email адрес'); + isValid = false; + } else { + hideError('email'); + } + + const phone = $('#phone').val(); + if (!validatePhone(phone)) { + showError('phone', 'Введите номер в формате: +7(912)999-12-23'); + isValid = false; + } else { + hideError('phone'); + } + + const password = $('#password').val(); + if (!validatePassword(password)) { + showError('password', 'Пароль должен содержать минимум 6 символов'); + isValid = false; + } else { + hideError('password'); + } + + const confirmPassword = $('#confirm-password').val(); + if (password !== confirmPassword) { + showError('confirm-password', 'Пароли не совпадают'); + isValid = false; + } else { + hideError('confirm-password'); + } + + if (!$('#privacy').is(':checked')) { + $('#privacy-error').show(); + isValid = false; + } else { + $('#privacy-error').hide(); + } + + return isValid; + } + + $('input').on('blur', function() { + const fieldId = $(this).attr('id'); + const value = $(this).val(); + + switch(fieldId) { + case 'fio': + if (!validateFIO(value)) { + if (/\d/.test(value)) { + showError(fieldId, 'ФИО не должно содержать цифры'); + } else { + showError(fieldId, 'ФИО должно содержать минимум 2 слова'); + } + } else { + hideError(fieldId); + } + break; + case 'city': + if (!validateCity(value)) { + showError(fieldId, 'Укажите корректное название города'); + } else { + hideError(fieldId); + } + break; + case 'email': + if (!validateEmail(value)) { + showError(fieldId, 'Введите корректный email адрес'); + } else { + hideError(fieldId); + } + break; + case 'phone': + if (!validatePhone(value)) { + showError(fieldId, 'Введите номер в формате: +7(912)999-12-23'); + } else { + hideError(fieldId); + } + break; + case 'password': + if (!validatePassword(value)) { + showError(fieldId, 'Пароль должен содержать минимум 6 символов'); + } else { + hideError(fieldId); + } + break; + case 'confirm-password': + const password = $('#password').val(); + if (value !== password) { + showError(fieldId, 'Пароли не совпадают'); + } else { + hideError(fieldId); + } + break; + } + }); + + $('#registrationForm').on('submit', function(e) { + e.preventDefault(); + + if (validateForm()) { + const email = $('#email').val(); + const isAdmin = isAdminEmail(email); + + const userData = { + email: email, + fio: $('#fio').val(), + phone: $('#phone').val(), + isAdmin: isAdmin, + registered: new Date().toISOString() + }; + + localStorage.setItem('userData', JSON.stringify(userData)); + localStorage.setItem('isLoggedIn', 'true'); + localStorage.setItem('isAdmin', isAdmin.toString()); + + showMessage('success', 'Регистрация прошла успешно! ' + + (isAdmin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!')); + + setTimeout(() => { + + window.location.href = 'cite_mebel.php'; + }, 2000); + } else { + showMessage('error', 'Пожалуйста, исправьте ошибки в форме'); + } + }); + + $('a[href^="#"]').on('click', function(event) { + var target = $(this.getAttribute('href')); + if (target.length) { + event.preventDefault(); + $('html, body').stop().animate({ + scrollTop: target.offset().top + }, 1000); + } + }); + + $('.login-btn').on('click', function() { + showMessage('warning', 'Переход к форме входа...'); + setTimeout(() => { + window.location.href = 'вход.php'; + }, 1000); + }); + + $('.password-link').on('click', function(e) { + e.preventDefault(); + showMessage('warning', 'Функция смены пароля будет доступна после регистрации'); + }); + + $('#phone').on('input', function() { + let value = $(this).val().replace(/\D/g, ''); + if (value.startsWith('7') || value.startsWith('8')) { + value = value.substring(1); + } + if (value.length > 0) { + value = '+7(' + value; + if (value.length > 6) value = value.substring(0, 6) + ')' + value.substring(6); + if (value.length > 10) value = value.substring(0, 10) + '-' + value.substring(10); + if (value.length > 13) value = value.substring(0, 13) + '-' + value.substring(13); + if (value.length > 16) value = value.substring(0, 16); + } + $(this).val(value); + }); + + $('#fio').on('input', function() { + let value = $(this).val(); + + value = value.replace(/\d/g, ''); + $(this).val(value); + }); +}); + +$(document).ready(function() { + + if (localStorage.getItem('isLoggedIn') === 'true') { + const userData = JSON.parse(localStorage.getItem('userData') || '{}'); + if (userData.email) { + $('#login-email').val(userData.email); + } + } + + function checkAdminPassword(email, password) { + + const adminAccounts = { + 'admin@aeterna.ru': 'admin123', + 'administrator@aeterna.ru': 'admin123', + 'aeterna@mail.ru': 'admin123' + }; + + return adminAccounts[email.toLowerCase()] === password; + } + + $('#loginForm').on('submit', function(e) { + e.preventDefault(); + + let isValid = true; + const email = $('#login-email').val(); + const password = $('#login-password').val(); + + if (!isValidEmail(email)) { + $('#email-error').show(); + isValid = false; + } else { + $('#email-error').hide(); + } + + if (password.length < 6) { + $('#password-error').show(); + isValid = false; + } else { + $('#password-error').hide(); + } + + if (isValid) { + + showMessage('success', 'Вы успешно вошли в систему!'); + + setTimeout(function() { + window.location.href = 'cite_mebel.php'; + }, 1500); + } + }); + + function showMessage(type, text) { + const messageId = type + 'Message'; + const $message = $('#' + messageId); + + $message.text(text).show(); + + setTimeout(function() { + $message.fadeOut(); + }, 3000); + } + + $('input').on('focus', function() { + $(this).next('.error-message').hide(); + }); + + $('#remember').on('change', function() { + if ($(this).is(':checked')) { + const email = $('#login-email').val(); + if (email) { + localStorage.setItem('rememberedEmail', email); + } + } else { + localStorage.removeItem('rememberedEmail'); + } + }); + + const rememberedEmail = localStorage.getItem('rememberedEmail'); + if (rememberedEmail) { + $('#login-email').val(rememberedEmail); + $('#remember').prop('checked', true); + } + + $('.forgot-password').on('click', function(e) { + e.preventDefault(); + showMessage('info', 'Для восстановления пароля обратитесь к администратору'); + }); +}); diff --git a/public/assets/less/checkout.less b/public/assets/less/checkout.less index fb07c54..a6fe073 100644 --- a/public/assets/less/checkout.less +++ b/public/assets/less/checkout.less @@ -1,142 +1,137 @@ -.error-message { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; -} - -.form__input.error { - border-color: #ff0000; -} - -.form__group { - position: relative; - margin-bottom: 15px; -} - -/* Стили для сообщений внизу страницы */ -.page-messages { - position: fixed; - bottom: 20px; - left: 50%; - transform: translateX(-50%); - z-index: 1000; - width: 90%; - max-width: 500px; -} - -.message { - padding: 15px; - margin: 10px 0; - border-radius: 5px; - text-align: center; - font-weight: bold; - display: none; -} - -.message.error { - background-color: #ffebee; - color: #c62828; - border: 1px solid #ffcdd2; -} - -.message.success { - background-color: #e8f5e9; - color: #453227; - border: 1px solid #c8e6c9; -} - -.message.warning { - background-color: #fff3e0; - color: #ef6c00; - border: 1px solid #ffe0b2; -} - -.privacy-error { - color: #ff0000; - font-size: 12px; - margin-top: 5px; - display: none; - text-align: center; -} - -/* Дополнительные стили для формы регистрации */ -.input-group { - position: relative; - margin-bottom: 20px; -} - -.profile-form input.error { - border-color: #ff0000; - background-color: #fff5f5; -} - -.privacy-checkbox { - margin: 20px 0; - text-align: center; -} - -.privacy-checkbox label { - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - cursor: pointer; - font-size: 14px; -} - -.privacy-checkbox input[type="checkbox"] { - margin: 0; -} - -/* Исправление отступов для страницы регистрации */ -.profile-page-main { - padding: 40px 0; - min-height: calc(100vh - 200px); -} - -/* Убедимся, что контейнер не перекрывает шапку и футер */ -.profile-container { - margin: 0 auto; - position: relative; - z-index: 1; -} - -.input-hint { - font-size: 12px; - color: #666; - margin-top: 5px; -} - -/* Стили для страницы входа */ -.form-options { - display: flex; - justify-content: space-between; - align-items: center; - margin: 20px 0; -} - -.remember-me { - display: flex; - align-items: center; - gap: 8px; - font-size: 14px; - color: #453227; -} - -.remember-me input[type="checkbox"] { - width: 16px; - height: 16px; - cursor: pointer; -} - -.forgot-password { - font-size: 14px; - color: #453227; - text-decoration: underline; -} - -.forgot-password:hover { - color: #617365; - text-decoration: none; +.error-message { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; +} + +.form__input.error { + border-color: #ff0000; +} + +.form__group { + position: relative; + margin-bottom: 15px; +} + +.page-messages { + position: fixed; + bottom: 20px; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + width: 90%; + max-width: 500px; +} + +.message { + padding: 15px; + margin: 10px 0; + border-radius: 5px; + text-align: center; + font-weight: bold; + display: none; +} + +.message.error { + background-color: #ffebee; + color: #c62828; + border: 1px solid #ffcdd2; +} + +.message.success { + background-color: #e8f5e9; + color: #453227; + border: 1px solid #c8e6c9; +} + +.message.warning { + background-color: #fff3e0; + color: #ef6c00; + border: 1px solid #ffe0b2; +} + +.privacy-error { + color: #ff0000; + font-size: 12px; + margin-top: 5px; + display: none; + text-align: center; +} + +.input-group { + position: relative; + margin-bottom: 20px; +} + +.profile-form input.error { + border-color: #ff0000; + background-color: #fff5f5; +} + +.privacy-checkbox { + margin: 20px 0; + text-align: center; +} + +.privacy-checkbox label { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + cursor: pointer; + font-size: 14px; +} + +.privacy-checkbox input[type="checkbox"] { + margin: 0; +} + +.profile-page-main { + padding: 40px 0; + min-height: calc(100vh - 200px); +} + +.profile-container { + margin: 0 auto; + position: relative; + z-index: 1; +} + +.input-hint { + font-size: 12px; + color: #666; + margin-top: 5px; +} + +.form-options { + display: flex; + justify-content: space-between; + align-items: center; + margin: 20px 0; +} + +.remember-me { + display: flex; + align-items: center; + gap: 8px; + font-size: 14px; + color: #453227; +} + +.remember-me input[type="checkbox"] { + width: 16px; + height: 16px; + cursor: pointer; +} + +.forgot-password { + font-size: 14px; + color: #453227; + text-decoration: underline; +} + +.forgot-password:hover { + color: #617365; + text-decoration: none; } \ No newline at end of file diff --git a/public/assets/less/mixins.less b/public/assets/less/mixins.less index 630b7bd..10638f0 100644 --- a/public/assets/less/mixins.less +++ b/public/assets/less/mixins.less @@ -83,4 +83,3 @@ border-color: @color-primary; } } - diff --git a/public/catalog.php b/public/catalog.php index 1a0aadc..5b13ae1 100644 --- a/public/catalog.php +++ b/public/catalog.php @@ -1,1343 +1,1306 @@ -getConnection(); - -// Получаем параметры фильтрации -$category_id = $_GET['category'] ?? 0; -$search = $_GET['search'] ?? ''; -$min_price = $_GET['min_price'] ?? 0; -$max_price = $_GET['max_price'] ?? 1000000; -$colors = isset($_GET['colors']) ? (array)$_GET['colors'] : []; -$materials = isset($_GET['materials']) ? (array)$_GET['materials'] : []; -$show_all = isset($_GET['show_all']) && $_GET['show_all'] == '1'; - -// Проверяем уведомления -$success_message = $_GET['success'] ?? ''; -$error_message = $_GET['error'] ?? ''; - -try { - // Получаем информацию о пользователе - $user_id = $_SESSION['user_id'] ?? 0; - $userStmt = $db->prepare("SELECT * FROM users WHERE user_id = ?"); - $userStmt->execute([$user_id]); - $user = $userStmt->fetch(); - - $isAdmin = isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === true; - $userEmail = $_SESSION['user_email'] ?? ''; - $fullName = $_SESSION['full_name'] ?? $userEmail; - $loginTime = $_SESSION['login_time'] ?? time(); - - // Получаем категории (ИСПРАВЛЕНО: убрано дублирование fetchAll) - try { - $categoriesStmt = $db->prepare(" - SELECT * FROM categories - WHERE is_active = TRUE - ORDER BY sort_order, name - "); - $categoriesStmt->execute(); - $categories = $categoriesStmt->fetchAll(); - } catch (PDOException $e) { - $categories = []; - error_log("Ошибка получения категорий: " . $e->getMessage()); - } - - // Получаем подкатегории для текущей категории (если выбрана) - $subcategories = []; - if ($category_id > 0) { - $subStmt = $db->prepare(" - SELECT * FROM subcategories - WHERE category_id = ? AND is_active = TRUE - ORDER BY sort_order, name - "); - $subStmt->execute([$category_id]); - $subcategories = $subStmt->fetchAll(); - } - - // Проверяем наличие столбцов color и material в таблице products - $checkColumns = $db->query(" - SELECT column_name - FROM information_schema.columns - WHERE table_name = 'products' - AND column_name IN ('color', 'material') - "); - $existingColumns = $checkColumns->fetchAll(PDO::FETCH_COLUMN); - - $hasColorColumn = in_array('color', $existingColumns); - $hasMaterialColumn = in_array('material', $existingColumns); - - // Получаем доступные цвета из базы данных (если столбец существует) - $availableColors = []; - if ($hasColorColumn) { - $colorsStmt = $db->query(" - SELECT DISTINCT color FROM products - WHERE color IS NOT NULL AND color != '' AND is_available = TRUE - ORDER BY color - "); - $availableColors = $colorsStmt->fetchAll(PDO::FETCH_COLUMN); - } - - // Получаем доступные материалы из базы данных (если столбец существует) - $availableMaterials = []; - if ($hasMaterialColumn) { - $materialsStmt = $db->query(" - SELECT DISTINCT material FROM products - WHERE material IS NOT NULL AND material != '' AND is_available = TRUE - ORDER BY material - "); - $availableMaterials = $materialsStmt->fetchAll(PDO::FETCH_COLUMN); - } - - // Получаем товары из базы данных с фильтрами - $sql = "SELECT p.*, c.name as category_name - FROM products p - LEFT JOIN categories c ON p.category_id = c.category_id - WHERE 1=1"; - - $params = []; - - // Фильтрация по доступности - if (!$show_all && !$isAdmin) { - $sql .= " AND p.is_available = TRUE"; - } - - // Фильтрация по категории - if ($category_id > 0) { - $sql .= " AND p.category_id = ?"; - $params[] = $category_id; - } - - // Фильтрация по цене - if ($min_price > 0 || $max_price < 1000000) { - $sql .= " AND p.price BETWEEN ? AND ?"; - $params[] = $min_price; - $params[] = $max_price; - } - - // Фильтрация по цвету - if ($hasColorColumn && !empty($colors)) { - $placeholders = implode(',', array_fill(0, count($colors), '?')); - $sql .= " AND p.color IN ($placeholders)"; - $params = array_merge($params, $colors); - } - - // Фильтрация по материалу - if ($hasMaterialColumn && !empty($materials)) { - $placeholders = implode(',', array_fill(0, count($materials), '?')); - $sql .= " AND p.material IN ($placeholders)"; - $params = array_merge($params, $materials); - } - - // Поиск - if (!empty($search)) { - $sql .= " AND (p.name LIKE ? OR p.description LIKE ?)"; - $params[] = "%$search%"; - $params[] = "%$search%"; - } - - $sql .= " ORDER BY p.product_id ASC LIMIT 50"; // Увеличил лимит до 50 - - $stmt = $db->prepare($sql); - $stmt->execute($params); - $filteredProducts = $stmt->fetchAll(); - - // Оригинальные размеры для первых 9 товаров (ID 1-9) - $originalSizes = [ - 1 => 'small', // Светильник MINNIGHT - 2 => 'large', // Диван MODERN (Кровать MODER) - 3 => 'tall align-right', // Торшер MARCIA - 4 => 'wide', // Светильник POLET - 5 => 'small1', // Стол NORD - 6 => 'wide2', // Диван ROYALTY - 7 => 'wide3', // Кресло MINIMAL - 8 => 'wide2_1', // Стол LONKI - 9 => 'full-width' // Диван HEMMINS - ]; - - // Классы для изображений - $imgClasses = ['small1', 'wide2', 'wide3', 'wide2_1']; - -} catch (PDOException $e) { - die("Ошибка базы данных: " . $e->getMessage()); -} -?> - - - - - - AETERNA - Каталог - - - - - - - -
- -
-
-
- - -
-
- Все категории - -
- -
- -
- - - 0 - - - -
-
-
- - -
- -
-
- - - -
- 'Категория успешно добавлена!', - 'category_updated' => 'Категория успешно обновлена!', - 'category_deleted' => 'Категория успешно удалена!', - 'product_added' => 'Товар успешно добавлен!', - 'product_updated' => 'Товар успешно обновлен!', - 'product_deleted' => 'Товар успешно удален!' - ]; - echo $messages[$success_message] ?? 'Операция выполнена успешно!'; - ?> -
- - - -
- Ошибка: -
- - - - - - -
-

- Настройки отображения -

- - - Скрыть недоступные товары - - - - Показать все товары - - - - Недоступные товары отмечены серым цветом - -
- - -
- Добро пожаловать, ! - - - Администратор - - - - - Показаны все товары - - -
- -
- - -
-
-

- Каталог мебели - - ( товаров) - -

- - -

- Результаты поиска по запросу: "" - - Очистить поиск - -

- - - -
- - - Показаны все товары, включая недоступные. Недоступные товары отмечены серым цветом. - -
- -
- - -
- ['name' => 'Светильник MINNIGHT', 'price' => 7999, 'image' => 'img2/1_2.png', 'size' => 'small'], - 2 => ['name' => 'Кровать MODER', 'price' => 45999, 'image' => 'img2/3_3.png', 'size' => 'large'], - 3 => ['name' => 'Торшер MARCIA', 'price' => 11999, 'image' => 'img2/2_2.png', 'size' => 'tall align-right'], - 4 => ['name' => 'Светильник POLET', 'price' => 5499, 'image' => 'img2/4.jpg', 'size' => 'wide'], - 5 => ['name' => 'Стол NORD', 'price' => 23999, 'image' => 'img2/5_5.png', 'size' => 'small1'], - 6 => ['name' => 'Диван ROYALTY', 'price' => 78999, 'image' => 'img2/6_6.png', 'size' => 'wide2'], - 7 => ['name' => 'Кресло MINIMAL', 'price' => 29999, 'image' => 'img2/7_7.png', 'size' => 'wide3'], - 8 => ['name' => 'Стол LONKI', 'price' => 34999, 'image' => 'img2/8_8.png', 'size' => 'wide2_1'], - 9 => ['name' => 'Диван HEMMINS', 'price' => 89999, 'image' => 'img2/9_9.png', 'size' => 'full-width'] - ]; - - // Если в базе данных товаров нет, показываем оригинальные - if (empty($filteredProducts)) { - foreach ($originalProducts as $id => $product): ?> -
-
- <?= $product['name'] ?> - -
-
-
-
- - -
-
- -
-
- <?= htmlspecialchars($product['name']) ?> - -
-
-
-
- - -
-
- -
-
-
-
-
- - - - - +getConnection(); + +$category_id = $_GET['category'] ?? 0; +$search = $_GET['search'] ?? ''; +$min_price = $_GET['min_price'] ?? 0; +$max_price = $_GET['max_price'] ?? 1000000; +$colors = isset($_GET['colors']) ? (array)$_GET['colors'] : []; +$materials = isset($_GET['materials']) ? (array)$_GET['materials'] : []; +$show_all = isset($_GET['show_all']) && $_GET['show_all'] == '1'; + +$success_message = $_GET['success'] ?? ''; +$error_message = $_GET['error'] ?? ''; + +try { + + $user_id = $_SESSION['user_id'] ?? 0; + $userStmt = $db->prepare("SELECT * FROM users WHERE user_id = ?"); + $userStmt->execute([$user_id]); + $user = $userStmt->fetch(); + + $isAdmin = isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === true; + $userEmail = $_SESSION['user_email'] ?? ''; + $fullName = $_SESSION['full_name'] ?? $userEmail; + $loginTime = $_SESSION['login_time'] ?? time(); + + try { + $categoriesStmt = $db->prepare(" + SELECT * FROM categories + WHERE is_active = TRUE + ORDER BY sort_order, name + "); + $categoriesStmt->execute(); + $categories = $categoriesStmt->fetchAll(); + } catch (PDOException $e) { + $categories = []; + error_log("Ошибка получения категорий: " . $e->getMessage()); + } + + $subcategories = []; + if ($category_id > 0) { + $subStmt = $db->prepare(" + SELECT * FROM subcategories + WHERE category_id = ? AND is_active = TRUE + ORDER BY sort_order, name + "); + $subStmt->execute([$category_id]); + $subcategories = $subStmt->fetchAll(); + } + + $checkColumns = $db->query(" + SELECT column_name + FROM information_schema.columns + WHERE table_name = 'products' + AND column_name IN ('color', 'material') + "); + $existingColumns = $checkColumns->fetchAll(PDO::FETCH_COLUMN); + + $hasColorColumn = in_array('color', $existingColumns); + $hasMaterialColumn = in_array('material', $existingColumns); + + $availableColors = []; + if ($hasColorColumn) { + $colorsStmt = $db->query(" + SELECT DISTINCT color FROM products + WHERE color IS NOT NULL AND color != '' AND is_available = TRUE + ORDER BY color + "); + $availableColors = $colorsStmt->fetchAll(PDO::FETCH_COLUMN); + } + + $availableMaterials = []; + if ($hasMaterialColumn) { + $materialsStmt = $db->query(" + SELECT DISTINCT material FROM products + WHERE material IS NOT NULL AND material != '' AND is_available = TRUE + ORDER BY material + "); + $availableMaterials = $materialsStmt->fetchAll(PDO::FETCH_COLUMN); + } + + $sql = "SELECT p.*, c.name as category_name + FROM products p + LEFT JOIN categories c ON p.category_id = c.category_id + WHERE 1=1"; + + $params = []; + + if (!$show_all && !$isAdmin) { + $sql .= " AND p.is_available = TRUE"; + } + + if ($category_id > 0) { + $sql .= " AND p.category_id = ?"; + $params[] = $category_id; + } + + if ($min_price > 0 || $max_price < 1000000) { + $sql .= " AND p.price BETWEEN ? AND ?"; + $params[] = $min_price; + $params[] = $max_price; + } + + if ($hasColorColumn && !empty($colors)) { + $placeholders = implode(',', array_fill(0, count($colors), '?')); + $sql .= " AND p.color IN ($placeholders)"; + $params = array_merge($params, $colors); + } + + if ($hasMaterialColumn && !empty($materials)) { + $placeholders = implode(',', array_fill(0, count($materials), '?')); + $sql .= " AND p.material IN ($placeholders)"; + $params = array_merge($params, $materials); + } + + if (!empty($search)) { + $sql .= " AND (p.name LIKE ? OR p.description LIKE ?)"; + $params[] = "%$search%"; + $params[] = "%$search%"; + } + + $sql .= " ORDER BY p.product_id ASC LIMIT 50"; + + $stmt = $db->prepare($sql); + $stmt->execute($params); + $filteredProducts = $stmt->fetchAll(); + + $originalSizes = [ + 1 => 'small', + 2 => 'large', + 3 => 'tall align-right', + 4 => 'wide', + 5 => 'small1', + 6 => 'wide2', + 7 => 'wide3', + 8 => 'wide2_1', + 9 => 'full-width' + ]; + + $imgClasses = ['small1', 'wide2', 'wide3', 'wide2_1']; + +} catch (PDOException $e) { + die("Ошибка базы данных: " . $e->getMessage()); +} +?> + + + + + + AETERNA - Каталог + + + + + + + +
+ +
+
+
+ + +
+
+ Все категории + +
+ +
+ +
+ + + 0 + + + +
+
+
+ + +
+ +
+
+ + + +
+ 'Категория успешно добавлена!', + 'category_updated' => 'Категория успешно обновлена!', + 'category_deleted' => 'Категория успешно удалена!', + 'product_added' => 'Товар успешно добавлен!', + 'product_updated' => 'Товар успешно обновлен!', + 'product_deleted' => 'Товар успешно удален!' + ]; + echo $messages[$success_message] ?? 'Операция выполнена успешно!'; + ?> +
+ + + +
+ Ошибка: +
+ + + + + + +
+

+ Настройки отображения +

+ + + Скрыть недоступные товары + + + + Показать все товары + + + + Недоступные товары отмечены серым цветом + +
+ + +
+ Добро пожаловать, ! + + + Администратор + + + + + Показаны все товары + + +
+ +
+ + +
+
+

+ Каталог мебели + + ( товаров) + +

+ + +

+ Результаты поиска по запросу: "" + + Очистить поиск + +

+ + + +
+ + + Показаны все товары, включая недоступные. Недоступные товары отмечены серым цветом. + +
+ +
+ +
+ ['name' => 'Светильник MINNIGHT', 'price' => 7999, 'image' => 'img2/1_2.png', 'size' => 'small'], + 2 => ['name' => 'Кровать MODER', 'price' => 45999, 'image' => 'img2/3_3.png', 'size' => 'large'], + 3 => ['name' => 'Торшер MARCIA', 'price' => 11999, 'image' => 'img2/2_2.png', 'size' => 'tall align-right'], + 4 => ['name' => 'Светильник POLET', 'price' => 5499, 'image' => 'img2/4.jpg', 'size' => 'wide'], + 5 => ['name' => 'Стол NORD', 'price' => 23999, 'image' => 'img2/5_5.png', 'size' => 'small1'], + 6 => ['name' => 'Диван ROYALTY', 'price' => 78999, 'image' => 'img2/6_6.png', 'size' => 'wide2'], + 7 => ['name' => 'Кресло MINIMAL', 'price' => 29999, 'image' => 'img2/7_7.png', 'size' => 'wide3'], + 8 => ['name' => 'Стол LONKI', 'price' => 34999, 'image' => 'img2/8_8.png', 'size' => 'wide2_1'], + 9 => ['name' => 'Диван HEMMINS', 'price' => 89999, 'image' => 'img2/9_9.png', 'size' => 'full-width'] + ]; + + if (empty($filteredProducts)) { + foreach ($originalProducts as $id => $product): ?> +
+
+ <?= $product['name'] ?> + +
+
+
+
+ + +
+
+ +
+
+ <?= htmlspecialchars($product['name']) ?> + +
+
+
+
+ + +
+
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/public/check_auth.js b/public/check_auth.js index e67bbe1..a4e0551 100644 --- a/public/check_auth.js +++ b/public/check_auth.js @@ -1,114 +1,107 @@ -// check_auth.js -$(document).ready(function() { - // Проверка авторизации при загрузке страницы - checkAuthStatus(); - - // Обработка формы входа - $('#loginForm').on('submit', function(e) { - e.preventDefault(); - - const email = $('#login-email').val(); - const password = $('#login-password').val(); - const remember = $('#remember').is(':checked'); - - $.ajax({ - url: 'login_handler.php', - method: 'POST', - data: { - email: email, - password: password - }, - success: function(response) { - try { - const result = JSON.parse(response); - if (result.success) { - // Сохраняем в localStorage если выбрано "Запомнить меня" - if (remember) { - localStorage.setItem('rememberedEmail', email); - } else { - localStorage.removeItem('rememberedEmail'); - } - - // Перенаправляем - window.location.href = result.redirect || 'catalog.php'; - } else { - showMessage('error', result.message || 'Ошибка авторизации'); - } - } catch(e) { - showMessage('error', 'Ошибка обработки ответа'); - } - }, - error: function() { - showMessage('error', 'Ошибка сервера'); - } - }); - }); - - // Проверка статуса авторизации - function checkAuthStatus() { - $.ajax({ - url: 'check_auth_status.php', - method: 'GET', - success: function(response) { - try { - const result = JSON.parse(response); - if (result.loggedIn) { - updateUserProfile(result.user); - } - } catch(e) { - console.error('Ошибка проверки авторизации', e); - } - } - }); - } - - // Обновление профиля пользователя - function updateUserProfile(user) { - // Обновляем шапку, если есть элементы для профиля - if ($('#userEmail').length) { - $('#userEmail').text(user.email); - } - if ($('#userName').length) { - $('#userName').text(user.full_name); - } - } - - // Показать сообщение - function showMessage(type, text) { - const $message = $('#' + type + 'Message'); - if ($message.length) { - $message.text(text).fadeIn(); - setTimeout(() => $message.fadeOut(), 5000); - } else { - alert(text); - } - } - - // Проверка авторизации для ссылок - function checkAuth(redirectUrl) { - $.ajax({ - url: 'check_auth_status.php', - method: 'GET', - success: function(response) { - try { - const result = JSON.parse(response); - if (result.loggedIn) { - window.location.href = redirectUrl; - } else { - // Показываем модальное окно или перенаправляем на вход - showLoginModal(redirectUrl); - } - } catch(e) { - showLoginModal(redirectUrl); - } - } - }); - return false; - } - - // Показать модальное окно входа - function showLoginModal(redirectUrl) { - // Можно реализовать модальное окно или перенаправить на страницу входа - window.location.href = 'вход.php?redirect=' + encodeURIComponent(redirectUrl); - } -}); \ No newline at end of file + +$(document).ready(function() { + + checkAuthStatus(); + + $('#loginForm').on('submit', function(e) { + e.preventDefault(); + + const email = $('#login-email').val(); + const password = $('#login-password').val(); + const remember = $('#remember').is(':checked'); + + $.ajax({ + url: 'login_handler.php', + method: 'POST', + data: { + email: email, + password: password + }, + success: function(response) { + try { + const result = JSON.parse(response); + if (result.success) { + + if (remember) { + localStorage.setItem('rememberedEmail', email); + } else { + localStorage.removeItem('rememberedEmail'); + } + + window.location.href = result.redirect || 'catalog.php'; + } else { + showMessage('error', result.message || 'Ошибка авторизации'); + } + } catch(e) { + showMessage('error', 'Ошибка обработки ответа'); + } + }, + error: function() { + showMessage('error', 'Ошибка сервера'); + } + }); + }); + + function checkAuthStatus() { + $.ajax({ + url: 'check_auth_status.php', + method: 'GET', + success: function(response) { + try { + const result = JSON.parse(response); + if (result.loggedIn) { + updateUserProfile(result.user); + } + } catch(e) { + console.error('Ошибка проверки авторизации', e); + } + } + }); + } + + function updateUserProfile(user) { + + if ($('#userEmail').length) { + $('#userEmail').text(user.email); + } + if ($('#userName').length) { + $('#userName').text(user.full_name); + } + } + + function showMessage(type, text) { + const $message = $('#' + type + 'Message'); + if ($message.length) { + $message.text(text).fadeIn(); + setTimeout(() => $message.fadeOut(), 5000); + } else { + alert(text); + } + } + + function checkAuth(redirectUrl) { + $.ajax({ + url: 'check_auth_status.php', + method: 'GET', + success: function(response) { + try { + const result = JSON.parse(response); + if (result.loggedIn) { + window.location.href = redirectUrl; + } else { + + showLoginModal(redirectUrl); + } + } catch(e) { + showLoginModal(redirectUrl); + } + } + }); + return false; + } + + function showLoginModal(redirectUrl) { + + window.location.href = 'вход.php?redirect=' + encodeURIComponent(redirectUrl); + } +}); diff --git a/public/checkout.php b/public/checkout.php index 290490f..25f26c9 100644 --- a/public/checkout.php +++ b/public/checkout.php @@ -1,505 +1,496 @@ -getConnection(); - -// Получаем корзину пользователя -$cart_items = []; -$total_amount = 0; -$total_quantity = 0; - -try { - $stmt = $db->prepare(" - SELECT - c.cart_id, - c.product_id, - c.quantity, - p.name, - p.price, - p.image_url, - p.stock_quantity - FROM cart c - JOIN products p ON c.product_id = p.product_id - WHERE c.user_id = ? AND p.is_available = TRUE - ORDER BY c.created_at DESC - "); - $stmt->execute([$user_id]); - $cart_items = $stmt->fetchAll(); - - // Рассчитываем общую сумму - foreach ($cart_items as $item) { - $total_amount += $item['price'] * $item['quantity']; - $total_quantity += $item['quantity']; - } - -} catch (PDOException $e) { - $error = "Ошибка загрузки корзины: " . $e->getMessage(); -} -?> - - - - - - AETERNA - Оформление заказа - - - - - - - - - -
-
-
- -

Товары в корзине

- - -
- -

Ваша корзина пуста

- -
- -
- -
-
- <?= htmlspecialchars($item['name']) ?> -
-
-
-
-
-
- - - -
- -
-
-
- -
- -
- - -
-
-
-

Оформление заказа

-
Товары,
-
- -
-

СПОСОБ ДОСТАВКИ

-
- - -
- -
- - -
-
-
- -
-
- -
-
-
- -
-

СПОСОБ ОПЛАТЫ

-
- - -
- -
-
- -
-
- -
-
-
- -
-
- -
- -
- - -
- -
-
- Товары, шт. - -
-
- Скидка - 0 ₽ - -
-
- Доставка - 2000 ₽ - -
-
- ИТОГО: - -
-
- - - - - - -
-

УСЛУГИ

-
- Доставка - 2000 ₽ -
-
- Сборка - 1000 ₽ -
-
-
-
- -
-
- -
- - -
- - - - - - - +getConnection(); + +$cart_items = []; +$total_amount = 0; +$total_quantity = 0; + +try { + $stmt = $db->prepare(" + SELECT + c.cart_id, + c.product_id, + c.quantity, + p.name, + p.price, + p.image_url, + p.stock_quantity + FROM cart c + JOIN products p ON c.product_id = p.product_id + WHERE c.user_id = ? AND p.is_available = TRUE + ORDER BY c.created_at DESC + "); + $stmt->execute([$user_id]); + $cart_items = $stmt->fetchAll(); + + foreach ($cart_items as $item) { + $total_amount += $item['price'] * $item['quantity']; + $total_quantity += $item['quantity']; + } + +} catch (PDOException $e) { + $error = "Ошибка загрузки корзины: " . $e->getMessage(); +} +?> + + + + + + AETERNA - Оформление заказа + + + + + + + + + +
+
+
+ +

Товары в корзине

+ + +
+ +

Ваша корзина пуста

+ +
+ +
+ +
+
+ <?= htmlspecialchars($item['name']) ?> +
+
+
+
+
+
+ + + +
+ +
+
+
+ +
+ +
+ + +
+
+
+

Оформление заказа

+
Товары,
+
+ +
+

СПОСОБ ДОСТАВКИ

+
+ + +
+ +
+ + +
+
+
+ +
+
+ +
+
+
+ +
+

СПОСОБ ОПЛАТЫ

+
+ + +
+ +
+
+ +
+
+ +
+
+
+ +
+
+ +
+ +
+ + +
+ +
+
+ Товары, шт. + +
+
+ Скидка + 0 ₽ + +
+
+ Доставка + 2000 ₽ + +
+
+ ИТОГО: + +
+
+ + + + + + +
+

УСЛУГИ

+
+ Доставка + 2000 ₽ +
+
+ Сборка + 1000 ₽ +
+
+
+
+ +
+
+ +
+ + +
+ + + + + + + \ No newline at end of file diff --git a/public/config/check_auth.js b/public/config/check_auth.js index e67bbe1..a4e0551 100644 --- a/public/config/check_auth.js +++ b/public/config/check_auth.js @@ -1,114 +1,107 @@ -// check_auth.js -$(document).ready(function() { - // Проверка авторизации при загрузке страницы - checkAuthStatus(); - - // Обработка формы входа - $('#loginForm').on('submit', function(e) { - e.preventDefault(); - - const email = $('#login-email').val(); - const password = $('#login-password').val(); - const remember = $('#remember').is(':checked'); - - $.ajax({ - url: 'login_handler.php', - method: 'POST', - data: { - email: email, - password: password - }, - success: function(response) { - try { - const result = JSON.parse(response); - if (result.success) { - // Сохраняем в localStorage если выбрано "Запомнить меня" - if (remember) { - localStorage.setItem('rememberedEmail', email); - } else { - localStorage.removeItem('rememberedEmail'); - } - - // Перенаправляем - window.location.href = result.redirect || 'catalog.php'; - } else { - showMessage('error', result.message || 'Ошибка авторизации'); - } - } catch(e) { - showMessage('error', 'Ошибка обработки ответа'); - } - }, - error: function() { - showMessage('error', 'Ошибка сервера'); - } - }); - }); - - // Проверка статуса авторизации - function checkAuthStatus() { - $.ajax({ - url: 'check_auth_status.php', - method: 'GET', - success: function(response) { - try { - const result = JSON.parse(response); - if (result.loggedIn) { - updateUserProfile(result.user); - } - } catch(e) { - console.error('Ошибка проверки авторизации', e); - } - } - }); - } - - // Обновление профиля пользователя - function updateUserProfile(user) { - // Обновляем шапку, если есть элементы для профиля - if ($('#userEmail').length) { - $('#userEmail').text(user.email); - } - if ($('#userName').length) { - $('#userName').text(user.full_name); - } - } - - // Показать сообщение - function showMessage(type, text) { - const $message = $('#' + type + 'Message'); - if ($message.length) { - $message.text(text).fadeIn(); - setTimeout(() => $message.fadeOut(), 5000); - } else { - alert(text); - } - } - - // Проверка авторизации для ссылок - function checkAuth(redirectUrl) { - $.ajax({ - url: 'check_auth_status.php', - method: 'GET', - success: function(response) { - try { - const result = JSON.parse(response); - if (result.loggedIn) { - window.location.href = redirectUrl; - } else { - // Показываем модальное окно или перенаправляем на вход - showLoginModal(redirectUrl); - } - } catch(e) { - showLoginModal(redirectUrl); - } - } - }); - return false; - } - - // Показать модальное окно входа - function showLoginModal(redirectUrl) { - // Можно реализовать модальное окно или перенаправить на страницу входа - window.location.href = 'вход.php?redirect=' + encodeURIComponent(redirectUrl); - } -}); \ No newline at end of file + +$(document).ready(function() { + + checkAuthStatus(); + + $('#loginForm').on('submit', function(e) { + e.preventDefault(); + + const email = $('#login-email').val(); + const password = $('#login-password').val(); + const remember = $('#remember').is(':checked'); + + $.ajax({ + url: 'login_handler.php', + method: 'POST', + data: { + email: email, + password: password + }, + success: function(response) { + try { + const result = JSON.parse(response); + if (result.success) { + + if (remember) { + localStorage.setItem('rememberedEmail', email); + } else { + localStorage.removeItem('rememberedEmail'); + } + + window.location.href = result.redirect || 'catalog.php'; + } else { + showMessage('error', result.message || 'Ошибка авторизации'); + } + } catch(e) { + showMessage('error', 'Ошибка обработки ответа'); + } + }, + error: function() { + showMessage('error', 'Ошибка сервера'); + } + }); + }); + + function checkAuthStatus() { + $.ajax({ + url: 'check_auth_status.php', + method: 'GET', + success: function(response) { + try { + const result = JSON.parse(response); + if (result.loggedIn) { + updateUserProfile(result.user); + } + } catch(e) { + console.error('Ошибка проверки авторизации', e); + } + } + }); + } + + function updateUserProfile(user) { + + if ($('#userEmail').length) { + $('#userEmail').text(user.email); + } + if ($('#userName').length) { + $('#userName').text(user.full_name); + } + } + + function showMessage(type, text) { + const $message = $('#' + type + 'Message'); + if ($message.length) { + $message.text(text).fadeIn(); + setTimeout(() => $message.fadeOut(), 5000); + } else { + alert(text); + } + } + + function checkAuth(redirectUrl) { + $.ajax({ + url: 'check_auth_status.php', + method: 'GET', + success: function(response) { + try { + const result = JSON.parse(response); + if (result.loggedIn) { + window.location.href = redirectUrl; + } else { + + showLoginModal(redirectUrl); + } + } catch(e) { + showLoginModal(redirectUrl); + } + } + }); + return false; + } + + function showLoginModal(redirectUrl) { + + window.location.href = 'вход.php?redirect=' + encodeURIComponent(redirectUrl); + } +}); diff --git a/public/config/database.php b/public/config/database.php index 762cdec..7e3062f 100644 --- a/public/config/database.php +++ b/public/config/database.php @@ -1,32 +1,32 @@ -connection = new PDO( - "pgsql:host=185.130.224.177;port=5481;dbname=postgres", - "admin", - "38feaad2840ccfda0e71243a6faaecfd" - ); - $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - $this->connection->exec("SET NAMES 'utf8'"); - } catch(PDOException $e) { - die("Ошибка подключения: " . $e->getMessage()); - } - } - - public static function getInstance() { - if (self::$instance == null) { - self::$instance = new Database(); - } - return self::$instance; - } - - public function getConnection() { - return $this->connection; - } -} +connection = new PDO( + "pgsql:host=185.130.224.177;port=5481;dbname=postgres", + "admin", + "38feaad2840ccfda0e71243a6faaecfd" + ); + $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->connection->exec("SET NAMES 'utf8'"); + } catch(PDOException $e) { + die("Ошибка подключения: " . $e->getMessage()); + } + } + + public static function getInstance() { + if (self::$instance == null) { + self::$instance = new Database(); + } + return self::$instance; + } + + public function getConnection() { + return $this->connection; + } +} ?> \ No newline at end of file diff --git a/public/delivery.php b/public/delivery.php index c2e2ed0..13ca5b9 100644 --- a/public/delivery.php +++ b/public/delivery.php @@ -1,174 +1,174 @@ - - - - - - AETERNA - Доставка и оплата - - - - - - - - - - - -
-
- - -
-

ДОСТАВКА И ОПЛАТА

- -
-
-
- -
-

Курьерская доставка

-
-
- Бесплатная доставка: - при заказе от 30 000 ₽ -
-
- В пределах МКАД: - 1 500 ₽ -
-
- За МКАД: - 1 500 ₽ + 50 ₽/км -
-
- Время доставки: - с 9:00 до 21:00 -
-
-
- -
-
- -
-

Самовывоз из шоурума

-
-
- Адрес: - г. Москва, ул. Дизайнерская, 15 -
-
- Стоимость: - Бесплатно -
-
- Время получения: - в течение 2 часов после подтверждения -
-
- Парковка: - Бесплатная для клиентов -
-
-
- -
-
- -
-

Доставка по России

-
-
- Стоимость: - рассчитывается индивидуально -
-
- Сроки: - от 3 до 14 дней -
-
- Транспортные компании: - СДЭК, Boxberry, Деловые Линии -
-
-
-
- -
-
-
- - - + + + + + + AETERNA - Доставка и оплата + + + + + + + + + + + +
+
+ + +
+

ДОСТАВКА И ОПЛАТА

+ +
+
+
+ +
+

Курьерская доставка

+
+
+ Бесплатная доставка: + при заказе от 30 000 ₽ +
+
+ В пределах МКАД: + 1 500 ₽ +
+
+ За МКАД: + 1 500 ₽ + 50 ₽/км +
+
+ Время доставки: + с 9:00 до 21:00 +
+
+
+ +
+
+ +
+

Самовывоз из шоурума

+
+
+ Адрес: + г. Москва, ул. Дизайнерская, 15 +
+
+ Стоимость: + Бесплатно +
+
+ Время получения: + в течение 2 часов после подтверждения +
+
+ Парковка: + Бесплатная для клиентов +
+
+
+ +
+
+ +
+

Доставка по России

+
+
+ Стоимость: + рассчитывается индивидуально +
+
+ Сроки: + от 3 до 14 дней +
+
+ Транспортные компании: + СДЭК, Boxberry, Деловые Линии +
+
+
+
+ +
+
+
+ + + \ No newline at end of file diff --git a/public/footer.php b/public/footer.php index 439cf70..98e1481 100644 --- a/public/footer.php +++ b/public/footer.php @@ -47,4 +47,3 @@ - diff --git a/public/header_common.php b/public/header_common.php index fb90bd1..8654ef6 100644 --- a/public/header_common.php +++ b/public/header_common.php @@ -1,18 +1,11 @@ - + 0 -