diff --git a/client/api/api.ts b/client/api/api.ts index c7e0b96..270c90b 100644 --- a/client/api/api.ts +++ b/client/api/api.ts @@ -16,60 +16,65 @@ interface getActivityArgs { track_id: number; } -function getLastListens( +async function handleJson(r: Response): Promise { + if (!r.ok) { + const err = await r.json(); + throw Error(err.error); + } + return (await r.json()) as T; +} +async function getLastListens( args: getItemsArgs ): Promise> { - return fetch( + const r = await fetch( `/apis/web/v1/listens?period=${args.period}&limit=${args.limit}&artist_id=${args.artist_id}&album_id=${args.album_id}&track_id=${args.track_id}&page=${args.page}` - ).then((r) => r.json() as Promise>); + ); + return handleJson>(r); } -function getTopTracks(args: getItemsArgs): Promise> { - if (args.artist_id) { - return fetch( - `/apis/web/v1/top-tracks?period=${args.period}&limit=${args.limit}&artist_id=${args.artist_id}&page=${args.page}` - ).then((r) => r.json() as Promise>); - } else if (args.album_id) { - return fetch( - `/apis/web/v1/top-tracks?period=${args.period}&limit=${args.limit}&album_id=${args.album_id}&page=${args.page}` - ).then((r) => r.json() as Promise>); - } else { - return fetch( - `/apis/web/v1/top-tracks?period=${args.period}&limit=${args.limit}&page=${args.page}` - ).then((r) => r.json() as Promise>); - } +async function getTopTracks( + args: getItemsArgs +): Promise> { + let url = `/apis/web/v1/top-tracks?period=${args.period}&limit=${args.limit}&page=${args.page}`; + + if (args.artist_id) url += `&artist_id=${args.artist_id}`; + else if (args.album_id) url += `&album_id=${args.album_id}`; + + const r = await fetch(url); + return handleJson>(r); } -function getTopAlbums(args: getItemsArgs): Promise> { - const baseUri = `/apis/web/v1/top-albums?period=${args.period}&limit=${args.limit}&page=${args.page}`; - if (args.artist_id) { - return fetch(baseUri + `&artist_id=${args.artist_id}`).then( - (r) => r.json() as Promise> - ); - } else { - return fetch(baseUri).then( - (r) => r.json() as Promise> - ); - } +async function getTopAlbums( + args: getItemsArgs +): Promise> { + let url = `/apis/web/v1/top-albums?period=${args.period}&limit=${args.limit}&page=${args.page}`; + if (args.artist_id) url += `&artist_id=${args.artist_id}`; + + const r = await fetch(url); + return handleJson>(r); } -function getTopArtists(args: getItemsArgs): Promise> { - const baseUri = `/apis/web/v1/top-artists?period=${args.period}&limit=${args.limit}&page=${args.page}`; - return fetch(baseUri).then( - (r) => r.json() as Promise> - ); +async function getTopArtists( + args: getItemsArgs +): Promise> { + const url = `/apis/web/v1/top-artists?period=${args.period}&limit=${args.limit}&page=${args.page}`; + const r = await fetch(url); + return handleJson>(r); } -function getActivity(args: getActivityArgs): Promise { - return fetch( +async function getActivity( + args: getActivityArgs +): Promise { + const r = await fetch( `/apis/web/v1/listen-activity?step=${args.step}&range=${args.range}&month=${args.month}&year=${args.year}&album_id=${args.album_id}&artist_id=${args.artist_id}&track_id=${args.track_id}` - ).then((r) => r.json() as Promise); + ); + return handleJson(r); } -function getStats(period: string): Promise { - return fetch(`/apis/web/v1/stats?period=${period}`).then( - (r) => r.json() as Promise - ); +async function getStats(period: string): Promise { + const r = await fetch(`/apis/web/v1/stats?period=${period}`); + + return handleJson(r); } function search(q: string): Promise { @@ -416,4 +421,5 @@ export type { ApiError, Config, NowPlaying, + Stats, }; diff --git a/client/app/components/ActivityGrid.tsx b/client/app/components/ActivityGrid.tsx index 9628df6..1404503 100644 --- a/client/app/components/ActivityGrid.tsx +++ b/client/app/components/ActivityGrid.tsx @@ -73,8 +73,14 @@ export default function ActivityGrid({

Loading...

); + } else if (isError) { + return ( +
+

Activity

+

Error: {error.message}

+
+ ); } - if (isError) return

Error:{error.message}

; // from https://css-tricks.com/snippets/javascript/lighten-darken-color/ function LightenDarkenColor(hex: string, lum: number) { diff --git a/client/app/components/AllTimeStats.tsx b/client/app/components/AllTimeStats.tsx index cc45c65..2f60270 100644 --- a/client/app/components/AllTimeStats.tsx +++ b/client/app/components/AllTimeStats.tsx @@ -1,45 +1,56 @@ -import { useQuery } from "@tanstack/react-query" -import { getStats } from "api/api" +import { useQuery } from "@tanstack/react-query"; +import { getStats, type Stats, type ApiError } from "api/api"; export default function AllTimeStats() { + const { isPending, isError, data, error } = useQuery({ + queryKey: ["stats", "all_time"], + queryFn: ({ queryKey }) => getStats(queryKey[1]), + }); - const { isPending, isError, data, error } = useQuery({ - queryKey: ['stats', 'all_time'], - queryFn: ({ queryKey }) => getStats(queryKey[1]), - }) - - if (isPending) { - return ( -
-

All Time Stats

-

Loading...

-
- ) - } - if (isError) { - return

Error:{error.message}

- } - - const numberClasses = 'header-font font-bold text-xl' - + if (isPending) { return ( +
+

All Time Stats

+

Loading...

+
+ ); + } else if (isError) { + return ( + <>
-

All Time Stats

-
- {Math.floor(data.minutes_listened / 60)} Hours Listened -
-
- {data.listen_count} Plays -
-
- {data.artist_count} Artists -
-
- {data.album_count} Albums -
-
- {data.track_count} Tracks -
+

All Time Stats

+

Error: {error.message}

- ) -} \ No newline at end of file + + ); + } + + const numberClasses = "header-font font-bold text-xl"; + + return ( +
+

All Time Stats

+
+ + {Math.floor(data.minutes_listened / 60)} + {" "} + Hours Listened +
+
+ {data.listen_count} Plays +
+
+ {data.artist_count} Artists +
+
+ {data.album_count} Albums +
+
+ {data.track_count} Tracks +
+
+ ); +} diff --git a/client/app/components/LastPlays.tsx b/client/app/components/LastPlays.tsx index af95bf0..a2fd3a3 100644 --- a/client/app/components/LastPlays.tsx +++ b/client/app/components/LastPlays.tsx @@ -67,12 +67,14 @@ export default function LastPlays(props: Props) {

Loading...

); + } else if (isError) { + return ( +
+

Last Played

+

Error: {error.message}

+
+ ); } - if (isError) { - return

Error: {error.message}

; - } - - if (!data.items) return; const listens = items ?? data.items; diff --git a/client/app/components/TopAlbums.tsx b/client/app/components/TopAlbums.tsx index 6f034c5..d4730e2 100644 --- a/client/app/components/TopAlbums.tsx +++ b/client/app/components/TopAlbums.tsx @@ -37,11 +37,14 @@ export default function TopAlbums(props: Props) {

Loading...

); + } else if (isError) { + return ( +
+

Top Albums

+

Error: {error.message}

+
+ ); } - if (isError) { - return

Error:{error.message}

; - } - if (!data.items) return; return (
diff --git a/client/app/components/TopArtists.tsx b/client/app/components/TopArtists.tsx index fbe83ee..fca9456 100644 --- a/client/app/components/TopArtists.tsx +++ b/client/app/components/TopArtists.tsx @@ -28,11 +28,14 @@ export default function TopArtists(props: Props) {

Loading...

); + } else if (isError) { + return ( +
+

Top Artists

+

Error: {error.message}

+
+ ); } - if (isError) { - return

Error:{error.message}

; - } - if (!data.items) return; return (
diff --git a/client/app/components/TopTracks.tsx b/client/app/components/TopTracks.tsx index 5dc3950..2e1c6fb 100644 --- a/client/app/components/TopTracks.tsx +++ b/client/app/components/TopTracks.tsx @@ -35,9 +35,13 @@ const TopTracks = (props: Props) => {

Loading...

); - } - if (isError) { - return

Error:{error.message}

; + } else if (isError) { + return ( +
+

Top Tracks

+

Error: {error.message}

+
+ ); } if (!data.items) return;