браузер не видит компоненты, класс!
This commit is contained in:
18
basket.html
18
basket.html
@@ -58,8 +58,9 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- В main контейнере basket.html замените содержимое на: -->
|
||||
<main class="container my-4">
|
||||
<div class="text-center py-5">
|
||||
<div class="empty-basket text-center py-5">
|
||||
<h1 class="mb-4">Здесь будут лежать твои товары</h1>
|
||||
<p class="lead mb-4">А пока здесь так пусто...</p>
|
||||
<img src="img/sad1.jpg" alt="Пустая корзина" class="img-fluid rounded" style="max-height: 300px;">
|
||||
@@ -69,6 +70,8 @@
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="basketContainer"></div>
|
||||
</main>
|
||||
|
||||
<footer class="py-4 mt-5" style="background-color: #00264d; color: white;">
|
||||
@@ -98,5 +101,18 @@
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="./components/basket/model.js"></script>
|
||||
<script src="./components/basket/view.js"></script>
|
||||
<script src="./components/basket/controller.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Проверяем, есть ли необходимые элементы на странице
|
||||
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
|
||||
const model = new Model();
|
||||
const view = new View();
|
||||
new Controller(model, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
14
catalog.html
14
catalog.html
@@ -353,5 +353,19 @@
|
||||
this.reset();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="./components/basket/model.js"></script>
|
||||
<script src="./components/basket/view.js"></script>
|
||||
<script src="./components/basket/controller.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Проверяем, есть ли необходимые элементы на странице
|
||||
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
|
||||
const model = new Model();
|
||||
const view = new View();
|
||||
new Controller(model, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
133
components/basket/controller.js
Normal file
133
components/basket/controller.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// controller.js
|
||||
export class Controller {
|
||||
constructor(model, view) {
|
||||
this.model = model;
|
||||
this.view = view;
|
||||
this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// Для страницы корзины
|
||||
if (window.location.pathname.includes('basket.html')) {
|
||||
await this.loadBasket();
|
||||
this.setupBasketEventListeners();
|
||||
}
|
||||
|
||||
// Для страницы каталога
|
||||
if (window.location.pathname.includes('catalog.html')) {
|
||||
this.setupCatalogEventListeners();
|
||||
}
|
||||
}
|
||||
|
||||
// Загрузить и отобразить корзину
|
||||
async loadBasket() {
|
||||
const basketItems = await this.model.getBasketItems();
|
||||
this.view.showBasket(basketItems);
|
||||
}
|
||||
|
||||
// Настройка обработчиков событий для корзины
|
||||
setupBasketEventListeners() {
|
||||
document.addEventListener('click', async (e) => {
|
||||
const basketItem = e.target.closest('.basket-item');
|
||||
if (!basketItem) return;
|
||||
|
||||
const productId = basketItem.dataset.id;
|
||||
|
||||
// Удаление товара
|
||||
if (e.target.closest('.remove-btn')) {
|
||||
await this.model.removeFromBasket(productId);
|
||||
this.view.showNotification('Товар удален из корзины');
|
||||
await this.loadBasket();
|
||||
}
|
||||
|
||||
// Увеличение количества
|
||||
if (e.target.closest('.increase-btn')) {
|
||||
const quantityInput = basketItem.querySelector('.quantity-input');
|
||||
const newQuantity = parseInt(quantityInput.value) + 1;
|
||||
quantityInput.value = newQuantity;
|
||||
await this.model.updateBasketItem(productId, newQuantity);
|
||||
await this.loadBasket();
|
||||
}
|
||||
|
||||
// Уменьшение количества
|
||||
if (e.target.closest('.decrease-btn')) {
|
||||
const quantityInput = basketItem.querySelector('.quantity-input');
|
||||
let newQuantity = parseInt(quantityInput.value) - 1;
|
||||
if (newQuantity < 1) newQuantity = 1;
|
||||
quantityInput.value = newQuantity;
|
||||
await this.model.updateBasketItem(productId, newQuantity);
|
||||
await this.loadBasket();
|
||||
}
|
||||
});
|
||||
|
||||
// Обработка изменения количества через input
|
||||
document.addEventListener('change', async (e) => {
|
||||
if (e.target.classList.contains('quantity-input')) {
|
||||
const basketItem = e.target.closest('.basket-item');
|
||||
const productId = basketItem.dataset.id;
|
||||
const newQuantity = parseInt(e.target.value) || 1;
|
||||
|
||||
if (newQuantity < 1) {
|
||||
e.target.value = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
await this.model.updateBasketItem(productId, newQuantity);
|
||||
await this.loadBasket();
|
||||
}
|
||||
});
|
||||
|
||||
// Оформление заказа
|
||||
document.addEventListener('click', async (e) => {
|
||||
if (e.target.id === 'checkoutBtn') {
|
||||
const basketItems = await this.model.getBasketItems();
|
||||
if (basketItems.length === 0) {
|
||||
this.view.showNotification('Корзина пуста', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
this.view.showNotification('Заказ оформлен! Спасибо за покупку!');
|
||||
await this.model.clearBasket();
|
||||
await this.loadBasket();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Настройка обработчиков событий для каталога
|
||||
setupCatalogEventListeners() {
|
||||
document.addEventListener('click', async (e) => {
|
||||
if (e.target.closest('.btn') && e.target.closest('.btn').textContent.includes('В корзину')) {
|
||||
const card = e.target.closest('.card');
|
||||
const product = this.extractProductData(card);
|
||||
|
||||
if (product) {
|
||||
await this.model.addToBasket(product);
|
||||
this.view.showNotification('Товар добавлен в корзину!');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
extractProductData(card) {
|
||||
try {
|
||||
const name = card.querySelector('.card-title').textContent;
|
||||
const priceText = card.querySelector('.text-muted').textContent.replace('$', '');
|
||||
const description = card.querySelector('.card-text').textContent;
|
||||
const image = card.querySelector('img').src;
|
||||
|
||||
// Генерируем ID на основе содержимого карточки
|
||||
const id = btoa(`${name}-${priceText}`).substring(0, 8);
|
||||
|
||||
return {
|
||||
id: id,
|
||||
name: name.trim(),
|
||||
price: parseFloat(priceText),
|
||||
description: description.trim(),
|
||||
image: image
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Ошибка при извлечении данных товара:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
components/basket/model.js
Normal file
118
components/basket/model.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// model.js
|
||||
export class Model {
|
||||
constructor() {
|
||||
this.apiUrl = 'http://localhost:3000';
|
||||
}
|
||||
|
||||
async request(url, options = {}) {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}${url}`, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Request failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getBasketItems() {
|
||||
try {
|
||||
return await this.request('/basket');
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении корзины:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Добавить товар в корзину
|
||||
async addToBasket(product) {
|
||||
try {
|
||||
// Проверяем, есть ли товар уже в корзине
|
||||
const basketItems = await this.getBasketItems();
|
||||
const existingItem = basketItems.find(item => item.id === product.id);
|
||||
|
||||
if (existingItem) {
|
||||
// Если товар уже есть, увеличиваем количество
|
||||
await this.updateBasketItem(product.id, existingItem.quantity + 1);
|
||||
} else {
|
||||
// Если товара нет, добавляем новый
|
||||
const basketItem = {
|
||||
...product,
|
||||
quantity: 1,
|
||||
addedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
const response = await fetch(`${this.apiUrl}/basket`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(basketItem)
|
||||
});
|
||||
return await response.json();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при добавлении в корзину:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Обновить количество товара в корзине
|
||||
async updateBasketItem(productId, quantity) {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}/basket/${productId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ quantity })
|
||||
});
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Ошибка при обновлении корзины:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Удалить товар из корзины
|
||||
async removeFromBasket(productId) {
|
||||
try {
|
||||
await fetch(`${this.apiUrl}/basket/${productId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Ошибка при удалении из корзины:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Очистить корзину
|
||||
async clearBasket() {
|
||||
try {
|
||||
const basketItems = await this.getBasketItems();
|
||||
for (const item of basketItems) {
|
||||
await this.removeFromBasket(item.id);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка при очистке корзины:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Получить все товары из каталога
|
||||
async getProducts() {
|
||||
try {
|
||||
const response = await fetch(`${this.apiUrl}/shmots`);
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error('Ошибка при получении товаров:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
113
components/basket/view.js
Normal file
113
components/basket/view.js
Normal file
@@ -0,0 +1,113 @@
|
||||
// view.js
|
||||
export class View {
|
||||
constructor() {
|
||||
this.basketContainer = document.getElementById('basketContainer');
|
||||
this.emptyBasketElement = document.querySelector('.empty-basket');
|
||||
}
|
||||
|
||||
// Показать корзину с товарами
|
||||
showBasket(items) {
|
||||
if (items.length === 0) {
|
||||
this.showEmptyBasket();
|
||||
return;
|
||||
}
|
||||
|
||||
this.hideEmptyBasket();
|
||||
|
||||
const basketHTML = items.map(item => this.createBasketItemHTML(item)).join('');
|
||||
this.basketContainer.innerHTML = `
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card border-0 shadow">
|
||||
<div class="card-header" style="background-color: #00264d; color: white;">
|
||||
<h5 class="mb-0"><i class="bi bi-cart me-2"></i>Корзина</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
${basketHTML}
|
||||
<div class="d-flex justify-content-between align-items-center mt-4 pt-3 border-top">
|
||||
<h5>Итого: $${this.calculateTotal(items).toFixed(2)}</h5>
|
||||
<button class="btn btn-lg" style="background-color: #00264d; color: white;" id="checkoutBtn">
|
||||
<i class="bi bi-credit-card me-2"></i>Оформить заказ
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Создать HTML для элемента корзины
|
||||
createBasketItemHTML(item) {
|
||||
return `
|
||||
<div class="row align-items-center mb-3 basket-item" data-id="${item.id}">
|
||||
<div class="col-md-2">
|
||||
<img src="${item.image}" alt="${item.name}" class="img-fluid rounded" style="max-height: 80px;">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6 class="mb-1">${item.name}</h6>
|
||||
<p class="text-muted small mb-0">${item.description}</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<span class="fw-bold">$${item.price}</span>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="input-group input-group-sm">
|
||||
<button class="btn btn-outline-secondary decrease-btn" type="button">-</button>
|
||||
<input type="number" class="form-control text-center quantity-input" value="${item.quantity}" min="1">
|
||||
<button class="btn btn-outline-secondary increase-btn" type="button">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<span class="fw-bold me-3">$${(item.price * item.quantity).toFixed(2)}</span>
|
||||
<button class="btn btn-sm btn-outline-danger remove-btn">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Показать пустую корзину
|
||||
showEmptyBasket() {
|
||||
if (this.emptyBasketElement) {
|
||||
this.emptyBasketElement.style.display = 'block';
|
||||
}
|
||||
if (this.basketContainer) {
|
||||
this.basketContainer.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Скрыть сообщение о пустой корзине
|
||||
hideEmptyBasket() {
|
||||
if (this.emptyBasketElement) {
|
||||
this.emptyBasketElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Рассчитать общую сумму
|
||||
calculateTotal(items) {
|
||||
return items.reduce((total, item) => total + (item.price * item.quantity), 0);
|
||||
}
|
||||
|
||||
// Показать уведомление
|
||||
showNotification(message, type = 'success') {
|
||||
// Создаем элемент уведомления
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `alert alert-${type === 'success' ? 'success' : 'danger'} alert-dismissible fade show`;
|
||||
notification.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 1050; min-width: 300px;';
|
||||
notification.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Автоматически удаляем через 3 секунды
|
||||
setTimeout(() => {
|
||||
if (notification.parentNode) {
|
||||
notification.remove();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
0
components/likes/controller.js
Normal file
0
components/likes/controller.js
Normal file
0
components/likes/model.js
Normal file
0
components/likes/model.js
Normal file
0
components/likes/view.js
Normal file
0
components/likes/view.js
Normal file
18
dist/basket.html
vendored
18
dist/basket.html
vendored
@@ -58,8 +58,9 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- В main контейнере basket.html замените содержимое на: -->
|
||||
<main class="container my-4">
|
||||
<main class="container my-4">
|
||||
<div class="empty-basket text-center py-5">
|
||||
<h1 class="mb-4">Здесь будут лежать твои товары</h1>
|
||||
<p class="lead mb-4">А пока здесь так пусто...</p>
|
||||
@@ -69,6 +70,8 @@
|
||||
<i class="bi bi-arrow-left me-2"></i>Вернуться в каталог
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="basketContainer"></div>
|
||||
</main>
|
||||
|
||||
@@ -98,5 +101,18 @@
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="./components/basket/model.js"></script>
|
||||
<script src="./components/basket/view.js"></script>
|
||||
<script src="./components/basket/controller.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Проверяем, есть ли необходимые элементы на странице
|
||||
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
|
||||
const model = new Model();
|
||||
const view = new View();
|
||||
new Controller(model, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
14
dist/catalog.html
vendored
14
dist/catalog.html
vendored
@@ -353,5 +353,19 @@
|
||||
|
||||
this.reset();
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="./components/basket/model.js"></script>
|
||||
<script src="./components/basket/view.js"></script>
|
||||
<script src="./components/basket/controller.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Проверяем, есть ли необходимые элементы на странице
|
||||
if (document.getElementById('basketContainer') || document.getElementById('productsContainer')) {
|
||||
const model = new Model();
|
||||
const view = new View();
|
||||
new Controller(model, view);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
Reference in New Issue
Block a user