From 1839ec9609fb6b455af8cee86f6916e793b3383c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20P=C4=99dzich?= Date: Thu, 12 Jan 2023 20:42:33 +0100 Subject: [PATCH] Add loading and "no playlists found" states --- src/components/vue/PlaylistSearchInput.vue | 82 +++++++++++++++------- src/styles/global.css | 4 ++ 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/components/vue/PlaylistSearchInput.vue b/src/components/vue/PlaylistSearchInput.vue index 658e54f..d238b65 100644 --- a/src/components/vue/PlaylistSearchInput.vue +++ b/src/components/vue/PlaylistSearchInput.vue @@ -4,9 +4,9 @@ import { onMounted, ref, watch } from 'vue'; import { search } from 'fast-fuzzy'; import { debounce } from 'debounce'; -import type { PlaylistSnapshot } from '../../models/playlist-snapshot'; -import type { SearchSuggestion } from '../../models/search-suggestion'; -import { getPlaylistIdFromUrl } from '../../utils/getPlaylistIdFromUrl'; +import type { PlaylistSnapshot } from '@/models/playlist-snapshot'; +import type { SearchSuggestion } from '@/models/search-suggestion'; +import { getPlaylistIdFromUrl } from '@/utils/getPlaylistIdFromUrl'; const searchTerm = ref(''); const searchHistory = ref( @@ -17,19 +17,24 @@ const playlistRegistry = ref([]); const searchSuggestions = ref(searchHistory.value); const isFetchingPlaylists = ref(true); -const errorOccurred = ref(false); +const registryFetchErrorOccurred = ref(false); + +const isPreparingSuggestions = ref(false); const canShowSuggestions = ref(false); const fetchAvailablePlaylists = async () => { try { isFetchingPlaylists.value = true; - errorOccurred.value = false; + registryFetchErrorOccurred.value = false; - const playlistMetadata: Record = await ( - await fetch( - 'https://raw.githubusercontent.com/mackorone/spotify-playlist-archive/main/playlists/metadata.json' - ) - ).json(); + const githubResponse = await fetch( + 'https://raw.githubusercontent.com/mackorone/spotify-playlist-archive/main/playlists/metadata.json' + ); + + if (!githubResponse.ok) throw new Error(githubResponse.statusText); + + const playlistMetadata: Record = + await githubResponse.json(); const playlistEntries = Object.entries(playlistMetadata).map( ([id, { original_name }]) => ({ id, name: original_name }) @@ -38,7 +43,7 @@ const fetchAvailablePlaylists = async () => { playlistRegistry.value = playlistEntries; } catch (error) { console.error(error); - errorOccurred.value = true; + registryFetchErrorOccurred.value = true; } finally { isFetchingPlaylists.value = false; } @@ -48,6 +53,8 @@ const showSearchHistory = () => (searchSuggestions.value = searchHistory.value); const findMatchingPlaylists = debounce(async (name: string) => { try { + isPreparingSuggestions.value = true; + if (name.length === 0) return showSearchHistory(); else if (name.length < 3) return (searchSuggestions.value = []); @@ -56,24 +63,26 @@ const findMatchingPlaylists = debounce(async (name: string) => { `https://raw.githubusercontent.com/mackorone/spotify-playlist-archive/main/playlists/pretty/${playlistId}.json` ); - if (!githubResponse.ok) throw new Error('Entry does not exist'); + if (!githubResponse.ok) + throw new Error(`GitHub ${githubResponse.status.toString()}`); const playlist: PlaylistSnapshot = await githubResponse.json(); const suggestion = { id: playlistId, name: playlist.original_name }; - return (searchSuggestions.value = [suggestion]); + searchSuggestions.value = [suggestion]; } catch (error) { - const noopErrorMessages = ['Invalid playlist URL', 'Entry does not exist']; + const errorMessage = (error as Error).message; - if (noopErrorMessages.includes((error as Error).message)) { - return (searchSuggestions.value = []); - } + if (errorMessage === 'GitHub 404') return (searchSuggestions.value = []); const suggestions = search(name, playlistRegistry.value, { keySelector: (obj) => obj.name }); searchSuggestions.value = suggestions.slice(0, 5); + } finally { + isPreparingSuggestions.value = false; + canShowSuggestions.value = true; } }, 250); @@ -98,7 +107,10 @@ watch(searchTerm, (newSearchTerm) => findMatchingPlaylists(newSearchTerm)); v-if="isFetchingPlaylists" class="fa-solid fa-spinner fa-spin text-5xl" > -
+
Failed to load playlist registry
@@ -121,16 +133,32 @@ watch(searchTerm, (newSearchTerm) => findMatchingPlaylists(newSearchTerm)); v-show="canShowSuggestions" class="w-full absolute z-10 top-full left-0 right-0 bg-base-100 text-left border-l-[1px] border-r-[1px] border-solid border-base-content border-opacity-20" > - - - - {{ suggestion.name }} - + +
+
diff --git a/src/styles/global.css b/src/styles/global.css index cef91ea..c5eeede 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -17,3 +17,7 @@ a { li > a { @apply hover:text-inherit focus:text-primary-content focus:bg-primary; } + +.search-suggestion { + @apply block p-3 text-inherit border-b-[1px] border-solid border-base-content border-opacity-20; +}