Skip to content

Commit d6e0957

Browse files
committed
Primeira publicação projeto shopping-cart
1 parent 3cc927c commit d6e0957

File tree

7 files changed

+605
-0
lines changed

7 files changed

+605
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const fetchItem = async (itemID) => {
2+
const url = `https://api.mercadolibre.com/items/${itemID}`;
3+
try {
4+
const response = await fetch(url);
5+
const data = await response.json();
6+
return data;
7+
} catch (erro) {
8+
throw new Error('You must provide an url');
9+
}
10+
};
11+
12+
if (typeof module !== 'undefined') {
13+
module.exports = {
14+
fetchItem,
15+
};
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const fetchProducts = async (query) => {
2+
const url = `https://api.mercadolibre.com/sites/MLB/search?q=${query}`;
3+
try {
4+
const responseUrl = await fetch(url);
5+
const data = await responseUrl.json();
6+
return data;
7+
} catch (erro) {
8+
throw new Error('You must provide an url');
9+
}
10+
};
11+
12+
if (typeof module !== 'undefined') {
13+
module.exports = {
14+
fetchProducts,
15+
};
16+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const getSavedCartItems = (cartItem) => localStorage.getItem(cartItem);
2+
3+
if (typeof module !== 'undefined') {
4+
module.exports = getSavedCartItems;
5+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const saveCartItems = (item) => {
2+
localStorage.setItem('cartItems', item);
3+
};
4+
5+
if (typeof module !== 'undefined') {
6+
module.exports = saveCartItems;
7+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html lang="pt-BR">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
7+
<title>TrybeShopping</title>
8+
<link rel="stylesheet" href="style.css" />
9+
<link rel="preconnect" href="https://fonts.googleapis.com">
10+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11+
<link href="https://fonts.googleapis.com/css2?family=Epilogue:wght@400;700&display=swap" rel="stylesheet">
12+
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
13+
<script src="./helpers/fetchItem.js" defer></script>
14+
<script src="./helpers/fetchProducts.js" defer></script>
15+
<script src="./helpers/saveCartItems.js" defer></script>
16+
<script src="./helpers/getSavedCartItems.js" defer></script>
17+
<script src="script.js" defer></script>
18+
<script src="https://kit.fontawesome.com/c14177f602.js" crossorigin="anonymous"></script>
19+
</head>
20+
<body>
21+
<header class="header">
22+
<div class="container-title">
23+
<span class="title"><strong>trybe</strong>shopping</span>
24+
<input class="search_input" type="text" placeholder="Buscar produtos, marcas e muito mais...">
25+
<i class="fa-brands fa-searchengin fa-xl"></i>
26+
</div>
27+
<i class="material-icons" style="font-size:45px;color:white">shopping_cart</i>
28+
<div class="container-cartTitle">
29+
<span class="cart__title">Meu carrinho</span>
30+
</div>
31+
</header>
32+
<section class="container">
33+
<section class="items"></section>
34+
<section class="cart">
35+
<ol class="cart__items"></ol>
36+
<button class="empty-cart">Esvaziar carrinho</button>
37+
</section>
38+
</section>
39+
</body>
40+
</html>
Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
const round = (num, places) => {
2+
if (!(`${num}`).includes('e')) {
3+
return +(`${Math.round(`${num}e+${places}`)}e-${places}`);
4+
}
5+
const arr = (`${num}`).split('e');
6+
let sig = '';
7+
if (+arr[1] + places > 0) {
8+
sig = '+';
9+
}
10+
return +(`${Math.round(`${+arr[0]}e${sig}${+arr[1] + places}`)}e-${places}`);
11+
};
12+
// Creditos da função acima ao A Kunin, user:1736537 do stackoverflow, apenas modificada do original para as regras do linter e funcionamento na minha aplicação. Função utilizada para trabalhar com casas decimais de forma mais precisa possível.
13+
14+
const createProductImageElement = (imageSource) => {
15+
const img = document.createElement('img');
16+
img.className = 'item__image';
17+
img.src = imageSource;
18+
return img;
19+
};
20+
21+
const createCustomElement = (element, className, innerText) => {
22+
const e = document.createElement(element);
23+
e.className = className;
24+
e.innerText = innerText;
25+
return e;
26+
};
27+
28+
const createProductItemElement = ({ sku, name, image }) => {
29+
const section = document.createElement('section');
30+
section.className = 'item';
31+
32+
section.appendChild(createCustomElement('span', 'item__sku', sku));
33+
section.appendChild(createCustomElement('span', 'item__title', name));
34+
section.appendChild(createProductImageElement(image));
35+
section.appendChild(createCustomElement('button', 'item__add', 'Adicionar ao carrinho!'));
36+
37+
return section;
38+
};
39+
40+
const getSkuFromProductItem = (item) => item.querySelector('span.item__sku').innerText;
41+
42+
const selectTotalPrice = () => {
43+
priceContainer = document.querySelector('.total-price');
44+
return priceContainer;
45+
};
46+
47+
const subtractTotalCart = (event) => {
48+
const itemCartRemove = event.path[0];
49+
const priceCapture = itemCartRemove.innerText.split(' ').pop().split('$').pop();
50+
const priceConvertion = parseFloat(selectTotalPrice().innerText) - parseFloat(priceCapture);
51+
const priceRound = round(priceConvertion, 2);
52+
selectTotalPrice().innerText = priceRound;
53+
localStorage.setItem('total', priceRound);
54+
};
55+
const handleAllLocalStorage = (event) => {
56+
localStorage.removeItem('cartItems');
57+
subtractTotalCart(event);
58+
localStorage.removeItem('total');
59+
};
60+
61+
const removeItemCart = (event) => {
62+
const itemCartRemove = event.path[0];
63+
const divRemove = itemCartRemove.parentNode;
64+
itemCartRemove.remove();
65+
divRemove.remove();
66+
if (getSavedCartItems('cartItems').split(',').length === 1) {
67+
return handleAllLocalStorage(event);
68+
}
69+
const idCapture = itemCartRemove.innerText.split(' ')[1];
70+
const ls = getSavedCartItems('cartItems').split(',');
71+
const newLs = ls.filter((element) => element !== idCapture);
72+
saveCartItems(newLs.toString());
73+
subtractTotalCart(event);
74+
};
75+
76+
const cartItemClickListener = (event) => {
77+
removeItemCart(event);
78+
};
79+
80+
const itemCartOver = (event) => {
81+
const divCartContainer = event.path[0];
82+
const remover = document.createElement('i');
83+
remover.className = 'fa-solid fa-trash-can';
84+
divCartContainer.appendChild(remover);
85+
}
86+
87+
const removeItemCartOver = () => {
88+
const textRemover = document.querySelector('.fa-trash-can');
89+
textRemover.remove();
90+
}
91+
92+
const createCartItemElement = ({ sku, name, salePrice, img }) => {
93+
const div = document.createElement('div');
94+
div.className = 'cart_item_container';
95+
const image = document.createElement('img');
96+
image.className = 'cart_item_img';
97+
image.setAttribute('src', img);
98+
const li = document.createElement('li');
99+
li.className = 'cart__item';
100+
li.innerText = `SKU: ${sku} | NAME: ${name} | PRICE: R$${salePrice}`;
101+
li.addEventListener('click', cartItemClickListener);
102+
div.appendChild(image);
103+
div.appendChild(li);
104+
div.addEventListener('mouseover', itemCartOver);
105+
div.addEventListener('mouseout', removeItemCartOver);
106+
return div;
107+
};
108+
109+
const messageCallingApi = () => {
110+
const cartContainer = document.querySelector('.cart');
111+
const messageElement = document.createElement('h3');
112+
messageElement.className = 'loading';
113+
messageElement.innerText = 'carregando...';
114+
cartContainer.appendChild(messageElement);
115+
};
116+
117+
const messageLoadPage = () => {
118+
const containerTitle = document.querySelector('.container-title')
119+
const messageElement = document.createElement('h3');
120+
messageElement.className = 'loading';
121+
messageElement.innerText = 'carregando...'
122+
containerTitle.appendChild(messageElement);
123+
}
124+
125+
const removeMessageCallingApi = () => {
126+
const messageContainer = document.querySelector('.loading');
127+
messageContainer.remove();
128+
};
129+
130+
const searchInput = document.querySelector('.search_input');
131+
const buttonSearch = document.querySelector('.fa-searchengin');
132+
const searchProducts = () => searchInput.value;
133+
134+
const cleanPage = () => {
135+
const allItemsContainer = document.querySelectorAll('.item');
136+
allItemsContainer.forEach((e) => {
137+
e.remove();
138+
})
139+
};
140+
141+
searchInput.addEventListener('keypress', function (event) {
142+
if (event.which === 13) {
143+
cleanPage();
144+
createIntensHtml(searchProducts());
145+
}
146+
});
147+
148+
buttonSearch.addEventListener('click', function () {
149+
cleanPage();
150+
createIntensHtml(searchProducts());
151+
})
152+
153+
buttonSearch.addEventListener('mouseover', function () {
154+
buttonSearch.classList.add('fa-beat');
155+
})
156+
157+
buttonSearch.addEventListener('mouseout', function () {
158+
buttonSearch.classList.remove('fa-beat');
159+
})
160+
161+
const createIntensHtml = async (product) => {
162+
messageLoadPage();
163+
const itemsContainer = document.querySelector('.items');
164+
const data = await fetchProducts(product);
165+
const { results } = data;
166+
await results.forEach(({ id, title, thumbnail }) => {
167+
const item = {
168+
sku: id,
169+
name: title,
170+
image: thumbnail,
171+
};
172+
itemsContainer.appendChild(createProductItemElement(item));
173+
});
174+
removeMessageCallingApi();
175+
};
176+
177+
const defaultIntensHtml = async () => {
178+
messageLoadPage();
179+
const itemsContainer = document.querySelector('.items');
180+
const data = await fetchProducts('informática');
181+
const { results } = data;
182+
await results.forEach(({ id, title, thumbnail }) => {
183+
const item = {
184+
sku: id,
185+
name: title,
186+
image: thumbnail,
187+
};
188+
itemsContainer.appendChild(createProductItemElement(item));
189+
});
190+
removeMessageCallingApi();
191+
};
192+
193+
const addItemCartHtml = async (itemID) => {
194+
const cartContainer = document.querySelector('.cart__items');
195+
const data = await fetchItem(itemID);
196+
const { id } = data;
197+
const { title } = data;
198+
const { price } = data;
199+
const { thumbnail } = data;
200+
const item = {
201+
sku: id,
202+
name: title,
203+
salePrice: price,
204+
img: thumbnail,
205+
};
206+
cartContainer.appendChild(createCartItemElement(item));
207+
};
208+
209+
const addTotalCart = async (itemID) => {
210+
const data = await fetchItem(itemID);
211+
const { price } = data;
212+
const priceConvertion = parseFloat(selectTotalPrice().innerText) + price;
213+
const priceRound = round(priceConvertion, 2);
214+
selectTotalPrice().innerText = priceRound;
215+
localStorage.setItem('total', priceRound);
216+
};
217+
218+
const loadTotalStorage = () => {
219+
const priceContainer = document.querySelector('.total-price');
220+
const currentStorage = () => {
221+
priceContainer.innerText = localStorage.getItem('total');
222+
};
223+
if ('total' in localStorage) {
224+
return currentStorage();
225+
}
226+
priceContainer.innerText = 0;
227+
};
228+
229+
const createSumElement = () => {
230+
const divTotal = document.createElement('div');
231+
divTotal.className = 'div-total';
232+
const h3TitleTotal = document.createElement('h3');
233+
h3TitleTotal.className = 'title-total';
234+
h3TitleTotal.innerText = 'Total Carrinho: R$'
235+
const cartContainer = document.querySelector('.cart');
236+
const elementSum = document.createElement('h3');
237+
elementSum.className = 'total-price';
238+
divTotal.appendChild(h3TitleTotal);
239+
divTotal.appendChild(elementSum);
240+
cartContainer.appendChild(divTotal);
241+
loadTotalStorage();
242+
};
243+
244+
const createItemCart = async (event) => {
245+
if (event.target.classList.contains('item__add')) {
246+
const idItem = getSkuFromProductItem(event.target.parentNode);
247+
messageCallingApi();
248+
await addItemCartHtml(idItem);
249+
await addTotalCart(idItem);
250+
removeMessageCallingApi();
251+
if ('cartItems' in localStorage) {
252+
return saveCartItems(`${getSavedCartItems('cartItems')},${idItem}`);
253+
}
254+
saveCartItems(idItem);
255+
}
256+
};
257+
258+
const buttonItemAdd = document.querySelector('.container');
259+
buttonItemAdd.addEventListener('click', function async(e) {
260+
createItemCart(e);
261+
});
262+
263+
const validSplit = () => {
264+
if ('cartItems' in localStorage) {
265+
return getSavedCartItems('cartItems').split(',').length;
266+
}
267+
return 0;
268+
};
269+
270+
const handleLocalStorage = () => {
271+
if ('cartItems' in localStorage && validSplit() > 1) {
272+
const ls = getSavedCartItems('cartItems').split(',');
273+
return ls.forEach((element) => {
274+
addItemCartHtml(element);
275+
});
276+
} if (validSplit() === 1) {
277+
return addItemCartHtml(getSavedCartItems('cartItems'));
278+
}
279+
};
280+
281+
const clearCart = () => {
282+
if ('cartItems' in localStorage) {
283+
localStorage.removeItem('cartItems');
284+
localStorage.removeItem('total');
285+
window.location.reload();
286+
}
287+
};
288+
289+
const buttonClear = document.querySelector('.empty-cart');
290+
buttonClear.addEventListener('click', () => clearCart());
291+
292+
window.onload = async () => {
293+
await defaultIntensHtml();
294+
await handleLocalStorage();
295+
await createSumElement();
296+
};

0 commit comments

Comments
 (0)