Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added box if band/artist stopped performing #27

Merged
merged 3 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 20 additions & 36 deletions components/Home/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,31 @@ import React, {
} from "react";
import { useRouter } from "next/router";
import { Search as SearchIcon, X as CloseIcon } from "lucide-react";

type Artist = {
id: string;
name: string;
disambiguation?: string;
};
import { useSearchArtistByName } from "services/searchArtist";
import { ArtistInfo } from "types";

const Search = () => {
const [searchTerm, setSearchTerm] = useState("");
const [suggestions, setSuggestions] = useState<Artist[]>([]);
const [suggestions, setSuggestions] = useState<ArtistInfo[]>([]);
const [selectedIndex, setSelectedIndex] = useState(-1);
const [isOpen, setIsOpen] = useState(false);
const search = useRef<HTMLInputElement>(null);
const wrapperRef = useRef<HTMLFormElement>(null);
const router = useRouter();

useEffect(() => {
const fetchSuggestions = async () => {
if (searchTerm.length > 1) {
try {
const response = await fetch(
`https://musicbrainz.org/ws/2/artist?query=${encodeURIComponent(searchTerm)}&fmt=json`,
);
const data = await response.json();
setSuggestions(data.artists.slice(0, 5));
setSelectedIndex(-1);
setIsOpen(true);
} catch (error) {
console.error("Error fetching suggestions:", error);
}
} else {
setSuggestions([]);
setSelectedIndex(-1);
setIsOpen(false);
}
};
const { data } = useSearchArtistByName(searchTerm);

const debounceTimer = setTimeout(fetchSuggestions, 300);
return () => clearTimeout(debounceTimer);
}, [searchTerm]);
useEffect(() => {
if (data && searchTerm.length > 1) {
const newSuggestions = data.artists.slice(0, 5);
setSuggestions(newSuggestions);
setSelectedIndex(-1);
setIsOpen(newSuggestions.length > 0);
} else if (searchTerm.length <= 1) {
setSuggestions([]);
setIsOpen(false);
}
}, [data, searchTerm]);

useEffect(() => {
function handleClickOutside(event: MouseEvent) {
Expand All @@ -62,33 +47,32 @@ const Search = () => {
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [wrapperRef]);
}, []);

const onFormSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
if (selectedIndex >= 0 && selectedIndex < suggestions.length) {
handleSuggestionSelect(suggestions[selectedIndex]);
} else {
searchTerm && router.push("/[...artist]", `/${searchTerm}`);
} else if (searchTerm) {
router.push("/[...artist]", `/${searchTerm}`);
}
};

const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(event.target.value);
};

const handleSuggestionSelect = (suggestion: Artist) => {
const handleSuggestionSelect = (suggestion: ArtistInfo) => {
setSearchTerm(suggestion.name);
setSuggestions([]);
setIsOpen(false);
router.push("/[...artist]", `/${suggestion.name}/${suggestion.id}`);
};

const clearSearch = () => {
setSearchTerm("");
setSuggestions([]);
setSelectedIndex(-1);
setIsOpen(false);
setSuggestions([]);
if (search.current) {
search.current.focus();
}
Expand Down
47 changes: 34 additions & 13 deletions components/Result/Result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,25 @@ import SavePlaylist from "components/SavePlaylist/SavePlaylist";
import { useArtistData } from "services/artistData";
import { useTracks } from "services/tracks";
import { useEvents } from "services/events";
import { ArrowLeft, Frown } from "lucide-react";
import { ArrowLeft, Frown, TriangleAlert } from "lucide-react";
import Link from "next/link";
import { useGetArtist } from "services/searchArtist";

interface Props {
artist: string[];
artistQuery: string[];
}

const Result = ({ artist }: Props) => {
const Result = ({ artistQuery }: Props) => {
const [initialBaground] = useState<string>(document.body.style.background);
const { artistData, isLoading: isLoadingArtist } = useArtistData(artist[0]);
const { artistData, isLoading: isLoadingArtist } = useArtistData(
artistQuery[0],
);
const { tracks, isLoading: isLoadingTracks } = useTracks(
artist[0],
artist[1],
artistQuery[0],
artistQuery[1],
);
const { events } = useEvents(artist[0]);
const { artist } = useGetArtist(artistQuery?.[1]);
const { events } = useEvents(artistQuery[0]);

const from = `rgba(${artistData?.palette?.DarkVibrant.rgb.join(",")},100)`;

Expand Down Expand Up @@ -79,11 +83,28 @@ const Result = ({ artist }: Props) => {

{events && <Events events={events} />}

{/* <div className="bg-black bg-opacity-30 rounded-lg p-4 mb-6">
<h2 className="text-xl font-semibold mb-2">Playlist Info</h2>
<p>Based on last 20 concerts from 2022 to 2024</p>
<p>13 songs • Estimated playtime: 65 minutes</p>
</div> */}
{artist?.["life-span"].ended && (
<div className="bg-black bg-opacity-30 rounded-lg p-4 mb-6">
<h2 className="text-xl font-semibold mb-2 flex gap-1">
<TriangleAlert /> Important notice
</h2>
<p>
The data displayed may not be fully accurate as this artist or
band stopped performing on{" "}
<strong>
{new Date(artist["life-span"].end).toLocaleDateString(
undefined,
{
year: "numeric",
month: "long",
day: "numeric",
},
)}
</strong>
.
</p>
</div>
)}

<SavePlaylist artistData={artistData} tracks={tracks} />
<Tracks
Expand All @@ -98,7 +119,7 @@ const Result = ({ artist }: Props) => {
<Frown height={100} width={100} />
</div>
<div className="m-auto text-center text-2xl p-3">
No setlists found for <b>{artist[0]}</b>
No setlists found for <b>{artistQuery[0]}</b>
</div>
</div>
)}
Expand Down
5 changes: 2 additions & 3 deletions components/Tracks/Tracks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Track, Link, ArtistData } from "types";
import { isSameSong } from "utils/matchSongs";

import { Disc3 as Disc } from "lucide-react";
import classNames from "classnames";
import SpotifyLogo from "components/Icons/Spotify";
import PauseIcon from "components/Icons/Pause";
import PlayIcon from "components/Icons/Play";
Expand Down Expand Up @@ -102,7 +101,7 @@ const Tracks = ({ tracks, links, palette }: TracksProps) => {
{link?.previewUrl && (
<button
onClick={() => handlePreview(link.previewUrl, title)}
className={classNames("absolute left-0 top-0 h-full p-3")}
className="absolute left-0 top-0 h-full p-3 rounded-full bg-transparent hover:bg-black/50 transition-colors duration-300"
aria-pressed={isPlaying}
aria-label={isPlaying ? "Pause" : "Play"}
>
Expand All @@ -127,7 +126,7 @@ const Tracks = ({ tracks, links, palette }: TracksProps) => {
)}
<div className="text-sm opacity-75">
<span className="hidden md:inline">Played </span>
{count} times
<span className="whitespace-nowrap">{count} times</span>
</div>
</div>
</li>
Expand Down
2 changes: 1 addition & 1 deletion pages/[...artist].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const ResultPage = () => {
<Loader height={80} width={80} ariaLabel="loading" color="white" />
</div>
) : (
<Result artist={artist} />
<Result artistQuery={artist} />
)}
{!isLoading && (
<Footer
Expand Down
44 changes: 44 additions & 0 deletions services/searchArtist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import useSWR from "swr";
import { ArtistInfo } from "types";
import { fetcher } from "utils/api";

export type SearchResults = {
artists: ArtistInfo[];
};

export const useSearchArtistByName = (searchTerm: string | undefined) => {
const { data, error, isLoading } = useSWR(
searchTerm && searchTerm.length > 1
? `https://musicbrainz.org/ws/2/artist?query=${encodeURIComponent(searchTerm)}&fmt=json`
: null,
fetcher<SearchResults>,
{
dedupingInterval: 300,
revalidateOnFocus: false,
revalidateOnReconnect: false,
},
);

return {
data,
isLoading,
isError: error,
};
};

export const useGetArtist = (mbid: string | undefined) => {
const { data, error, isLoading } = useSWR(
mbid ? `https://musicbrainz.org/ws/2/artist/${mbid}?fmt=json` : null,
fetcher<ArtistInfo>,
{
revalidateOnFocus: false,
revalidateOnReconnect: false,
},
);

return {
artist: data,
isLoading,
isError: error,
};
};
13 changes: 13 additions & 0 deletions types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface Palette {
rgb: [number, number, number];
}

// returned by Spotify
export interface ArtistData {
name: string;
image: string | undefined;
Expand All @@ -31,3 +32,15 @@ export interface ArtistData {
LightVibrant: Palette;
};
}

// returned by MusicBrainz
export interface ArtistInfo {
id: string;
name: string;
disambiguation: string;
"life-span": {
end: string;
begin: string;
ended: boolean;
};
}