diff --git a/MovieVerse-Mobile/app/js/LICENSE b/MovieVerse-Mobile/app/js/LICENSE index 19d3d823..a0ef1b39 100644 --- a/MovieVerse-Mobile/app/js/LICENSE +++ b/MovieVerse-Mobile/app/js/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Son Nguyen Hoang +Copyright (c) 2024 Son Nguyen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MovieVerse-Mobile/app/js/about.js b/MovieVerse-Mobile/app/js/about.js index 9e0b86c1..f26e588f 100644 --- a/MovieVerse-Mobile/app/js/about.js +++ b/MovieVerse-Mobile/app/js/about.js @@ -17,7 +17,7 @@ async function showMovieOfTheDay() { } } catch (error) { - console.error('Error fetching movie:', error); + console.log('Error fetching movie:', error); fallbackMovieSelection(); } } @@ -43,6 +43,7 @@ function getMovieVerseData(input) { function fallbackMovieSelection() { const fallbackMovies = [432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, 424, 98]; const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; + localStorage.setItem('selectedMovieId', randomFallbackMovie); window.location.href = 'movie-details.html'; } @@ -131,7 +132,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -163,7 +164,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -171,8 +172,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, diff --git a/MovieVerse-Mobile/app/js/actor-details.js b/MovieVerse-Mobile/app/js/actor-details.js index 38c00f99..1b7c45c0 100644 --- a/MovieVerse-Mobile/app/js/actor-details.js +++ b/MovieVerse-Mobile/app/js/actor-details.js @@ -126,7 +126,7 @@ async function fetchActorDetails(actorId) { hideSpinner(); } catch (error) { - console.error('Error fetching actor details:', error); + console.log('Error fetching actor details:', error); document.getElementById('actor-details-container').innerHTML = `
Biography: ${actor.biography || 'N/A'}
-Date of Birth: ${actor.birthday || 'N/A'}
-Date of Death: ${actor.deathday || 'N/A'}
+Biography: ${actor.biography || 'Information Unavailable'}
+Also Known As: ${actor.also_known_as.join(', ') || 'Information Unavailable'}
+Date of Birth: ${actor.birthday || 'Information Unavailable'}
+Date of Death: ${actor.deathday || 'Information Unavailable'}
Age: ${ageOrStatus}
-Place of Birth: ${actor.place_of_birth || 'N/A'}
-Known For: ${actor.known_for_department || 'N/A'}
-Height: ${actor.height || 'N/A'}
+Place of Birth: ${actor.place_of_birth || 'Information Unavailable'}
+Known For: ${actor.known_for_department || 'Information Unavailable'}
+Height: ${actor.height || 'Information Unavailable'}
`; const gender = document.createElement('div'); - gender.innerHTML = `Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'N/A'}
`; + gender.innerHTML = `Gender: ${actor.gender === 1 ? 'Female' : actor.gender === 2 ? 'Male' : 'Information Unavailable'}
`; actorDescription.appendChild(gender); const popularity = document.createElement('div'); @@ -192,7 +193,8 @@ function populateActorDetails(actor, credits) { const movieList = document.createElement('div'); movieList.classList.add('movie-list'); - credits.cast.forEach(movie => { + + credits.cast.forEach((movie, index) => { const movieLink = document.createElement('span'); movieLink.textContent = movie.title; movieLink.classList.add('movie-link'); @@ -201,10 +203,157 @@ function populateActorDetails(actor, credits) { window.location.href = 'movie-details.html'; }); movieList.appendChild(movieLink); - movieList.appendChild(document.createTextNode(', ')); + + if (index < credits.cast.length - 1) { + movieList.appendChild(document.createTextNode(', ')); + } }); filmographyHeading.appendChild(movieList); + + const mediaUrl = `https://${getMovieVerseData()}/3/person/${actor.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + + const detailsContainer = document.getElementById('actor-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + mediaContainer.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w1280${images[0].file_path}`; + } + + imageElement.addEventListener('click', function() { + const imageUrl = this.src; + const modalHtml = ` +No media available
'; + } + applySettings(); } @@ -234,7 +383,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -266,7 +415,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -274,8 +423,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, @@ -463,7 +641,7 @@ async function showMovieOfTheDay() { } } catch (error) { - console.error('Error fetching movie:', error); + console.log('Error fetching movie:', error); fallbackMovieSelection(); } } diff --git a/MovieVerse-Mobile/app/js/add-to-favorites.js b/MovieVerse-Mobile/app/js/add-to-favorites.js index bfbb04e3..0df2c998 100644 --- a/MovieVerse-Mobile/app/js/add-to-favorites.js +++ b/MovieVerse-Mobile/app/js/add-to-favorites.js @@ -53,29 +53,40 @@ export async function checkAndUpdateFavoriteButton() { const movieId = localStorage.getItem('selectedMovieId'); if (!movieId) { - console.error('Movie ID is missing'); + console.log('Movie ID is missing'); return; } - if (!userEmail) { - console.log('User is not signed in. Checking local storage for favorites.'); - const localFavorites = JSON.parse(localStorage.getItem('favoritesMovies')) || []; - updateFavoriteButton(movieId, localFavorites); - return; - } + try { + if (!userEmail) { + console.log('User is not signed in. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + return; + } - const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); - const querySnapshot = await getDocs(usersRef); + const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); + const querySnapshot = await getDocs(usersRef); - if (querySnapshot.empty) { - console.error('No user found with that email'); - return; - } + if (querySnapshot.empty) { + console.log('No user found with that email'); + return; + } - const userData = querySnapshot.docs[0].data(); - const favorites = userData.favoritesMovies || []; + const userData = querySnapshot.docs[0].data(); + const favorites = userData.favoritesMovies || []; - updateFavoriteButton(movieId, favorites); + updateFavoriteButton(movieId, favorites); + } + catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Checking local storage for favorites.'); + const localFavorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + updateFavoriteButton(movieId, localFavorites); + } else { + console.error('An error occurred:', error); + } + } } function updateFavoriteButton(movieId, favorites) { @@ -88,7 +99,7 @@ function updateFavoriteButton(movieId, favorites) { } else { favoriteButton.classList.remove('favorited'); - favoriteButton.style.background = 'transparent'; + favoriteButton.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; favoriteButton.title = 'Add to favorites'; } } @@ -109,75 +120,125 @@ export async function toggleFavorite() { const movieId = localStorage.getItem('selectedMovieId'); if (!movieId) { - console.error('Movie ID is missing'); + console.log('Movie ID is missing'); return; } const movieGenre = await getMovieGenre(movieId); - if (!userEmail) { - console.log('User is not signed in. Using localStorage for favorites.'); - let favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; - let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + try { + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + })); + } + else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } + + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; + } + + const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); + const querySnapshot = await getDocs(usersRef); - if (favoritesMovies.includes(movieId)) { - favoritesMovies = favoritesMovies.filter(id => id !== movieId); - favoriteGenres = favoriteGenres.filter(genre => genre !== movieGenre || favoritesMovies.some(id => localStorage.getItem(id).genre === movieGenre)); + let userDocRef; + + if (querySnapshot.empty && userEmail === "") { + const newUserRef = doc(collection(db, "MovieVerseUsers")); + userDocRef = newUserRef; + await setDoc(newUserRef, {email: userEmail, favoritesMovies: [movieId]}); + console.log('New user created with favorite movie.'); + } + else if (!querySnapshot.empty) { + userDocRef = doc(db, "MovieVerseUsers", querySnapshot.docs[0].id); } else { - favoritesMovies.push(movieId); - if (!favoriteGenres.includes(movieGenre)) { - favoriteGenres.push(movieGenre); - } + console.log('No user found with that email and user is supposed to be signed in.'); + return; } - localStorage.setItem('favoritesMovies', JSON.stringify(favoritesMovies)); - localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + if (userDocRef) { + const userData = querySnapshot.empty ? {favoritesMovies: []} : querySnapshot.docs[0].data(); + let favoritesMovies = userData.favoritesMovies || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + })); + } + else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } - console.log('Favorites movies updated successfully in localStorage'); - window.location.reload(); - return; - } + await updateDoc(userDocRef, {favoritesMovies}); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in Firestore'); + } - const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); - const querySnapshot = await getDocs(usersRef); + updateMoviesFavorited(movieId); - let userDocRef; + } catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; - if (querySnapshot.empty && userEmail === "") { - const newUserRef = doc(collection(db, "MovieVerseUsers")); - userDocRef = newUserRef; - await setDoc(newUserRef, { email: userEmail, favoritesMovies: [movieId] }); - console.log('New user created with favorite movie.'); - } - else if (!querySnapshot.empty) { - userDocRef = doc(db, "MovieVerseUsers", querySnapshot.docs[0].id); - } - else { - console.error('No user found with that email and user is supposed to be signed in.'); - return; - } - - if (userDocRef) { - const userData = querySnapshot.empty ? { favoritesMovies: [] } : querySnapshot.docs[0].data(); - let favoritesMovies = userData.favoritesMovies || []; - let favoriteGenres = JSON.parse(localStorage.getItem('favoriteGenres')) || []; + if (favoritesMovies.includes(movieId)) { + favoritesMovies = favoritesMovies.filter(id => id !== movieId); + favoriteGenres = favoriteGenres.filter(genre => favoritesMovies.some(id => { + const movieDetails = JSON.parse(localStorage.getItem(id)); + return movieDetails && movieDetails.genre === genre; + })); + } + else { + favoritesMovies.push(movieId); + if (!favoriteGenres.includes(movieGenre)) { + favoriteGenres.push(movieGenre); + } + } - if (favoritesMovies.includes(movieId)) { - favoritesMovies = favoritesMovies.filter(id => id !== movieId); - favoriteGenres = favoriteGenres.filter(genre => genre !== movieGenre || favoritesMovies.some(id => localStorage.getItem(id).genre === movieGenre)); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritesMovies)); + localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); + console.log('Favorites movies updated successfully in localStorage'); + window.location.reload(); + return; } else { - favoritesMovies.push(movieId); - if (!favoriteGenres.includes(movieGenre)) { - favoriteGenres.push(movieGenre); - } + console.error('An error occurred:', error); } - await updateDoc(userDocRef, { favoritesMovies }); - localStorage.setItem('favoriteGenres', JSON.stringify(favoriteGenres)); - console.log('Favorites movies updated successfully in Firestore'); + updateMoviesFavorited(movieId); } window.location.reload(); } + +function updateMoviesFavorited(movieId) { + let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + if (!favoritedMovies.includes(movieId)) { + favoritedMovies.push(movieId); + localStorage.setItem('moviesFavorited', JSON.stringify(favoritedMovies)); + } +} \ No newline at end of file diff --git a/MovieVerse-Mobile/app/js/add-to-tv-favorites.js b/MovieVerse-Mobile/app/js/add-to-tv-favorites.js index f400c046..da298d83 100644 --- a/MovieVerse-Mobile/app/js/add-to-tv-favorites.js +++ b/MovieVerse-Mobile/app/js/add-to-tv-favorites.js @@ -43,79 +43,113 @@ const app = initializeApp(firebaseConfig); const db = getFirestore(app); export async function toggleFavoriteTVSeries() { - let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); - if (!tvSeriesId) { - console.error('TV Series ID is missing'); - return; - } + try { + let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } + + if (!userEmail) { + console.log('User is not signed in. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + await checkAndUpdateFavoriteButtonTVSeries(); + return; + } + + const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); + const querySnapshot = await getDocs(usersRef); + + let userDocRef; + if (querySnapshot.empty) { + console.log('Signed-in user does not have a Firestore document.'); + return; + } else { + userDocRef = doc(db, "MovieVerseUsers", querySnapshot.docs[0].id); + } + + const userData = querySnapshot.docs[0].data(); + let favoritesTVSeries = userData.favoritesTVSeries || []; - if (!userEmail) { - console.log('User is not signed in. Using localStorage for favorites.'); - let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; if (favoritesTVSeries.includes(tvSeriesId)) { favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); } else { favoritesTVSeries.push(tvSeriesId); } - localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); - console.log('Favorites TV Series updated successfully in localStorage'); - await checkAndUpdateFavoriteButtonTVSeries(); - return; - } - const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); - const querySnapshot = await getDocs(usersRef); + await updateDoc(userDocRef, {favoritesTVSeries}); + console.log('Favorites TV Series updated successfully in Firestore'); + await checkAndUpdateFavoriteButtonTVSeries(); + window.location.reload(); - let userDocRef; - if (querySnapshot.empty) { - console.error('Signed-in user does not have a Firestore document.'); - return; - } - else { - userDocRef = doc(db, "MovieVerseUsers", querySnapshot.docs[0].id); } - - const userData = querySnapshot.docs[0].data(); - let favoritesTVSeries = userData.favoritesTVSeries || []; - - if (favoritesTVSeries.includes(tvSeriesId)) { - favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); - } else { - favoritesTVSeries.push(tvSeriesId); + catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + if (favoritesTVSeries.includes(tvSeriesId)) { + favoritesTVSeries = favoritesTVSeries.filter(id => id !== tvSeriesId); + } + else { + favoritesTVSeries.push(tvSeriesId); + } + localStorage.setItem('favoritesTVSeries', JSON.stringify(favoritesTVSeries)); + console.log('Favorites TV Series updated successfully in localStorage'); + } + else { + console.error('An error occurred:', error); + } + window.location.reload(); } - - await updateDoc(userDocRef, { favoritesTVSeries }); - console.log('Favorites TV Series updated successfully in Firestore'); - await checkAndUpdateFavoriteButtonTVSeries(); } export async function checkAndUpdateFavoriteButtonTVSeries() { let userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); - if (!tvSeriesId) { - console.error('TV Series ID is missing'); - return; - } + try { - let favoritesTVSeries = []; + if (!tvSeriesId) { + console.log('TV Series ID is missing'); + return; + } - if (userEmail) { - const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); - const querySnapshot = await getDocs(usersRef); + let favoritesTVSeries = []; + + if (userEmail) { + const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", userEmail)); + const querySnapshot = await getDocs(usersRef); - if (!querySnapshot.empty) { - const userData = querySnapshot.docs[0].data(); - favoritesTVSeries = userData.favoritesTVSeries || []; + if (!querySnapshot.empty) { + const userData = querySnapshot.docs[0].data(); + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } else { + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; } + + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); } - else { - favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); + } + else { + console.error('An error occurred:', error); + } } - - updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries); } function updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries) { @@ -129,6 +163,6 @@ function updateFavoriteButtonTVSeries(tvSeriesId, favoritesTVSeries) { else { favoriteBtn.classList.remove('favorited'); favoriteBtn.title = 'Add to Favorites'; - favoriteBtn.style.backgroundColor = 'transparent'; + favoriteBtn.style.backgroundColor = 'rgba(255, 255, 255, 0.05)'; } } \ No newline at end of file diff --git a/MovieVerse-Mobile/app/js/analytics.js b/MovieVerse-Mobile/app/js/analytics.js index ae2d7801..82b83a28 100644 --- a/MovieVerse-Mobile/app/js/analytics.js +++ b/MovieVerse-Mobile/app/js/analytics.js @@ -32,7 +32,7 @@ async function fetchData(url) { return await response.json(); } catch (error) { - console.error('Error fetching data:', error); + console.log('Error fetching data:', error); return null; } } @@ -334,6 +334,82 @@ async function loadMoviesByProductionCountriesChart() { hideSpinner(); } +async function loadTopRatedMoviesPerYearChart() { + const years = []; + const topMovies = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&sort_by=vote_average.desc&vote_count.gte=100`); + if (response.results.length > 0) { + topMovies.push(response.results[0].vote_average); + } + else { + topMovies.push(0); + } + } + + createChart('chart11', 'bar', { + labels: years, + datasets: [{ + label: 'Top Rated Movie Score', + data: topMovies, + backgroundColor: 'rgba(255, 159, 64, 1)', + borderColor: 'rgba(255, 159, 64, 1)', + borderWidth: 1 + }] + }); +} + +async function loadTotalMovieVotesOverYearsChart() { + const years = []; + const totalVoteCounts = []; + const currentYear = new Date().getFullYear(); + + for (let year = currentYear - 10; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}`); + const yearlyTotalVotes = response.results.reduce((sum, movie) => sum + movie.vote_count, 0); + totalVoteCounts.push(yearlyTotalVotes); + } + + createChart('chartVotesOverYears', 'line', { + labels: years, + datasets: [{ + label: 'Total Movie Votes', + data: totalVoteCounts, + backgroundColor: 'rgba(255, 193, 7, 1)', + borderColor: 'rgba(255, 193, 7, 1)', + borderWidth: 1 + }] + }); +} + +async function loadHighlyRatedMoviesOverYearsChart() { + const years = []; + const highRatedMovieCounts = []; + const currentYear = new Date().getFullYear(); + const startYear = currentYear - 10; + + for (let year = startYear; year <= currentYear; year++) { + years.push(year); + const response = await fetchData(`${BASE_URL}/discover/movie?${generateMovieNames()}=${string}&primary_release_year=${year}&vote_average.gte=8`); + highRatedMovieCounts.push(response.total_results); + } + + createChart('chartHighlyRatedMovies', 'line', { + labels: years, + datasets: [{ + label: 'Highly Rated Movies (Rating >= 8)', + data: highRatedMovieCounts, + backgroundColor: 'rgba(0, 206, 209, 1)', + borderColor: 'rgba(0, 206, 209, 1)', + borderWidth: 1 + }] + }); +} + function loadAllCharts() { loadMoviesByYearChart(); loadGenrePopularityChart(); @@ -344,6 +420,9 @@ function loadAllCharts() { loadMovieReleaseDatesByMonthChart(); loadMoviesByDecadeChart(); loadMoviesByProductionCountriesChart(); + loadTopRatedMoviesPerYearChart(); + loadTotalMovieVotesOverYearsChart(); + loadHighlyRatedMoviesOverYearsChart(); } document.addEventListener('DOMContentLoaded', loadAllCharts); @@ -369,7 +448,7 @@ async function showMovieOfTheDay() { } } catch (error) { - console.error('Error fetching movie:', error); + console.log('Error fetching movie:', error); fallbackMovieSelection(); } } @@ -465,7 +544,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -497,7 +576,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -505,8 +584,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, @@ -647,4 +755,4 @@ function handleSearch() { const searchQuery = document.getElementById('search').value; localStorage.setItem('searchQuery', searchQuery); window.location.href = 'search.html'; -} \ No newline at end of file +} diff --git a/MovieVerse-Mobile/app/js/chat-auxiliary.js b/MovieVerse-Mobile/app/js/chat-auxiliary.js new file mode 100644 index 00000000..e0096978 --- /dev/null +++ b/MovieVerse-Mobile/app/js/chat-auxiliary.js @@ -0,0 +1,288 @@ +document.addEventListener('DOMContentLoaded', function() { + const searchBar = document.getElementById('search'); + const searchButton = document.getElementById('button-search'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + + function toggleVisibility() { + const query = searchBar.value.trim(); + if (query) { + if (window.innerWidth > 800) { + myHeading.style.visibility = 'hidden'; + myHeading.style.opacity = '0'; + localTime.style.visibility = 'hidden'; + localTime.style.opacity = '0'; + } + } + else { + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + } +} + searchBar.addEventListener('input', toggleVisibility); + toggleVisibility(); +}); + +document.addEventListener('DOMContentLoaded', function() { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + const myHeading = document.getElementById('my-heading'); + const localTime = document.getElementById('local-time'); + const searchButton = document.getElementById('button-search'); + + function toggleButtons() { + const query = searchInput.value.trim(); + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + clearSearchBtn.addEventListener('click', function() { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + + myHeading.style.visibility = 'visible'; + myHeading.style.opacity = '1'; + localTime.style.visibility = 'visible'; + localTime.style.opacity = '1'; + }); + + toggleButtons(); + searchInput.addEventListener('input', toggleButtons); +}); + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} + +document.addEventListener('DOMContentLoaded', function() { + document.getElementById('search').addEventListener('input', function(e) { + showSpinner(); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const searchInput = document.getElementById('search'); + const query = e.target.value.trim(); + const searchResultsContainer = document.getElementById('search-results'); + + viewAllResultsBtn.style.display = query ? 'block' : 'none'; + + function toggleButtons() { + viewAllResultsBtn.style.display = query ? 'inline-block' : 'none'; + const clearSearchBtn = document.getElementById('clear-search'); + clearSearchBtn.style.display = query ? 'inline-block' : 'none'; + } + + if (query) { + const searchURL = `https://${getMovieVerseData()}/3/search/multi?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(query)}`; + fetch(searchURL) + .then(response => response.json()) + .then(data => { + const sortedResults = data.results.sort((a, b) => b.popularity - a.popularity); + displaySearchResults(sortedResults.slice(0, 5)); + }) + .catch(err => console.log("Fetching error:", err)); + } + else { + searchInput.value = ''; + searchResultsContainer.innerHTML = ''; + toggleButtons(); + searchInput.focus(); + } + + searchInput.addEventListener('input', function() { + if (searchInput.value.trim()) { + viewAllResultsBtn.style.display = 'block'; + } + else { + viewAllResultsBtn.style.display = 'none'; + } + }); + + viewAllResultsBtn.addEventListener('click', function() { + const searchQuery = searchInput.value.trim(); + if (searchQuery) { + localStorage.setItem('searchQuery', searchQuery); + window.location.href = 'search.html'; + } + else { + alert('Please enter a search query.'); + } + }); + + hideSpinner(); + }); + + function displaySearchResults(results) { + showSpinner(); + const resultsContainer = document.getElementById('search-results'); + resultsContainer.innerHTML = ''; + + results.forEach(item => { + const card = document.createElement('div'); + card.className = 'search-result-card'; + card.style.cursor = 'pointer'; + + const imagePath = item.poster_path || item.profile_path ? `https://image.tmdb.org/t/p/w500${item.poster_path || item.profile_path}` : null; + + if (imagePath) { + const image = document.createElement('img'); + image.src = imagePath; + image.className = 'result-image'; + card.appendChild(image); + } + else { + const placeholder = document.createElement('div'); + placeholder.className = 'result-image-placeholder'; + placeholder.textContent = 'Image Not Available'; + placeholder.style.textAlign = 'center'; + placeholder.style.padding = '10px'; + card.appendChild(placeholder); + } + + const details = document.createElement('div'); + details.className = 'result-details'; + + const name = document.createElement('div'); + name.className = 'result-name'; + name.textContent = item.title || item.name; + details.appendChild(name); + + const type = document.createElement('div'); + type.className = 'result-type'; + type.textContent = item.media_type === 'movie' ? 'Movie' : item.media_type === 'tv' ? 'TV Series' : 'Person'; + details.appendChild(type); + + card.appendChild(details); + resultsContainer.appendChild(card); + + card.addEventListener('click', () => handleResultClick(item)); + }); + + hideSpinner(); + } + + async function handleResultClick(item) { + console.log('Clicked item:', item.media_type, item.id); + + if (!item.media_type) { + console.log('Media type is undefined'); + return; + } + + if (item.media_type === 'movie') { + localStorage.setItem('selectedMovieId', item.id); + window.location.href = 'movie-details.html'; + } + else if (item.media_type === 'tv') { + localStorage.setItem('selectedTvSeriesId', item.id); + window.location.href = 'tv-details.html'; + } + else if (item.media_type === 'person') { + try { + const personDetailsUrl = `https://${getMovieVerseData()}/3/person/${item.id}?${generateMovieNames()}${getMovieCode()}`; + const response = await fetch(personDetailsUrl); + const personDetails = await response.json(); + + if (personDetails.known_for_department === 'Directing') { + localStorage.setItem('selectedDirectorId', item.id); + window.location.href = 'director-details.html?' + item.id; + } + else { + localStorage.setItem('selectedActorId', item.id); + window.location.href = 'actor-details.html?' + item.id; + } + } + catch (error) { + console.log('Error fetching person details:', error); + } + } + else { + console.log('Unknown media type:', item.media_type); + } + } +}); + +document.addEventListener('DOMContentLoaded', function() { + const searchInput = document.getElementById('search'); + const viewAllResultsBtn = document.getElementById('view-all-results'); + const clearSearchBtn = document.getElementById('clear-search'); + const searchResultsContainer = document.getElementById('search-results'); + let selectedIndex = -1; + + function clearSelection() { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + if (selectedIndex >= 0 && selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = ''; + } + else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = ''; + } + else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = ''; + } + } + + function moveSelection(direction) { + const results = searchResultsContainer.getElementsByClassName('search-result-card'); + const totalElements = results.length + 2; + clearSelection(); + + if (direction === 'down') { + selectedIndex = (selectedIndex + 1) % totalElements; + } + else if (direction === 'up') { + selectedIndex = (selectedIndex - 1 + totalElements) % totalElements; + } + + if (selectedIndex < results.length) { + results[selectedIndex].style.backgroundColor = '#ff8623'; + results[selectedIndex].scrollIntoView({ block: "nearest" }); + } + else if (selectedIndex === results.length) { + viewAllResultsBtn.style.backgroundColor = '#ff8623'; + viewAllResultsBtn.scrollIntoView({ block: "nearest" }); + } + else if (selectedIndex === results.length + 1) { + clearSearchBtn.style.backgroundColor = '#ff8623'; + clearSearchBtn.scrollIntoView({ block: "nearest" }); + } + } + + searchInput.addEventListener('keydown', function(e) { + if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) { + e.preventDefault(); + moveSelection('down'); + } + else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) { + e.preventDefault(); + moveSelection('up'); + } + else if (e.key === 'Enter') { + e.preventDefault(); + if (selectedIndex >= 0 && selectedIndex < searchResultsContainer.getElementsByClassName('search-result-card').length) { + searchResultsContainer.getElementsByClassName('search-result-card')[selectedIndex].click(); + } + else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length) { + viewAllResultsBtn.click(); + } + else if (selectedIndex === searchResultsContainer.getElementsByClassName('search-result-card').length + 1) { + clearSearchBtn.click(); + } + else { + const query = searchInput.value.trim(); + localStorage.setItem('searchQuery', query); + window.location.href = 'search.html'; + } + } + }); + + searchInput.addEventListener('blur', clearSelection); +}); diff --git a/MovieVerse-Mobile/app/js/chat.js b/MovieVerse-Mobile/app/js/chat.js new file mode 100644 index 00000000..7c9f6f1c --- /dev/null +++ b/MovieVerse-Mobile/app/js/chat.js @@ -0,0 +1,470 @@ +import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js"; +import { getFirestore, collection, addDoc, doc, startAfter, getDocs, query, where, orderBy, onSnapshot, documentId, serverTimestamp, limit } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js"; + +document.addEventListener('DOMContentLoaded', () => { + const mainElement = document.getElementById('main'); + const isLoggedIn = localStorage.getItem('isSignedIn'); + + if (!isLoggedIn || isLoggedIn !== 'true') { + mainElement.style.display = 'none'; + + const signInMessage = document.createElement('div'); + signInMessage.innerHTML = '${user.bio || ''}
`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + } + + searchUserResults.style.display = 'block'; + hideSpinner(); + + if (isNewSearch || !querySnapshot.empty && querySnapshot.size === initialFetchLimit) { + const loadMoreButton = document.createElement('button'); + loadMoreButton.textContent = 'Load More'; + loadMoreButton.id = 'loadMoreButton'; + loadMoreButton.style.marginBottom = '20px'; + loadMoreButton.addEventListener('click', () => performSearch(searchText)); + searchUserResults.appendChild(loadMoreButton); + + if (searchUserResults.children.length >= maxTotalFetch) { + loadMoreButton.style.display = 'none'; + } + } + } + catch (error) { + console.error("Error fetching user list: ", error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.margin = '25px auto'; + } + hideSpinner(); + } + } +} + +let previouslySelectedUserElement = null; + +async function loadUserList() { + try { + showSpinner(); + + const userLimit = 5; + const messageLimit = 30; + + const sentMessagesQuery = query( + collection(db, "messages"), + orderBy("timestamp", "desc"), + where("sender", "==", currentUserEmail), + limit(messageLimit) + ); + const receivedMessagesQuery = query( + collection(db, "messages"), + orderBy("timestamp", "desc"), + where("recipient", "==", currentUserEmail), + limit(messageLimit) + ); + + const [sentMessagesSnapshot, receivedMessagesSnapshot] = await Promise.all([ + getDocs(sentMessagesQuery), + getDocs(receivedMessagesQuery) + ]); + + let userEmails = new Set(); + sentMessagesSnapshot.forEach(doc => userEmails.add(doc.data().recipient)); + receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); + + let users = []; + for (let email of userEmails) { + if (email) { + const userQuery = query(collection(db, "MovieVerseUsers"), where("email", "==", email)); + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + let userData = doc.data(); + if (userData.email) { + users.push(userData); + } + }); + } + } + + users.sort((a, b) => { + const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find(doc => doc.data().sender === a.email || doc.data().recipient === a.email); + const bLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find(doc => doc.data().sender === b.email || doc.data().recipient === b.email); + return (bLastMessage?.data().timestamp.toDate() || 0) - (aLastMessage?.data().timestamp.toDate() || 0); + }); + + users = users.slice(0, userLimit); + + userListDiv.innerHTML = ''; + for (const user of users) { + const userElement = document.createElement('div'); + userElement.classList.add('user'); + userElement.setAttribute('data-email', user.email); + userElement.onclick = () => { + if (previouslySelectedUserElement) { + previouslySelectedUserElement.classList.remove('selected'); + previouslySelectedUserElement.style.backgroundColor = ''; + } + selectedUserEmail = user.email; + loadMessages(user.email); + document.querySelectorAll('.user').forEach(u => u.classList.remove('selected')); + userElement.classList.add('selected'); + userElement.style.backgroundColor = '#ff8623'; + previouslySelectedUserElement = userElement; + }; + + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + let imageUrl = '../../images/user-default.png'; + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + } + + const img = document.createElement('img'); + img.src = imageUrl; + img.style.width = '50px'; + img.style.borderRadius = '25px'; + img.style.marginRight = '10px'; + userElement.appendChild(img); + + const emailDiv = document.createElement('div'); + emailDiv.textContent = user.email; + userElement.appendChild(emailDiv); + + userListDiv.appendChild(userElement); + } + + hideSpinner(); + } + catch (error) { + console.error("Error fetching user list: ", error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('noUserSelected'); + if (noUserSelected) { + noUserSelected.textContent = "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + } + hideSpinner(); + } + } +} + +function showSpinner() { + document.getElementById('myModal').classList.add('modal-visible'); +} + +function hideSpinner() { + document.getElementById('myModal').classList.remove('modal-visible'); +} diff --git a/MovieVerse-Mobile/app/js/chatbot.js b/MovieVerse-Mobile/app/js/chatbot.js index f915220f..800a1f5f 100644 --- a/MovieVerse-Mobile/app/js/chatbot.js +++ b/MovieVerse-Mobile/app/js/chatbot.js @@ -52,7 +52,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -84,7 +84,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -92,8 +92,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, @@ -424,7 +453,7 @@ async function fetchAndRedirectToMovieDetails(movieName) { } } catch (error) { - console.error('Error fetching movie details:', error); + console.log('Error fetching movie details:', error); alert('Failed to fetch movie details. Please try again later.'); } } @@ -449,12 +478,13 @@ async function fetchMovieTrailer(movieName) { } } catch (error) { - console.error('Error fetching movie trailer:', error); + console.log('Error fetching movie trailer:', error); } } async function getTrailerUrl(movieId) { const trailerApiUrl = `https://${getMovieVerseData()}/3/movie/${movieId}/videos?${generateMovieNames()}${getMovieCode()}`; + try { const response = await fetch(trailerApiUrl); const data = await response.json(); @@ -462,7 +492,7 @@ async function getTrailerUrl(movieId) { return trailer ? `https://www.youtube.com/watch?v=${trailer.key}` : null; } catch (error) { - console.error('Error fetching trailer:', error); + console.log('Error fetching trailer:', error); return null; } } @@ -485,6 +515,7 @@ async function fetchPersonDetails(name, type) { const response = await fetch(searchUrl); const data = await response.json(); const person = data.results[0]; + if (person) { localStorage.setItem(type === 'director' ? 'selectedDirectorId' : 'selectedActorId', person.id); window.location.href = type === 'director' ? 'director-details.html' : 'actor-details.html'; @@ -494,7 +525,7 @@ async function fetchPersonDetails(name, type) { } } catch (error) { - console.error(`Error fetching ${type} details:`, error); + console.log(`Error fetching ${type} details:`, error); alert(`Failed to fetch ${type} details. Please try again later.`); } } @@ -505,6 +536,7 @@ async function fetchCompanyDetails(companyName) { const response = await fetch(searchUrl); const data = await response.json(); const company = data.results[0]; + if (company) { localStorage.setItem('selectedCompanyId', company.id); window.location.href = 'company-details.html'; @@ -514,13 +546,14 @@ async function fetchCompanyDetails(companyName) { } } catch (error) { - console.error('Error fetching company details:', error); + console.log('Error fetching company details:', error); alert('Failed to fetch company details. Please try again later.'); } } async function movieVerseResponse(message) { const lowerMessage = message.toLowerCase(); + if (lowerMessage.startsWith("do you know about ") || lowerMessage.startsWith("tell me about ") || lowerMessage.startsWith("what is ")) { const movieName = lowerMessage.replace(/^(do you know about|show me|tell me about|what is) /, ''); return await fetchMovieDetailsFromTMDB(movieName); @@ -552,161 +585,258 @@ async function movieVerseResponse(message) { } if (lowerMessage.includes("hello") || lowerMessage.includes("hi") || lowerMessage.includes("hey")) { return "Hello! How can I assist you with MovieVerse today?"; - } else if (lowerMessage.includes("bye") || lowerMessage.includes("goodbye")) { + } + else if (lowerMessage.includes("bye") || lowerMessage.includes("goodbye")) { return "Goodbye! Thank you for using MovieVerse Assistant and have a nice day!"; - } else if (lowerMessage.includes("how are you")) { + } + else if (lowerMessage.includes("how are you")) { return "I'm your digital MovieVerse assistant, ready to help! How can I assist you with movie info?"; - } else if (lowerMessage.includes("search movie")) { + } + else if (lowerMessage.includes("search movie")) { return "To find information about a movie, please provide its name or keyword related to it."; - } else if (lowerMessage.includes("imdb rating")) { + } + else if (lowerMessage.includes("imdb rating")) { return "You can search for a movie, and I'll provide its IMDb rating among other details. Please provide the movie name!"; - } else if (lowerMessage.includes("movie description") || lowerMessage.includes("tell me about")) { + } + else if (lowerMessage.includes("movie description") || lowerMessage.includes("tell me about")) { return "Sure, please provide the movie name you want to learn about, and I'll fetch its description for you!"; - } else if (lowerMessage.includes("how many movies")) { + } + else if (lowerMessage.includes("how many movies")) { return "MovieVerse has a vast MovieVerse-Databases of millions of movies. You can search for any movie, and I'll try to fetch details for you!"; - } else if (lowerMessage.includes("latest movies")) { + } + else if (lowerMessage.includes("latest movies")) { return "I can provide information on recent movie releases. However, for the most up-to-date releases, consider checking the 'Latest Movies' section of MovieVerse!"; - } else if (lowerMessage.includes("recommend a movie") || lowerMessage.includes("suggestion")) { + } + else if (lowerMessage.includes("recommend a movie") || lowerMessage.includes("suggestion")) { return "Certainly! How about watching 'Inception'? It's a critically acclaimed movie with a captivating plot!"; - } else if (lowerMessage.includes("how does this work") || lowerMessage.includes("how to use")) { + } + else if (lowerMessage.includes("how does this work") || lowerMessage.includes("how to use")) { return "Simply type in your query related to a movie, and I'll provide details from our MovieVerse MovieVerse-Databases. You can ask about IMDb ratings, descriptions, and more!"; - } else if (lowerMessage.includes("who created this") || lowerMessage.includes("developer")) { + } + else if (lowerMessage.includes("who created this") || lowerMessage.includes("developer")) { return "MovieVerse is the result of the hard work of dedicated developers passionate about movies. We hope you find it helpful!"; - } else if (lowerMessage.includes("top rated movies")) { + } + else if (lowerMessage.includes("top rated movies")) { return "Our top-rated movies include 'The Shawshank Redemption', 'The Godfather', and 'The Dark Knight'. Would you like a detailed list?"; - } else if (lowerMessage.includes("genre")) { + } + else if (lowerMessage.includes("genre")) { return "We have movies spanning various genres: Action, Drama, Comedy, Romance, Thriller, and more! Which genre are you interested in?"; - } else if (lowerMessage.includes("actor") || lowerMessage.includes("actress")) { + } + else if (lowerMessage.includes("actor") || lowerMessage.includes("actress")) { return "Sure, which actor or actress are you interested in? Provide a name, and I'll fetch the movies they've starred in!"; - } else if (lowerMessage.includes("director")) { + } + else if (lowerMessage.includes("director")) { return "Great! Which director's filmography are you interested in?"; - } else if (lowerMessage.includes("animated movies")) { + } + else if (lowerMessage.includes("animated movies")) { return "We have a wide collection of animated movies! Some popular ones include 'Toy Story', 'Frozen', and 'Spirited Away'."; - } else if (lowerMessage.includes("thank you") || lowerMessage.includes("thanks")) { + } + else if (lowerMessage.includes("thank you") || lowerMessage.includes("thanks")) { return "You're welcome! If you have any more questions, feel free to ask. Enjoy your movie experience!"; - } else if (lowerMessage.includes("subscription") || lowerMessage.includes("membership")) { + } + else if (lowerMessage.includes("subscription") || lowerMessage.includes("membership")) { return "MovieVerse offers different subscription tiers. For detailed information, you might want to check our 'Subscription' section."; - } else if (lowerMessage.includes("watch movie")) { + } + else if (lowerMessage.includes("watch movie")) { return "While MovieVerse provides detailed information on movies, to watch them, you might need to visit specific streaming platforms or theaters!"; - } else if (lowerMessage.includes("are you a bot")) { + } + else if (lowerMessage.includes("are you a bot")) { return "Yes, I'm the MovieVerse digital assistant. How can I help you further?"; - } else if (lowerMessage.includes("documentary")) { + } + else if (lowerMessage.includes("documentary")) { return "We have an extensive collection of documentaries. From nature to history and science, what topic interests you?"; - } else if (lowerMessage.includes("foreign films")) { + } + else if (lowerMessage.includes("foreign films")) { return "MovieVerse has films from all around the world. Looking for any specific region or language?"; - } else if (lowerMessage.includes("classic movies")) { + } + else if (lowerMessage.includes("classic movies")) { return "Ah, classics! Some all-time favorites include 'Casablanca', 'Gone with the Wind', and 'Citizen Kane'. Would you like more recommendations?"; - } else if (lowerMessage.includes("family movies")) { + } + else if (lowerMessage.includes("family movies")) { return "We have plenty of family-friendly movies. 'The Lion King', 'Finding Nemo', and 'Toy Story' are a few favorites. Looking for anything specific?"; - } else if (lowerMessage.includes("comedy")) { + } + else if (lowerMessage.includes("comedy")) { return "In need of a good laugh? We've got comedies like 'Dumb and Dumber', 'Bridesmaids', and 'Anchorman' to name a few!"; - } else if (lowerMessage.includes("action movies")) { + } + else if (lowerMessage.includes("action movies")) { return "For adrenaline junkies, we've got action-packed movies like 'Die Hard', 'Mad Max: Fury Road', and 'The Dark Knight'. Ready to dive in?"; - } else if (lowerMessage.includes("horror")) { + } + else if (lowerMessage.includes("horror")) { return "Looking for a scare? Consider watching 'The Exorcist', 'Psycho', or 'Get Out'. Don't forget to keep the lights on!"; - } else if (lowerMessage.includes("romance")) { + } + else if (lowerMessage.includes("romance")) { return "Feeling romantic? Check out 'The Notebook', 'Pride and Prejudice', or 'Before Sunrise'. Love is in the air!"; - } else if (lowerMessage.includes("sci-fi")) { + } + else if (lowerMessage.includes("sci-fi")) { return "For sci-fi enthusiasts, we recommend 'Blade Runner', 'Star Wars', or 'Interstellar'. Ready to travel through space and time?"; - } else if (lowerMessage.includes("trailers")) { + } + else if (lowerMessage.includes("trailers")) { return "Want to see what's coming up? Our 'Trailers' section has the latest teasers and previews of upcoming films!"; - } else if (lowerMessage.includes("membership benefits")) { + } + else if (lowerMessage.includes("membership benefits")) { return "Members get exclusive access to early releases, high-definition streaming, and ad-free experience. Interested in upgrading?"; - } else if (lowerMessage.includes("create an account")) { + } + else if (lowerMessage.includes("create an account")) { return "Creating an account is easy! Just head to the 'Sign Up' section on our website and follow the steps."; - } else if (lowerMessage.includes("forgot password")) { + } + else if (lowerMessage.includes("forgot password")) { return "No worries! Just click on the 'Forgot Password' link on the login page, and we'll guide you through the reset process."; - } else if (lowerMessage.includes("movie ratings")) { + } + else if (lowerMessage.includes("movie ratings")) { return "Our ratings are sourced from critics and viewers like you. They provide a combined score to help you pick the best movies!"; - } else if (lowerMessage.includes("how do you work")) { + } + else if (lowerMessage.includes("how do you work")) { return "I'm here to answer your questions about MovieVerse and movies in general. Just ask away!"; - } else if (lowerMessage.includes("are you real")) { + } + else if (lowerMessage.includes("are you real")) { return "I'm a virtual assistant powered by code. While I'm not real, I'm here to help!"; - } else if (lowerMessage.includes("oscar winners")) { + } + else if (lowerMessage.includes("oscar winners")) { return "Looking for Oscar winners? We have a dedicated section for 'Academy Award Winners'. Check it out for a list of acclaimed films!"; - } else if (lowerMessage.includes("in theaters now")) { + } + else if (lowerMessage.includes("in theaters now")) { return "Our 'Now Showing' section provides a list of movies currently playing in theaters. Planning a movie outing?"; - } else if (lowerMessage.includes("coming soon")) { + } + else if (lowerMessage.includes("coming soon")) { return "Anticipating new releases? Head over to our 'Coming Soon' tab to check out movies hitting the theaters soon!"; - } else if (lowerMessage.includes("movie runtime")) { + } + else if (lowerMessage.includes("movie runtime")) { return "Please specify the movie you're inquiring about, and I'll fetch its runtime for you!"; - } else if (lowerMessage.includes("indie films")) { + } + else if (lowerMessage.includes("indie films")) { return "Indie films offer unique storytelling. Some of our favorites include 'Moonlight', 'Lady Bird', and 'Whiplash'. Would you like to explore more indie titles?"; - } else if (lowerMessage.includes("film festivals")) { + } + else if (lowerMessage.includes("film festivals")) { return "We have a collection of movies that have made waves in film festivals. From Cannes to Sundance, which festival's winners are you interested in?"; - } else if (lowerMessage.includes("animation studios")) { + } + else if (lowerMessage.includes("animation studios")) { return "From Pixar to Studio Ghibli, we have movies from renowned animation studios. Any particular studio you're fond of?"; - } else if (lowerMessage.includes("musicals")) { + } + else if (lowerMessage.includes("musicals")) { return "Sing your heart out! 'La La Land', 'The Greatest Showman', or classics like 'The Sound of Music' are all available. Ready for a song and dance?"; - } else if (lowerMessage.includes("kid movies")) { + } + else if (lowerMessage.includes("kid movies")) { return "For the little ones, we have 'Despicable Me', 'Frozen', and many more. Anything in particular they enjoy?"; - } else if (lowerMessage.includes("adaptations")) { + } + else if (lowerMessage.includes("adaptations")) { return "Books turned movies? We have 'Harry Potter', 'The Hunger Games', and classics like 'To Kill a Mockingbird'. Interested in a specific adaptation?"; - } else if (lowerMessage.includes("based on true stories")) { + } + else if (lowerMessage.includes("based on true stories")) { return "The truth can be stranger than fiction! Check out 'The Imitation Game', 'Schindler's List', or 'Catch Me If You Can'. Any specific era or event you're interested in?"; - } else if (lowerMessage.includes("customer support")) { + } + else if (lowerMessage.includes("customer support")) { return "Having issues? Our customer support team is here to help. You can reach out via the 'Support' section on our website."; - } else if (lowerMessage.includes("subscription cancel")) { + } + else if (lowerMessage.includes("subscription cancel")) { return "We're sad to see you go. To cancel your subscription, please go to the 'Account Settings' section."; - } else if (lowerMessage.includes("refunds")) { + } + else if (lowerMessage.includes("refunds")) { return "For refund queries, please get in touch with our customer support. They'll guide you through the process."; - } else if (lowerMessage.includes("device compatibility")) { + } + else if (lowerMessage.includes("device compatibility")) { return "MovieVerse is compatible with a range of devices, from smartphones and tablets to desktops and smart TVs. Any specific device you're asking about?"; - } else if (lowerMessage.includes("movie suggestions based on mood")) { + } + else if (lowerMessage.includes("movie suggestions based on mood")) { return "Of course! Let me know your mood, and I'll suggest a movie accordingly!"; - } else if (lowerMessage.includes("movie for date night")) { + } + else if (lowerMessage.includes("movie for date night")) { return "How about a romantic comedy? 'Pride & Prejudice' or something light-hearted like '500 Days of Summer'?"; - } else if (lowerMessage.includes("is there a series section")) { + } + else if (lowerMessage.includes("is there a series section")) { return "Yes, apart from movies, we also have a collection of TV series. From 'Breaking Bad' to 'Stranger Things', binge away!"; - } else if (lowerMessage.includes("award-winning movies")) { + } + else if (lowerMessage.includes("award-winning movies")) { return "Looking for critically acclaimed cinema? Check our 'Award Winners' section for movies that have received major accolades!"; - } else if (lowerMessage.includes("do you have classics from the 80s")) { + } + else if (lowerMessage.includes("do you have classics from the 80s")) { return "Absolutely! The 80s were iconic. Dive into classics like 'E.T.', 'The Breakfast Club', or 'Back to the Future'. Ready for some nostalgia?"; - } else if (lowerMessage.includes("movie suggestions based on genre")) { + } + else if (lowerMessage.includes("movie suggestions based on genre")) { return "Sure! Let me know your favorite genre, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie suggestions based on actor")) { + } + else if (lowerMessage.includes("movie suggestions based on actor")) { return "Of course! Let me know your favorite actor, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie suggestions based on director")) { + } + else if (lowerMessage.includes("movie suggestions based on director")) { return "Of course! Let me know your favorite director, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie suggestions based on year")) { + } + else if (lowerMessage.includes("movie suggestions based on year")) { return "Of course! Let me know your favorite year, and I'll suggest some movies accordingly!"; - } else if (lowerMessage.includes("movie") || lowerMessage.includes("movies")) { + } + else if (lowerMessage.includes("movie") || lowerMessage.includes("movies")) { return "You can search for a movie using the search field above!"; - } else if (lowerMessage.includes("1900s")) { + } + else if (lowerMessage.includes("1900s")) { return "Movies in the 1900s include: A Trip to the Moon, The Great Train Robbery, etc."; - } else if (lowerMessage.includes("1910s")) { + } + else if (lowerMessage.includes("1910s")) { return "Movies in the 1910s include: The Birth of a Nation, Intolerance, etc."; - } else if (lowerMessage.includes("1920s")) { + } + else if (lowerMessage.includes("1920s")) { return "Movies in the 1920s include: The Kid, The Gold Rush, etc."; - } else if (lowerMessage.includes("1930s")) { + } + else if (lowerMessage.includes("1930s")) { return "Movies in the 1930s include: King Kong, Snow White and the Seven Dwarfs, etc."; - } else if (lowerMessage.includes("1940s")) { + } + else if (lowerMessage.includes("1940s")) { return "Movies in the 1940s include: Citizen Kane, Casablanca, etc."; - } else if (lowerMessage.includes("1950s")) { + } + else if (lowerMessage.includes("1950s")) { return "Movies in the 1950s include: Sunset Boulevard, Singin' in the Rain, etc."; - } else if (lowerMessage.includes("1960s")) { + } + else if (lowerMessage.includes("1960s")) { return "Movies in the 1960s include: Psycho, The Apartment, etc."; - } else if (lowerMessage.includes("1970s")) { + } + else if (lowerMessage.includes("1970s")) { return "Movies in the 1970s include: The Godfather, Star Wars, etc."; - } else if (lowerMessage.includes("1980s")) { + } + else if (lowerMessage.includes("1980s")) { return "Movies in the 1980s include: Back to the Future, The Shining, etc."; - } else if (lowerMessage.includes("1990s")) { + } + else if (lowerMessage.includes("1990s")) { return "Movies in the 1990s include: The Silence of the Lambs, Titanic, etc."; - } else if (lowerMessage.includes("2000s")) { + } + else if (lowerMessage.includes("2000s")) { return "Movies in the 2000s include: The Lord of the Rings: The Return of the King, The Dark Knight, etc."; - } else if (lowerMessage.includes("2010s")) { + } + else if (lowerMessage.includes("2010s")) { return "Movies in the 2010s include: Inception, The Avengers, etc."; - } else if (lowerMessage.includes("2020s")) { + } + else if (lowerMessage.includes("2020s")) { return "Movies in the 2020s include: Tenet, Soul, etc."; - } else if (lowerMessage.includes("2022")) { + } + else if (lowerMessage.includes("2022")) { return "Movies in 2022 include: Thor: Love and Thunder, Doctor Strange in the Multiverse of Madness, etc."; - } else if (lowerMessage.includes("2023")) { + } + else if (lowerMessage.includes("2023")) { return "Movies in 2023 include: The Flash, Black Panther: Wakanda Forever, etc."; - } else if (lowerMessage.includes("2024")) { + } + else if (lowerMessage.includes("2024")) { return "Movies in 2024 include: Indiana Jones 5, The Batman, etc."; - } else if (lowerMessage.includes("movieverse analytics") || lowerMessage.includes("movieverse stats") || lowerMessage.includes("movieverse insights")) { + } + else if (lowerMessage.includes("movieverse analytics") || lowerMessage.includes("movieverse stats") || lowerMessage.includes("movieverse insights")) { return "MovieVerse Analytics provides insights into user activity, popular movies, and more. You can access it by pressing the About button on the top right, then selecting MovieVerse Analytics at the bottom of the page."; - } else { + } + else if (lowerMessage.includes("most visited director")) { + return `The most visited director is ${getMostVisitedDirector()}.`; + } + else if (lowerMessage.includes("trivia accuracy")) { + return `Your trivia accuracy is ${getTriviaAccuracy()}.`; + } + else if (lowerMessage.includes("most common genre") || lowerMessage.includes("favorite genre")) { + return `Your most common genre is ${getMostCommonGenre()}.`; + } + else if (lowerMessage.includes("movie of the day")) { + showMovieOfTheDay(); + return "Searching for the movie of the day. Please wait..."; + } + else if (lowerMessage.includes("sign in") || lowerMessage.includes("sign out")) { + return "Please click the Sign In/Out button at the top to sign in or out."; + } + else if (lowerMessage.includes("sign up")) { + return "Please click the Sign In button at the top to create an account."; + } + else { return "Sorry, I didn't catch that or find any movies with that name in our databases. Can you rephrase, check your spelling, or ask another question?"; } } @@ -715,9 +845,11 @@ const movieee = `https://${getMovieVerseData()}/3`; async function fetchMovieDetailsFromTMDB(movieName) { const url = `${movieee}/search/movie?${generateMovieNames()}${getMovieCode()}&query=${encodeURIComponent(movieName)}`; + try { const response = await fetch(url); const data = await response.json(); + if (data.results.length > 0) { const movie = data.results[0]; localStorage.setItem('selectedMovieId', movie.id); @@ -731,7 +863,7 @@ async function fetchMovieDetailsFromTMDB(movieName) { } } catch (error) { - console.error('Error fetching movie details:', error); + console.log('Error fetching movie details:', error); return "Sorry, I encountered an error while trying to fetch movie details. Please try again later."; } } @@ -755,50 +887,11 @@ async function showMovieOfTheDay() { } } catch (error) { - console.error('Error fetching movie:', error); + console.log('Error fetching movie:', error); fallbackMovieSelection(); } } -function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - - if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); - } - else { - window.location.href = 'sign-in.html'; - return; - } - - updateSignInButtonState(); -} - -function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); - - if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; - } - else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; - } -} - -document.addEventListener("DOMContentLoaded", function() { - updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); -}); - function fallbackMovieSelection() { const fallbackMovies = [432413, 299534, 1726, 562, 118340, 455207, 493922, 447332, 22970, 530385, 27205, 264660, 120467, 603, 577922, 76341, 539, 419704, 515001, 118340, 424, 98]; const randomFallbackMovie = fallbackMovies[Math.floor(Math.random() * fallbackMovies.length)]; diff --git a/MovieVerse-Mobile/app/js/christopher-nolan.js b/MovieVerse-Mobile/app/js/christopher-nolan.js index 6d9a9cfd..1424a4dc 100644 --- a/MovieVerse-Mobile/app/js/christopher-nolan.js +++ b/MovieVerse-Mobile/app/js/christopher-nolan.js @@ -225,7 +225,7 @@ async function fetchDirectorDetails(directorId) { } } catch (error) { - console.error('Error fetching director details:', error); + console.log('Error fetching director details:', error); document.getElementById('director-details-container').innerHTML = '+ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +
+ `; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById("prev-page").disabled = currentPage <= 1; + document.getElementById("next-page").disabled = currentPage >= totalPages; + } + catch (error) { + console.error("Error fetching user list: ", error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; + } + hideSpinner(); + } + } +} + +function formatCommentDate(commentDate) { + const formattedDate = commentDate.toLocaleString('default', { month: 'short' }) + " " + + commentDate.getDate() + "th, " + + commentDate.getFullYear(); + return formattedDate; +} + +function formatAMPM(date) { + let hours = date.getHours(); + let minutes = date.getMinutes(); + const ampm = hours >= 12 ? 'PM' : 'AM'; + hours = hours % 12; + hours = hours || 12; + minutes = minutes < 10 ? '0' + minutes : minutes; + const strTime = hours + ':' + minutes + ' ' + ampm; + return strTime; +} + +document.getElementById("prev-page").addEventListener("click", () => { + if (currentPage > 1) { + currentPage--; + fetchComments(); + } +}); + +document.getElementById("next-page").addEventListener("click", () => { + if (currentPage < totalPages) { + currentPage++; + fetchComments(); + } +}); + +fetchComments(); diff --git a/MovieVerse-Mobile/app/js/comments.js b/MovieVerse-Mobile/app/js/comments.js index 6d879f8a..ba5dc79a 100644 --- a/MovieVerse-Mobile/app/js/comments.js +++ b/MovieVerse-Mobile/app/js/comments.js @@ -1,17 +1,6 @@ import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js"; import { getFirestore, collection, addDoc, getDocs, query, orderBy, where } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js"; - -const firebaseConfig = { - apiKey: "AIzaSyDL6kQnSfUdD8Ut8HFrp9kuivqz1xdXm7k", - authDomain: "movieverse-app.firebaseapp.com", - projectId: "movieverse-app", - storageBucket: "movieverse-app.appspot.com", - messagingSenderId: "802943718871", - appId: "1:802943718871:web:48bc916cc99e2724212792" -}; - -const app = initializeApp(firebaseConfig); -const db = getFirestore(app); +import { app, db } from './firebase.js'; const commentForm = document.getElementById("comment-form"); commentForm.addEventListener("submit", async (e) => { @@ -32,13 +21,13 @@ commentForm.addEventListener("submit", async (e) => { fetchComments(); } catch (error) { - console.error("Error adding comment: ", error); + console.log("Error adding comment: ", error); } }); -var modal = document.getElementById("comment-modal"); -var btn = document.getElementById("toggle-comment-modal"); -var span = document.getElementsByClassName("close")[0]; +let modal = document.getElementById("comment-modal"); +let btn = document.getElementById("toggle-comment-modal"); +let span = document.getElementsByClassName("close")[0]; btn.onclick = function() { modal.style.display = "block"; @@ -66,61 +55,75 @@ let totalComments = 0; let totalPages = 1; async function fetchComments() { - const commentsContainer = document.getElementById("comments-container"); - commentsContainer.innerHTML = ''; - commentsContainer.style.maxWidth = "100%"; - const movieId = localStorage.getItem("selectedMovieId"); - - const q = query(collection(db, "comments"), where("movieId", "==", movieId), orderBy("commentDate", "desc")); - const querySnapshot = await getDocs(q); - - totalComments = querySnapshot.size; - totalPages = Math.ceil(totalComments / commentsPerPage); - - let index = 0; - let displayedComments = 0; - - if (querySnapshot.empty) { - const noCommentsMsg = document.createElement("p"); - noCommentsMsg.textContent = "No comments for this movie/TV show yet."; - commentsContainer.appendChild(noCommentsMsg); - } - else { - querySnapshot.forEach((doc) => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - const commentDate = comment.commentDate.toDate(); - - const formattedDate = formatCommentDate(commentDate); - const formattedTime = formatAMPM(commentDate); - - const timezoneOffset = -commentDate.getTimezoneOffset() / 60; - const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; - const commentElement = document.createElement("div"); - - commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; - const commentStyle = ` + try { + const commentsContainer = document.getElementById("comments-container"); + commentsContainer.innerHTML = ''; + commentsContainer.style.maxWidth = "100%"; + const movieId = localStorage.getItem("selectedMovieId"); + + const q = query(collection(db, "comments"), where("movieId", "==", movieId), orderBy("commentDate", "desc")); + const querySnapshot = await getDocs(q); + + totalComments = querySnapshot.size; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let index = 0; + let displayedComments = 0; + + if (querySnapshot.empty) { + const noCommentsMsg = document.createElement("p"); + noCommentsMsg.textContent = "No comments for this movie/TV show yet."; + commentsContainer.appendChild(noCommentsMsg); + } else { + querySnapshot.forEach((doc) => { + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { + const comment = doc.data(); + const commentDate = comment.commentDate.toDate(); + + const formattedDate = formatCommentDate(commentDate); + const formattedTime = formatAMPM(commentDate); + + const timezoneOffset = -commentDate.getTimezoneOffset() / 60; + const utcOffset = timezoneOffset >= 0 ? `UTC+${timezoneOffset}` : `UTC${timezoneOffset}`; + const commentElement = document.createElement("div"); + + commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; + const commentStyle = ` max-width: 100%; word-wrap: break-word; overflow-wrap: break-word; margin-bottom: 1rem; // Add some space between comments `; - commentElement.style.cssText = commentStyle; - commentElement.innerHTML = ` + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = `${comment.userName} on ${formattedDate}: ${comment.userComment}
`; - commentsContainer.appendChild(commentElement); - displayedComments++; + commentsContainer.appendChild(commentElement); + displayedComments++; + } + index++; + }); + } + + document.getElementById("prev-page").disabled = currentPage <= 1; + document.getElementById("next-page").disabled = currentPage >= totalPages; + } + catch (error) { + console.error("Error fetching user list: ", error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('comments-section'); + if (noUserSelected) { + noUserSelected.innerHTML = "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + noUserSelected.style.textAlign = 'center'; + noUserSelected.style.maxWidth = '350px'; } - index++; - }); + hideSpinner(); + } } - - document.getElementById("prev-page").disabled = currentPage <= 1; - document.getElementById("next-page").disabled = currentPage >= totalPages; } function formatCommentDate(commentDate) { diff --git a/MovieVerse-Mobile/app/js/company-details.js b/MovieVerse-Mobile/app/js/company-details.js index 06fddc39..ac8ff7c1 100644 --- a/MovieVerse-Mobile/app/js/company-details.js +++ b/MovieVerse-Mobile/app/js/company-details.js @@ -59,7 +59,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -91,7 +91,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -99,8 +99,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, @@ -368,8 +397,8 @@ async function fetchCompanyDetails(companyId) { try { const response = await fetch(url); const company = await response.json(); - const logoImg = document.getElementById('company-logo'); + if (company.logo_path) { logoImg.src = `https://image.tmdb.org/t/p/w500${company.logo_path}`; } @@ -382,9 +411,9 @@ async function fetchCompanyDetails(companyId) { const fullCountryName = twoLetterCountryCodes.find(country => country.code === company.origin_country)?.name; - document.getElementById('company-name').textContent = company.name || 'Name Not Available'; - document.getElementById('company-headquarters').textContent = company.headquarters || 'Headquarters Not Available'; - document.getElementById('company-country').textContent = fullCountryName || 'Country Not Available'; + document.getElementById('company-name').textContent = company.name || 'Information Unavailable'; + document.getElementById('company-headquarters').textContent = company.headquarters || 'Information Unavailable'; + document.getElementById('company-country').textContent = fullCountryName || 'Information Unavailable'; document.title = `${company.name} - Company Details`; const homepage = company.homepage || '#'; @@ -394,14 +423,14 @@ async function fetchCompanyDetails(companyId) { companyWebsite.textContent = homepage; } else { - companyWebsite.textContent = 'Website Not Available'; + companyWebsite.textContent = 'Information Unavailable'; } updateBrowserURL(company.name); hideSpinner(); } catch (error) { - console.error('Error fetching company details:', error); + console.log('Error fetching company details:', error); const companyDetailsContainer = document.getElementById('company-details-container'); companyDetailsContainer.innerHTML = `Biography: ${director.biography || 'N/A'}
-Date of Birth: ${director.birthday || 'N/A'}
-Date of Death: ${director.deathday || 'N/A'}
+Biography: ${director.biography || 'Information Unavailable'}
+Also Known As: ${director.also_known_as.join(', ') || 'Information Unavailable'}
+Date of Birth: ${director.birthday || 'Information Unavailable'}
+Date of Death: ${director.deathday || 'Information Unavailable'}
Age: ${ageOrStatus}
-Place of Birth: ${director.place_of_birth || 'N/A'}
+Place of Birth: ${director.place_of_birth || 'Information Unavailable'}
Known For: Directing
`; const filmographyHeading = document.createElement('p'); filmographyHeading.innerHTML = 'Filmography: '; directorDescription.appendChild(filmographyHeading); + const movieList = document.createElement('div'); movieList.classList.add('movie-list'); - credits.crew.forEach(movie => { - if (movie.job === "Director") { - const movieLink = document.createElement('span'); - movieLink.textContent = movie.title; - movieLink.classList.add('movie-link'); - movieLink.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', movie.id); - window.location.href = 'movie-details.html'; - }); - movieList.appendChild(movieLink); + + const directedMovies = credits.crew.filter(movie => movie.job === "Director"); + + directedMovies.forEach((movie, index) => { + const movieLink = document.createElement('span'); + movieLink.textContent = movie.title; + movieLink.classList.add('movie-link'); + movieLink.addEventListener('click', () => { + localStorage.setItem('selectedMovieId', movie.id); + window.location.href = 'movie-details.html'; + }); + movieList.appendChild(movieLink); + + if (index < directedMovies.length - 1) { movieList.appendChild(document.createTextNode(', ')); } }); + filmographyHeading.appendChild(movieList); + const mediaUrl = `https://${getMovieVerseData()}/3/person/${director.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.profiles; + + const detailsContainer = document.getElementById('director-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } + + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: center; + margin-bottom: 5px; + `; + } + + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + mediaContainer.appendChild(imageElement); + } + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w1280${images[0].file_path}`; + } + + if (images.length === 0) { + mediaContainer.innerHTML = 'No media available
'; + } + + imageElement.addEventListener('click', function() { + const imageUrl = this.src; + const modalHtml = ` +No Favorite Movies Added Yet.
'; + } + else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } + } + + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); + + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); + + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; + } + else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } + return; + } + + const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", currentUserEmail)); + const userSnapshot = await getDocs(usersRef); - if (!currentUserEmail) { - const favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; - const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + const createForm = document.getElementById('create-watchlist-form'); let container = document.getElementById('favorites-container'); if (!container) { container = document.createElement('div'); container.id = 'favorites-container'; - document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + createForm.insertBefore(container, createForm.querySelector('button[type="submit"]')); } else { container.innerHTML = ''; } - let moviesLabel = document.createElement('label'); - moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; - container.appendChild(moviesLabel); + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + const moviesFavorited = userData.favoritesMovies || []; + const favoritesTVSeries = userData.favoritesTVSeries || []; - let moviesContainer = document.createElement('div'); - moviesContainer.id = 'movies-container'; - moviesContainer.style.marginTop = '-20px'; - container.appendChild(moviesContainer); + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); - if (favoritesMovies.length === 0) { - moviesContainer.innerHTML = 'No Favorite Movies Added Yet.
'; - } - else { - for (const movieId of favoritesMovies) { - const movieTitle = await getMovieTitle(movieId); - appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); + + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = 'No Favorite Movies Added Yet.
'; + } + else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } } - } - let tvSeriesLabel = document.createElement('label'); - tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; - container.appendChild(tvSeriesLabel); + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); - let tvSeriesContainer = document.createElement('div'); - tvSeriesContainer.id = 'tvseries-container'; - tvSeriesContainer.style.marginTop = '-20px'; - container.appendChild(tvSeriesContainer); + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); - if (favoritesTVSeries.length === 0) { - tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; + } + else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } + } } else { - for (const seriesId of favoritesTVSeries) { - const seriesTitle = await getTVSeriesTitle(seriesId); - appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); - } + container.innerHTML = 'No favorites found. Please add some favorites first.
'; } - return; - } - - const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", currentUserEmail)); - const userSnapshot = await getDocs(usersRef); - - const createForm = document.getElementById('create-watchlist-form'); - - let container = document.getElementById('favorites-container'); - if (!container) { - container = document.createElement('div'); - container.id = 'favorites-container'; - createForm.insertBefore(container, createForm.querySelector('button[type="submit"]')); - } - else { - container.innerHTML = ''; } + catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for favorites.'); + const moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + const favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + let container = document.getElementById('favorites-container'); + if (!container) { + container = document.createElement('div'); + container.id = 'favorites-container'; + document.getElementById('create-watchlist-form').insertBefore(container, document.querySelector('button[type="submit"]')); + } + else { + container.innerHTML = ''; + } - if (!userSnapshot.empty) { - const userData = userSnapshot.docs[0].data(); - const favoritesMovies = userData.favoritesMovies || []; - const favoritesTVSeries = userData.favoritesTVSeries || []; - - let moviesLabel = document.createElement('label'); - moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; - container.appendChild(moviesLabel); + let moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + container.appendChild(moviesLabel); - let moviesContainer = document.createElement('div'); - moviesContainer.id = 'movies-container'; - moviesContainer.style.marginTop = '-20px'; - container.appendChild(moviesContainer); + let moviesContainer = document.createElement('div'); + moviesContainer.id = 'movies-container'; + moviesContainer.style.marginTop = '-20px'; + container.appendChild(moviesContainer); - if (favoritesMovies.length === 0) { - moviesContainer.innerHTML = 'No Favorite Movies Added Yet.
'; - } - else { - for (const movieId of favoritesMovies) { - const movieTitle = await getMovieTitle(movieId); - appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + if (moviesFavorited.length === 0) { + moviesContainer.innerHTML = 'No Favorite Movies Added Yet.
'; + } + else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies'); + } } - } - let tvSeriesLabel = document.createElement('label'); - tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; - container.appendChild(tvSeriesLabel); + let tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + container.appendChild(tvSeriesLabel); - let tvSeriesContainer = document.createElement('div'); - tvSeriesContainer.id = 'tvseries-container'; - tvSeriesContainer.style.marginTop = '-20px'; - container.appendChild(tvSeriesContainer); + let tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'tvseries-container'; + tvSeriesContainer.style.marginTop = '-20px'; + container.appendChild(tvSeriesContainer); - if (favoritesTVSeries.length === 0) { - tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; - } - else { - for (const seriesId of favoritesTVSeries) { - const seriesTitle = await getTVSeriesTitle(seriesId); - appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + if (favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; + } + else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries'); + } } } } - else { - container.innerHTML = 'No favorites found. Please add some favorites first.
'; - } + document.addEventListener('keydown', function(event) { + if (event.key === "Escape") { + closeModal('create-watchlist-modal'); + } + }); } document.getElementById('create-watchlist-form').addEventListener('submit', async function(e) { - showSpinner(); - e.preventDefault(); - - const name = document.getElementById('new-watchlist-name').value; - const description = document.getElementById('new-watchlist-description').value; - const selectedMovies = Array.from(document.querySelectorAll('#movies-container input:checked')).map(checkbox => checkbox.value); - const selectedTVSeries = Array.from(document.querySelectorAll('#tvseries-container input:checked')).map(checkbox => checkbox.value); - const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); - const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); - const querySnapshot = await getDocs(q); - let maxOrder = querySnapshot.docs.reduce((max, docSnapshot) => Math.max(max, docSnapshot.data().order || 0), 0); + try { + showSpinner(); + e.preventDefault(); + + const name = document.getElementById('new-watchlist-name').value; + const description = document.getElementById('new-watchlist-description').value; + const selectedMovies = Array.from(document.querySelectorAll('#movies-container input:checked')).map(checkbox => checkbox.value); + const selectedTVSeries = Array.from(document.querySelectorAll('#tvseries-container input:checked')).map(checkbox => checkbox.value); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); + const querySnapshot = await getDocs(q); + let maxOrder = querySnapshot.docs.reduce((max, docSnapshot) => Math.max(max, docSnapshot.data().order || 0), 0); + + if (currentUserEmail) { + const newWatchlistRef = doc(collection(db, 'watchlists')); + await setDoc(newWatchlistRef, { + userEmail: currentUserEmail, + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString(), + order: maxOrder + 1, + }); + } + else { + const localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: "", + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString() + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } - if (currentUserEmail) { - const newWatchlistRef = doc(collection(db, 'watchlists')); - await setDoc(newWatchlistRef, { - userEmail: currentUserEmail, - name, - description, - movies: selectedMovies, - tvSeries: selectedTVSeries, - pinned: false, - createdAt: new Date().toISOString(), - order: maxOrder + 1, - }); + closeModal('create-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); } - else { - const localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - localWatchlists.push({ - id: `local-${new Date().getTime()}`, - userEmail: "", - name, - description, - movies: selectedMovies, - tvSeries: selectedTVSeries, - pinned: false, - createdAt: new Date().toISOString() - }); - localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + const name = document.getElementById('new-watchlist-name').value; + const description = document.getElementById('new-watchlist-description').value; + const selectedMovies = Array.from(document.querySelectorAll('#movies-container input:checked')).map(checkbox => checkbox.value); + const selectedTVSeries = Array.from(document.querySelectorAll('#tvseries-container input:checked')).map(checkbox => checkbox.value); + const localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + localWatchlists.push({ + id: `local-${new Date().getTime()}`, + userEmail: "", + name, + description, + movies: selectedMovies, + tvSeries: selectedTVSeries, + pinned: false, + createdAt: new Date().toISOString() + }); + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + closeModal('create-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } } - - closeModal('create-watchlist-modal'); - loadWatchLists(); - hideSpinner(); - window.location.reload(); }); async function getTVSeriesTitle(seriesId) { @@ -552,7 +670,6 @@ function appendCheckbox(container, id, title, name, isChecked = false) { container.appendChild(item); } - document.getElementById('create-watchlist-btn').addEventListener('click', function() { document.getElementById('create-watchlist-form').reset(); populateCreateModalWithFavorites(); @@ -570,279 +687,528 @@ document.getElementById('edit-watchlist-btn').addEventListener('click', async fu }); async function populateEditModal() { - let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); - let watchlists = []; - let favoritesMovies = []; - let favoritesTVSeries = []; + let watchlists = []; + let moviesFavorited = []; + let favoritesTVSeries = []; - if (currentUserEmail) { - const qWatchlists = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); - const qUsers = query(collection(db, "MovieVerseUsers"), where("email", "==", currentUserEmail)); + if (currentUserEmail) { + const qWatchlists = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); + const qUsers = query(collection(db, "MovieVerseUsers"), where("email", "==", currentUserEmail)); - const [watchlistsSnapshot, usersSnapshot] = await Promise.all([ - getDocs(qWatchlists), - getDocs(qUsers) - ]); + const [watchlistsSnapshot, usersSnapshot] = await Promise.all([ + getDocs(qWatchlists), + getDocs(qUsers) + ]); - watchlists = watchlistsSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); + watchlists = watchlistsSnapshot.docs.map(doc => ({id: doc.id, ...doc.data()})); - if (!usersSnapshot.empty) { - const userData = usersSnapshot.docs[0].data(); - favoritesMovies = userData.favoritesMovies || []; - favoritesTVSeries = userData.favoritesTVSeries || []; + if (!usersSnapshot.empty) { + const userData = usersSnapshot.docs[0].data(); + moviesFavorited = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + } + } + else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; } - } - else { - watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - favoritesMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; - favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; - } - const editForm = document.getElementById('edit-watchlist-form'); - editForm.innerHTML = ''; + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; - if (watchlists.length === 0) { - const noWatchlistMsg = document.createElement('div'); - noWatchlistMsg.textContent = 'No Watchlists Available for Edit'; - noWatchlistMsg.style.textAlign = 'center'; - noWatchlistMsg.style.marginTop = '30px'; - noWatchlistMsg.style.color = 'white'; - editForm.appendChild(noWatchlistMsg); - return; - } + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } - const selectLabel = document.createElement('label'); - selectLabel.textContent = 'Select A Watch List:'; - selectLabel.setAttribute("for", "watchlist-select"); - editForm.appendChild(selectLabel); - - const select = document.createElement('select'); - select.id = 'watchlist-select'; - select.style.font = 'inherit'; - watchlists.forEach((watchlist) => { - const option = document.createElement('option'); - option.value = watchlist.id; - option.textContent = watchlist.name; - select.appendChild(option); - }); + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute("for", "watchlist-select"); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach((watchlist) => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); - const nameLabel = document.createElement('label'); - nameLabel.textContent = 'Watch List Name:'; - const nameInput = document.createElement('input'); - nameInput.type = 'text'; - nameInput.id = 'edit-watchlist-name'; - nameInput.style.font = 'inherit'; - nameInput.placeholder = 'New Watchlist Name'; - - const descLabel = document.createElement('label'); - descLabel.textContent = 'Description:'; - const descInput = document.createElement('textarea'); - descInput.id = 'edit-watchlist-description'; - descInput.style.font = 'inherit'; - descInput.placeholder = 'New Watchlist Description'; + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; - const moviesContainer = document.createElement('div'); - moviesContainer.id = 'edit-movies-container'; - const moviesLabel = document.createElement('label'); - moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; - editForm.appendChild(select); - editForm.appendChild(nameLabel); - editForm.appendChild(nameInput); - editForm.appendChild(descLabel); - editForm.appendChild(descInput); - editForm.appendChild(moviesLabel); - editForm.appendChild(moviesContainer); - - const tvSeriesContainer = document.createElement('div'); - tvSeriesContainer.id = 'edit-tvseries-container'; - const tvSeriesLabel = document.createElement('label'); - tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; - tvSeriesLabel.style.marginTop = '20px'; - editForm.appendChild(tvSeriesLabel); - editForm.appendChild(tvSeriesContainer); - - const updateForm = async (watchlist) => { - nameInput.value = watchlist.name; - descInput.value = watchlist.description; - moviesContainer.innerHTML = ''; - tvSeriesContainer.innerHTML = ''; + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); - initialMoviesSelection = watchlist.movies.slice(); - initialTVSeriesSelection = watchlist.tvSeries.slice(); + const updateForm = async (watchlist) => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; - if (!favoritesMovies || favoritesMovies.length === 0) { - moviesContainer.innerHTML = 'No Favorite Movies Added Yet.
'; - } - else { - for (const movieId of favoritesMovies) { - const movieTitle = await getMovieTitle(movieId); - const isChecked = watchlist.movies.includes(movieId); - appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = 'No Favorite Movies Added Yet.
'; + } + else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } } - } - if (!favoritesTVSeries || favoritesTVSeries.length === 0) { - tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; - } - else { - for (const seriesId of favoritesTVSeries) { - const seriesTitle = await getTVSeriesTitle(seriesId); - const isChecked = watchlist.tvSeries.includes(seriesId); - appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; } - } - }; + else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; - select.addEventListener('change', function () { - const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); - updateForm(selectedWatchlist); - }); + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); - selectLabel.addEventListener('click', function () { - updateForm(watchlists[select.value]); - }); + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } - if (watchlists.length > 0) { - updateForm(watchlists[0]); + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); } + catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let moviesFavorited = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + let favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; + + const editForm = document.getElementById('edit-watchlist-form'); + editForm.innerHTML = ''; + + if (watchlists.length === 0) { + const noWatchlistMsg = document.createElement('div'); + noWatchlistMsg.textContent = 'No Watch Lists Available for Edit'; + noWatchlistMsg.style.textAlign = 'center'; + noWatchlistMsg.style.marginTop = '30px'; + noWatchlistMsg.style.color = 'white'; + editForm.appendChild(noWatchlistMsg); + return; + } + + const selectLabel = document.createElement('label'); + selectLabel.textContent = 'Select A Watch List:'; + selectLabel.setAttribute("for", "watchlist-select"); + editForm.appendChild(selectLabel); + + const select = document.createElement('select'); + select.id = 'watchlist-select'; + select.style.font = 'inherit'; + watchlists.forEach((watchlist) => { + const option = document.createElement('option'); + option.value = watchlist.id; + option.textContent = watchlist.name; + select.appendChild(option); + }); + + const nameLabel = document.createElement('label'); + nameLabel.textContent = 'Watch List Name:'; + const nameInput = document.createElement('input'); + nameInput.type = 'text'; + nameInput.id = 'edit-watchlist-name'; + nameInput.style.font = 'inherit'; + nameInput.placeholder = 'New Watchlist Name'; + + const descLabel = document.createElement('label'); + descLabel.textContent = 'Description:'; + const descInput = document.createElement('textarea'); + descInput.id = 'edit-watchlist-description'; + descInput.style.font = 'inherit'; + descInput.placeholder = 'New Watchlist Description'; + + const moviesContainer = document.createElement('div'); + moviesContainer.id = 'edit-movies-container'; + const moviesLabel = document.createElement('label'); + moviesLabel.textContent = 'Select favorite movies to include in watchlist:'; + editForm.appendChild(select); + editForm.appendChild(nameLabel); + editForm.appendChild(nameInput); + editForm.appendChild(descLabel); + editForm.appendChild(descInput); + editForm.appendChild(moviesLabel); + editForm.appendChild(moviesContainer); + + const tvSeriesContainer = document.createElement('div'); + tvSeriesContainer.id = 'edit-tvseries-container'; + const tvSeriesLabel = document.createElement('label'); + tvSeriesLabel.textContent = 'Select favorite TV series to include in watchlist:'; + tvSeriesLabel.style.marginTop = '20px'; + editForm.appendChild(tvSeriesLabel); + editForm.appendChild(tvSeriesContainer); + + const updateForm = async (watchlist) => { + nameInput.value = watchlist.name; + descInput.value = watchlist.description; + moviesContainer.innerHTML = ''; + tvSeriesContainer.innerHTML = ''; + + initialMoviesSelection = watchlist.movies.slice(); + initialTVSeriesSelection = watchlist.tvSeries.slice(); + + if (!moviesFavorited || moviesFavorited.length === 0) { + moviesContainer.innerHTML = 'No Favorite Movies Added Yet.
'; + } + else { + for (const movieId of moviesFavorited) { + const movieTitle = await getMovieTitle(movieId); + const isChecked = watchlist.movies.includes(movieId); + appendCheckbox(moviesContainer, movieId, movieTitle, 'favoritedMovies', isChecked); + } + } - const submitButton = document.createElement('button'); - submitButton.type = 'submit'; - submitButton.textContent = 'Save Changes'; - editForm.appendChild(submitButton); - - const cancelButton = document.createElement('button'); - cancelButton.type = 'button'; - cancelButton.textContent = 'Cancel Changes'; - cancelButton.style.marginTop = '20px'; - cancelButton.onclick = () => closeModal('edit-watchlist-modal'); - editForm.appendChild(cancelButton); + if (!favoritesTVSeries || favoritesTVSeries.length === 0) { + tvSeriesContainer.innerHTML = 'No Favorite TV Series Added Yet.
'; + } + else { + for (const seriesId of favoritesTVSeries) { + const seriesTitle = await getTVSeriesTitle(seriesId); + const isChecked = watchlist.tvSeries.includes(seriesId); + appendCheckbox(tvSeriesContainer, seriesId, seriesTitle, 'favoritedTVSeries', isChecked); + } + } + }; + + select.addEventListener('change', function () { + const selectedWatchlist = watchlists.find(watchlist => watchlist.id === this.value); + updateForm(selectedWatchlist); + }); + + selectLabel.addEventListener('click', function () { + updateForm(watchlists[select.value]); + }); + + if (watchlists.length > 0) { + updateForm(watchlists[0]); + } + + const submitButton = document.createElement('button'); + submitButton.type = 'submit'; + submitButton.textContent = 'Save Changes'; + editForm.appendChild(submitButton); + + const cancelButton = document.createElement('button'); + cancelButton.type = 'button'; + cancelButton.textContent = 'Cancel Changes'; + cancelButton.style.marginTop = '20px'; + cancelButton.onclick = () => closeModal('edit-watchlist-modal'); + editForm.appendChild(cancelButton); + } + } + document.addEventListener('keydown', function(event) { + if (event.key === "Escape") { + closeModal('edit-watchlist-modal'); + } + }); } document.getElementById('edit-watchlist-form').addEventListener('submit', async function(e) { - showSpinner(); + try { + showSpinner(); + e.preventDefault(); - e.preventDefault(); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; - const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); - const selectedOption = document.getElementById('watchlist-select'); - const watchlistId = selectedOption.value; - const newName = document.getElementById('edit-watchlist-name').value; - const newDescription = document.getElementById('edit-watchlist-description').value; + let selectedMovies; + let selectedTVSeries; - let selectedMovies; - let selectedTVSeries; + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map(checkbox => checkbox.value); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map(checkbox => checkbox.value); - const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map(checkbox => checkbox.value); - const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map(checkbox => checkbox.value); + const moviesSelectionChanged = !(initialMoviesSelection.length === currentMoviesSelection.length && initialMoviesSelection.every(value => currentMoviesSelection.includes(value))); + const tvSeriesSelectionChanged = !(initialTVSeriesSelection.length === currentTVSeriesSelection.length && initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value))); - const moviesSelectionChanged = !(initialMoviesSelection.length === currentMoviesSelection.length && initialMoviesSelection.every(value => currentMoviesSelection.includes(value))); - const tvSeriesSelectionChanged = !(initialTVSeriesSelection.length === currentTVSeriesSelection.length && initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value))); + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } + else { + selectedMovies = initialMoviesSelection; + } - if (moviesSelectionChanged) { - selectedMovies = currentMoviesSelection; - } - else { - selectedMovies = initialMoviesSelection; - } + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } + else { + selectedTVSeries = initialTVSeriesSelection; + } - if (tvSeriesSelectionChanged) { - selectedTVSeries = currentTVSeriesSelection; - } - else { - selectedTVSeries = initialTVSeriesSelection; - } + if (currentUserEmail) { + const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); + const querySnapshot = await getDocs(q); - if (currentUserEmail) { - const watchlistRef = doc(db, 'watchlists', watchlistId); - await updateDoc(watchlistRef, { - name: newName, - description: newDescription, - movies: selectedMovies, - tvSeries: selectedTVSeries - }); - } - else { - let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); - if (watchlistIndex !== -1) { - localWatchlists[watchlistIndex] = { - ...localWatchlists[watchlistIndex], + const watchlistRef = doc(db, 'watchlists', watchlistId); + await updateDoc(watchlistRef, { name: newName, description: newDescription, movies: selectedMovies, tvSeries: selectedTVSeries - }; - localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + }); + } + else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); } + catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); - closeModal('edit-watchlist-modal'); - loadWatchLists(); - hideSpinner(); - window.location.reload(); + e.preventDefault(); + + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedOption = document.getElementById('watchlist-select'); + const watchlistId = selectedOption.value; + const newName = document.getElementById('edit-watchlist-name').value; + const newDescription = document.getElementById('edit-watchlist-description').value; + + let selectedMovies; + let selectedTVSeries; + + const currentMoviesSelection = Array.from(document.querySelectorAll('#edit-movies-container input[type="checkbox"]:checked')).map(checkbox => checkbox.value); + const currentTVSeriesSelection = Array.from(document.querySelectorAll('#edit-tvseries-container input[type="checkbox"]:checked')).map(checkbox => checkbox.value); + + const moviesSelectionChanged = !(initialMoviesSelection.length === currentMoviesSelection.length && initialMoviesSelection.every(value => currentMoviesSelection.includes(value))); + const tvSeriesSelectionChanged = !(initialTVSeriesSelection.length === currentTVSeriesSelection.length && initialTVSeriesSelection.every(value => currentTVSeriesSelection.includes(value))); + + if (moviesSelectionChanged) { + selectedMovies = currentMoviesSelection; + } + else { + selectedMovies = initialMoviesSelection; + } + + if (tvSeriesSelectionChanged) { + selectedTVSeries = currentTVSeriesSelection; + } + else { + selectedTVSeries = initialTVSeriesSelection; + } + + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + let watchlistIndex = localWatchlists.findIndex(watchlist => watchlist.id === watchlistId); + if (watchlistIndex !== -1) { + localWatchlists[watchlistIndex] = { + ...localWatchlists[watchlistIndex], + name: newName, + description: newDescription, + movies: selectedMovies, + tvSeries: selectedTVSeries + }; + localStorage.setItem('localWatchlists', JSON.stringify(localWatchlists)); + } + + closeModal('edit-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } }); async function populateDeleteModal() { - let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + try { + let currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); - const deleteForm = document.getElementById('delete-watchlist-form'); - deleteForm.innerHTML = ''; + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; - let watchlists = []; + let watchlists = []; - if (currentUserEmail) { - const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); - const querySnapshot = await getDocs(q); - watchlists = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); - } - else { - watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - } + if (currentUserEmail) { + const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({id: doc.id, ...doc.data()})); + } else { + watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + } - if (watchlists.length === 0) { - deleteForm.innerHTML = 'No Watchlists Available to Delete.
'; - return; + if (watchlists.length === 0) { + deleteForm.innerHTML = 'No Watchlists Available to Delete.
'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); + + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); } + catch (error) { + if (error.code === 'resource-exhausted') { + console.log('Firebase quota exceeded. Using localStorage for watchlists.'); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - const checkboxesContainer = document.createElement('div'); - checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; + const deleteForm = document.getElementById('delete-watchlist-form'); + deleteForm.innerHTML = ''; - watchlists.forEach(watchlist => { - appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); - }); + if (watchlists.length === 0) { + deleteForm.innerHTML = 'No Watchlists Available to Delete.
'; + return; + } + + const checkboxesContainer = document.createElement('div'); + checkboxesContainer.id = 'delete-watchlist-checkboxes-container'; - deleteForm.appendChild(checkboxesContainer); + watchlists.forEach(watchlist => { + appendCheckbox(checkboxesContainer, watchlist.id, watchlist.name, 'watchlistToDelete'); + }); + + deleteForm.appendChild(checkboxesContainer); - const deleteButton = document.createElement('button'); - deleteButton.type = 'button'; - deleteButton.textContent = 'Delete Selected'; - deleteButton.onclick = deleteSelectedWatchlists; - deleteForm.appendChild(deleteButton); + const deleteButton = document.createElement('button'); + deleteButton.type = 'button'; + deleteButton.textContent = 'Delete Selected'; + deleteButton.onclick = deleteSelectedWatchlists; + deleteForm.appendChild(deleteButton); + } + } + document.addEventListener('keydown', function(event) { + if (event.key === "Escape") { + closeModal('delete-watchlist-modal'); + } + }); } async function deleteSelectedWatchlists() { - showSpinner(); - const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); - const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); - const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); + try { + showSpinner(); + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); - if (currentUserEmail) { - for (const id of selectedIds) { - await deleteDoc(doc(db, 'watchlists', id)); + if (currentUserEmail) { + const q = query(collection(db, "watchlists"), where("userEmail", "==", currentUserEmail)); + const querySnapshot = await getDocs(q); + + for (const id of selectedIds) { + await deleteDoc(doc(db, 'watchlists', id)); + } } + else { + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + } + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); } - else { - let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); - localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); - } + catch (error) { + if (error.code === 'resource-exhausted') { + showSpinner(); + const selectedCheckboxes = document.querySelectorAll('#delete-watchlist-checkboxes-container input[type="checkbox"]:checked'); + const selectedIds = Array.from(selectedCheckboxes).map(checkbox => checkbox.value); - closeModal('delete-watchlist-modal'); - loadWatchLists(); - hideSpinner(); - window.location.reload(); + let watchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + watchlists = watchlists.filter(watchlist => !selectedIds.includes(watchlist.id)); + localStorage.setItem('localWatchlists', JSON.stringify(watchlists)); + + closeModal('delete-watchlist-modal'); + loadWatchLists(); + hideSpinner(); + window.location.reload(); + } + } } document.getElementById('delete-watchlist-btn').addEventListener('click', populateDeleteModal); @@ -854,7 +1220,9 @@ async function fetchMovieDetails(movieId) { try { const response = await fetch(url); const movie = await response.json(); - return createMovieCard(movie); + const movieCard = createMovieCard(movie); + movieCard.setAttribute('data-movie-title', movie.title); + return movieCard; } catch (error) { const errorDiv = document.createElement('div'); @@ -867,21 +1235,40 @@ function createMovieCard(movie) { const movieEl = document.createElement('div'); movieEl.classList.add('movie'); movieEl.style.cursor = 'pointer'; + movieEl.style.zIndex = '1000'; + + let movieTitle = movie.title; + const words = movieTitle.split(' '); + if (words.length >= 9) { + words[8] = '...'; + movieTitle = words.slice(0, 9).join(' '); + } + + const ratingClass = movie.vote_count === 0 ? "unrated" : getClassByRate(movie.vote_average); + const voteAvg = movie.vote_count === 0 ? "Unrated" : movie.vote_average.toFixed(1); + + let overview = movie.overview; + if (overview === "") { + overview = "No overview available."; + } movieEl.innerHTML = ` -No watch lists found. Click on "Create Watch Lists" to start adding movies.
'; + } + else { + watchlists.sort((a, b) => a.order - b.order); + watchlists.sort((a, b) => (b.pinned === a.pinned) ? 0 : b.pinned ? 1 : -1); + for (const watchlist of watchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } } - return b.popularity - a.popularity; - }); + else { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; - if (allMovies.length > 0) { - showMovies(allMovies.slice(0, numberOfMovies)); - } - else { - searchResultsMain.innerHTML = `No movie with the specified search term found. Please try again.
`; - } -} + if (localWatchlists.length === 0) { + displaySection.innerHTML = 'No watch lists found. Start by adding movies to your watchlist.
'; + } + else { + localWatchlists.sort((a, b) => (b.pinned === a.pinned) ? 0 : b.pinned ? 1 : -1); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); + } + } + } -function showMovies(movies){ - searchResultsMain.innerHTML = ''; - movies.forEach((movie) => { - const { id, poster_path, title, vote_average, overview } = movie; - const movieE1 = document.createElement('div'); - const voteAverage = vote_average.toFixed(1); - movieE1.classList.add('movie'); - - const movieImage = poster_path - ? `` - : `No favorite movies added yet.
No watch lists found. Click on "Create a Watch List" to start adding movies.
'; + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); + + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; + + for (const tvSeriesId of favoritesTVSeries) { + const tvSeriesCard = await fetchTVSeriesDetails(tvSeriesId); + moviesContainer.appendChild(tvSeriesCard); + } + + favoritesDiv.appendChild(moviesContainer); + displaySection.appendChild(favoritesDiv); } else { - watchlists.sort((a, b) => a.order - b.order); - watchlists.sort((a, b) => (b.pinned === a.pinned) ? 0 : b.pinned ? 1 : -1); - for (const watchlist of watchlists) { - const watchlistDiv = await createWatchListDiv(watchlist); - if (watchlist.pinned) { - watchlistDiv.classList.add('pinned'); - } - displaySection.appendChild(watchlistDiv); - } + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorites-tvseries-watchlist'; + favoritesDiv.innerHTML = 'No favorite TV series added yet.
No watch lists found. Start by adding movies to your watchlist.
'; - } - else { - localWatchlists.sort((a, b) => (b.pinned === a.pinned) ? 0 : b.pinned ? 1 : -1); - for (const watchlist of localWatchlists) { - const watchlistDiv = await createWatchListDiv(watchlist); - if (watchlist.pinned) { - watchlistDiv.classList.add('pinned'); + catch (error) { + if (error.code === 'resource-exhausted') { + let localWatchlists = JSON.parse(localStorage.getItem('localWatchlists')) || []; + + if (localWatchlists.length === 0) { + displaySection.innerHTML = 'No watch lists found. Start by adding movies to your watchlist.
'; + } + else { + localWatchlists.sort((a, b) => (b.pinned === a.pinned) ? 0 : b.pinned ? 1 : -1); + for (const watchlist of localWatchlists) { + const watchlistDiv = await createWatchListDiv(watchlist); + if (watchlist.pinned) { + watchlistDiv.classList.add('pinned'); + } + displaySection.appendChild(watchlistDiv); } - displaySection.appendChild(watchlistDiv); } - } - } - let favorites = []; - let favoritesTVSeries = []; - if (currentUserEmail) { - const usersRef = query(collection(db, "MovieVerseUsers"), where("email", "==", currentUserEmail)); - const userSnapshot = await getDocs(usersRef); + let favorites = []; + let favoritesTVSeries = []; - if (!userSnapshot.empty) { - const userData = userSnapshot.docs[0].data(); - favorites = userData.favoritesMovies || []; - favoritesTVSeries = userData.favoritesTVSeries || []; - } - } - else { - favorites = JSON.parse(localStorage.getItem('favoritesMovies')) || []; - favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; - } + favorites = JSON.parse(localStorage.getItem('moviesFavorited')) || []; + favoritesTVSeries = JSON.parse(localStorage.getItem('favoritesTVSeries')) || []; - if (favorites.length > 0) { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-watchlist'; + if (favorites.length > 0) { + const favoritesDiv = document.createElement('div'); + favoritesDiv.className = 'watchlist'; + favoritesDiv.id = 'favorites-watchlist'; - const title = document.createElement('h3'); - title.textContent = "Favorite Movies"; - title.className = 'watchlist-title'; + const title = document.createElement('h3'); + title.textContent = "Favorite Movies"; + title.className = 'watchlist-title'; - const description = document.createElement('p'); - description.textContent = "A collection of your favorite movies."; - description.className = 'watchlist-description'; + const description = document.createElement('p'); + description.textContent = "A collection of your favorite movies."; + description.className = 'watchlist-description'; - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); + favoritesDiv.appendChild(title); + favoritesDiv.appendChild(description); - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; + const moviesContainer = document.createElement('div'); + moviesContainer.className = 'movies-container'; - for (const movieId of favorites) { - const movieCard = await fetchMovieDetails(movieId); - moviesContainer.appendChild(movieCard); - } + for (const movieId of favorites) { + const movieCard = await fetchMovieDetails(movieId); + moviesContainer.appendChild(movieCard); + } - favoritesDiv.appendChild(moviesContainer); - displaySection.appendChild(favoritesDiv); - } - else { - const favoritesDiv = document.createElement('div'); - favoritesDiv.className = 'watchlist'; - favoritesDiv.id = 'favorites-watchlist'; - favoritesDiv.innerHTML = 'No favorite movies added yet.
No favorite movies added yet.
No favorite TV series added yet.
No movie with the specified search term found. Please try again.
`; - document.getElementById('clear-search-btn').style.display = 'none'; - } -} - -function clearMovieDetails() { - const movieDetailsContainer = document.getElementById('movie-details-container'); - if (movieDetailsContainer) { - movieDetailsContainer.innerHTML = ''; - } -} - -function showMovies(movies){ - main.innerHTML = ''; - movies.forEach((movie) => { - const { id, poster_path, title, vote_average, overview } = movie; - const movieE1 = document.createElement('div'); - const voteAverage = vote_average.toFixed(1); - movieE1.classList.add('movie'); - - const movieImage = poster_path - ? `` - : `Rated: ${ratingDetails.text}${ratingDetails.description}
` : ''; - document.getElementById('movie-rating').innerHTML = ` - IMDB Rating: ${imdbRating} - `; - document.getElementById('movie-rating').style.marginTop = '120px'; + document.getElementById('movie-rating').innerHTML = ``; document.title = movie.title + " - Movie Details"; - const movieImage = document.getElementById('movie-image'); const movieDescription = document.getElementById('movie-description'); - - const metascoreElement = metascore ? `Metascore: ${metascore}
` : ''; + const metascoreElement = metascore ? `Metascore: ${metascore}
` : ''; const awardsElement = awards ? `Awards: ${awards}
` : ''; - if (movie.poster_path) { - movieImage.src = IMGPATH + movie.poster_path; - movieImage.alt = movie.title; - } - else { - movieImage.style.display = 'none'; - const noImageText = document.createElement('h2'); - noImageText.textContent = 'Movie Image Not Available'; - noImageText.style.textAlign = 'center'; - noImageText.style.height = '800px'; - document.querySelector('.movie-left').appendChild(noImageText); - } - - const fullLanguage = twoLetterLangCodes.find(lang => lang.code === movie.original_language).name; - const overview = movie.overview; + const overview = movie.overview ? movie.overview : 'No overview available'; const genres = movie.genres.map(genre => genre.name).join(', '); - const releaseDate = movie.release_date; + const releaseDate = movie.release_date ? movie.release_date : 'Release date not available'; const budget = movie.budget === 0 ? 'Information Not Available' : `$${movie.budget.toLocaleString()}`; const revenue = movie.revenue <= 1000 ? 'Information Not Available' : `$${movie.revenue.toLocaleString()}`; @@ -1045,35 +1013,31 @@ function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, ra const languages = movie.spoken_languages.map(lang => lang.name).join(', '); const countries = movie.production_countries.map(country => country.name).join(', '); - const originalLanguage = fullLanguage; const popularityScore = movie.popularity.toFixed(0); - const status = movie.status; - const voteCount = movie.vote_count.toLocaleString(); let keywords = movie.keywords ? movie.keywords.keywords.map(kw => kw.name).join(', ') : 'None Available'; - const similarTitles = movie.similar ? movie.similar.results.map(m => m.title).join(', ') : 'None Available'; const scaledRating = (movie.vote_average / 2).toFixed(1); if (keywords.length === 0) { - keywords = 'None Available'; + keywords = 'No keywords have been added'; } const popularityThreshold = 80; const isPopular = movie.popularity >= popularityThreshold; const popularityText = isPopular ? `${popularityScore} (This movie is popular)` : `${popularityScore} (This movie is unpopular)`; - const adultContentIndicator = movie.adult - ? `Adult Content` - : `General Audience`; - const movieStatus = `Status: ${movie.status}
`; - const runtime = movie.runtime > 0 ? movie.runtime + ' minutes' : 'Runtime Info Not Available'; + const originalTitle = movie.original_title !== movie.title ? `Original Title: ${movie.original_title}
` : `Original Title: ${movie.title}
`; + const tmdbRating = movie.vote_average.toFixed(1); + document.getElementById('movie-description').innerHTML += `Description: ${overview}
+ ${originalTitle} +Tagline: ${tagline}
Genres: ${genres}
${ratedElement} ${movieStatus} @@ -1083,30 +1047,29 @@ function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, raRevenue: ${revenue}
Languages: ${languages}
Countries of Production: ${countries}
-Original Language: ${originalLanguage}
Popularity Score: ${popularityText}
-MovieVerse User Ratings: ${scaledRating}/5.0 (based on ${movie.vote_count} votes)
+MovieVerse User Rating: ${scaledRating}/5.0 (based on ${movie.vote_count} votes)
${awardsElement} +TMDb Rating: ${tmdbRating}/10.0
${metascoreElement} -Rotten Tomatoes: ${rtRating}
-Tagline: ${tagline}
`; if (movie.credits && movie.credits.crew) { - const director = movie.credits.crew.find(member => member.job === 'Director'); - if (director) { - const directorAge = director.birthday ? calculateAge(director.birthday) : 'N/A'; - const directorElement = document.createElement('p'); - directorElement.innerHTML = `Director: ${director.name}`; - directorElement.querySelector('.director-link').addEventListener('click', (e) => { - e.preventDefault(); - localStorage.setItem('selectedDirectorId', director.id); - document.title = `${director.name} - Director's Details`; - window.location.href = 'director-details.html'; - updateUniqueDirectorsViewed(director.id); - updateDirectorVisitCount(director.id, director.name); - }); - document.getElementById('movie-description').appendChild(directorElement); + const directors = movie.credits.crew.filter(member => member.job === 'Director'); + + if (directors.length > 0) { + const directorsLinks = directors.map(director => + `${director.name}` + ).join(', '); + + const directorsElement = document.createElement('p'); + directorsElement.innerHTML = `Director: ${directorsLinks}`; + document.getElementById('movie-description').appendChild(directorsElement); + } + else { + const noDirectorsElement = document.createElement('p'); + noDirectorsElement.innerHTML = `Director: Information not available`; + document.getElementById('movie-description').appendChild(noDirectorsElement); } } @@ -1117,18 +1080,9 @@ function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, ra if (movie.credits && movie.credits.cast.length > 0) { const topTenCast = movie.credits.cast.slice(0, 10); topTenCast.forEach((actor, index) => { - const actorLink = document.createElement('span'); - actorLink.textContent = actor.name; - actorLink.classList.add('actor-link'); - actorLink.addEventListener('click', () => { - localStorage.setItem('selectedActorId', actor.id); - window.location.href = 'actor-details.html'; - updateUniqueActorsViewed(actor.id); - updateActorVisitCount(actor.id, actor.name); - }); - + const actorLink = document.createElement('a'); + actorLink.innerHTML = `${actor.name}`; castHeading.appendChild(actorLink); - if (index < topTenCast.length - 1) { castHeading.appendChild(document.createTextNode(', ')); } @@ -1138,83 +1092,322 @@ function populateMovieDetails(movie, imdbRating, rtRating, metascore, awards, ra castHeading.appendChild(document.createTextNode('None available.')); } - const productionCompanies = movie.production_companies; - const productionCompaniesElement = document.createElement('p'); - productionCompaniesElement.innerHTML = 'Production Companies: '; - - if (productionCompanies.length === 0) { - productionCompaniesElement.innerHTML += 'None available.'; - } - productionCompanies.forEach((company, index) => { - const companyLink = document.createElement('a'); - companyLink.textContent = company.name; - companyLink.style.cursor = 'pointer'; - companyLink.style.textDecoration = 'underline'; - companyLink.href = '#'; - companyLink.classList.add('company-link'); - companyLink.addEventListener('click', (e) => { - e.preventDefault(); - localStorage.setItem('selectedCompanyId', company.id); - window.location.href = 'company-details.html'; - updateUniqueCompaniesViewed(company.id); - }); + if (movie.production_companies && movie.production_companies.length > 0) { + let companiesHTML = movie.production_companies.map(company => { + return `${company.name}`; + }).join(', '); + + const productionCompaniesElement = document.createElement('p'); + productionCompaniesElement.innerHTML = `Production Companies: ${companiesHTML}`; + document.getElementById('movie-description').appendChild(productionCompaniesElement); + } + else { + const noCompaniesElement = document.createElement('p'); + noCompaniesElement.innerHTML = `Production Companies: Information not available`; + document.getElementById('movie-description').appendChild(noCompaniesElement); + } - productionCompaniesElement.appendChild(companyLink); + if (movie.similar && movie.similar.results && movie.similar.results.length > 0) { + let similarMoviesHTML = movie.similar.results.map(similarMovie => { + return `${similarMovie.title}`; + }).join(', '); - if (index < productionCompanies.length - 1) { - productionCompaniesElement.appendChild(document.createTextNode(', ')); - } - }); + const similarMoviesElement = document.createElement('p'); + similarMoviesElement.innerHTML = `Similar Movies: ${similarMoviesHTML}`; + document.getElementById('movie-description').appendChild(similarMoviesElement); + } + else { + const noSimilarMoviesElement = document.createElement('p'); + noSimilarMoviesElement.innerHTML = `Similar Movies: None available`; + document.getElementById('movie-description').appendChild(noSimilarMoviesElement); + } - document.getElementById('movie-description').appendChild(productionCompaniesElement); - const similarMoviesHeading = document.createElement('p'); + document.getElementById('movie-description').innerHTML += ` +Streaming Options: ${streamingHTML}
`; - similarMoviesHeading.innerHTML = 'Similar Movies: '; - document.getElementById('movie-description').appendChild(similarMoviesHeading); + const homepage = document.createElement('p'); + homepage.innerHTML = movie.homepage ? `Homepage: Visit homepage` : `Homepage: Information unavailable`; + movieDescription.appendChild(homepage); - if (movie.similar && movie.similar.results.length > 0) { - movie.similar.results.forEach((similarMovie, index) => { - const movieLink = document.createElement('span'); - movieLink.textContent = similarMovie.title; - movieLink.style.cursor = 'pointer'; - movieLink.style.textDecoration = 'underline'; - movieLink.addEventListener('mouseenter', () => { - movieLink.style.color = '#f509d9'; - }); + const keywordsElement = document.createElement('p'); + keywordsElement.innerHTML = `Keywords: ${keywords}`; + movieDescription.appendChild(keywordsElement); - movieLink.addEventListener('mouseleave', () => { - movieLink.style.color = getSavedTextColor(); - }); + createImdbRatingCircle(imdbRating, imdbLink); + + const mediaUrl = `https://${getMovieVerseData()}/3/movie/${movie.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + const mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 90vw; + max-width: 450px; + margin: 20px auto; + overflow: hidden; + box-sizing: border-box; + `; - movieLink.addEventListener('click', () => { - localStorage.setItem('selectedMovieId', similarMovie.id); - window.location.href = 'movie-details.html'; - }); + const mediaTitle = document.createElement('p'); + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; - similarMoviesHeading.appendChild(movieLink); + detailsContainer.appendChild(mediaTitle); + detailsContainer.appendChild(mediaContainer); + + const imageWrapper = document.createElement('div'); + imageWrapper.style = ` + width: 100%; + max-height: 210px; + border-radius: 16px; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + `; - if (index < movie.similar.results.length - 1) { - similarMoviesHeading.appendChild(document.createTextNode(', ')); + const imageElement = document.createElement('img'); + imageElement.style = ` + width: 100%; + height: auto; + transition: opacity 0.5s ease-in-out; + opacity: 1; + cursor: pointer; + object-fit: contain; + `; + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + imageWrapper.appendChild(imageElement); + mediaContainer.appendChild(imageWrapper); + + imageElement.addEventListener('click', function() { + let imageUrl = this.src.replace('w780', 'w1280'); + const modalHtml = ` +No media available
'; + } + + const movieImage = document.getElementById('movie-image'); + if (movie.poster_path) { + movieImage.src = IMGPATH + movie.poster_path; + movieImage.alt = movie.title; + movieImage.loading = 'lazy'; } else { - similarMoviesHeading.appendChild(document.createTextNode('None available.')); + movieImage.style.display = 'none'; + const noImageText = document.createElement('h2'); + noImageText.textContent = 'Movie Image Not Available'; + noImageText.style.textAlign = 'center'; + noImageText.style.height = '800px'; + document.querySelector('.movie-left').appendChild(noImageText); } - const keywordsElement = document.createElement('p'); - keywordsElement.innerHTML = `Keywords: ${keywords}`; + hideSpinner(); +} - movieDescription.appendChild(keywordsElement); +function createImdbRatingCircle(imdbRating, imdbId) { + if (imdbRating === 'N/A' || imdbRating === null || imdbRating === undefined) { + imdbRating = 'N/A'; + } - updateMoviesFavorited(movie.id); - applySettings(); + let circleContainer = document.getElementById('imdbRatingCircleContainer'); + if (!circleContainer) { + circleContainer = document.createElement('div'); + circleContainer.id = 'imdbRatingCircleContainer'; + circleContainer.className = 'progress-container'; + const imdbLink = `${imdbId}`; + circleContainer.innerHTML = ` + + + + `; + + if (imdbRating === 'N/A') { + circleContainer.innerHTML += ` +Rating information currently unavailable
`; + } + + document.getElementById('movie-description').appendChild(circleContainer); + } + else { + const text = document.getElementById('imdbRatingText'); + text.textContent = `${imdbRating}`; + } + + const circle = circleContainer.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); +} + +function setProgress(circle, text, rating) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (rating / 10) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', rating <= 5 ? '#FF0000' : (rating >= 7.5 ? '#4CAF50' : '#2196F3')); + text.textContent = `${rating}`; + }, 10); +} + +function retriggerAnimation(imdbRating) { + const circle = document.querySelector('.progress-ring__progress'); + const text = document.getElementById('imdbRatingText'); + setProgress(circle, text, imdbRating); } function getSavedTextColor() { return localStorage.getItem('textColor') || 'white'; } +function handleDirectorClick(directorId, directorName) { + localStorage.setItem('selectedDirectorId', directorId); + document.title = `${directorName} - Director's Details`; + updateUniqueDirectorsViewed(directorId); + updateDirectorVisitCount(directorId, directorName); + window.location.href = 'director-details.html'; +} + +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } + else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + + localStorage.setItem('selectedActorId', actorId); + window.location.href = 'actor-details.html'; +} + +function handleCompanyClick(companyId, companyName) { + localStorage.setItem('selectedCompanyId', companyId); + document.title = `${companyName} - Company Details`; + window.location.href = 'company-details.html'; + updateUniqueCompaniesViewed(companyId); +} + +function handleSimilarMovieClick(movieId, movieTitle) { + localStorage.setItem('selectedMovieId', movieId); + document.title = `${movieTitle} - Movie Details`; + window.location.href = 'movie-details.html'; + updateMovieVisitCount(movieId, movieTitle); +} + function updateMoviesFavorited(movieId) { let favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; if (!favoritedMovies.includes(movieId)) { @@ -1327,4 +1520,4 @@ function applyTextColor(color) { .forEach(element => { element.style.color = color; }); -} \ No newline at end of file +} diff --git a/MovieVerse-Mobile/app/js/movie-match.js b/MovieVerse-Mobile/app/js/movie-match.js index f33a432c..db6cf0e0 100644 --- a/MovieVerse-Mobile/app/js/movie-match.js +++ b/MovieVerse-Mobile/app/js/movie-match.js @@ -38,7 +38,7 @@ async function showMovieOfTheDay() { } } catch (error) { - console.error('Error fetching movie:', error); + console.log('Error fetching movie:', error); fallbackMovieSelection(); } } @@ -55,7 +55,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -87,7 +87,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -95,8 +95,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, @@ -429,7 +458,6 @@ function findMovieMatch(mood, genre, period) { } const form = document.getElementById('form1'); - const IMGPATH = "https://image.tmdb.org/t/p/w1280"; const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; @@ -445,42 +473,3 @@ function handleSearch() { localStorage.setItem('searchQuery', searchQuery); window.location.href = 'search.html'; } - -function handleSignInOut() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - - if (isSignedIn) { - localStorage.setItem('isSignedIn', JSON.stringify(false)); - alert('You have been signed out.'); - } - else { - window.location.href = 'sign-in.html'; - return; - } - - updateSignInButtonState(); -} - -function updateSignInButtonState() { - const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; - - const signInText = document.getElementById('signInOutText'); - const signInIcon = document.getElementById('signInIcon'); - const signOutIcon = document.getElementById('signOutIcon'); - - if (isSignedIn) { - signInText.textContent = 'Sign Out'; - signInIcon.style.display = 'none'; - signOutIcon.style.display = 'inline-block'; - } - else { - signInText.textContent = 'Sign In'; - signInIcon.style.display = 'inline-block'; - signOutIcon.style.display = 'none'; - } -} - -document.addEventListener("DOMContentLoaded", function() { - updateSignInButtonState(); - document.getElementById('googleSignInBtn').addEventListener('click', handleSignInOut); -}); diff --git a/MovieVerse-Mobile/app/js/movie-timeline.js b/MovieVerse-Mobile/app/js/movie-timeline.js index 2013dabe..eabe2e25 100644 --- a/MovieVerse-Mobile/app/js/movie-timeline.js +++ b/MovieVerse-Mobile/app/js/movie-timeline.js @@ -22,7 +22,6 @@ document.getElementById('end-year').addEventListener('keydown', function(event) } }); - const movieCode = { part1: 'YzVhMjBjODY=', part2: 'MWFjZjdiYjg=', @@ -37,7 +36,7 @@ function generateMovieNames(input) { return String.fromCharCode(97, 112, 105, 95, 107, 101, 121, 61); } -const IMGPATH = "https://image.tmdb.org/t/p/w1280"; +const IMGPATH = "https://image.tmdb.org/t/p/w500"; const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; const searchTitle = document.getElementById("select-text"); const searchButton = document.getElementById("button-search"); @@ -62,7 +61,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -94,7 +93,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -102,8 +101,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, @@ -312,15 +340,25 @@ function showMovies(movies, mainElement) { : `No movie with the specified search term found. Please try again.
`; - document.getElementById('clear-search-btn').style.display = 'none'; - } -} - -document.getElementById('clear-search-btn').addEventListener('click', () => { - location.reload(); -}); - -function clearMovieDetails() { - const movieDetailsContainer = document.getElementById('quiz-container'); - if (movieDetailsContainer) { - movieDetailsContainer.innerHTML = ''; - } - document.getElementById('regenerate-questions').style.display = 'none'; - document.getElementById('submit').style.display = 'none'; -} - -function showMovies(movies){ - main.innerHTML = ''; - movies.forEach((movie) => { - const { id, poster_path, title, vote_average, overview } = movie; - const movieE1 = document.createElement('div'); - const voteAverage = vote_average.toFixed(1); - movieE1.classList.add('movie'); - - const movieImage = poster_path - ? `` - : `Error fetching results. Please try again later.
'; + console.log('Error fetching search results:', error); + } + finally { hideSpinner(); } - - updateBrowserURL(searchQuery); - document.title = `Search Results for "${searchQuery}" - The MovieVerse`; - - hideSpinner(); } document.querySelector('button[onclick="showResults(\'movie\')"]').addEventListener('click', function() { @@ -355,7 +707,7 @@ function displayResults(results, category, searchTerm) { const capitalizedCategory = category.charAt(0).toUpperCase() + category.slice(1); if (results.length === 0) { - container.innerHTML = `No results found for "${searchTerm}" in the ${capitalizedCategory} category. Please try again with a different query or look for it in another category.
`; + container.innerHTML = `No results found for "${searchTerm}" in the ${capitalizedCategory} category or no results with the specified filters found. Please try again with a different query or change your filters.
`; container.style.height = '800px'; return; } @@ -374,10 +726,21 @@ function showMovies(items, container, category) { const isMovie = item.title && hasVoteAverage; const isTvSeries = item.name && hasVoteAverage && category === 'tv'; - const title = item.title || item.name || "N/A"; - const overview = item.overview || 'No overview available.'; + let title = item.title || item.name || "N/A"; + const words = title.split(' '); + + if (words.length >= 9) { + words[8] = '...'; + title = words.slice(0, 9).join(' '); + } + + let overview = item.overview || 'No overview available.'; const biography = item.biography || 'Click to view the details of this person.'; + if (overview === '') { + overview = 'No overview available.'; + } + const { id, profile_path, poster_path } = item; const imagePath = profile_path || poster_path ? IMGPATH + (profile_path || poster_path) : null; @@ -405,10 +768,14 @@ function showMovies(items, container, category) { movieContentHTML += `No custom images uploaded.
'; + deleteSelectedImagesBtn.style.display = 'none'; + return; + } + + customImages.forEach((image, index) => { + const imageContainer = document.createElement('div'); + imageContainer.classList.add('image-container'); + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.classList.add('delete-checkbox'); + checkbox.value = index; + + const img = document.createElement('img'); + img.src = image.dataURL; + img.alt = image.name; + img.style.width = '100px'; + + const imageName = document.createElement('span'); + imageName.classList.add('image-name'); + imageName.textContent = image.name; + + // Toggle checkbox when image container is clicked + imageContainer.addEventListener('click', (e) => { + if (e.target !== checkbox) { // Prevent checkbox click event from toggling twice + checkbox.checked = !checkbox.checked; + } + }); + + imageContainer.appendChild(checkbox); + imageContainer.appendChild(img); + imageContainer.appendChild(imageName); + customImagesContainer.appendChild(imageContainer); + }); + + deleteSelectedImagesBtn.style.display = 'block'; + } function loadSettings() { let savedBg = localStorage.getItem('backgroundImage'); - const bgSelect = document.getElementById('background-select'); const customImages = JSON.parse(localStorage.getItem('customImages')) || []; const savedTextColor = localStorage.getItem('textColor'); const savedFontSize = localStorage.getItem('fontSize'); if (!savedBg) { - savedBg = '../../images/universe-1.png'; + savedBg = DEFAULT_BACKGROUND_IMAGE; + } + + const availableBackgrounds = [ + '../../images/universe-1.webp', '../../images/universe-2.webp', '../../images/universe-22.webp', + '../../images/universe-3.webp', '../../images/universe-4.webp', '../../images/universe-5.webp', + '../../images/universe-6.webp', '../../images/universe-7.webp', '../../images/universe-8.webp', + '../../images/universe-9.webp', '../../images/universe-10.webp', '../../images/universe-11.webp', + '../../images/universe-12.webp', '../../images/universe-13.webp', '../../images/universe-14.webp', + '../../images/universe-15.webp', '../../images/universe-16.webp', '../../images/universe-17.webp', + '../../images/universe-18.webp', '../../images/universe-19.webp', '../../images/universe-20.webp', + '../../images/universe-21.webp', '../../images/universe.webp', '../../images/universe-23.webp', + '../../images/black.webp', '../../images/grey.webp', '../../images/blue.webp', + '../../images/silver.webp', '../../images/gold.webp', '../../images/rose.webp', + '../../images/pink.webp', '../../images/red.webp', '../../images/green.webp', + '../../images/brown.webp', '../../images/purple.webp', '../../images/orange.webp', + '../../images/yellow.webp' + ]; + + if (!availableBackgrounds.includes(savedBg) && !customImages.find(image => image.dataURL === savedBg)) { + savedBg = DEFAULT_BACKGROUND_IMAGE; + localStorage.setItem('backgroundImage', savedBg); } - document.body.style.backgroundImage = `url('${savedBg}')`; + + if (savedBg) { + let imageUrl = savedBg; + if (savedBg === DEFAULT_BACKGROUND_IMAGE) { + if (window.innerWidth <= 680) { + imageUrl = '../../images/universe-1-small.webp'; + } + else if (window.innerWidth <= 1124) { + imageUrl = '../../images/universe-1-medium.webp'; + } + } + document.body.style.backgroundImage = `url('${imageUrl}')`; + } + const foundImage = customImages.find(image => image.dataURL === savedBg); - bgSelect.value = foundImage ? foundImage.dataURL : savedBg; if (savedTextColor) { document.querySelectorAll('h1, h2, h3, p, a, span, div, button, input, select, textarea, label, li').forEach(element => { @@ -53,61 +170,84 @@ document.addEventListener('DOMContentLoaded', () => { }); textColorInput.value = savedTextColor; } + if (savedFontSize) { const size = savedFontSize === 'small' ? '12px' : savedFontSize === 'medium' ? '16px' : '20px'; document.body.style.fontSize = size; fontSizeSelect.value = savedFontSize; } + + if (bgSelect) { + bgSelect.value = foundImage ? foundImage.dataURL : savedBg; + } } - document.getElementById('delete-uploaded-btn').addEventListener('click', function() { - deleteImagesPrompt(); - }); + function loadCustomBackgrounds() { + const bgSelect = document.getElementById('background-select'); + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + + if (bgSelect) { + customImages.forEach(image => { + const newOption = new Option(image.name, image.dataURL); + bgSelect.add(newOption); + }); + } + } }); -function loadCustomBackgrounds() { - const bgSelect = document.getElementById('background-select'); - const customImages = JSON.parse(localStorage.getItem('customImages')) || []; +document.addEventListener('DOMContentLoaded', () => { + const uploadButton = document.getElementById('upload-bg-btn'); - customImages.forEach(image => { - const newOption = new Option(image.name, image.dataURL); - bgSelect.add(newOption); - }); -} + if (!uploadButton) { + console.log('Upload button not found'); + return; + } -document.getElementById('upload-bg-btn').addEventListener('click', function() { - const fileInput = document.getElementById('custom-bg-upload'); - const imageNameInput = document.getElementById('custom-bg-name'); - const bgSelect = document.getElementById('background-select'); + uploadButton.addEventListener('click', function() { + const fileInput = document.getElementById('custom-bg-upload'); + const imageNameInput = document.getElementById('custom-bg-name'); + const bgSelect = document.getElementById('background-select'); - if (fileInput.files.length > 0) { - const file = fileInput.files[0]; - const customImages = JSON.parse(localStorage.getItem('customImages')) || []; - const totalSize = customImages.reduce((sum, img) => sum + img.dataURL.length, 0); - const quota = 4.5 * 1024 * 1024; + if (fileInput && fileInput.files.length > 0) { + const file = fileInput.files[0]; + const customImages = JSON.parse(localStorage.getItem('customImages')) || []; + const totalSize = customImages.reduce((sum, img) => sum + img.dataURL.length, 0); + const quota = 4.5 * 1024 * 1024; // 4.5 MB - if (totalSize >= quota) { - handleQuotaExceedance(); - } - else { - if (file.size > 204800) { // 200KB - resizeImage(file, 204800, (resizedDataUrl) => { + if (totalSize >= quota) { + handleQuotaExceedance(); + window.location.reload(); + return; + } + + if (file.size > 204800) { // 200 KB + resizeImage(file, 204800, (resizedDataUrl, err) => { + if (err) { + alert(`Error resizing the image due to a limitation in your browser. Browser error: ${err.message} Your image might still appear as the background, but it will not be stable. We recommend deleting it and then using a different browser or uploading an image smaller than 1MB.`); + return; + } processImageUpload(resizedDataUrl, imageNameInput, bgSelect); alert('The uploaded image was resized to fit the size limit of 200KB.'); + window.location.reload(); }); } else { const reader = new FileReader(); reader.onload = function (e) { processImageUpload(e.target.result, imageNameInput, bgSelect); + window.location.reload(); + }; + reader.onerror = function () { + alert('Error reading the file.'); + window.location.reload(); }; reader.readAsDataURL(file); } } - } - else { - alert('Please select an image to upload.'); - } + else { + alert('Please select an image to upload.'); + } + }); }); function handleQuotaExceedance() { @@ -178,37 +318,56 @@ function processImageUpload(dataUrl, imageNameInput, bgSelect) { } function resizeImage(file, maxSize, callback) { + if (!(window.FileReader && window.Blob && window.HTMLCanvasElement)) { + callback(null, new Error('Your browser does not support resizing images. Please use a different browser or upload an image smaller than 200KB.')); + return; + } + const reader = new FileReader(); reader.onload = function(e) { const img = new Image(); img.onload = function() { - let canvas = document.createElement('canvas'); - let ctx = canvas.getContext('2d'); - - let width = img.width; - let height = img.height; - - if (width > height) { - if (width > maxSize) { - height *= maxSize / width; - width = maxSize; + try { + let canvas = document.createElement('canvas'); + let ctx = canvas.getContext('2d'); + + let width = img.width; + let height = img.height; + + if (width > height) { + if (width > maxSize) { + height *= maxSize / width; + width = maxSize; + } } - } - else { - if (height > maxSize) { - width *= maxSize / height; - height = maxSize; + else { + if (height > maxSize) { + width *= maxSize / height; + height = maxSize; + } } - } - canvas.width = width; - canvas.height = height; - ctx.drawImage(img, 0, 0, width, height); + canvas.width = width; + canvas.height = height; + ctx.drawImage(img, 0, 0, width, height); - callback(canvas.toDataURL('image/jpeg')); + callback(canvas.toDataURL('image/jpeg'), null); + + canvas.height = 0; + canvas.width = 0; + canvas = null; + } + catch (error) { + callback(null, error); + } + }; + img.onerror = function() { + callback(null, new Error('Failed to load the image.')); }; img.src = e.target.result; }; + reader.onerror = function() { + callback(null, new Error('Failed to read the image file.')); + }; reader.readAsDataURL(file); } - diff --git a/MovieVerse-Mobile/app/js/sign-in.js b/MovieVerse-Mobile/app/js/sign-in.js index 0e3d5140..5cd52e60 100644 --- a/MovieVerse-Mobile/app/js/sign-in.js +++ b/MovieVerse-Mobile/app/js/sign-in.js @@ -45,21 +45,34 @@ const db = getFirestore(app); document.getElementById('signInForm').addEventListener('submit', async function(event) { event.preventDefault(); - const email = document.getElementById('signInEmail').value; - const password = document.getElementById('signInPassword').value; + try { - const usersRef = collection(db, "MovieVerseUsers"); - const q = query(usersRef, where("email", "==", email), where("password", "==", password)); - const querySnapshot = await getDocs(q); + const email = document.getElementById('signInEmail').value; + const password = document.getElementById('signInPassword').value; - if (!querySnapshot.empty) { - alert('Successfully signed in!'); - localStorage.setItem('isSignedIn', JSON.stringify(true)); - localStorage.setItem('currentlySignedInMovieVerseUser', email); - window.location.href = '../../index.html'; + const usersRef = collection(db, "MovieVerseUsers"); + const q = query(usersRef, where("email", "==", email), where("password", "==", password)); + const querySnapshot = await getDocs(q); + + if (!querySnapshot.empty) { + alert('Successfully signed in!'); + localStorage.setItem('isSignedIn', JSON.stringify(true)); + localStorage.setItem('currentlySignedInMovieVerseUser', email); + window.location.href = '../../index.html'; + } else { + alert('Invalid email or password. Ensure that you have entered a correct combination of email and password - one that we have on file.'); + } } - else { - alert('Invalid email or password. Ensure that you have entered a correct combination of email and password - one that we have on file.'); + catch (error) { + console.error("Error fetching user list: ", error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('signInForm'); + if (noUserSelected) { + noUserSelected.innerHTML = "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + hideSpinner(); + } } }); diff --git a/MovieVerse-Mobile/app/js/triviaModule.js b/MovieVerse-Mobile/app/js/triviaModule.js new file mode 100644 index 00000000..4ae5c28c --- /dev/null +++ b/MovieVerse-Mobile/app/js/triviaModule.js @@ -0,0 +1,69 @@ +import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js"; +import { getFirestore, doc, setDoc, getDoc } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js"; + +const firebaseConfig = { + apiKey: atob("QUl6YVN5REw2a1FuU2ZVZDhVdDhIRnJwS3VpdnF6MXhkWG03aw=="), + authDomain: atob("bW92aWV2ZXJzZS1hcHAuZmlyZWJhc2VhcHAuY29t"), + projectId: "movieverse-app", + storageBucket: atob("bW92aWV2ZXJzZS1hcHAuYXBwc3BvdC5jb20="), + messagingSenderId: atob("ODAyOTQzNzE4ODcx"), + appId: atob("MTo4MDI5NDM3MTg4NzE6d2ViOjQ4YmM5MTZjYzk5ZTI3MjQyMTI3OTI=") +}; + +const app = initializeApp(firebaseConfig); + +const db = getFirestore(app); + +export async function updateTriviaStats(currentUserEmail, correctAnswers, totalQuestions) { + if (!currentUserEmail) { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { totalCorrect: 0, totalAttempted: 0 }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } + else { + try { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + const docSnap = await getDoc(statsRef); + let triviaStats = docSnap.exists() ? docSnap.data() : {totalCorrect: 0, totalAttempted: 0}; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + await setDoc(statsRef, triviaStats, {merge: true}); + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } + catch (error) { + if (error.code === 'resource-exhausted') { + let triviaStats = JSON.parse(localStorage.getItem('triviaStats')) || { totalCorrect: 0, totalAttempted: 0 }; + triviaStats.totalCorrect += correctAnswers; + triviaStats.totalAttempted += totalQuestions; + localStorage.setItem('triviaStats', JSON.stringify(triviaStats)); + } + } + } +} + +export async function getTriviaStats(currentUserEmail) { + if (!currentUserEmail) { + return JSON.parse(localStorage.getItem('triviaStats')) || { totalCorrect: 0, totalAttempted: 0 }; + } + else { + const statsRef = doc(db, 'userTriviaStats', currentUserEmail); + try { + const docSnap = await getDoc(statsRef); + if (docSnap.exists()) { + console.log("Fetched trivia stats from Firebase:", docSnap.data()); + return docSnap.data(); + } + else { + console.log("No trivia stats found in Firebase for:", currentUserEmail); + return { totalCorrect: 0, totalAttempted: 0 }; + } + } + catch (error) { + if (error.code === 'resource-exhausted') { + console.error("Firebase quota exceeded, fetching trivia stats from localStorage."); + return JSON.parse(localStorage.getItem('triviaStats')) || {totalCorrect: 0, totalAttempted: 0}; + } + } + } +} diff --git a/MovieVerse-Mobile/app/js/tv-details.js b/MovieVerse-Mobile/app/js/tv-details.js index b92ee4fe..ebadb344 100644 --- a/MovieVerse-Mobile/app/js/tv-details.js +++ b/MovieVerse-Mobile/app/js/tv-details.js @@ -20,7 +20,7 @@ const form = document.getElementById("form1"); const SEARCHPATH = `https://${getMovieVerseData()}/3/search/movie?&${generateMovieNames()}${getMovieCode()}&query=`; const main = document.getElementById("main"); -const IMGPATH = "https://image.tmdb.org/t/p/w1280"; +const IMGPATH = "https://image.tmdb.org/t/p/w780"; const searchTitle = document.getElementById("search-title"); let initialMainContent; @@ -55,7 +55,7 @@ async function fetchGenreMap() { localStorage.setItem('genreMap', JSON.stringify(genreMap)); } catch (error) { - console.error('Error fetching genre map:', error); + console.log('Error fetching genre map:', error); } } @@ -87,7 +87,7 @@ async function rotateUserStats() { { label: "Favorite Movies", getValue: () => { - const favoritedMovies = JSON.parse(localStorage.getItem('favoritesMovies')) || []; + const favoritedMovies = JSON.parse(localStorage.getItem('moviesFavorited')) || []; return favoritedMovies.length; } }, @@ -95,8 +95,37 @@ async function rotateUserStats() { label: "Favorite Genre", getValue: () => { const mostCommonGenreCode = getMostCommonGenre(); - const genreMap = JSON.parse(localStorage.getItem('genreMap')) || {}; - return genreMap[mostCommonGenreCode] || 'Not Available'; + const genreMapString = localStorage.getItem('genreMap'); + if (!genreMapString) { + console.log('No genre map found in localStorage.'); + return 'Not Available'; + } + + let genreMap; + try { + genreMap = JSON.parse(genreMapString); + } + catch (e) { + console.log('Error parsing genre map:', e); + return 'Not Available'; + } + + let genreObject; + if (Array.isArray(genreMap)) { + genreObject = genreMap.reduce((acc, genre) => { + acc[genre.id] = genre.name; + return acc; + }, {}); + } + else if (typeof genreMap === 'object' && genreMap !== null) { + genreObject = genreMap; + } + else { + console.log('genreMap is neither an array nor a proper object:', genreMap); + return 'Not Available'; + } + + return genreObject[mostCommonGenreCode] || 'Not Available'; } }, { label: "Watchlists Created", getValue: () => localStorage.getItem('watchlistsCreated') || 0 }, @@ -229,31 +258,16 @@ document.addEventListener('DOMContentLoaded', rotateUserStats); function setStarRating(rating) { const stars = document.querySelectorAll('.rating .star'); stars.forEach(star => { - star.style.color = star.dataset.value > rating ? 'grey' : 'gold'; + star.style.color = star.dataset.value > rating ? 'white' : 'gold'; }); document.getElementById('rating-value').textContent = `${rating}.0/5.0`; } -document.addEventListener('DOMContentLoaded', () => { - setInitialStarRating(tvSeriesId); -}); - function getMovieVerseData(input) { return String.fromCharCode(97, 112, 105, 46, 116, 104, 101, 109, 111, 118, 105, 101, 100, 98, 46, 111, 114, 103); } -function setInitialStarRating(tvSeriesId) { - const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; - const tvSeriesRating = savedRatings[tvSeriesId]; - if (tvSeriesRating) { - setStarRating(tvSeriesRating); - } - else { - setStarRating(0); - } -} - document.querySelectorAll('.rating .star').forEach(star => { star.addEventListener('mouseover', (e) => { setStarRating(e.target.dataset.value); @@ -532,7 +546,6 @@ async function fetchTvDetails(tvSeriesId) { const response = await fetch(urlWithAppend); const tvSeriesDetails = await response.json(); const imdbId = tvSeriesDetails.external_ids.imdb_id; - const imdbRating = await fetchTVRatings(imdbId); populateTvSeriesDetails(tvSeriesDetails, imdbRating); @@ -551,25 +564,23 @@ async function fetchTvDetails(tvSeriesId) {Overview: ${tvSeries.overview || 'Overview not available.'}
`; + detailsHTML += `Original Title: ${tvSeries.original_name || 'Not available'}
`; + + detailsHTML += `Tagline: ${tvSeries.tagline || 'Not available'}
`; + const genres = tvSeries.genres && tvSeries.genres.length ? tvSeries.genres.map(genre => genre.name).join(', ') : 'Genres not available'; detailsHTML += `Genres: ${genres}
`; @@ -609,7 +624,7 @@ function populateTvSeriesDetails(tvSeries, imdbRating) { const voteAverage = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; const voteCount = tvSeries.vote_count ? tvSeries.vote_count.toLocaleString() : 'N/A'; - detailsHTML += `User Rating: ${(voteAverage / 2).toFixed(1)}/5.0 (based on ${voteCount} votes)
`; + detailsHTML += `MovieVerse User Rating: ${(voteAverage / 2).toFixed(1)}/5.0 (based on ${voteCount} votes)
`; if (tvSeries.external_ids && tvSeries.external_ids.imdb_id) { const imdbId = tvSeries.external_ids.imdb_id; @@ -617,15 +632,34 @@ function populateTvSeriesDetails(tvSeries, imdbRating) { detailsHTML += `IMDb Rating: ${imdbRating}
`; } else { - detailsHTML += `IMDb Rating: N/A
`; + detailsHTML += `IMDb Rating: IMDb rating not available
`; } - const homepage = tvSeries.homepage ? `Visit` : 'Not available'; + const tmdbRating = tvSeries.vote_average ? tvSeries.vote_average.toFixed(1) : 'N/A'; + detailsHTML += `TMDB Rating: ${tmdbRating}/10.0
`; + + const homepage = tvSeries.homepage ? `Visit homepage` : 'Not available'; detailsHTML += `Homepage: ${homepage}
`; + detailsHTML += `Seasons: ${tvSeries.number_of_seasons || 0}, Episodes: ${tvSeries.number_of_episodes || 0}
`; + + if (tvSeries.origin_country && tvSeries.origin_country.length > 0) { + const countryNames = tvSeries.origin_country.map(code => getCountryName(code)).join(', '); + detailsHTML += `Country of Origin: ${countryNames}
`; + } + else { + detailsHTML += `Country of Origin: Information not available
`; + } + + const languageName = getLanguageName(tvSeries.original_language); + detailsHTML += `Original Language: ${languageName}
`; + + const productionCountries = tvSeries.production_countries && tvSeries.production_countries.length > 0 ? tvSeries.production_countries.map(country => getCountryName(country.iso_3166_1)).join(', ') : 'Information not available'; + detailsHTML += `Production Countries: ${productionCountries}
`; + if (tvSeries.created_by && tvSeries.created_by.length) { const creatorsLinks = tvSeries.created_by.map(creator => - `${creator.name}` + `${creator.name}` ).join(', '); detailsHTML += `Directors: ${creatorsLinks}
`; } @@ -635,7 +669,8 @@ function populateTvSeriesDetails(tvSeries, imdbRating) { if (tvSeries.credits && tvSeries.credits.cast && tvSeries.credits.cast.length) { let castHTML = tvSeries.credits.cast.slice(0, 100).map(castMember => { - return `${castMember.name}`; + const escapedName = castMember.name.replace(/'/g, "\\'"); + return `${castMember.name}`; }).join(', '); detailsHTML += `Cast: ${castHTML}
`; } @@ -663,47 +698,276 @@ function populateTvSeriesDetails(tvSeries, imdbRating) { detailsHTML += `Similar TV Series: Information not available
`; } - detailsHTML += `Tagline: ${tvSeries.tagline || 'Not available'}
`; + if (tvSeries.last_episode_to_air) { + detailsHTML += `Last Episode: ${tvSeries.last_episode_to_air.name || 'Title not available'} - "${tvSeries.last_episode_to_air.overview || 'Overview not available.'}"
`; + } - detailsHTML += `Seasons: ${tvSeries.number_of_seasons || 0}, Episodes: ${tvSeries.number_of_episodes || 0}
`; + const tvSeriesTitleEncoded = encodeURIComponent(title); + const streamingProviders = await fetchTvSeriesStreamingLinks(tvSeries.id); + const streamingHTML = streamingProviders.length > 0 ? streamingProviders.map(provider => { + let providerLink = `https://www.google.com/search?q=watch+${tvSeriesTitleEncoded}+on+${encodeURIComponent(provider.provider_name)}`; + switch(provider.provider_name.toLowerCase()) { + case 'netflix': + providerLink = `https://www.netflix.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'disney plus': + providerLink = `https://www.disneyplus.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hbo max': + providerLink = `https://www.hbomax.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'hulu': + providerLink = `https://www.hulu.com/search?q=${tvSeriesTitleEncoded}`; + break; + case 'amazon prime video': + providerLink = `https://www.amazon.com/s?k=${tvSeriesTitleEncoded}`; + break; + case 'apple tv plus': + providerLink = `https://tv.apple.com/search?term=${tvSeriesTitleEncoded}`; + break; + case 'stan': + providerLink = `https://www.stan.com.au/search?q=${tvSeriesTitleEncoded}`; + break; + case 'player': + providerLink = `https://player.pl/szukaj?search=${tvSeriesTitleEncoded}`; + break; + } - // if (tvSeries.seasons && tvSeries.seasons.length) { - // const seasonsToShow = tvSeries.seasons.slice(0, 3); - // - // seasonsToShow.forEach(season => { - // detailsHTML += `${season.name || 'Season information not available'}: ${season.overview || 'Overview not available.'}
`; - // }); - // } + return ` + + `; + }).join('') + ` + + ` : 'No streaming options available.'; - if (tvSeries.origin_country && tvSeries.origin_country.length > 0) { - const countryNames = tvSeries.origin_country.map(code => getCountryName(code)).join(', '); - detailsHTML += `Country of Origin: ${countryNames}
`; + detailsHTML += `Streaming Options: ${streamingHTML}
`; + + if (tvSeries.keywords && tvSeries.keywords.results && tvSeries.keywords.results.length) { + let keywordsHTML = tvSeries.keywords.results.map(keyword => keyword.name).join(', '); + detailsHTML += `Keywords: ${keywordsHTML}
`; } else { - detailsHTML += `Country of Origin: Information not available
`; + detailsHTML += `Keywords: Information not available
`; } - const languageName = getLanguageName(tvSeries.original_language); - detailsHTML += `Original Language: ${languageName}
`; + const mediaUrl = `https://${getMovieVerseData()}/3/tv/${tvSeries.id}/images?${generateMovieNames()}${getMovieCode()}`; + const mediaResponse = await fetch(mediaUrl); + const mediaData = await mediaResponse.json(); + const images = mediaData.backdrops; + + const detailsContainer = document.getElementById('movie-description'); + + let mediaContainer = document.getElementById('media-container'); + if (!mediaContainer) { + mediaContainer = document.createElement('div'); + mediaContainer.id = 'media-container'; + mediaContainer.style = ` + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + position: relative; + width: 450px; + margin: 20px auto; + overflow: hidden; + max-width: 100%; + box-sizing: border-box; + `; + detailsContainer.appendChild(mediaContainer); + } - if (tvSeries.last_episode_to_air) { - detailsHTML += `Last Episode: ${tvSeries.last_episode_to_air.name || 'Title not available'} - "${tvSeries.last_episode_to_air.overview || 'Overview not available.'}"
`; + let mediaTitle = document.getElementById('media-title'); + if (!mediaTitle) { + mediaTitle = document.createElement('p'); + mediaTitle.id = 'media-title'; + mediaTitle.textContent = 'Media:'; + mediaTitle.style = ` + font-weight: bold; + align-self: start; + margin-bottom: 5px; + `; } - if (tvSeries.keywords && tvSeries.keywords.results && tvSeries.keywords.results.length) { - let keywordsHTML = tvSeries.keywords.results.map(keyword => keyword.name).join(', '); - detailsHTML += `Keywords: ${keywordsHTML}
`; + let imageElement = document.getElementById('series-media-image'); + if (!imageElement) { + imageElement = document.createElement('img'); + imageElement.id = 'series-media-image'; + imageElement.style = ` + max-width: 100%; + max-height: 210px; + transition: opacity 0.5s ease-in-out; + opacity: 1; + border-radius: 16px; + cursor: pointer; + `; + imageElement.loading = 'lazy'; + mediaContainer.appendChild(imageElement); } - else { - detailsHTML += `Keywords: Information not available
`; + + if (images.length > 0) { + imageElement.src = `https://image.tmdb.org/t/p/w780${images[0].file_path}`; + } + + imageElement.addEventListener('click', function() { + let imageUrl = this.src.replace('w780', 'w1280'); + const modalHtml = ` +No media available
'; } document.getElementById('movie-description').innerHTML = detailsHTML; + document.getElementById('movie-description').appendChild(mediaTitle); + document.getElementById('movie-description').appendChild(mediaContainer); +} + +async function fetchTvSeriesStreamingLinks(tvSeriesId) { + const url = `https://${getMovieVerseData()}/3/tv/${tvSeriesId}/watch/providers?${generateMovieNames()}${getMovieCode()}`; + try { + const response = await fetch(url); + const data = await response.json(); + const results = data.results || {}; + let providersMap = {}; + + Object.values(results).forEach(region => { + if (region.flatrate) { + region.flatrate.forEach(provider => { + providersMap[provider.provider_id] = provider; + }); + } + }); + + return Object.values(providersMap).slice(0, 7); + } + catch (error) { + console.error('Error fetching TV series streaming links:', error); + return []; + } +} + +function updateUniqueDirectorsViewed(directorId) { + let viewedDirectors = JSON.parse(localStorage.getItem('uniqueDirectorsViewed')) || []; + if (!viewedDirectors.includes(directorId)) { + viewedDirectors.push(directorId); + localStorage.setItem('uniqueDirectorsViewed', JSON.stringify(viewedDirectors)); + } +} + +function updateActorVisitCount(actorId, actorName) { + let actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + if (!actorVisits[actorId]) { + actorVisits[actorId] = { count: 0, name: actorName }; + } + + actorVisits[actorId].count += 1; + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); +} + +function updateDirectorVisitCount(directorId, directorName) { + let directorVisits = JSON.parse(localStorage.getItem('directorVisits')) || {}; + if (!directorVisits[directorId]) { + directorVisits[directorId] = { count: 0, name: directorName }; + } + + directorVisits[directorId].count += 1; + localStorage.setItem('directorVisits', JSON.stringify(directorVisits)); } -function selectActorId(actorId) { +function selectActorId(actorId, actorName) { + const actorVisits = JSON.parse(localStorage.getItem('actorVisits')) || {}; + const uniqueActorsViewed = JSON.parse(localStorage.getItem('uniqueActorsViewed')) || []; + + if (!uniqueActorsViewed.includes(actorId)) { + uniqueActorsViewed.push(actorId); + localStorage.setItem('uniqueActorsViewed', JSON.stringify(uniqueActorsViewed)); + } + + if (actorVisits[actorId]) { + actorVisits[actorId].count++; + } + else { + actorVisits[actorId] = { count: 1, name: actorName }; + } + + localStorage.setItem('actorVisits', JSON.stringify(actorVisits)); + localStorage.setItem('selectedActorId', actorId); - window.location.href = 'actor-details.html' + window.location.href = 'actor-details.html'; } function selectTvSeriesId(tvSeriesId) { @@ -724,8 +988,11 @@ function hideSpinner() { document.getElementById('myModal').classList.remove('modal-visible'); } -function handleCreatorClick(creatorId) { +function handleCreatorClick(creatorId, creatorName) { localStorage.setItem('selectedDirectorId', creatorId); + document.title = `${creatorName} - Director's Details`; + updateUniqueDirectorsViewed(creatorId); + updateDirectorVisitCount(creatorId, creatorName); window.location.href = 'director-details.html'; } @@ -740,7 +1007,7 @@ document.addEventListener('DOMContentLoaded', () => { document.getElementById('clear-search-btn').style.display = 'none'; - const savedRatings = JSON.parse(localStorage.getItem('movieRatings')) || {}; + const savedRatings = JSON.parse(localStorage.getItem('tvSeriesRatings')) || {}; const movieRating = savedRatings[tvSeriesId] || 0; setStarRating(movieRating); }); @@ -782,7 +1049,7 @@ async function showMovieOfTheDay() { } } catch (error) { - console.error('Error fetching movie:', error); + console.log('Error fetching movie:', error); fallbackMovieSelection(); } } diff --git a/MovieVerse-Mobile/app/js/user-profile.js b/MovieVerse-Mobile/app/js/user-profile.js index 0db0e1ac..f5f730f1 100644 --- a/MovieVerse-Mobile/app/js/user-profile.js +++ b/MovieVerse-Mobile/app/js/user-profile.js @@ -1,6 +1,7 @@ import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js"; -import { getFirestore, doc, getDoc, setDoc, deleteField } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js"; -import { getStorage, ref, uploadBytes, getDownloadURL, deleteObject } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-storage.js"; +import { getFirestore, doc, getDoc, setDoc, query, collection, where, getDocs, serverTimestamp, deleteDoc } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js"; +import { getAverageMovieRating } from './ratings-module.js'; +import { getTriviaStats } from './triviaModule.js'; function showSpinner() { document.getElementById('myModal').classList.add('modal-visible'); @@ -54,82 +55,445 @@ const db = getFirestore(app); document.addEventListener('DOMContentLoaded', function() { handleProfileDisplay(); setupEventListeners(); + setupSearchListeners(); }); +function updateProgressCircles(movieRating, triviaScore) { + const movieRatingPercent = movieRating; + const triviaScorePercent = triviaScore; + + setProgress(document.getElementById('avgMovieRatingCircle'), document.getElementById('avgMovieRatingText'), movieRatingPercent); + setProgress(document.getElementById('avgTriviaScoreCircle'), document.getElementById('avgTriviaScoreText'), triviaScorePercent); +} + +function setProgress(circle, text, percent) { + const radius = circle.r.baseVal.value; + const circumference = radius * 2 * Math.PI; + + circle.style.transition = 'none'; + circle.style.strokeDasharray = `${circumference} ${circumference}`; + circle.style.strokeDashoffset = circumference; + circle.getBoundingClientRect(); + + setTimeout(() => { + const offset = circumference - (percent / 100) * circumference; + circle.style.transition = 'stroke-dashoffset 0.6s ease-out, stroke 0.6s ease'; + circle.style.strokeDashoffset = offset; + circle.style.setProperty('--progress-color', percent > 50 ? '#4CAF50' : '#2196F3'); + text.textContent = `${Math.round(percent)}%`; + text.style.opacity = 1; + }, 10); +} + function handleProfileDisplay() { - showSpinner(); const isSignedIn = JSON.parse(localStorage.getItem('isSignedIn')) || false; const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); - const profileKey = `profileInfo-${userEmail}`; - const profile = JSON.parse(localStorage.getItem(profileKey)) || {}; const welcomeMessage = document.getElementById('welcomeMessage'); - const profileContainer = document.getElementById('profileContainer'); const signInPrompt = document.getElementById('signInPrompt'); + const viewMyProfileBtn = document.getElementById('viewMyProfileBtn'); + const profileContainer = document.getElementById('profileContainer'); + profileContainer.style.display = 'none'; + + showSpinner(); if (isSignedIn && userEmail) { - welcomeMessage.textContent = `Welcome, ${profile.username || 'User'}!`; - profileContainer.style.display = 'block'; - signInPrompt.style.display = 'none'; - window.document.title = `${profile.username || 'User'}'s Profile - The MovieVerse`; - loadProfile(); - hideSpinner(); + loadProfile(userEmail); + viewMyProfileBtn.disabled = false; + viewMyProfileBtn.style.display = 'block'; } else { - document.getElementById('welcomeMessage').textContent = ''; - document.getElementById('profileContainer').style.display = 'none'; - signInPrompt.textContent = 'Please sign in to view your profile'; - signInPrompt.style.fontWeight = '800'; - signInPrompt.style.color = '#ff8623'; - hideSpinner(); + welcomeMessage.textContent = 'Please sign in to view your profile'; + signInPrompt.style.display = 'block'; + viewMyProfileBtn.disabled = true; + viewMyProfileBtn.style.display = 'none'; + } + + document.getElementById('viewMyProfileBtn').addEventListener('click', () => { + loadCurrentUserProfile(); + }); + + function loadCurrentUserProfile() { + const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + if (currentUserEmail) { + loadProfile(currentUserEmail); + } + else { + console.error("No user is currently signed in"); + } + } + + hideSpinner(); +} + +function setupSearchListeners() { + try { + const searchUserInput = document.getElementById('searchUserInput'); + const searchUserResults = document.getElementById('searchUserResults'); + + searchUserInput.addEventListener('input', () => { + const searchText = searchUserInput.value.trim(); + + if (searchText) { + performSearch(searchText); + } + else { + searchUserResults.innerHTML = ''; + searchUserResults.style.display = 'none'; + } + }); + } + catch (error) { + console.error("Error fetching user list: ", error); + if (error.code === 'resource-exhausted') { + const noUserSelected = document.getElementById('profileContainer'); + if (noUserSelected) { + noUserSelected.innerHTML = "Sorry, our database is currently overloaded. Please try reloading once more, and if that still doesn't work, please try again in a couple hours. For full transparency, we are currently using a database that has a limited number of reads and writes per day due to lack of funding. Thank you for your patience as we work on scaling our services. At the mean time, feel free to use other MovieVerse features!"; + noUserSelected.style.height = '350px'; + } + } } } -async function loadProfile() { +async function performSearch(searchText) { + const searchUserResults = document.getElementById('searchUserResults'); + const db = getFirestore(); showSpinner(); - const userEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); - if (!userEmail) return; - const docRef = doc(db, 'profiles', userEmail); try { - const docSnap = await getDoc(docRef); - let profile = { - username: 'N/A', - dob: 'N/A', - bio: 'N/A', - favoriteGenres: 'N/A', - location: 'N/A', - favoriteMovie: 'N/A', - hobbies: 'N/A', - favoriteActor: 'N/A', - favoriteDirector: 'N/A', - personalQuote: 'N/A', - profileImage: '../../images/user-default.png' - }; + const userQuery = query(collection(db, 'profiles'), where('username', '>=', searchText), where('username', '<=', searchText + '\uf8ff')); + const querySnapshot = await getDocs(userQuery); - if (docSnap.exists()) { - profile = { ...profile, ...docSnap.data() }; - const imageUrl = profile.profileImage || '../../images/user-default.png'; - document.getElementById('profileImage').src = imageUrl; + searchUserResults.innerHTML = ''; + if (querySnapshot.empty) { + searchUserResults.innerHTML = `Bio: ${user.bio || 'Not Set'}
`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + } + hideSpinner(); + } + catch (error) { + console.error("Error during search: ", error); + searchUserResults.innerHTML = `