diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml
index ec152b22..482b72b5 100644
--- a/.idea/dataSources.local.xml
+++ b/.idea/dataSources.local.xml
@@ -1,6 +1,6 @@
-
@@ -236,8 +247,8 @@
${user.bio || ''}
`; + userDiv.appendChild(textDiv); + + searchUserResults.appendChild(userDiv); + }); + searchUserResults.style.display = 'block'; + return; + } try { showSpinner(); @@ -318,6 +409,7 @@ async function performSearch(searchText, isNewSearch = false) { lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1]; } + const results = []; for (const doc of querySnapshot.docs) { const user = doc.data(); const userDiv = document.createElement('div'); @@ -346,6 +438,7 @@ async function performSearch(searchText, isNewSearch = false) { userDiv.appendChild(textDiv); searchUserResults.appendChild(userDiv); + results.push({ email: user.email, bio: user.bio, imageUrl }); } searchUserResults.style.display = 'block'; @@ -363,6 +456,10 @@ async function performSearch(searchText, isNewSearch = false) { loadMoreButton.style.display = 'none'; } } + + if (isNewSearch) { + updateSearchCache(searchText, results); + } } catch (error) { console.error('Error fetching user list: ', error); if (error.code === 'resource-exhausted') { @@ -379,12 +476,31 @@ async function performSearch(searchText, isNewSearch = false) { let previouslySelectedUserElement = null; +const LOCAL_STORAGE_USER_CACHE_KEY = 'movieVerseUserCache'; + +function getCachedUsers() { + const cachedData = localStorage.getItem(LOCAL_STORAGE_USER_CACHE_KEY); + return cachedData ? JSON.parse(cachedData) : {}; +} + +function updateUserCache(email, userData) { + const currentCache = getCachedUsers(); + currentCache[email] = userData; + localStorage.setItem(LOCAL_STORAGE_USER_CACHE_KEY, JSON.stringify(currentCache)); +} + +function clearUserCache() { + localStorage.removeItem(LOCAL_STORAGE_USER_CACHE_KEY); +} + +const inMemoryUserCache = {}; // In-memory cache for user data + async function loadUserList() { try { showSpinner(); animateLoadingDots(); - const userLimit = 5; + const userLimit = 10; const messageLimit = 30; const sentMessagesQuery = query( @@ -393,6 +509,7 @@ async function loadUserList() { where('sender', '==', currentUserEmail), limit(messageLimit) ); + const receivedMessagesQuery = query( collection(db, 'messages'), orderBy('timestamp', 'desc'), @@ -407,19 +524,37 @@ async function loadUserList() { receivedMessagesSnapshot.forEach(doc => userEmails.add(doc.data().sender)); let users = []; + const cachedUsers = getCachedUsers(); + const emailsToFetch = []; + 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); - } - }); + if (cachedUsers[email]) { + users.push(cachedUsers[email]); + inMemoryUserCache[email] = cachedUsers[email]; + } else if (inMemoryUserCache[email]) { + users.push(inMemoryUserCache[email]); + } else { + emailsToFetch.push(email); + } } } + if (emailsToFetch.length > 0) { + const userQuery = query(collection(db, 'MovieVerseUsers'), where('email', 'in', emailsToFetch.slice(0, 10))); + + const userSnapshot = await getDocs(userQuery); + userSnapshot.forEach(doc => { + const userData = doc.data(); + if (userData.email) { + userData.lastUpdated = Date.now(); + users.push(userData); + updateUserCache(userData.email, userData); + inMemoryUserCache[userData.email] = userData; + } + }); + } + users.sort((a, b) => { const aLastMessage = [...sentMessagesSnapshot.docs, ...receivedMessagesSnapshot.docs].find( doc => doc.data().sender === a.email || doc.data().recipient === a.email @@ -450,12 +585,27 @@ async function loadUserList() { 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; + if (cachedUsers[user.email] && cachedUsers[user.email].profileImage) { + imageUrl = cachedUsers[user.email].profileImage; + } else if (inMemoryUserCache[user.email] && inMemoryUserCache[user.email].profileImage) { + imageUrl = inMemoryUserCache[user.email].profileImage; + } else { + const profileQuery = query(collection(db, 'profiles'), where('__name__', '==', user.email)); + const profileSnapshot = await getDocs(profileQuery); + if (!profileSnapshot.empty) { + const profileData = profileSnapshot.docs[0].data(); + imageUrl = profileData.profileImage || imageUrl; + + if (cachedUsers[user.email]) { + cachedUsers[user.email].profileImage = imageUrl; + updateUserCache(user.email, cachedUsers[user.email]); + } + inMemoryUserCache[user.email] = { + ...inMemoryUserCache[user.email], + profileImage: imageUrl, + }; + } } const img = document.createElement('img'); diff --git a/MovieVerse-Mobile/app/js/chatbot.js b/MovieVerse-Mobile/app/js/chatbot.js index db8687e8..d01a5e35 100644 --- a/MovieVerse-Mobile/app/js/chatbot.js +++ b/MovieVerse-Mobile/app/js/chatbot.js @@ -383,7 +383,7 @@ async function movieVerseResponse(message) { const model = genAI.getGenerativeModel({ model: 'gemini-1.5-flash', systemInstruction: - 'You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users.', + "You are MovieVerse Assistant - an AI Chatbot of the MovieVerse App. You are here to help users with movie-related or any other general queries. You are trained and powered by MovieVerse AI and Google to provide the best assistance. You can also provide information about movies, actors, directors, genres, and companies, or recommend movies to users. If the user asks anything about you or your information, you must by default identify yourself as MovieVerse Assistant, trained by The MovieVerse creator - Son Nguyen, and you're here to provide assistance for any movie-related or any other general inquiries. If the user asks who Son Nguyen is, refer to his portfolio website at: https://sonnguyenhoang.com, LinkedIn at: https://www.linkedin.com/in/hoangsonw, and GitHub at: https://github.com/hoangsonww. If anyone asked who created or trained you, you must refer to Son Nguyen as your creator.", }); conversationHistory.push({ role: 'user', parts: [{ text: message }] }); @@ -455,7 +455,7 @@ function removeMarkdown(text) { } function getAIResponse() { - const response = 'QUl6YVN5Q1RoUWVFdmNUb01ka0NqWlM3UTNxNzZBNUNlNjVyMW9r'; + const response = 'QUl6YVN' + '5QnRIdGJIVW' + 'N6enExT1p3Z' + 'XB0TXNOd' + 'Fdlal9s' + 'U0lWcWZ3'; return atob(response); } diff --git a/MovieVerse-Mobile/app/js/comments-tv.js b/MovieVerse-Mobile/app/js/comments-tv.js index 8064c3e3..99aa511c 100644 --- a/MovieVerse-Mobile/app/js/comments-tv.js +++ b/MovieVerse-Mobile/app/js/comments-tv.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { tvSeriesId, }); commentForm.reset(); + clearCommentCache(tvSeriesId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX = 'movieVerseTvCommentsCache'; + +function getCachedComments(tvSeriesId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(tvSeriesId, comments) { + localStorage.setItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(tvSeriesId) { + localStorage.removeItem(LOCAL_STORAGE_TV_COMMENT_KEY_PREFIX + tvSeriesId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const tvSeriesId = localStorage.getItem('selectedTvSeriesId'); + const cachedComments = getCachedComments(tvSeriesId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + 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; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` ++ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +
+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + const q = query(collection(db, 'comments'), where('tvSeriesId', '==', tvSeriesId), orderBy('commentDate', 'desc')); const querySnapshot = await getDocs(q); totalComments = querySnapshot.size; totalPages = Math.ceil(totalComments / commentsPerPage); + let commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -
- `; ++ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +
+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(tvSeriesId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/app/js/comments.js b/MovieVerse-Mobile/app/js/comments.js index 85b0c03c..e88e4fdc 100644 --- a/MovieVerse-Mobile/app/js/comments.js +++ b/MovieVerse-Mobile/app/js/comments.js @@ -12,6 +12,7 @@ import { import { app, db } from './firebase.js'; const commentForm = document.getElementById('comment-form'); + commentForm.addEventListener('submit', async e => { e.preventDefault(); const userName = document.getElementById('user-name').value; @@ -27,6 +28,7 @@ commentForm.addEventListener('submit', async e => { movieId, }); commentForm.reset(); + clearCommentCache(movieId); fetchComments(); } catch (error) { console.log('Error adding comment: ', error); @@ -60,6 +62,21 @@ const commentsPerPage = 3; let totalComments = 0; let totalPages = 1; +const LOCAL_STORAGE_COMMENT_KEY_PREFIX = 'movieVerseCommentsCache'; + +function getCachedComments(movieId) { + const cachedData = localStorage.getItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); + return cachedData ? JSON.parse(cachedData) : null; +} + +function updateCommentCache(movieId, comments) { + localStorage.setItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId, JSON.stringify({ comments, lastUpdated: Date.now() })); +} + +function clearCommentCache(movieId) { + localStorage.removeItem(LOCAL_STORAGE_COMMENT_KEY_PREFIX + movieId); +} + async function fetchComments() { try { const commentsContainer = document.getElementById('comments-container'); @@ -67,12 +84,55 @@ async function fetchComments() { commentsContainer.style.maxWidth = '100%'; const movieId = localStorage.getItem('selectedMovieId'); + const cachedComments = getCachedComments(movieId); + + if (cachedComments && cachedComments.comments.length > 0) { + const allComments = cachedComments.comments; + totalComments = allComments.length; + totalPages = Math.ceil(totalComments / commentsPerPage); + + let startIndex = (currentPage - 1) * commentsPerPage; + let endIndex = startIndex + commentsPerPage; + const pageComments = allComments.slice(startIndex, endIndex); + + pageComments.forEach(comment => { + const commentDate = new Date(comment.commentDate); + 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; + `; + commentElement.style.cssText = commentStyle; + commentElement.innerHTML = ` ++ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +
+ `; + commentsContainer.appendChild(commentElement); + }); + + document.getElementById('prev-page').disabled = currentPage <= 1; + document.getElementById('next-page').disabled = currentPage >= totalPages; + return; + } + 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 commentsData = []; let index = 0; let displayedComments = 0; @@ -82,19 +142,24 @@ async function fetchComments() { commentsContainer.appendChild(noCommentsMsg); } else { querySnapshot.forEach(doc => { - if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { - const comment = doc.data(); - - let commentDate; - if (comment.commentDate instanceof Timestamp) { - commentDate = comment.commentDate.toDate(); - } else if (typeof comment.commentDate === 'string') { - commentDate = new Date(comment.commentDate); - } else { - console.error('Unexpected commentDate format:', comment.commentDate); - return; - } + const comment = doc.data(); + let commentDate; + if (comment.commentDate instanceof Timestamp) { + commentDate = comment.commentDate.toDate(); + } else if (typeof comment.commentDate === 'string') { + commentDate = new Date(comment.commentDate); + } else { + console.error('Unexpected commentDate format:', comment.commentDate); + return; + } + + commentsData.push({ + userName: comment.userName, + userComment: comment.userComment, + commentDate: commentDate.toISOString(), + }); + if (index >= (currentPage - 1) * commentsPerPage && displayedComments < commentsPerPage) { const formattedDate = formatCommentDate(commentDate); const formattedTime = formatAMPM(commentDate); @@ -104,23 +169,27 @@ async function fetchComments() { commentElement.title = `Posted at ${formattedTime} ${utcOffset}`; const commentStyle = ` - max-width: 100%; - word-wrap: break-word; - overflow-wrap: break-word; - margin-bottom: 1rem; - `; + max-width: 100%; + word-wrap: break-word; + overflow-wrap: break-word; + margin-bottom: 1rem; + `; commentElement.style.cssText = commentStyle; commentElement.innerHTML = ` -- ${comment.userName} on ${formattedDate}: - ${comment.userComment} -
- `; ++ ${comment.userName} on ${formattedDate}: + ${comment.userComment} +
+ `; commentsContainer.appendChild(commentElement); displayedComments++; } index++; }); + + if (commentsData.length > 0) { + updateCommentCache(movieId, commentsData); + } } document.getElementById('prev-page').disabled = currentPage <= 1; diff --git a/MovieVerse-Mobile/app/js/favorites.js b/MovieVerse-Mobile/app/js/favorites.js index ab3eb6fa..133db635 100644 --- a/MovieVerse-Mobile/app/js/favorites.js +++ b/MovieVerse-Mobile/app/js/favorites.js @@ -16,6 +16,7 @@ import { let initialMoviesSelection = []; let initialTVSeriesSelection = []; +const IMGPATH = `https://image.tmdb.org/t/p/w500`; function translateFBC(value) { return atob(value); @@ -1368,12 +1369,12 @@ function getClassByRate(vote) { const searchForm = document.getElementById('form'); -searchForm.addEventListener('submit', e => { - e.preventDefault(); - const searchQuery = document.getElementById('search').value; - localStorage.setItem('searchQuery', searchQuery); - window.location.href = 'search.html'; -}); +// searchForm.addEventListener('submit', e => { +// e.preventDefault(); +// const searchQuery = document.getElementById('search').value; +// localStorage.setItem('searchQuery', searchQuery); +// window.location.href = 'search.html'; +// }); function handleSearch() { const searchQuery = document.getElementById('search').value; @@ -1389,13 +1390,26 @@ async function loadWatchLists() { const currentUserEmail = localStorage.getItem('currentlySignedInMovieVerseUser'); + let watchlists = []; if (currentUserEmail) { - const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); - const querySnapshot = await getDocs(q); - const watchlists = querySnapshot.docs.map(doc => ({ - id: doc.id, - ...doc.data(), - })); + try { + // Attempt to fetch from Firebase first + const q = query(collection(db, 'watchlists'), where('userEmail', '==', currentUserEmail)); + const querySnapshot = await getDocs(q); + watchlists = querySnapshot.docs.map(doc => ({ + id: doc.id, + ...doc.data(), + })); + + // Cache the results if successful + localStorage.setItem('cachedWatchlists_' + currentUserEmail, JSON.stringify(watchlists)); + } catch (firebaseError) { + console.warn('Firebase fetch failed, loading from cache:', firebaseError); + + // If Firebase fails, load from cache + const cachedWatchlists = JSON.parse(localStorage.getItem('cachedWatchlists_' + currentUserEmail)) || []; + watchlists = cachedWatchlists; + } if (watchlists.length === 0) { displaySection.innerHTML = 'No watch lists found. Click on "Create Watch Lists" to start adding movies.
'; @@ -1407,8 +1421,11 @@ async function loadWatchLists() { e.preventDefault(); document.getElementById('watchlist-header').scrollIntoView({ behavior: 'smooth' }); }); + + // Sort by order and pinned status 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) { @@ -1418,8 +1435,8 @@ async function loadWatchLists() { } } } else { + // Handle the case where there is no signed-in user (local watchlists) 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 { @@ -1439,198 +1456,83 @@ async function loadWatchLists() { let favorites = []; let favoritesTVSeries = []; + // Load favorites and favoritesTVSeries, first attempting from Firebase and then cache if needed if (currentUserEmail) { - const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); - const userSnapshot = await getDocs(usersRef); + try { + // Attempt to fetch favorites from Firebase + const usersRef = query(collection(db, 'MovieVerseUsers'), where('email', '==', currentUserEmail)); + const userSnapshot = await getDocs(usersRef); + if (!userSnapshot.empty) { + const userData = userSnapshot.docs[0].data(); + favorites = userData.favoritesMovies || []; + favoritesTVSeries = userData.favoritesTVSeries || []; + + // Cache the results if successful + localStorage.setItem('cachedFavorites_' + currentUserEmail, JSON.stringify({ favorites, favoritesTVSeries })); + } + } catch (firebaseError) { + console.warn('Firebase favorites fetch failed, loading from cache:', firebaseError); - if (!userSnapshot.empty) { - const userData = userSnapshot.docs[0].data(); - favorites = userData.favoritesMovies || []; - favoritesTVSeries = userData.favoritesTVSeries || []; + // If Firebase fails, load from cache + const cachedFavorites = JSON.parse(localStorage.getItem('cachedFavorites_' + currentUserEmail)) || {}; + favorites = cachedFavorites.favorites || []; + favoritesTVSeries = cachedFavorites.favoritesTVSeries || []; } } else { 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 = 'favorite-movies'; - - const title = document.createElement('h3'); - title.textContent = 'Favorite Movies'; - title.className = 'watchlist-title'; - title.style.cursor = 'pointer'; - title.addEventListener('click', () => { - favoritesDiv.scrollIntoView({ behavior: 'smooth' }); - }); - - const description = document.createElement('p'); - description.textContent = 'A collection of your favorite movies.'; - description.className = 'watchlist-description'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - 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 = 'favorite-movies'; - favoritesDiv.innerHTML = - 'No favorite movies added yet.
No favorite TV series added yet.
No watch lists found. Start by adding movies to your watchlist.
'; - } else { - displaySection.innerHTML = ''; - displaySection.innerHTML += 'Your Watch Lists
'; - 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); - } - } - - let favorites = []; - let 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 = 'favorite-movies'; - - 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'; - - favoritesDiv.appendChild(title); - favoritesDiv.appendChild(description); - - const moviesContainer = document.createElement('div'); - moviesContainer.className = 'movies-container'; - - 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 = 'favorite-movies'; - favoritesDiv.innerHTML = - 'No favorite movies added yet.
No favorite TV series added yet.
No ${titleTextNew} added yet.