diff --git a/apps/web/src/api/library.ts b/apps/web/src/api/library.ts index 85e9d2ac..b467087a 100644 --- a/apps/web/src/api/library.ts +++ b/apps/web/src/api/library.ts @@ -29,7 +29,7 @@ export const getSongByUri = async (uri: string) => { export const getArtistTracks = async ( uri: string, - limit = 10 + limit = 10, ): Promise< { id: string; @@ -45,14 +45,14 @@ export const getArtistTracks = async ( > => { const response = await client.get( "/xrpc/app.rocksky.artist.getArtistTracks", - { params: { uri, limit } } + { params: { uri, limit } }, ); return response.data.tracks; }; export const getArtistAlbums = async ( uri: string, - limit = 10 + limit = 10, ): Promise< { id: string; @@ -65,7 +65,7 @@ export const getArtistAlbums = async ( > => { const response = await client.get( "/xrpc/app.rocksky.artist.getArtistAlbums", - { params: { uri, limit } } + { params: { uri, limit } }, ); return response.data.albums; }; @@ -96,7 +96,7 @@ export const getLovedTracks = async (did: string, offset = 0, limit = 20) => { "/xrpc/app.rocksky.actor.getActorLovedSongs", { params: { did, limit, offset }, - } + }, ); return response.data.tracks; }; @@ -118,7 +118,7 @@ export const getArtist = async (did: string, rkey: string) => { export const getArtistListeners = async (uri: string, limit: number) => { const response = await client.get( "/xrpc/app.rocksky.artist.getArtistListeners", - { params: { uri, limit } } + { params: { uri, limit } }, ); return response.data; }; diff --git a/apps/web/src/components/ContextMenu/ContextMenu.tsx b/apps/web/src/components/ContextMenu/ContextMenu.tsx index dbba1025..b4542b8a 100644 --- a/apps/web/src/components/ContextMenu/ContextMenu.tsx +++ b/apps/web/src/components/ContextMenu/ContextMenu.tsx @@ -4,146 +4,146 @@ import { NestedMenus, StatefulMenu } from "baseui/menu"; import { StatefulPopover } from "baseui/popover"; export type ContextMenuProps = { - file: { - id: string; - name: string; - type: string; - }; + file: { + id: string; + name: string; + type: string; + }; }; function ContextMenu(props: ContextMenuProps) { - const { file } = props; - return ( - ( - - - - {file.type == "folder" && ( - - - - )} - {file.type !== "folder" && ( - - - - )} - - - {file.name} - - - - { - console.log(`Selected item: ${item.label}`); - close(); - }} - overrides={{ - List: { - style: { - boxShadow: "none", - outline: "none !important", - backgroundColor: "var(--color-background)", - }, - }, - ListItem: { - style: { - backgroundColor: "var(--color-background)", - color: "var(--color-text)", - ":hover": { - backgroundColor: "var(--color-menu-hover)", - }, - }, - }, - Option: { - props: { - getChildMenu: (item: { label: string }) => { - if (item.label === "Add to Playlist") { - return ( - - - - ); - } - return null; - }, - }, - }, - }} - /> - - - )} - overrides={{ - Inner: { - style: { - backgroundColor: "var(--color-background)", - }, - }, - }} - > - - - - - ); + const { file } = props; + return ( + ( + + + + {file.type == "folder" && ( + + + + )} + {file.type !== "folder" && ( + + + + )} + + + {file.name} + + + + { + console.log(`Selected item: ${item.label}`); + close(); + }} + overrides={{ + List: { + style: { + boxShadow: "none", + outline: "none !important", + backgroundColor: "var(--color-background)", + }, + }, + ListItem: { + style: { + backgroundColor: "var(--color-background)", + color: "var(--color-text)", + ":hover": { + backgroundColor: "var(--color-menu-hover)", + }, + }, + }, + Option: { + props: { + getChildMenu: (item: { label: string }) => { + if (item.label === "Add to Playlist") { + return ( + + + + ); + } + return null; + }, + }, + }, + }} + /> + + + )} + overrides={{ + Inner: { + style: { + backgroundColor: "var(--color-background)", + }, + }, + }} + > + + + + + ); } export default ContextMenu; diff --git a/apps/web/src/components/Handle/Handle.tsx b/apps/web/src/components/Handle/Handle.tsx index 115f718e..ca2e8a01 100644 --- a/apps/web/src/components/Handle/Handle.tsx +++ b/apps/web/src/components/Handle/Handle.tsx @@ -8,118 +8,118 @@ import { useEffect } from "react"; import { profilesAtom } from "../../atoms/profiles"; import { statsAtom } from "../../atoms/stats"; import { - useProfileByDidQuery, - useProfileStatsByDidQuery, + useProfileByDidQuery, + useProfileStatsByDidQuery, } from "../../hooks/useProfile"; import Stats from "../Stats"; import NowPlaying from "./NowPlaying"; export type HandleProps = { - link: string; - did: string; + link: string; + did: string; }; function Handle(props: HandleProps) { - const { link, did } = props; - const [profiles, setProfiles] = useAtom(profilesAtom); - const profile = useProfileByDidQuery(did); - const profileStats = useProfileStatsByDidQuery(did); - const [stats, setStats] = useAtom(statsAtom); + const { link, did } = props; + const [profiles, setProfiles] = useAtom(profilesAtom); + const profile = useProfileByDidQuery(did); + const profileStats = useProfileStatsByDidQuery(did); + const [stats, setStats] = useAtom(statsAtom); - useEffect(() => { - if (profile.isLoading || profile.isError) { - return; - } + useEffect(() => { + if (profile.isLoading || profile.isError) { + return; + } - if (!profile.data || !did) { - return; - } + if (!profile.data || !did) { + return; + } - setProfiles((profiles) => ({ - ...profiles, - [did]: { - avatar: profile.data.avatar, - displayName: profile.data.displayName, - handle: profile.data.handle, - spotifyConnected: profile.data.spotifyConnected, - createdAt: profile.data.createdAt, - did, - }, - })); + setProfiles((profiles) => ({ + ...profiles, + [did]: { + avatar: profile.data.avatar, + displayName: profile.data.displayName, + handle: profile.data.handle, + spotifyConnected: profile.data.spotifyConnected, + createdAt: profile.data.createdAt, + did, + }, + })); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [profile.data, profile.isLoading, profile.isError, did]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [profile.data, profile.isLoading, profile.isError, did]); - useEffect(() => { - if (profileStats.isLoading || profileStats.isError) { - return; - } + useEffect(() => { + if (profileStats.isLoading || profileStats.isError) { + return; + } - if (!profileStats.data || !did) { - return; - } + if (!profileStats.data || !did) { + return; + } - setStats((prev) => ({ - ...prev, - [did]: { - scrobbles: profileStats.data.scrobbles, - artists: profileStats.data.artists, - lovedTracks: profileStats.data.lovedTracks, - albums: profileStats.data.albums, - tracks: profileStats.data.tracks, - }, - })); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [profileStats.data, profileStats.isLoading, profileStats.isError, did]); + setStats((prev) => ({ + ...prev, + [did]: { + scrobbles: profileStats.data.scrobbles, + artists: profileStats.data.artists, + lovedTracks: profileStats.data.lovedTracks, + albums: profileStats.data.albums, + tracks: profileStats.data.tracks, + }, + })); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [profileStats.data, profileStats.isLoading, profileStats.isError, did]); - return ( - ( - - - - - - - - - {profiles[did]?.displayName} - - - - - @{did} - - - - + return ( + ( + + + + + + + + + {profiles[did]?.displayName} + + + + + @{did} + + + + - {stats[did] && } + {stats[did] && } - - - )} - triggerType={TRIGGER_TYPE.hover} - autoFocus={false} - focusLock={false} - > - - - @{did} - - - - ); + + + )} + triggerType={TRIGGER_TYPE.hover} + autoFocus={false} + focusLock={false} + > + + + @{did} + + + + ); } export default Handle; diff --git a/apps/web/src/components/SongCover/SongCover.tsx b/apps/web/src/components/SongCover/SongCover.tsx index 2c00ced1..820d690a 100644 --- a/apps/web/src/components/SongCover/SongCover.tsx +++ b/apps/web/src/components/SongCover/SongCover.tsx @@ -7,8 +7,8 @@ const Cover = styled.img<{ size?: number }>` width: 240px; margin-bottom: 10px; ${(props) => - props.size && - css` + props.size && + css` height: ${props.size}px; width: ${props.size}px; `} @@ -49,25 +49,25 @@ const CoverWrapper = styled.div` `; export type SongCoverProps = { - cover: string; - title?: string; - artist?: string; - size?: number; + cover: string; + title?: string; + artist?: string; + size?: number; }; function SongCover(props: SongCoverProps) { - const { title, artist, cover, size } = props; - return ( - - - - - {title} - - {artist} - - - ); + const { title, artist, cover, size } = props; + return ( + + + + + {title} + + {artist} + + + ); } export default SongCover; diff --git a/apps/web/src/hooks/useLibrary.tsx b/apps/web/src/hooks/useLibrary.tsx index 153c69d3..c107ba36 100644 --- a/apps/web/src/hooks/useLibrary.tsx +++ b/apps/web/src/hooks/useLibrary.tsx @@ -1,102 +1,102 @@ import { useQuery } from "@tanstack/react-query"; import { - getAlbum, - getAlbums, - getArtist, - getArtistAlbums, - getArtistListeners, - getArtists, - getArtistTracks, - getLovedTracks, - getSongByUri, - getTracks, + getAlbum, + getAlbums, + getArtist, + getArtistAlbums, + getArtistListeners, + getArtists, + getArtistTracks, + getLovedTracks, + getSongByUri, + getTracks, } from "../api/library"; export const useSongByUriQuery = (uri: string) => - useQuery({ - queryKey: ["songByUri", uri], - queryFn: () => getSongByUri(uri), - enabled: !!uri, - }); + useQuery({ + queryKey: ["songByUri", uri], + queryFn: () => getSongByUri(uri), + enabled: !!uri, + }); export const useArtistTracksQuery = (uri: string, limit = 10) => - useQuery({ - queryKey: ["artistTracks", uri, limit], - queryFn: () => getArtistTracks(uri, limit), - enabled: !!uri, - }); + useQuery({ + queryKey: ["artistTracks", uri, limit], + queryFn: () => getArtistTracks(uri, limit), + enabled: !!uri, + }); export const useArtistAlbumsQuery = (uri: string, limit = 10) => - useQuery({ - queryKey: ["artistAlbums", uri, limit], - queryFn: () => getArtistAlbums(uri, limit), - enabled: !!uri, - }); + useQuery({ + queryKey: ["artistAlbums", uri, limit], + queryFn: () => getArtistAlbums(uri, limit), + enabled: !!uri, + }); export const useArtistsQuery = (did: string, offset = 0, limit = 30) => - useQuery({ - queryKey: ["artists", did, offset, limit], - queryFn: () => getArtists(did, offset, limit), - enabled: !!did, - select: (data) => - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data?.artists.map((x: any) => ({ - ...x, - scrobbles: x.playCount, - })), - }); + useQuery({ + queryKey: ["artists", did, offset, limit], + queryFn: () => getArtists(did, offset, limit), + enabled: !!did, + select: (data) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data?.artists.map((x: any) => ({ + ...x, + scrobbles: x.playCount, + })), + }); export const useAlbumsQuery = (did: string, offset = 0, limit = 12) => - useQuery({ - queryKey: ["albums", did, offset, limit], - queryFn: () => getAlbums(did, offset, limit), - enabled: !!did, - select: (data) => - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data?.albums.map((x: any) => ({ - ...x, - scrobbles: x.playCount, - })), - }); + useQuery({ + queryKey: ["albums", did, offset, limit], + queryFn: () => getAlbums(did, offset, limit), + enabled: !!did, + select: (data) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data?.albums.map((x: any) => ({ + ...x, + scrobbles: x.playCount, + })), + }); export const useTracksQuery = (did: string, offset = 0, limit = 20) => - useQuery({ - queryKey: ["tracks", did, offset, limit], - queryFn: () => getTracks(did, offset, limit), - enabled: !!did, - select: (data) => - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data?.tracks.map((x: any) => ({ - ...x, - scrobbles: x.playCount, - })), - }); + useQuery({ + queryKey: ["tracks", did, offset, limit], + queryFn: () => getTracks(did, offset, limit), + enabled: !!did, + select: (data) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data?.tracks.map((x: any) => ({ + ...x, + scrobbles: x.playCount, + })), + }); export const useLovedTracksQuery = (did: string, offset = 0, limit = 20) => - useQuery({ - queryKey: ["lovedTracks", did, offset, limit], - queryFn: () => getLovedTracks(did, offset, limit), - enabled: !!did, - }); + useQuery({ + queryKey: ["lovedTracks", did, offset, limit], + queryFn: () => getLovedTracks(did, offset, limit), + enabled: !!did, + }); export const useAlbumQuery = (did: string, rkey: string) => - useQuery({ - queryKey: ["album", did, rkey], - queryFn: () => getAlbum(did, rkey), - enabled: !!did && !!rkey, - }); + useQuery({ + queryKey: ["album", did, rkey], + queryFn: () => getAlbum(did, rkey), + enabled: !!did && !!rkey, + }); export const useArtistQuery = (did: string, rkey: string) => - useQuery({ - queryKey: ["artist", did, rkey], - queryFn: () => getArtist(did, rkey), - enabled: !!did && !!rkey, - }); + useQuery({ + queryKey: ["artist", did, rkey], + queryFn: () => getArtist(did, rkey), + enabled: !!did && !!rkey, + }); export const useArtistListenersQuery = (uri: string, limit = 10) => - useQuery({ - queryKey: ["artistListeners", uri, limit], - queryFn: () => getArtistListeners(uri, limit), - enabled: !!uri, - select: (data) => data.listeners, - }); + useQuery({ + queryKey: ["artistListeners", uri, limit], + queryFn: () => getArtistListeners(uri, limit), + enabled: !!uri, + select: (data) => data.listeners, + }); diff --git a/apps/web/src/layouts/Main.tsx b/apps/web/src/layouts/Main.tsx index a1e1475c..d3ac4987 100644 --- a/apps/web/src/layouts/Main.tsx +++ b/apps/web/src/layouts/Main.tsx @@ -51,229 +51,229 @@ const Link = styled.a` `; export type MainProps = { - children: React.ReactNode; - withRightPane?: boolean; + children: React.ReactNode; + withRightPane?: boolean; }; function Main(props: MainProps) { - const { children } = props; - const withRightPane = props.withRightPane ?? true; - const [handle, setHandle] = useState(""); - const jwt = localStorage.getItem("token"); - const profile = useAtomValue(profileAtom); - const [token, setToken] = useState(null); - const { did, cli } = useSearch({ strict: false }); + const { children } = props; + const withRightPane = props.withRightPane ?? true; + const [handle, setHandle] = useState(""); + const jwt = localStorage.getItem("token"); + const profile = useAtomValue(profileAtom); + const [token, setToken] = useState(null); + const { did, cli } = useSearch({ strict: false }); - useEffect(() => { - if (did && did !== "null") { - localStorage.setItem("did", did); + useEffect(() => { + if (did && did !== "null") { + localStorage.setItem("did", did); - const fetchToken = async () => { - try { - const response = await fetch(`${API_URL}/token`, { - method: "GET", - headers: { - "session-did": did, - }, - }); - const data = await response.json(); - localStorage.setItem("token", data.token); - setToken(data.token); + const fetchToken = async () => { + try { + const response = await fetch(`${API_URL}/token`, { + method: "GET", + headers: { + "session-did": did, + }, + }); + const data = await response.json(); + localStorage.setItem("token", data.token); + setToken(data.token); - if (cli) { - await fetch("http://localhost:6996/token", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ token: data.token }), - }); - } + if (cli) { + await fetch("http://localhost:6996/token", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ token: data.token }), + }); + } - if (!jwt && data.token) { - window.location.href = "/"; - } - } catch (e) { - console.error(e); - } - }; - fetchToken(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + if (!jwt && data.token) { + window.location.href = "/"; + } + } catch (e) { + console.error(e); + } + }; + fetchToken(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); - useProfile(token || localStorage.getItem("token")); + useProfile(token || localStorage.getItem("token")); - const onLogin = async () => { - if (!handle.trim()) { - return; - } + const onLogin = async () => { + if (!handle.trim()) { + return; + } - if (API_URL.includes("localhost")) { - window.location.href = `${API_URL}/login?handle=${handle}`; - return; - } + if (API_URL.includes("localhost")) { + window.location.href = `${API_URL}/login?handle=${handle}`; + return; + } - window.location.href = `https://rocksky.pages.dev/loading?handle=${handle}`; - }; + window.location.href = `https://rocksky.pages.dev/loading?handle=${handle}`; + }; - return ( - - - - - - {children} - - - {withRightPane && ( - - - - - - {jwt && profile && !profile.spotifyConnected && } - {jwt && profile && } - {!jwt && ( - - - - - Bluesky handle - - - - @ - - } - placeholder=".bsky.social" - value={handle} - onChange={(e) => setHandle(e.target.value)} - overrides={{ - Root: { - style: { - backgroundColor: "var(--color-input-background)", - borderColor: "var(--color-input-background)", - }, - }, - StartEnhancer: { - style: { - backgroundColor: "var(--color-input-background)", - }, - }, - InputContainer: { - style: { - backgroundColor: "var(--color-input-background)", - }, - }, - Input: { - style: { - color: "var(--color-text)", - caretColor: "var(--color-text)", - }, - }, - }} - /> - - - Sign In - - - Don't have an account? - - - - Sign up for Bluesky - {" "} - to create one now! - - - )} + return ( + + + + + + {children} + + + {withRightPane && ( + + + + + + {jwt && profile && !profile.spotifyConnected && } + {jwt && profile && } + {!jwt && ( + + + + + Bluesky handle + + + + @ + + } + placeholder=".bsky.social" + value={handle} + onChange={(e) => setHandle(e.target.value)} + overrides={{ + Root: { + style: { + backgroundColor: "var(--color-input-background)", + borderColor: "var(--color-input-background)", + }, + }, + StartEnhancer: { + style: { + backgroundColor: "var(--color-input-background)", + }, + }, + InputContainer: { + style: { + backgroundColor: "var(--color-input-background)", + }, + }, + Input: { + style: { + color: "var(--color-text)", + caretColor: "var(--color-text)", + }, + }, + }} + /> + + + Sign In + + + Don't have an account? + + + + Sign up for Bluesky + {" "} + to create one now! + + + )} - - - - - - - About - - - FAQ - - - API Docs - - - Source - - - Discord - - - - - )} - - - ); + + + + + + + About + + + FAQ + + + API Docs + + + Source + + + Discord + + + + + )} + + + ); } export default Main; diff --git a/apps/web/src/layouts/Navbar/Navbar.tsx b/apps/web/src/layouts/Navbar/Navbar.tsx index 80ba18bf..a90beacf 100644 --- a/apps/web/src/layouts/Navbar/Navbar.tsx +++ b/apps/web/src/layouts/Navbar/Navbar.tsx @@ -86,7 +86,7 @@ function Navbar() { setTimeout(() => { setTooltipContent("Copy API Key"); }, 1500); - } + }; useEffect(() => { if (profile?.spotifyConnected && !!localStorage.getItem("spotify")) { @@ -169,7 +169,7 @@ function Navbar() { color="var(--color-text-muted)" className="text-center !mr-[5px]" > - {numeral(profileStats.data.scrobbles).format("0,0")} + {numeral(profileStats?.data?.scrobbles).format("0,0")} scrobbles @@ -363,7 +363,16 @@ function Navbar() { extension settings as a custom API URL: {webscrobblerWebhook} - + { - const { did, rkey } = useParams({ strict: false }); - - const uri = `at://${did}/app.rocksky.artist/${rkey}`; - const artistResult = useArtistQuery(did!, rkey!); - const artistTracksResult = useArtistTracksQuery(uri); - const artistAlbumsResult = useArtistAlbumsQuery(uri); - const artistListenersResult = useArtistListenersQuery(uri); - - const artist = useAtomValue(artistAtom); - const setArtist = useSetAtom(artistAtom); - const [topTracks, setTopTracks] = useState< - { - id: string; - title: string; - artist: string; - albumArtist: string; - albumArt: string; - uri: string; - scrobbles: number; - albumUri?: string; - artistUri?: string; - }[] - >([]); - const [topAlbums, setTopAlbums] = useState< - { - id: string; - title: string; - artist: string; - albumArt: string; - artistUri: string; - uri: string; - }[] - >([]); - - useEffect(() => { - if (artistResult.isLoading || artistResult.isError) { - return; - } - - if (!artistResult.data || !did) { - return; - } - - setArtist({ - id: artistResult.data.id, - name: artistResult.data.name, - born: artistResult.data.born, - bornIn: artistResult.data.bornIn, - died: artistResult.data.died, - listeners: artistResult.data.uniqueListeners, - scrobbles: artistResult.data.playCount, - picture: artistResult.data.picture, - tags: artistResult.data.tags, - uri: artistResult.data.uri, - spotifyLink: artistResult.data.spotifyLink, - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [artistResult.data, artistResult.isLoading, artistResult.isError, did]); - - useEffect(() => { - if (artistTracksResult.isLoading || artistTracksResult.isError) { - return; - } - - if (!artistTracksResult.data || !did) { - return; - } - - setTopTracks( - artistTracksResult.data.map((track) => ({ - ...track, - scrobbles: track.playCount || 1, - })), - ); - }, [ - artistTracksResult.data, - artistTracksResult.isLoading, - artistTracksResult.isError, - did, - ]); - - useEffect(() => { - if (artistAlbumsResult.isLoading || artistAlbumsResult.isError) { - return; - } - - if (!artistAlbumsResult.data || !did) { - return; - } - - setTopAlbums(artistAlbumsResult.data); - }, [ - artistAlbumsResult.data, - artistAlbumsResult.isLoading, - artistAlbumsResult.isError, - did, - ]); - - const loading = - artistResult.isLoading || - artistTracksResult.isLoading || - artistAlbumsResult.isLoading; - return ( - - - - - {artist?.picture && !loading && ( - - )} - {!artist?.picture && !loading && ( - - - - - - )} - - {artist && !loading && ( - - - {artist?.name} - - - - - Listeners - - - {numeral(artist?.listeners).format("0,0")} - - - - - Scrobbles - - - {numeral(artist?.scrobbles).format("0,0")} - - - - - - View on PDSls - - - - - )} - - - - - - - - - ); + const { did, rkey } = useParams({ strict: false }); + + const uri = `at://${did}/app.rocksky.artist/${rkey}`; + const artistResult = useArtistQuery(did!, rkey!); + const artistTracksResult = useArtistTracksQuery(uri); + const artistAlbumsResult = useArtistAlbumsQuery(uri); + const artistListenersResult = useArtistListenersQuery(uri); + + const artist = useAtomValue(artistAtom); + const setArtist = useSetAtom(artistAtom); + const [topTracks, setTopTracks] = useState< + { + id: string; + title: string; + artist: string; + albumArtist: string; + albumArt: string; + uri: string; + scrobbles: number; + albumUri?: string; + artistUri?: string; + }[] + >([]); + const [topAlbums, setTopAlbums] = useState< + { + id: string; + title: string; + artist: string; + albumArt: string; + artistUri: string; + uri: string; + }[] + >([]); + + useEffect(() => { + if (artistResult.isLoading || artistResult.isError) { + return; + } + + if (!artistResult.data || !did) { + return; + } + + setArtist({ + id: artistResult.data.id, + name: artistResult.data.name, + born: artistResult.data.born, + bornIn: artistResult.data.bornIn, + died: artistResult.data.died, + listeners: artistResult.data.uniqueListeners, + scrobbles: artistResult.data.playCount, + picture: artistResult.data.picture, + tags: artistResult.data.tags, + uri: artistResult.data.uri, + spotifyLink: artistResult.data.spotifyLink, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [artistResult.data, artistResult.isLoading, artistResult.isError, did]); + + useEffect(() => { + if (artistTracksResult.isLoading || artistTracksResult.isError) { + return; + } + + if (!artistTracksResult.data || !did) { + return; + } + + setTopTracks( + artistTracksResult.data.map((track) => ({ + ...track, + scrobbles: track.playCount || 1, + })), + ); + }, [ + artistTracksResult.data, + artistTracksResult.isLoading, + artistTracksResult.isError, + did, + ]); + + useEffect(() => { + if (artistAlbumsResult.isLoading || artistAlbumsResult.isError) { + return; + } + + if (!artistAlbumsResult.data || !did) { + return; + } + + setTopAlbums(artistAlbumsResult.data); + }, [ + artistAlbumsResult.data, + artistAlbumsResult.isLoading, + artistAlbumsResult.isError, + did, + ]); + + const loading = + artistResult.isLoading || + artistTracksResult.isLoading || + artistAlbumsResult.isLoading; + return ( + + + + + {artist?.picture && !loading && ( + + )} + {!artist?.picture && !loading && ( + + + + + + )} + + {artist && !loading && ( + + + {artist?.name} + + + + + Listeners + + + {numeral(artist?.listeners).format("0,0")} + + + + + Scrobbles + + + {numeral(artist?.scrobbles).format("0,0")} + + + + + + View on PDSls + + + + + )} + + + + + + + + + ); }; export default Artist; diff --git a/apps/web/src/pages/artist/ArtistListeners/ArtistListeners.tsx b/apps/web/src/pages/artist/ArtistListeners/ArtistListeners.tsx index 83dbc2af..c8efff50 100644 --- a/apps/web/src/pages/artist/ArtistListeners/ArtistListeners.tsx +++ b/apps/web/src/pages/artist/ArtistListeners/ArtistListeners.tsx @@ -3,72 +3,72 @@ import { Avatar } from "baseui/avatar"; import { HeadingSmall } from "baseui/typography"; interface ArtistListenersProps { - listeners: { - id: string; - did: string; - handle: string; - displayName: string; - avatar: string; - mostListenedSong: { - title: string; - uri: string; - playCount: number; - }; - totalPlays: number; - rank: number; - }[]; + listeners: { + id: string; + did: string; + handle: string; + displayName: string; + avatar: string; + mostListenedSong: { + title: string; + uri: string; + playCount: number; + }; + totalPlays: number; + rank: number; + }[]; } function ArtistListeners(props: ArtistListenersProps) { - return ( - <> - - Listeners - - {props.listeners?.map((item) => ( - - - - - - - @{item.handle} - - - Listens to{" "} - {item.mostListenedSong.uri && ( - - {item.mostListenedSong.title} - - )} - {!item.mostListenedSong.uri && ( - - {item.mostListenedSong.title} - - )}{" "} - a lot - - - - ))} - > - ); + return ( + <> + + Listeners + + {props.listeners?.map((item) => ( + + + + + + + @{item.handle} + + + Listens to{" "} + {item.mostListenedSong.uri && ( + + {item.mostListenedSong.title} + + )} + {!item.mostListenedSong.uri && ( + + {item.mostListenedSong.title} + + )}{" "} + a lot + + + + ))} + > + ); } export default ArtistListeners; diff --git a/apps/web/src/pages/home/feed/Feed.tsx b/apps/web/src/pages/home/feed/Feed.tsx index 49d81bde..f439ba72 100644 --- a/apps/web/src/pages/home/feed/Feed.tsx +++ b/apps/web/src/pages/home/feed/Feed.tsx @@ -15,9 +15,9 @@ import { useFeedQuery } from "../../../hooks/useFeed"; dayjs.extend(relativeTime); const itemProps: BlockProps = { - display: "flex", - alignItems: "flex-start", - flexDirection: "column", + display: "flex", + alignItems: "flex-start", + flexDirection: "column", }; const Container = styled.div` @@ -28,104 +28,104 @@ const Container = styled.div` `; function Feed() { - const { data, isLoading } = useFeedQuery(); - console.log(data); - return ( - - - Recently played - + const { data, isLoading } = useFeedQuery(); + console.log(data); + return ( + + + Recently played + - {isLoading && ( - - - - - - - - - - - - - - - - - - )} + {isLoading && ( + + + + + + + + + + + + + + + + + + )} - {!isLoading && ( - - - { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data.map((song: any) => ( - - - - - - - - - {" "} - - - recently played this song - - - - {dayjs(song.date).fromNow()} - - - - )) - } - - - )} - - ); + {!isLoading && ( + + + { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + data.map((song: any) => ( + + + + + + + + + {" "} + + + recently played this song + + + + {dayjs(song.date).fromNow()} + + + + )) + } + + + )} + + ); } export default Feed; diff --git a/apps/web/src/pages/profile/Profile.tsx b/apps/web/src/pages/profile/Profile.tsx index b37f23dd..c28cd151 100644 --- a/apps/web/src/pages/profile/Profile.tsx +++ b/apps/web/src/pages/profile/Profile.tsx @@ -26,200 +26,200 @@ const Group = styled.div` `; export type ProfileProps = { - activeKey?: string; + activeKey?: string; }; function Profile(props: ProfileProps) { - const [profiles, setProfiles] = useAtom(profilesAtom); - const [activeKey, setActiveKey] = useState( - _.get(props, "activeKey", "0").split("/")[0], - ); - const { did } = useParams({ strict: false }); - const profile = useProfileByDidQuery(did!); - const setUser = useSetAtom(userAtom); - const { tab } = useSearch({ strict: false }); + const [profiles, setProfiles] = useAtom(profilesAtom); + const [activeKey, setActiveKey] = useState( + _.get(props, "activeKey", "0").split("/")[0], + ); + const { did } = useParams({ strict: false }); + const profile = useProfileByDidQuery(did!); + const setUser = useSetAtom(userAtom); + const { tab } = useSearch({ strict: false }); - useEffect(() => { - if (tab === undefined) { - return; - } + useEffect(() => { + if (tab === undefined) { + return; + } - setActiveKey(1); - }, [tab]); + setActiveKey(1); + }, [tab]); - // biome-ignore lint/correctness/useExhaustiveDependencies: want to run only on profile.data changes - useEffect(() => { - if (profile.isLoading || profile.isError) { - return; - } + // biome-ignore lint/correctness/useExhaustiveDependencies: want to run only on profile.data changes + useEffect(() => { + if (profile.isLoading || profile.isError) { + return; + } - if (!profile.data || !did) { - return; - } + if (!profile.data || !did) { + return; + } - setUser({ - avatar: profile.data.avatar, - displayName: profile.data.displayName, - handle: profile.data.handle, - spotifyUser: { - isBeta: profile.data.spotifyUser?.isBetaUser, - }, - spotifyConnected: profile.data.spotifyConnected, - did: profile.data.did, - }); + setUser({ + avatar: profile.data.avatar, + displayName: profile.data.displayName, + handle: profile.data.handle, + spotifyUser: { + isBeta: profile.data.spotifyUser?.isBetaUser, + }, + spotifyConnected: profile.data.spotifyConnected, + did: profile.data.did, + }); - setProfiles((profiles) => ({ - ...profiles, - [did]: { - avatar: profile.data.avatar, - displayName: profile.data.displayName, - handle: profile.data.handle, - spotifyConnected: profile.data.spotifyConnected, - createdAt: profile.data.createdAt, - did, - }, - })); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [profile.data, profile.isLoading, profile.isError, did]); + setProfiles((profiles) => ({ + ...profiles, + [did]: { + avatar: profile.data.avatar, + displayName: profile.data.displayName, + handle: profile.data.handle, + spotifyConnected: profile.data.spotifyConnected, + createdAt: profile.data.createdAt, + did, + }, + })); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [profile.data, profile.isLoading, profile.isError, did]); - if (!did) { - return; - } + if (!did) { + return; + } - return ( - - - - - - - - - {profiles[did]?.displayName} - - - - @{profiles[did]?.handle} - - - {" "} - • scrobbling since{" "} - {dayjs(profiles[did]?.createdAt).format("DD MMM YYYY")} - - - - - - View on PDSls - - - - + return ( + + + + + + + + + {profiles[did]?.displayName} + + + + @{profiles[did]?.handle} + + + {" "} + • scrobbling since{" "} + {dayjs(profiles[did]?.createdAt).format("DD MMM YYYY")} + + + + + + View on PDSls + + + + - { - setActiveKey(activeKey); - }} - overrides={{ - TabHighlight: { - style: { - backgroundColor: "var(--color-purple)", - }, - }, - TabBorder: { - style: { - display: "none", - }, - }, - }} - activateOnFocus - > - - - - - - - - - - - - - - - - - - ); + { + setActiveKey(activeKey); + }} + overrides={{ + TabHighlight: { + style: { + backgroundColor: "var(--color-purple)", + }, + }, + TabBorder: { + style: { + display: "none", + }, + }, + }} + activateOnFocus + > + + + + + + + + + + + + + + + + + + ); } export default Profile;
{webscrobblerWebhook}