50 lines
7.6 KiB
JavaScript
50 lines
7.6 KiB
JavaScript
class r{constructor(){this.apiUrl="http://localhost:3000"}async request(t,s={}){try{const e=await fetch(`${this.apiUrl}${t}`,{...s,headers:{"Content-Type":"application/json",...s.headers}});if(!e.ok)throw new Error(`HTTP error! status: ${e.status}`);return await e.json()}catch(e){throw console.error("Request failed:",e),e}}async getBasketItems(){try{return await this.request("/basket")}catch(t){return console.error("Ошибка при получении корзины:",t),[]}}async addToBasket(t){try{const e=(await this.getBasketItems()).find(a=>a.id===t.id);if(e)await this.updateBasketItem(t.id,e.quantity+1);else{const a={...t,quantity:1,addedAt:new Date().toISOString()};return await(await fetch(`${this.apiUrl}/basket`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).json()}}catch(s){console.error("Ошибка при добавлении в корзину:",s)}}async updateBasketItem(t,s){try{return await(await fetch(`${this.apiUrl}/basket/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({quantity:s})})).json()}catch(e){console.error("Ошибка при обновлении корзины:",e)}}async removeFromBasket(t){try{await fetch(`${this.apiUrl}/basket/${t}`,{method:"DELETE"})}catch(s){console.error("Ошибка при удалении из корзины:",s)}}async clearBasket(){try{const t=await this.getBasketItems();for(const s of t)await this.removeFromBasket(s.id)}catch(t){console.error("Ошибка при очистке корзины:",t)}}async getProducts(){try{return await(await fetch(`${this.apiUrl}/shmots`)).json()}catch(t){return console.error("Ошибка при получении товаров:",t),[]}}}class c{constructor(){this.basketContainer=document.getElementById("basketContainer"),this.emptyBasketElement=document.querySelector(".empty-basket")}showBasket(t){if(t.length===0){this.showEmptyBasket();return}this.hideEmptyBasket();const s=t.map(e=>this.createBasketItemHTML(e)).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">
|
||
${s}
|
||
<div class="d-flex justify-content-between align-items-center mt-4 pt-3 border-top">
|
||
<h5>Итого: $${this.calculateTotal(t).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>
|
||
`}createBasketItemHTML(t){return`
|
||
<div class="row align-items-center mb-3 basket-item" data-id="${t.id}">
|
||
<div class="col-md-2">
|
||
<img src="${t.image}" alt="${t.name}" class="img-fluid rounded" style="max-height: 80px;">
|
||
</div>
|
||
<div class="col-md-4">
|
||
<h6 class="mb-1">${t.name}</h6>
|
||
<p class="text-muted small mb-0">${t.description}</p>
|
||
</div>
|
||
<div class="col-md-2">
|
||
<span class="fw-bold">$${t.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="${t.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">$${(t.price*t.quantity).toFixed(2)}</span>
|
||
<button class="btn btn-sm btn-outline-danger remove-btn">
|
||
<i class="bi bi-trash"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`}showEmptyBasket(){this.emptyBasketElement&&(this.emptyBasketElement.style.display="block"),this.basketContainer&&(this.basketContainer.innerHTML="")}hideEmptyBasket(){this.emptyBasketElement&&(this.emptyBasketElement.style.display="none")}calculateTotal(t){return t.reduce((s,e)=>s+e.price*e.quantity,0)}showNotification(t,s="success"){const e=document.createElement("div");e.className=`alert alert-${s==="success"?"success":"danger"} alert-dismissible fade show`,e.style.cssText="position: fixed; top: 20px; right: 20px; z-index: 1050; min-width: 300px;",e.innerHTML=`
|
||
${t}
|
||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||
`,document.body.appendChild(e),setTimeout(()=>{e.parentNode&&e.remove()},3e3)}}class l{constructor(t,s){this.model=t,this.view=s,this.init()}async init(){window.location.pathname.includes("basket.html")&&(await this.loadBasket(),this.setupBasketEventListeners()),window.location.pathname.includes("catalog.html")&&this.setupCatalogEventListeners()}async loadBasket(){const t=await this.model.getBasketItems();this.view.showBasket(t)}setupBasketEventListeners(){document.addEventListener("click",async t=>{const s=t.target.closest(".basket-item");if(!s)return;const e=s.dataset.id;if(t.target.closest(".remove-btn")&&(await this.model.removeFromBasket(e),this.view.showNotification("Товар удален из корзины"),await this.loadBasket()),t.target.closest(".increase-btn")){const a=s.querySelector(".quantity-input"),i=parseInt(a.value)+1;a.value=i,await this.model.updateBasketItem(e,i),await this.loadBasket()}if(t.target.closest(".decrease-btn")){const a=s.querySelector(".quantity-input");let i=parseInt(a.value)-1;i<1&&(i=1),a.value=i,await this.model.updateBasketItem(e,i),await this.loadBasket()}}),document.addEventListener("change",async t=>{if(t.target.classList.contains("quantity-input")){const e=t.target.closest(".basket-item").dataset.id,a=parseInt(t.target.value)||1;if(a<1){t.target.value=1;return}await this.model.updateBasketItem(e,a),await this.loadBasket()}}),document.addEventListener("click",async t=>{if(t.target.id==="checkoutBtn"){if((await this.model.getBasketItems()).length===0){this.view.showNotification("Корзина пуста","error");return}this.view.showNotification("Заказ оформлен! Спасибо за покупку!"),await this.model.clearBasket(),await this.loadBasket()}})}setupCatalogEventListeners(){document.addEventListener("click",async t=>{if(t.target.closest(".btn")&&t.target.closest(".btn").textContent.includes("В корзину")){const s=t.target.closest(".card"),e=this.extractProductData(s);e&&(await this.model.addToBasket(e),this.view.showNotification("Товар добавлен в корзину!"))}})}extractProductData(t){try{const s=t.querySelector(".card-title").textContent,e=t.querySelector(".text-muted").textContent.replace("$",""),a=t.querySelector(".card-text").textContent,i=t.querySelector("img").src;return{id:btoa(`${s}-${e}`).substring(0,8),name:s.trim(),price:parseFloat(e),description:a.trim(),image:i}}catch(s){return console.error("Ошибка при извлечении данных товара:",s),null}}}export{l as C,r as M,c as V};
|