У меня есть код для сайта по продаже ПК, но есть проблема. Во вкладке "Собственная сборка" не работает добавление комплектующих. Список выводится, но при нажатии ничего не происходит и итоговая сумма сборки тоже не изменяется, оставшись на 0.
1. Обновленный index.html

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>PC Shop</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <header>
        <div class="logo">PC Shop</div>
        <div class="search-container">
            <input type="text" id="searchInput" placeholder="Поиск товаров...">
        </div>
        <div class="user-section" id="userSection">
            <button id="loginBtn">Вход / Регистрация</button>
        </div>
    </header>

    <div class="modal" id="authModal">
        <div class="modal-content">
            <span class="close" id="closeModal">&times;</span>
            <h2>Регистрация / Вход</h2>
            <form id="authForm">
                <label for="username">Логин:</label>
                <input type="text" id="username" name="username" required>
                
                <label for="password">Пароль:</label>
                <input type="password" id="password" name="password" required>
                
                <button type="submit" id="authSubmit">Войти</button>
            </form>
            <p id="authMessage"></p>
        </div>
    </div>

    <main>
        <nav class="tabs">
            <button class="tab-btn active" data-tab="ready">Готовые сборки</button>
            <button class="tab-btn" data-tab="custom">Собственная сборка</button>
        </nav>

        <section id="ready" class="tab-content active">
            <div class="products-container" id="productsContainer">
                <!-- Продукты будут динамически загружены здесь -->
            </div>
        </section>

        <section id="custom" class="tab-content">
            <div class="custom-build-container">
                <div class="components-grid" id="componentsGrid">
                    <!-- Ячейки для комплектующих -->
                </div>
                <div class="build-summary">
                    <p>Итого: <span id="totalPrice">0 руб</span></p>
                    <button id="makeOrderBtn">Сделать заказ</button>
                </div>
            </div>
        </section>
    </main>

    <footer>
        <p>&copy; 2023 PC Shop</p>
    </footer>

    <script src="script.js"></script>
</body>
</html>
Объяснение изменений:

Вкладка "Собственная сборка": Внутри <section id="custom"> добавлены контейнеры для сетки комплектующих (componentsGrid) и для отображения итого стоимости и кнопки заказа (build-summary).
2. Обновленный styles.css

/* Общие стили */
body {
    margin: 0;
    font-family: Arial, sans-serif;
    background-color: #111;
    color: #eee;
}

header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #000;
    padding: 10px 20px;
    position: sticky;
    top: 0;
    z-index: 1000;
}

.logo {
    font-size: 24px;
    color: #0f0;
}

.search-container input {
    padding: 5px;
    border: none;
    border-radius: 3px;
}

.user-section {
    position: relative;
}

.user-section button {
    padding: 5px 10px;
    background-color: #0f0;
    border: none;
    border-radius: 3px;
    cursor: pointer;
}

.user-section span {
    color: #0f0;
    font-weight: bold;
}

main {
    padding: 20px;
}

.tabs {
    display: flex;
    margin-bottom: 20px;
}

.tab-btn {
    padding: 10px 20px;
    background-color: #222;
    border: none;
    color: #0f0;
    cursor: pointer;
    margin-right: 5px;
    border-radius: 3px;
}

.tab-btn.active {
    background-color: #0f0;
    color: #000;
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

.products-container {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

.product {
    background-color: #222;
    padding: 10px;
    border-radius: 5px;
    width: calc(25% - 20px);
    box-sizing: border-box;
    text-align: center;
}

.product img {
    max-width: 100%;
    height: auto;
    border-bottom: 1px solid #0f0;
    margin-bottom: 10px;
}

.product h3 {
    margin: 10px 0;
    color: #0f0;
}

.product button {
    padding: 5px 10px;
    background-color: #0f0;
    border: none;
    border-radius: 3px;
    cursor: pointer;
    color: #000;
}

footer {
    text-align: center;
    padding: 20px;
    background-color: #000;
    color: #0f0;
    position: fixed;
    width: 100%;
    bottom: 0;
}

/* Модальное окно */
.modal {
    display: none; 
    position: fixed; 
    z-index: 2000; 
    left: 0;
    top: 0;
    width: 100%; 
    height: 100%; 
    overflow: auto; 
    background-color: rgba(0,0,0,0.8); 
}

.modal-content {
    background-color: #111;
    margin: 10% auto; 
    padding: 20px;
    border: 1px solid #0f0;
    width: 300px; 
    border-radius: 5px;
    color: #0f0;
}

.close {
    color: #0f0;
    float: right;
    font-size: 28px;
    font-weight: bold;
    cursor: pointer;
}

.close:hover,
.close:focus {
    color: #fff;
    text-decoration: none;
    cursor: pointer;
}

form label {
    display: block;
    margin: 10px 0 5px;
}

form input {
    width: 100%;
    padding: 5px;
    border: none;
    border-radius: 3px;
}

form button {
    margin-top: 15px;
    padding: 10px;
    width: 100%;
    background-color: #0f0;
    border: none;
    border-radius: 3px;
    cursor: pointer;
    color: #000;
}

#authMessage {
    margin-top: 10px;
    color: #f00;
    text-align: center;
}

/* Стили для "Собственной сборки" */
.custom-build-container {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.components-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 20px;
    width: 100%;
    max-width: 800px;
    margin-bottom: 30px;
}

.component-cell {
    background-color: #0f0;
    border: 2px dashed #0a0;
    border-radius: 5px;
    height: 150px;
    position: relative;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
}

.component-cell img {
    max-width: 80%;
    max-height: 60%;
    margin-bottom: 5px;
}

.component-cell .component-name {
    color: #000;
    font-weight: bold;
}

.dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background-color: #222;
    border: 1px solid #0f0;
    z-index: 100;
    max-height: 200px;
    overflow-y: auto;
    display: none;
}

.dropdown div {
    padding: 10px;
    cursor: pointer;
    color: #0f0;
}

.dropdown div:hover {
    background-color: #0a0;
}

.build-summary {
    position: fixed;
    top: 100px;
    right: 20px;
    background-color: #222;
    padding: 20px;
    border: 2px solid #0f0;
    border-radius: 5px;
    color: #0f0;
}

.build-summary p {
    margin: 0 0 10px 0;
    font-size: 18px;
}

.build-summary button {
    padding: 10px 20px;
    background-color: #0f0;
    border: none;
    border-radius: 3px;
    cursor: pointer;
    color: #000;
    font-size: 16px;
}

.build-summary button:hover {
    background-color: #0a0;
}
Объяснение изменений:

Сетка комплектующих (components-grid): Используется CSS Grid для расположения ячеек комплектующих.
Ячейки комплектующих (component-cell): Стиль зеленых ячеек с dashed рамкой, которые могут быть кликабельны.
Выпадающий список (dropdown): Скрытый по умолчанию список, который появляется при клике на ячейку.
Сводка сборки (build-summary): Фиксированная панель справа для отображения итоговой стоимости и кнопки заказа.
3. Обновленный script.js

// Пример списка товаров
const products = [
    {
        id: 1,
        name: "Процессор Intel i5",
        image: "https://via.placeholder.com/150",
        price: "15000 руб",
        category: "CPU"
    },
    {
        id: 2,
        name: "Материнская плата ASUS",
        image: "https://via.placeholder.com/150",
        price: "12000 руб",
        category: "Motherboard"
    },
    {
        id: 3,
        name: "Оперативная память 16GB",
        image: "https://via.placeholder.com/150",
        price: "8000 руб",
        category: "RAM"
    },
    {
        id: 4,
        name: "Видеокарта NVIDIA GTX 1660",
        image: "https://via.placeholder.com/150",
        price: "20000 руб",
        category: "GPU"
    },
    // Добавьте больше товаров по необходимости
    // CPU
    {
        id: 5,
        name: "Процессор AMD Ryzen 7",
        image: "https://via.placeholder.com/150",
        price: "20000 руб",
        category: "CPU"
    },
    // Motherboard
    {
        id: 6,
        name: "Материнская плата MSI",
        image: "https://via.placeholder.com/150",
        price: "13000 руб",
        category: "Motherboard"
    },
    // RAM
    {
        id: 7,
        name: "Оперативная память 32GB",
        image: "https://via.placeholder.com/150",
        price: "15000 руб",
        category: "RAM"
    },
    // GPU
    {
        id: 8,
        name: "Видеокарта NVIDIA RTX 3060",
        image: "https://via.placeholder.com/150",
        price: "35000 руб",
        category: "GPU"
    }
];

// Комплектующие для собственной сборки, разделенные по категориям
const componentCategories = {
    "CPU": [
        {
            id: 1,
            name: "Процессор Intel i5",
            image: "https://via.placeholder.com/100",
            price: 15000
        },
        {
            id: 5,
            name: "Процессор AMD Ryzen 7",
            image: "https://via.placeholder.com/100",
            price: 20000
        }
    ],
    "Motherboard": [
        {
            id: 2,
            name: "Материнская плата ASUS",
            image: "https://via.placeholder.com/100",
            price: 12000
        },
        {
            id: 6,
            name: "Материнская плата MSI",
            image: "https://via.placeholder.com/100",
            price: 13000
        }
    ],
    "RAM": [
        {
            id: 3,
            name: "Оперативная память 16GB",
            image: "https://via.placeholder.com/100",
            price: 8000
        },
        {
            id: 7,
            name: "Оперативная память 32GB",
            image: "https://via.placeholder.com/100",
            price: 15000
        }
    ],
    "GPU": [
        {
            id: 4,
            name: "Видеокарта NVIDIA GTX 1660",
            image: "https://via.placeholder.com/100",
            price: 20000
        },
        {
            id: 8,
            name: "Видеокарта NVIDIA RTX 3060",
            image: "https://via.placeholder.com/100",
            price: 35000
        }
    ],
    // Добавьте другие категории по необходимости
};

// Для хранения выбранных компонентов
let selectedComponents = {
    "CPU": null,
    "Motherboard": null,
    "RAM": null,
    "GPU": null
    // Добавьте другие категории по необходимости
};

// Регистрация и авторизация
const authModal = document.getElementById('authModal');
const loginBtn = document.getElementById('loginBtn');
const closeModal = document.getElementById('closeModal');
const authForm = document.getElementById('authForm');
const authMessage = document.getElementById('authMessage');
const userSection = document.getElementById('userSection');

// Показываем модальное окно
loginBtn.addEventListener('click', () => {
    authModal.style.display = 'block';
});

// Закрываем модальное окно
closeModal.addEventListener('click', () => {
    authModal.style.display = 'none';
});

// Закрываем при клике вне модального окна
window.addEventListener('click', (e) => {
    if (e.target == authModal) {
        authModal.style.display = 'none';
    }
});

// Обработка формы авторизации
authForm.addEventListener('submit', (e) => {
    e.preventDefault();
    const username = authForm.username.value.trim();
    const password = authForm.password.value.trim();

    if (!username || !password) {
        authMessage.textContent = "Пожалуйста, заполните все поля.";
        return;
    }

    // Получаем пользователей из localStorage
    let users = JSON.parse(localStorage.getItem('users')) || [];

    // Проверка, существует ли пользователь
    const user = users.find(u => u.username === username);

    if (user) {
        // Проверка пароля
        if (user.password === password) {
            // Успешный вход
            localStorage.setItem('currentUser', username);
            updateUserSection();
            authModal.style.display = 'none';
            authMessage.textContent = '';
        } else {
            authMessage.textContent = "Неверный пароль.";
        }
    } else {
        // Регистрация нового пользователя
        users.push({ username, password });
        localStorage.setItem('users', JSON.stringify(users));
        localStorage.setItem('currentUser', username);
        updateUserSection();
        authModal.style.display = 'none';
        authMessage.textContent = '';
    }
});

// Обновление секции пользователя
function updateUserSection() {
    const currentUser = localStorage.getItem('currentUser');
    if (currentUser) {
        userSection.innerHTML = `<span>Привет, ${currentUser}</span> <button id="logoutBtn">Выйти</button>`;

        document.getElementById('logoutBtn').addEventListener('click', () => {
            localStorage.removeItem('currentUser');
            userSection.innerHTML = `<button id="loginBtn">Вход / Регистрация</button>`;
            document.getElementById('loginBtn').addEventListener('click', () => {
                authModal.style.display = 'block';
            });
        });
    }
}

// Инициализация при загрузке страницы
document.addEventListener('DOMContentLoaded', () => {
    updateUserSection();
    displayProducts(products);
    initializeCustomBuild();
});

// Переключение вкладок
const tabButtons = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');

tabButtons.forEach(btn => {
    btn.addEventListener('click', () => {
        // Удаляем активный класс у всех кнопок и добавляем текущей
        tabButtons.forEach(b => b.classList.remove('active'));
        btn.classList.add('active');

        // Скрываем все контенты и показываем нужный
        tabContents.forEach(content => content.classList.remove('active'));
        const activeTab = btn.getAttribute('data-tab');
        document.getElementById(activeTab).classList.add('active');
    });
});

// Отображение продуктов
function displayProducts(productList) {
    const container = document.getElementById('productsContainer');
    container.innerHTML = '';

    if (productList.length === 0) {
        container.innerHTML = '<p>Товары не найдены.</p>';
        return;
    }

    productList.forEach(product => {
        const div = document.createElement('div');
        div.classList.add('product');
        div.innerHTML = `
            <img src="${product.image}" alt="${product.name}">
            <h3>${product.name}</h3>
            <p>${product.price}</p>
            <button>Добавить в сборку</button>
        `;
        container.appendChild(div);
    });
}

// Поиск товаров
const searchInput = document.getElementById('searchInput');
searchInput.addEventListener('input', () => {
    const query = searchInput.value.toLowerCase();
    const filteredProducts = products.filter(p => p.name.toLowerCase().includes(query));
    displayProducts(filteredProducts);
});

/* ======================== */
/* Новая часть: Собственная сборка */
/* ======================== */

// Инициализация интерфейса собственной сборки
function initializeCustomBuild() {
    const componentsGrid = document.getElementById('componentsGrid');

    // Определяем категории, которые будут доступны для сборки
    const categories = Object.keys(componentCategories);

    categories.forEach(category => {
        const cell = document.createElement('div');
        cell.classList.add('component-cell');
        cell.setAttribute('data-category', category);

        cell.innerHTML = `
            <span class="component-name">${category}</span>
            <div class="dropdown" id="dropdown-${category}">
                ${componentCategories[category].map(comp => `<div data-id="${comp.id}">${comp.name} (${comp.price} руб)</div>`).join('')}
            </div>
        `;

        // Обработчик клика для отображения/скрытия списка
        cell.addEventListener('click', (e) => {
            e.stopPropagation();
            // Закрыть другие dropdown
            closeAllDropdowns();
            const dropdown = cell.querySelector('.dropdown');
            dropdown.style.display = dropdown.style.display === 'block' ? 'none' : 'block';
        });

        componentsGrid.appendChild(cell);
    });

    // Закрытие dropdown при клике вне
    window.addEventListener('click', () => {
        closeAllDropdowns();
    });

    // Обработчик выбора компонента
    componentsGrid.addEventListener('click', (e) => {
        if (e.target && e.target.matches('div[data-id]')) {
            const selectedId = parseInt(e.target.getAttribute('data-id'));
            const category = e.target.closest('.component-cell').getAttribute('data-category');
            const component = componentCategories[category].find(c => c.id === selectedId);
            if (component) {
                selectComponent(category, component);
            }
            closeAllDropdowns();
        }
    });

    // Обработчик кнопки "Сделать заказ"
    const makeOrderBtn = document.getElementById('makeOrderBtn');
    makeOrderBtn.addEventListener('click', makeOrder);
}

// Закрыть все dropdown
function closeAllDropdowns() {
    const dropdowns = document.querySelectorAll('.dropdown');
    dropdowns.forEach(dd => dd.style.display = 'none');
}

// Выбор компонента
function selectComponent(category, component) {
    selectedComponents[category] = component;
    updateComponentsGrid();
    updateTotalPrice();
}

// Обновление сетки комплектующих после выбора
function updateComponentsGrid() {
    const componentsGrid = document.getElementById('componentsGrid');
    const categories = Object.keys(componentCategories);

    categories.forEach(category => {
        const cell = componentsGrid.querySelector(`.component-cell[data-category="${category}"]`);
        if (selectedComponents[category]) {
            cell.innerHTML = `
                <img src="${selectedComponents[category].image}" alt="${selectedComponents[category].name}">
                <span class="component-name">${selectedComponents[category].name}</span>
            `;
        } else {
            cell.innerHTML = `
                <span class="component-name">${category}</span>
                <div class="dropdown" id="dropdown-${category}">
                    ${componentCategories[category].map(comp => `<div data-id="${comp.id}">${comp.name} (${comp.price} руб)</div>`).join('')}
                </div>
            `;
            // Повторно добавляем обработчики
            const newCell = componentsGrid.querySelector(`.component-cell[data-category="${category}"]`);
            newCell.addEventListener('click', (e) => {
                e.stopPropagation();
                closeAllDropdowns();
                const dropdown = newCell.querySelector('.dropdown');
                dropdown.style.display = dropdown.style.display === 'block' ? 'none' : 'block';
            });
        }
    });
}

// Обновление общей стоимости сборки
function updateTotalPrice() {
    let total = 0;
    Object.values(selectedComponents).forEach(comp => {
        if (comp) {
            total += comp.price;
        }
    });
    document.getElementById('totalPrice').textContent = `${total} руб`;
}

// Обработка заказа
function makeOrder() {
    // Проверяем, все ли компоненты выбраны (опционально)
    const allSelected = Object.values(selectedComponents).every(comp => comp !== null);
    if (!allSelected) {
        alert("Пожалуйста, выберите все необходимые компоненты для сборки.");
        return;
    }

    // Здесь можно добавить логику отправки заказа на сервер

    alert("Заказ успешно сделан! С вами свяжется менеджер.");
    
    // Сброс сборки
    resetCustomBuild();
}

// Сброс сборки
function resetCustomBuild() {
    selectedComponents = {
        "CPU": null,
        "Motherboard": null,
        "RAM": null,
        "GPU": null
        // Добавьте другие категории по необходимости
    };
    updateComponentsGrid();
    updateTotalPrice();
}