Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
const savedData = localStorage.getItem('shoppingCart');

let products = savedData ? JSON.parse(savedData) : [
{id: 1, name: "Помідори", amount: 2, isBought: true, isEditing: false},
{id: 2, name: "Печиво", amount: 2, isBought: false, isEditing: false},
{id: 3, name: "Сир", amount: 1, isBought: false, isEditing: false}
];

const productsContainer = document.getElementById("items-list");
const leftStatsContainer = document.getElementById("remaining-container");
const boughtStatsContainer = document.getElementById("bought-container");
const shoppingForm = document.getElementById("shopping-form");
const searchInput = document.getElementById("item-input");

function render() {
localStorage.setItem('shoppingCart', JSON.stringify(products));

if (!productsContainer || !leftStatsContainer || !boughtStatsContainer) return;

productsContainer.innerHTML = "";
leftStatsContainer.innerHTML = "";
boughtStatsContainer.innerHTML = "";

products.forEach(product => {
let itemHtml = '';

if (product.isBought) {
itemHtml = `
<li class="item-row is-bought" data-id="${product.id}">
<span class="item-name">${product.name}</span>
<div class="item-controls">
<span class="item-quantity">${product.amount}</span>
</div>
<div class="item-actions">
<button class="btn-bought buy-btn" type="button" data-tooltip="Відмітити як не куплене">Не куплено</button>
</div>
</li>
`;
boughtStatsContainer.insertAdjacentHTML('beforeend', `
<span class="tag is-bought">
${product.name} <span class="tag-count">${product.amount}</span>
</span>
`);
} else {
let nameContent = '';
if (product.isEditing) {
nameContent = `<input type="text" class="item-edit-input item-input-edit" value="${product.name}">`;
} else {
nameContent = `<span class="item-name">${product.name}</span>`;
}

itemHtml = `
<li class="item-row" data-id="${product.id}">
${nameContent}
<div class="item-controls">
<button class="btn-minus minus" type="button" ${product.amount === 1 ? "disabled" : ""} data-tooltip="Зменшити">-</button>
<span class="item-quantity">${product.amount}</span>
<button class="btn-plus plus" type="button" data-tooltip="Збільшити">+</button>
</div>
<div class="item-actions">
<button class="btn-bought buy-btn" type="button" data-tooltip="Відмітити як куплене">Куплено</button>
<button class="btn-delete delete-btn" type="button" data-tooltip="Видалити">✖</button>
</div>
</li>
`;
leftStatsContainer.insertAdjacentHTML('beforeend', `
<span class="tag">
${product.name} <span class="tag-count">${product.amount}</span>
</span>
`);
}

productsContainer.insertAdjacentHTML("beforeend", itemHtml);
});
}

if (shoppingForm) {
shoppingForm.addEventListener("submit", (event) => {
event.preventDefault();
const newProductName = searchInput.value.trim();

if (newProductName) {
products.push({
id: Date.now(),
name: newProductName,
amount: 1,
isBought: false,
isEditing: false
});
searchInput.value = "";
render();
}
searchInput.focus();
});
}

if (productsContainer) {
productsContainer.addEventListener("click", (event) => {
const itemContainer = event.target.closest("[data-id]");
if (!itemContainer) return;

const productId = Number(itemContainer.dataset.id);

if (event.target.classList.contains("delete-btn")) {
products = products.filter(product => product.id !== productId);
render();
return;
}
if (event.target.classList.contains("buy-btn")) {
const product = products.find(p => p.id === productId);
if (product) product.isBought = !product.isBought;
render();
return;
}
if (event.target.classList.contains("plus")) {
const product = products.find(p => p.id === productId);
if (product) product.amount++;
render();
return;
}
if (event.target.classList.contains("minus")) {
const product = products.find(p => p.id === productId);
if (product && product.amount > 1) product.amount--;
render();
return;
}
if (event.target.classList.contains("item-name")) {
const product = products.find(p => p.id === productId);
if (product && !product.isBought) {
product.isEditing = true;
render();
const input = productsContainer.querySelector(`[data-id="${productId}"] .item-input-edit`);
if (input) input.focus();
}
}
});

productsContainer.addEventListener("blur", (event) => {
if (event.target.classList.contains("item-input-edit")) {
const itemContainer = event.target.closest("[data-id]");
const productId = Number(itemContainer.dataset.id);
const product = products.find(p => p.id === productId);

if (product) {
const newName = event.target.value.trim();
if (newName) {
product.name = newName;
}
product.isEditing = false;
render();
}
}
}, true);
}

render();
44 changes: 36 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,44 @@
<!DOCTYPE html>
<html>
<head lang="uk">
<html lang="uk">
<head>
<meta charset="UTF-8">
<title>My Page</title>


<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="main.css" />
<script src="app.js" defer></script>
</head>
<body>
<span class="product-item">
Apple
<span class="amount">4</span>
</span>
<main class="main-container">

<section class="left-column">
<form class="form" id="shopping-form">
<input type="text" id="item-input" placeholder="Назва товару" aria-label="Назва товару" required>
<button type="submit">Додати</button>
</form>

<ul class="items-list" id="items-list"></ul>
</section>

<aside class="sidebar">
<div class="stats-block">
<h2>Залишилося</h2>
<div class="tags-container" id="remaining-container"></div>
</div>

<hr class="divider">

<div class="stats-block">
<h2>Куплено</h2>
<div class="tags-container" id="bought-container"></div>
</div>
</aside>

</main>

<div class="badge">
<span class="badge-title">Buy List</span>
<span class="badge-author">Created by:<br>Микола Ващук</span>
</div>

</body>
</html>
Loading