leanwebclub/web-apps/store-front/js/grid-of-photos.js

133 lines
3.2 KiB
JavaScript

const endpoint = 'https://leanwebclub.com/course-apis/photos.json';
class GridOfPhotos extends HTMLElement {
/**
* Instantiate the component
*/
constructor () {
// Inherit parent class properties
super();
// Track the current focused image button on the grid
this.currentImageBtn = null;
// Listen for events
this.addEventListener('click', this);
}
/**
* Runs each time the element is appended to or moved in the DOM
*/
async connectedCallback () {
// Fetch the photos from the API
this.photos = await this.fetchPhotos();
// If there are no photos
if (!this.photos || !this.photos.length) {
this.innerHTML = '<p>There are no available photos at this time. Please try again later. Sorry!</p>';
}
// Render the element
this.innerHTML = `
<div>
${this.photos.map( (image) => {
return `<button id="open-photo-button" class="outline contrast"><img id="${image.id}" src="${image.url}" alt="${image.description}"></img></button>`
} ).join('')}
</div>
`
}
/**
* Fetch photos from the API
* @return {Promise} response - The response from the API
*/
async fetchPhotos () {
try {
let response = await fetch(endpoint);
if (!response.ok) throw response.status;
let data = await response.json();
if (!data) throw 'No data!';
return data;
} catch (error) {
console.warn("ERR:", error);
}
}
/**
* Handle events
* @param {Event} event - The event object
*/
handleEvent (event) {
this[`on${event.type}`](event);
}
/**
* Open the modal window that shows the photo.
*/
handleOpenPhoto (event) {
let btn = event.target.closest('#open-photo-button');
if (!btn) return;
this.currentImageBtn = btn;
let id = btn.querySelector('img').getAttribute('id');
let image = this.photos.find( (image) => { return image.id === id } );
// Create the dialog element
let dialog = document.createElement('dialog');
dialog.setAttribute('open', '');
dialog.setAttribute('aria-live', 'polite');
dialog.innerHTML = `
<article>
<h2>${image.name}</h2>
<p>
${image.description}
</p>
<img id="${image.id}" src="${image.url}" alt="${image.description}"></img>
<footer>
<button id="add-photo-button" class="primary">Add to cart</button>
<button id="close-photo-button" class="secondary">Cancel</button>
</footer>
</article>
`
this.append(dialog);
dialog.focus();
}
/**
* Close the modal window that shows the photo.
*/
handleClosePhoto (event) {
let btn = event.target.closest('#close-photo-button');
if (!btn) return;
let dialog = event.target.closest('dialog');
if (!dialog) return;
dialog.close();
dialog.remove();
this.currentImageBtn.focus();
}
/**
* Handle the click event
* @param {Event} event - The event object
*/
onclick (event) {
this.handleOpenPhoto(event);
this.handleClosePhoto(event);
}
}
// Define the new web component
if ('customElements' in window) {
customElements.define('grid-of-photos', GridOfPhotos);
}