import { MouseEventHandler, useEffect, useRef, useState } from 'react' import { full as FullSdk } from '@audius/sdk' import { ThemeProvider as HarmonyThemeProvider, Hint, IconInfo, IconPause, IconPlay, Paper, Text, TextInput, TextInputSize, Button, Flex } from '@audius/harmony' import { hc } from 'hono/client' import { css } from '@emotion/react' import { useSdk } from './hooks/useSdk' import { useAuth } from './contexts/AuthProvider' import type { AppType } from '..' import { Status } from './contexts/types' // eslint-disable-next-line @typescript-eslint/no-explicit-any const client = hc('/') as any export default function App() { const { sdk } = useSdk() const { user, login, status } = useAuth() const [tracks, setTracks] = useState([]) const [isPlaying, setIsPlaying] = useState(false) const [playingTrackId, setPlayingTrackId] = useState() const [playingTrackSrc, setPlayingTrackSrc] = useState() const [favorites, setFavorites] = useState>({}) const audioRef = useRef(null) const handleInputRef = useRef(null) const loginWithAudiusButtonRef = useRef(null) /** * Init @audius/sdk oauth */ useEffect(() => { sdk.oauth?.init({ successCallback: async (u, token) => { const userRes = await sdk.users.getUser({ id: u.userId }) if (!userRes?.data) { return } const user = userRes.data login(user, token) }, errorCallback: (error: string) => console.log('Got error', error) }) if (loginWithAudiusButtonRef.current) { sdk.oauth?.renderButton({ element: loginWithAudiusButtonRef.current, scope: 'write' }) } }, [loginWithAudiusButtonRef, sdk.users, sdk.oauth, login]) /** * Fetch tracks based on the user handle present in handleInputRef * Update favorites state with the results of the fetch */ const fetchTrack = async () => { const { data: selectedUser } = await sdk.users.getUserByHandle({ handle: handleInputRef.current?.value ?? '' }) if (!selectedUser) { return } const res = await client.tracksByUser.$get({ query: { id: selectedUser.id, userId: user?.id ?? '' } }) const { data: tracks } = await res.json() setTracks(tracks ?? []) const trackFavorites = (tracks ?? []).reduce( (result: Record, track: FullSdk.TrackFull) => ({ ...result, [track.id]: track.hasCurrentUserSaved }), {} as Record ) setFavorites(trackFavorites) } /** * Set the streamUrl for the audio player based on the clicked track */ const streamTrack = async (trackId: string) => { if (trackId === playingTrackId) { setIsPlaying((prev) => !prev) } else { const streamUrl = await sdk.tracks.getTrackStreamUrl({ trackId }) setPlayingTrackSrc(streamUrl) setPlayingTrackId(trackId) setIsPlaying(true) } } /** * Favorite or unfavorite a track. This requires a user to be authenticated and granted * write permissions to the app. Uses the client-side SDK with hedgehog wallet for signing. */ const favoriteTrack = (trackId: string, favorite = true): MouseEventHandler => async (e) => { e.stopPropagation() if (user) { setFavorites((prev) => ({ ...prev, [trackId]: favorite })) try { if (favorite) { await sdk.tracks.favoriteTrack({ userId: user.id, trackId }) } else { await sdk.tracks.unfavoriteTrack({ userId: user.id, trackId }) } } catch (e) { console.error('Failed to favorite track', e) setFavorites((prev) => ({ ...prev, [trackId]: !favorite })) } } else { alert('Please log in with Audius to perform write operations') } } /** * Update the audio player based on the isPlaying state */ useEffect(() => { if (isPlaying && audioRef.current?.src) { audioRef.current?.play() } else { audioRef.current?.pause() } }, [isPlaying]) return ( React + Hono + @audius/sdk Stream and favorite tracks! {status !== Status.LOADING ? ( !user ? ( } m='m' css={{ maxWidth: 400 }} > To perform writes with @audius/sdk please authorize this app to perform writes on your behalf
) : ( Logged in as: {`@${user.handle}`} ) ) : null} Enter a user handle to fetch their tracks: {tracks.map((track) => ( streamTrack(track.id)} css={{ width: 400 }} > svg { display: block; } } `} > {track.title} {!isPlaying || track.id !== playingTrackId ? ( ) : ( )} {track.title} {track.user.name} ))}