Created
July 27, 2023 18:02
-
-
Save kenny-io/7f97430a2f4651564de56f4cf44977bc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const state = { | |
currentPage: window.location.pathname, | |
search: { | |
term: '', | |
type: '', | |
page: 1, | |
totalPages: 1, | |
totalResults: 0, | |
}, | |
api: { | |
//Api key is showing because this is a small project | |
apiKey: 'e3bcd3ddedc1aeb5f13eda82709a14e1', | |
apiUrl: 'https://api.themoviedb.org/3', | |
}, | |
}; | |
//Display Popular Movies | |
async function displayPopularMovies() { | |
const { results } = await fetchAPIData('movie/popular'); | |
results.forEach((movie) => { | |
const movieDiv = document.createElement('div'); | |
movieDiv.classList.add('card'); | |
movieDiv.innerHTML = ` | |
<a href="movie-details.html?id=${movie.id}"> | |
${ | |
movie.poster_path | |
? `<img | |
src="https://image.tmdb.org/t/p/w500${movie.poster_path}" | |
class="card-img-top" | |
alt="${movie.title}" | |
/>` | |
: ` <img | |
src="../images/no-image.jpg" | |
class="card-img-top" | |
alt="${movie.title}" | |
/>` | |
} | |
</a> | |
<div class="card-body"> | |
<h5 class="card-title">${movie.title}</h5> | |
<p class="card-text"> | |
<small class="text-muted">Release: ${movie.release_date}</small> | |
</p> | |
</div> | |
`; | |
document.querySelector('#popular-movies').appendChild(movieDiv); | |
}); | |
} | |
//Display Popular Tv Shows | |
async function displayPopularShows() { | |
const { results } = await fetchAPIData('tv/popular'); | |
results.forEach((show) => { | |
const showsDiv = document.createElement('div'); | |
showsDiv.classList.add('card'); | |
showsDiv.innerHTML = ` | |
<a href="tv-details.html?id=${show.id}"> | |
${ | |
show.poster_path | |
? `<img | |
src="https://image.tmdb.org/t/p/w500${show.poster_path}" | |
class="card-img-top" | |
alt="${show.name}" | |
/>` | |
: ` <img | |
src="../images/no-image.jpg" | |
class="card-img-top" | |
alt="${show.name}" | |
/>` | |
} | |
</a> | |
<div class="card-body"> | |
<h5 class="card-title">${show.name}</h5> | |
<p class="card-text"> | |
<small class="text-muted">Air Date: ${show.first_air_date}</small> | |
</p> | |
</div> | |
`; | |
document.querySelector('#popular-shows').appendChild(showsDiv); | |
}); | |
} | |
// Display Movie Details | |
async function displayMovieDetails() { | |
const movieId = window.location.search.split('=')[1]; | |
const movie = await fetchAPIData(`movie/${movieId}`); | |
//backdrop image | |
displayBackgroundImage('movie', movie.backdrop_path); | |
const div = document.createElement('div'); | |
div.innerHTML = ` | |
<div class="details-top"> | |
<div> | |
${ | |
movie.poster_path | |
? `<img | |
src="https://image.tmdb.org/t/p/w500${movie.poster_path}" | |
class="card-img-top" | |
alt="${movie.title}" | |
/>` | |
: ` <img | |
src="../images/no-image.jpg" | |
class="card-img-top" | |
alt="${movie.title}" | |
/>` | |
} | |
</div> | |
<div> | |
<h2>${movie.title}</h2> | |
<p> | |
<i class="fas fa-star text-primary"></i> | |
${movie.vote_average.toFixed(1)} / 10 | |
</p> | |
<p class="text-muted">Release Date:${movie.release_date}</p> | |
<p> | |
${movie.overview} | |
</p> | |
<h5>Genres</h5> | |
<ul class="list-group"> | |
${movie.genres.map((genre) => `<li>${genre.name}</li>`).join('')} | |
</ul> | |
<a href="${ | |
movie.homepage | |
}" target="_blank" class="btn">Visit Movie Homepage</a> | |
</div> | |
</div> | |
<div class="details-bottom"> | |
<h2>Movie Info</h2> | |
<ul> | |
<li><span class="text-secondary">Budget:</span> $${addCommasToNumbers( | |
movie.budget | |
)}</li> | |
<li><span class="text-secondary">Revenue:</span> $${addCommasToNumbers( | |
movie.revenue | |
)}</li> | |
<li><span class="text-secondary">Runtime:</span> ${ | |
movie.runtime | |
} minutes</li> | |
<li><span class="text-secondary">Status:</span> ${movie.status}</li> | |
</ul> | |
<h4>Production Companies</h4> | |
<div class="list-group"> ${movie.production_companies | |
.map((company) => `<span>${company.name}</span>`) | |
.join(', ')}</div> | |
</div>`; | |
document.querySelector('#movie-details').appendChild(div); | |
} | |
//Display Show details | |
async function displayShowDetails() { | |
const showId = window.location.search.split('=')[1]; | |
const show = await fetchAPIData(`tv/${showId}`); | |
//backdrop image | |
displayBackgroundImage('tv', show.backdrop_path); | |
const div = document.createElement('div'); | |
div.innerHTML = ` | |
<div class="details-top"> | |
<div> | |
${ | |
show.poster_path | |
? `<img | |
src="https://image.tmdb.org/t/p/w500${show.poster_path}" | |
class="card-img-top" | |
alt="${show.name}" | |
/>` | |
: ` <img | |
src="../images/no-image.jpg" | |
class="card-img-top" | |
alt="${show.name}" | |
/>` | |
} | |
</div> | |
<div> | |
<h2>${show.name}</h2> | |
<p> | |
<i class="fas fa-star text-primary"></i> | |
${show.vote_average.toFixed(1)} / 10 | |
</p> | |
<p class="text-muted">Last Air Date:${show.last_air_date}</p> | |
<p> | |
${show.overview} | |
</p> | |
<h5>Genres</h5> | |
<ul class="list-group"> | |
${show.genres.map((genre) => `<li>${genre.name}</li>`).join('')} | |
</ul> | |
<a href="${ | |
show.homepage | |
}" target="_blank" class="btn">Visit Show Homepage</a> | |
</div> | |
</div> | |
<div class="details-bottom"> | |
<h2>Movie Info</h2> | |
<ul> | |
<li><span class="text-secondary">Number of Episodes</span> ${ | |
show.number_of_episodes | |
}</li> | |
<li><span class="text-secondary">Number of Seasons</span> ${ | |
show.number_of_seasons | |
}</li> | |
<li><span class="text-secondary">Last Episode to Air:</span> ${ | |
show.last_episode_to_air.name | |
}</li> | |
<li><span class="text-secondary">Status:</span> ${show.status}</li> | |
</ul> | |
<h4>Production Companies</h4> | |
<div class="list-group"> ${show.production_companies | |
.map((company) => `<span>${company.name}</span>`) | |
.join(', ')}</div> | |
</div>`; | |
document.querySelector('#show-details').appendChild(div); | |
} | |
//To Display Backdrop to Movie/show Details page | |
function displayBackgroundImage(type, backgroundPath) { | |
const overlayDiv = document.createElement('div'); | |
overlayDiv.style.backgroundImage = `url(https://image.tmdb.org/t/p/original/${backgroundPath})`; | |
overlayDiv.style.backgroundSize = 'cover'; | |
overlayDiv.style.backgroundPosition = 'center'; | |
overlayDiv.style.backgroundRepeat = 'no-repeat'; | |
overlayDiv.style.height = '100vh'; | |
overlayDiv.style.width = '100vw'; | |
overlayDiv.style.position = 'absolute'; | |
overlayDiv.style.top = '0'; | |
overlayDiv.style.left = '0'; | |
overlayDiv.style.zIndex = '-1'; | |
overlayDiv.style.opacity = '0.1'; | |
if (type === 'movie') { | |
document.querySelector('#movie-details').appendChild(overlayDiv); | |
} else { | |
document.querySelector('#show-details').appendChild(overlayDiv); | |
} | |
} | |
//To Display Slider Movies | |
async function displaySlider() { | |
const { results } = await fetchAPIData('movie/now_playing'); | |
console.log(results); | |
results.forEach((movie) => { | |
const sliderDiv = document.createElement('div'); | |
sliderDiv.classList.add('swiper-slide'); | |
sliderDiv.innerHTML = ` | |
<a href="movie-details.html?id=${movie.id}"> | |
<img src="https://image.tmdb.org/t/p/w500${movie.poster_path}" alt="${movie.original_title}" /> | |
</a> | |
<h4 class="swiper-rating"> | |
<i class="fas fa-star text-secondary"></i> ${movie.vote_average} /10 | |
</h4> | |
`; | |
document.querySelector('.swiper-wrapper').appendChild(sliderDiv); | |
initSwiper(); | |
}); | |
} | |
function initSwiper() { | |
const swiper = new Swiper('.swiper', { | |
slidesPerView: 1, | |
spaceBetween: 30, | |
freeMode: true, | |
loop: true, | |
autoplay: { | |
delay: 4000, | |
disableOnInteraction: false, | |
}, | |
breakpoints: { | |
500: { | |
slidesPerView: 2, | |
}, | |
700: { | |
slidesPerView: 3, | |
}, | |
1200: { | |
slidesPerView: 4, | |
}, | |
}, | |
}); | |
} | |
//To search movies/shows | |
async function search() { | |
const queryString = window.location.search; | |
const urlParams = new URLSearchParams(queryString); | |
state.search.type = urlParams.get('type'); | |
state.search.term = urlParams.get('search-term'); | |
if (state.search.term !== '' && state.search.term !== null) { | |
const { results, total_pages, page, total_results } = await searchAPIData(); | |
state.search.page = page; | |
state.search.totalPages = total_pages; | |
state.search.totalResults = total_results; | |
if (results.length === 0) { | |
showAlert('No results found'); | |
return; | |
} | |
displaySearchResults(results); | |
document.querySelector('#search-term').value = ''; | |
} else { | |
showAlert('please enter a search item'); | |
} | |
} | |
//To display search result | |
async function displaySearchResults(results) { | |
// To clear previous results | |
document.querySelector('#search-results').innerHTML = ''; | |
document.querySelector('#search-results-heading').innerHTML = ''; | |
document.querySelector('#pagination').innerHTML = ''; | |
results.forEach((result) => { | |
const div = document.createElement('div'); | |
div.classList.add('card'); | |
div.innerHTML = ` | |
<a href="${state.search.type}-details.html?id=${result.id}"> | |
${ | |
result.poster_path | |
? `<img | |
src="https://image.tmdb.org/t/p/w500/${result.poster_path}" | |
class="card-img-top" | |
alt="${ | |
state.search.type === 'movie' ? result.title : result.name | |
}" | |
/>` | |
: ` <img | |
src="../images/no-image.jpg" | |
class="card-img-top" | |
alt="${ | |
state.search.type === 'movie' ? result.title : result.name | |
}" | |
/>` | |
} | |
</a> | |
<div class="card-body"> | |
<h5 class="card-title">${ | |
state.search.type === 'movie' ? result.title : result.name | |
}</h5> | |
<p class="card-text"> | |
<small class="text-muted">Release: ${ | |
state.search.type === 'movie' | |
? result.release_date | |
: result.first_air_date | |
}</small> | |
</p> | |
</div> | |
`; | |
document.querySelector('#search-results-heading').innerHTML = ` | |
<h2>${results.length} of ${state.search.totalResults} Results for ${state.search.term}</h2> | |
`; | |
document.querySelector('#search-results').appendChild(div); | |
}); | |
displayPagination(); | |
} | |
//To display pagination for search | |
function displayPagination() { | |
const div = document.createElement('div'); | |
div.classList.add('pagination'); | |
div.innerHTML = ` | |
<button class="btn btn-primary" id="prev">Prev</button> | |
<button class="btn btn-primary" id="next">Next</button> | |
<div class="page-counter">Page ${state.search.page} of ${state.search.totalPages}</div> | |
`; | |
document.querySelector('#pagination').appendChild(div); | |
//To disable prev button if on first page | |
if (state.search.page === 1) { | |
document.querySelector('#prev').disabled = true; | |
} | |
//To disable next button if on last page | |
if (state.search.page === state.search.totalPages) { | |
document.querySelector('#next').disabled = true; | |
} | |
//To go to next page | |
document.querySelector('#next').addEventListener('click', async () => { | |
state.search.page++; | |
const { results, total_pages } = await searchAPIData(); | |
displaySearchResults(results); | |
}); | |
//To make prev button functional | |
document.querySelector('#prev').addEventListener('click', async () => { | |
state.search.page--; | |
const { results, total_pages } = await searchAPIData(); | |
displaySearchResults(results); | |
}); | |
} | |
// FETCH data from TMDB | |
async function fetchAPIData(endpoint) { | |
//Api key is showing because this is a small project | |
const API_KEY = state.api.apiKey; | |
const API_URL = state.api.apiUrl; | |
showSpinner(); | |
const response = await fetch( | |
`${API_URL}/${endpoint}?api_key=${API_KEY}&language=en-US` | |
); | |
const data = await response.json(); | |
console.log(data); | |
hideSpinner(); | |
return data; | |
} | |
//To make request to Search | |
async function searchAPIData() { | |
const API_KEY = state.api.apiKey; | |
const API_URL = state.api.apiUrl; | |
showSpinner(); | |
const response = await fetch( | |
`${API_URL}/search/${state.search.type}?api_key=${API_KEY}&language=en-US&query=${state.search.term}&page=${state.search.page}` | |
); | |
const data = await response.json(); | |
hideSpinner(); | |
return data; | |
} | |
//adding and hiding spinner | |
function showSpinner() { | |
document.querySelector('.spinner').classList.add('show'); | |
} | |
function hideSpinner() { | |
document.querySelector('.spinner').classList.remove('show'); | |
} | |
// To show active link | |
function showActiveLink() { | |
const links = document.querySelectorAll('.nav-link'); | |
links.forEach((link) => { | |
if (link.getAttribute('href') === state.currentPage) { | |
link.classList.add('active'); | |
} | |
}); | |
} | |
// To Add commas to numbers | |
function addCommasToNumbers(number) { | |
return number.toLocaleString(); | |
} | |
//To show alert | |
function showAlert(message, className = 'error') { | |
const alertEl = document.createElement('div'); | |
alertEl.classList.add('alert', className); | |
alertEl.appendChild(document.createTextNode(message)); | |
document.querySelector('#alert').appendChild(alertEl); | |
setTimeout(() => alertEl.remove(), 3000); | |
} | |
//To initialize app | |
function init() { | |
switch (state.currentPage) { | |
case '/': | |
case '/index.html': | |
displaySlider(); | |
displayPopularMovies(); | |
break; | |
case '/movie-details.html': | |
displayMovieDetails(); | |
break; | |
case '/shows.html': | |
displayPopularShows(); | |
break; | |
case '/tv-details.html': | |
displayShowDetails(); | |
break; | |
case '/search.html': | |
search(); | |
break; | |
} | |
showActiveLink(); | |
} | |
document.addEventListener('DOMContentLoaded', init); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment