Skip to content

Commit fb96a90

Browse files
Merge pull request #15 from jap-2024-grupo2/feature/calificaciones-productos-relacionados
feat: calificaciones productos relacionados
2 parents e617f1c + d09bfeb commit fb96a90

File tree

3 files changed

+168
-17
lines changed

3 files changed

+168
-17
lines changed

js/product-info.js

Lines changed: 112 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Obtenemos la ID del producto guardado previamente en el localStorage
22
const productID = localStorage.getItem('productID')
33

4+
const commentsSection = document.getElementById('comments-section')
5+
46
// Creamos un elemento para el carrusel con la imagen correspondiente
57
const createCarouselItem = (imgSrc, isActive, altText) => `
68
<div class="carousel-item ${isActive ? 'active' : ''}">
@@ -42,11 +44,11 @@ fetch(`https://japceibal.github.io/emercado-api/products/${productID}.json`)
4244

4345
// Generamos el contenido del carrusel horizontal
4446
const carouselInner = images
45-
.slice(1, 4) // Seleccionamos solo las imágenes necesarias
47+
.slice(1, 4) // Seleccionamos solo las imágenes necesarias
4648
.map((imgSrc, index) =>
4749
createCarouselItem(
4850
imgSrc,
49-
index === 0, // Marcamos la primera imagen como activa
51+
index === 0, // Marcamos la primera imagen como activa
5052
`Imagen ${index + 1} de ${name}`
5153
)
5254
)
@@ -71,12 +73,12 @@ fetch(`https://japceibal.github.io/emercado-api/products/${productID}.json`)
7173

7274
// Generamos el contenido de las imágenes verticales
7375
const verticalImagesInner = images
74-
.slice(1, 4) // Seleccionamos las imágenes necesarias
76+
.slice(1, 4) // Seleccionamos las imágenes necesarias
7577
.map((imgSrc, index, array) =>
7678
createImageElement(
7779
imgSrc,
7880
`Imagen ${index + 1} de ${name}`,
79-
index === array.length - 1 // Eliminamos margen para la última imagen
81+
index === array.length - 1 // Eliminamos margen para la última imagen
8082
)
8183
)
8284
.join('')
@@ -92,11 +94,114 @@ fetch(`https://japceibal.github.io/emercado-api/products/${productID}.json`)
9294

9395
// Ajustamos los carruseles según el tamaño de la pantalla al cargar la página
9496
adjustCarousels(horizontalCarousel, verticalImages)
95-
window.addEventListener('resize', () =>
96-
adjustCarousels(horizontalCarousel, verticalImages) // Reajustamos carruseles al redimensionar la ventana
97+
window.addEventListener('resize', () => adjustCarousels(horizontalCarousel, verticalImages) // Reajustamos carruseles al redimensionar la ventana
9798
)
9899
}
99100
)
100101
.catch((error) => {
101-
console.error('Error fetching datos del producto:', error) // Capturamos errores en la obtención de datos
102+
console.error('Error fetching datos del producto:', error) // Capturamos errores en la obtención de datos
103+
})
104+
105+
// Fetch para listar los comentarios provinientes de la API
106+
fetch(`https://japceibal.github.io/emercado-api/products_comments/${productID}.json`)
107+
.then((res) => res.json())
108+
.then((comments) => {
109+
comments.forEach(({ score, description, user, dateTime }) => {
110+
commentsSection.innerHTML += createComment(user, dateTime, score, description)
111+
})
112+
})
113+
.catch((error) => console.error('Error fetching comentarios:', error))
114+
115+
// Función para crear un comentario
116+
function createComment(user, dateTime, score, description) {
117+
return `
118+
<div class="my-1">
119+
<div class="row">
120+
<div class="col-md-8 w-100">
121+
<div class="card review-card shadow-sm">
122+
<div class="card-body">
123+
<div class="row">
124+
<div class="col-md-4 border-end">
125+
<h5 class="mb-0 customer-name">${user}</h5>
126+
<small class="text-muted">${formatDate(dateTime)}</small>
127+
</div>
128+
<div class="col-md-8">
129+
<div class="stars mb-2" aria-label="Rating: ${score} out of 5 stars">
130+
${createStars(score)}
131+
</div>
132+
<p class="review-text mb-2">${description}</p>
133+
</div>
134+
</div>
135+
</div>
136+
</div>
137+
</div>
138+
</div>
139+
</div>
140+
`
141+
}
142+
143+
// Función para crear las estrellas
144+
function createStars(userScore) {
145+
let estrellasHTML = ''
146+
for (let i = 1; i <= 5; i++) {
147+
estrellasHTML += `<i class="fa fa-star ${i <= userScore ? 'checked' : ''}"></i>`
148+
}
149+
150+
return estrellasHTML
151+
}
152+
153+
// Función para formatear la fecha que viene por la API
154+
function formatDate(dateTimeString) {
155+
const date = new Date(dateTimeString) // Creamos una instancia de Date a partir del string de la fecha que viene de la API
156+
157+
// Opciones para formatear la fecha
158+
const options = {
159+
year: 'numeric',
160+
month: 'short',
161+
day: 'numeric',
162+
hour: '2-digit',
163+
minute: '2-digit'
164+
}
165+
166+
// Formateamos la fecha con toLocaleDateString 'es-ES' para español
167+
return date.toLocaleDateString('es-ES', options)
168+
}
169+
170+
// Simulación de envío de comentario
171+
function submitComment() {
172+
const user = localStorage.getItem('userName')
173+
const commentText = document.getElementById('rating-text').value.trim()
174+
const ratingStars = document.getElementById('rating-stars').value
175+
176+
const newComment = createComment(user, new Date(), ratingStars, commentText)
177+
178+
commentsSection.innerHTML += newComment
179+
document.getElementById('rating-text').value = ''
180+
}
181+
182+
// Cargar los productos relacionados desde la API
183+
fetch(`https://japceibal.github.io/emercado-api/products/${productID}.json`)
184+
.then((response) => response.json())
185+
.then(({ relatedProducts }) => {
186+
const relatedSection = document.getElementById('related-products')
187+
188+
relatedProducts.forEach(({ id, name, image }) => {
189+
relatedSection.innerHTML += `
190+
<div class="col-12 col-md-6 col-lg-4 my-2" style="width: 18rem;">
191+
<div class="related-product card cursor-active" onclick="selectProduct(${id})">
192+
<img src="${image}" class="card-img-top" alt="${name}" loading="lazy">
193+
<div class="card-body">
194+
<h5 class="card-title">${name}</h5>
195+
</div>
196+
</div>
197+
</div>
198+
`
199+
})
102200
})
201+
.catch((error) => console.error('Error fetching related products:', error))
202+
203+
// Actualizamos el ID del producto en el localStorage y redirigimos
204+
function selectProduct(id) {
205+
localStorage.setItem('productID', id)
206+
window.location = 'product-info.html'
207+
}

js/products.js

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,15 +159,30 @@ document
159159
showProductsList()
160160
})
161161

162-
document.getElementById("inputSearch").addEventListener("input", function () {
163-
const searchText = this.value.toLowerCase()
164-
const filteredProducts = currentProductsArray.filter(({ name, description }) => {
165-
return (
166-
name.toLowerCase().includes(searchText) || description.toLowerCase().includes(searchText)
167-
)
168-
})
162+
// Función para normalizar el texto: lo convierte a minúsculas, elimina acentos y carecteres especiales
163+
function normalizeText(text) {
164+
return text
165+
.toLowerCase()
166+
.normalize('NFD')
167+
.replace(/[\u0300-\u036f]/g, '')
168+
}
169+
170+
document.getElementById('inputSearch').addEventListener('input', function () {
171+
const searchTerm = normalizeText(this.value) // Normalizamos el término de búsqueda.
172+
173+
const filteredProducts = currentProductsArray.filter(
174+
({ name, description }) => {
175+
const normalizedTitle = normalizeText(name) // Normalizamos el nombre del producto.
176+
const normalizedDescription = normalizeText(description) // Normalizamos la descripción del producto.
177+
178+
return (
179+
normalizedTitle.includes(searchTerm) || // Buscamos coincidencias en el nombre.
180+
normalizedDescription.includes(searchTerm) // Buscamos coincidencias en la descripción.
181+
)
182+
}
183+
)
169184

170-
showProductsList(filteredProducts)
185+
showProductsList(filteredProducts) // Mostrar los productos filtrados
171186
})
172187

173188
function showAlert(message) {

product-info.html

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
</div>
5757
</div>
5858
</nav>
59-
<main>
59+
<main class="container">
6060
<section class="py-5">
6161
<div class="container-xl px-lg-5 my-1 my-md-5">
6262
<div class="row gx-4 gx-lg-5 align-items-center" id="content-container">
@@ -70,7 +70,8 @@ <h1 class="display-5 fw-bolder" id="product-info-name"></h1>
7070
</div>
7171
<p class="lead" id="product-info-description"></p>
7272
<div class="d-flex flex-row flex-sm-column flex-lg-row" id="product-info-soldCount-addToCart">
73-
<span class="form-control text-center mb-sm-2 mb-lg-0 me-3 me-sm-0 me-lg-3 w-auto" id="product-info-soldCount"></span>
73+
<span class="form-control text-center mb-sm-2 mb-lg-0 me-3 me-sm-0 me-lg-3 w-auto"
74+
id="product-info-soldCount"></span>
7475
<button class="btn btn-primary flex-shrink-0" type="button">
7576
<i class="bi-cart-fill me-1"></i>
7677
Agregar al carro
@@ -81,7 +82,37 @@ <h1 class="display-5 fw-bolder" id="product-info-name"></h1>
8182
</div>
8283
</section>
8384

85+
<section class="container">
86+
<h2>Productos relacionados</h2>
87+
<div class="row" id="related-products"></div>
88+
</section>
89+
90+
<section class="container my-5" id="rate-product">
91+
<h2>Dejar una calificación</h2>
92+
<form id="rating-form">
93+
<div class="mb-3">
94+
<label for="rating-text" class="form-label">Comentario</label>
95+
<textarea class="form-control" id="rating-text" rows="3"></textarea>
96+
</div>
97+
<div class="mb-3">
98+
<label for="rating-stars" class="form-label">Calificación</label>
99+
<select id="rating-stars" class="form-select">
100+
<option value="1"></option>
101+
<option value="2">⭐⭐</option>
102+
<option value="3">⭐⭐⭐</option>
103+
<option value="4">⭐⭐⭐⭐</option>
104+
<option value="5">⭐⭐⭐⭐⭐</option>
105+
</select>
106+
</div>
107+
<button type="button" class="btn btn-primary" onclick="submitComment()">Enviar</button>
108+
</form>
109+
</section>
110+
111+
<section class="container" id="comments-section">
112+
<h2>Calificaciones</h2>
113+
</section>
84114
</main>
115+
85116
<footer class="text-muted">
86117
<div class="container">
87118
<p class="float-end">

0 commit comments

Comments
 (0)