diff --git a/packages/nextjs/context/PlayerContext.tsx b/packages/nextjs/context/PlayerContext.tsx new file mode 100644 index 0000000..a56bf10 --- /dev/null +++ b/packages/nextjs/context/PlayerContext.tsx @@ -0,0 +1,100 @@ +import { createContext, useContext, useEffect, useState } from "react"; +import { Track } from "../types/spotify"; + +const PlayerContext = createContext({} as any); + +export default function PlayerProvider({ children }: any) { + const [currentTrack, setCurrentTrack] = useState(null); + const [currentTrackAudio, setCurrentTrackAudio] = useState(null); + const [isPlaying, setIsPlaying] = useState(false); + const [duration, setDuration] = useState(0); + const [currentTime, setCurrentTime] = useState(0); + const [slider, setSlider] = useState(1); + const [drag, setDrag] = useState(0); + + useEffect(() => { + if (!currentTrack) return; + if (isPlaying) { + pause(); + setCurrentTrackAudio(null); + } + const tempAudio = new Audio(currentTrack.preview_url); + + const setAudioData = () => { + setDuration(tempAudio.duration); + setCurrentTime(tempAudio.currentTime); + }; + + const setAudioTime = () => { + const currTime = tempAudio.currentTime; + setCurrentTime(currTime); + setSlider(currTime ? Number(((currTime * 100) / tempAudio.duration).toFixed(1)) : 0); + }; + + tempAudio.addEventListener("loadeddata", setAudioData); + tempAudio.addEventListener("timeupdate", setAudioTime); + tempAudio.preload = "none"; + + setCurrentTrackAudio(tempAudio); + console.log("audio set"); + + return () => { + pause(); + setCurrentTrackAudio(null); + }; + }, [currentTrack]); + + useEffect(() => { + const handlePlay = async () => { + if (currentTrackAudio) { + await play(); + } + }; + handlePlay(); + }, [currentTrackAudio]); + + const togglePlay = async () => { + if (isPlaying) pause(); + else await play(); + }; + + const play = async () => { + setIsPlaying(true); + await currentTrackAudio?.play(); + }; + + const pause = () => { + setIsPlaying(false); + currentTrackAudio?.pause(); + }; + + useEffect(() => { + if (currentTrackAudio && drag) { + currentTrackAudio.currentTime = Math.round((drag * currentTrackAudio.duration) / 100); + } + }, [drag]); + + return ( + + {children} + + ); +} + +export const usePlayer = () => useContext(PlayerContext); diff --git a/packages/nextjs/context/SpotifyContext.tsx b/packages/nextjs/context/SpotifyContext.tsx new file mode 100644 index 0000000..a9a4f13 --- /dev/null +++ b/packages/nextjs/context/SpotifyContext.tsx @@ -0,0 +1,66 @@ +import { Dispatch, SetStateAction, createContext, useContext, useState } from "react"; +import axios from "axios"; +import { PlaylistType, SearchResults, Track } from "~~/types/spotify"; + +interface ContextProps { + playlists: PlaylistType[]; + searchResults: SearchResults | null; + query: string; + setQuery: Dispatch>; + fetchPlaylists: () => void; + fetchSearchResults: (query: string) => void; + currentTrack: Track | null; + setCurrentTrack: Dispatch>; + tracksQueue: Track[]; + setTracksQueue: Dispatch>; +} + +const SpotifyContext = createContext({} as ContextProps); + +export const SpotifyProvider = ({ children }: any) => { + const [playlists, setPlaylists] = useState([]); + const [searchResults, setSearchResults] = useState(null); + const [tracksQueue, setTracksQueue] = useState([]); + const [currentTrack, setCurrentTrack] = useState(null); + const [query, setQuery] = useState(""); + + const fetchPlaylists = async () => { + try { + const resp = await axios.get("/api/playlists"); + const data = resp.data; + setPlaylists(data.items); + } catch (err) { + console.log(err); + } + }; + + const fetchSearchResults = async () => { + try { + const resp = await axios.get(`/api/search?q=${query}`); + setSearchResults(resp.data); + } catch (err) { + console.error(err); + } + }; + + return ( + + {children} + + ); +}; + +export const useSpotify = () => useContext(SpotifyContext); diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 6799a75..27e47c8 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -35,6 +35,7 @@ "react-dom": "^18.2.0", "react-fast-marquee": "^1.3.5", "react-hot-toast": "^2.4.0", + "react-icons": "^4.12.0", "react-spotify-auth": "^1.4.3", "spotify-web-api-node": "^5.0.2", "use-debounce": "^8.0.4", diff --git a/packages/nextjs/pages/_app.tsx b/packages/nextjs/pages/_app.tsx index 2c3e710..ec19a09 100644 --- a/packages/nextjs/pages/_app.tsx +++ b/packages/nextjs/pages/_app.tsx @@ -9,6 +9,8 @@ import { Toaster } from "react-hot-toast"; import { useDarkMode } from "usehooks-ts"; import { WagmiConfig } from "wagmi"; import { BlockieAvatar } from "~~/components/scaffold-eth"; +import PlayerProvider from "~~/context/PlayerContext"; +import { SpotifyProvider } from "~~/context/SpotifyContext"; import { useNativeCurrencyPrice } from "~~/hooks/scaffold-eth"; import { useGlobalState } from "~~/services/store/store"; import { wagmiClient } from "~~/services/web3/wagmiClient"; @@ -43,7 +45,11 @@ const ScaffoldEthApp = ({ Component, pageProps }: AppProps) => { >
- + + + + +
diff --git a/yarn.lock b/yarn.lock index 24b589d..effd6bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3696,6 +3696,7 @@ __metadata: react-dom: ^18.2.0 react-fast-marquee: ^1.3.5 react-hot-toast: ^2.4.0 + react-icons: ^4.12.0 react-spotify-auth: ^1.4.3 spotify-web-api-node: ^5.0.2 tailwindcss: ^3.1.8 @@ -15453,6 +15454,15 @@ __metadata: languageName: node linkType: hard +"react-icons@npm:^4.12.0": + version: 4.12.0 + resolution: "react-icons@npm:4.12.0" + peerDependencies: + react: "*" + checksum: db82a141117edcd884ade4229f0294b2ce15d82f68e0533294db07765d6dce00b129cf504338ec7081ce364fe899b296cb7752554ea08665b1d6bad811134e79 + languageName: node + linkType: hard + "react-is@npm:^16.13.1": version: 16.13.1 resolution: "react-is@npm:16.13.1"