diff --git a/atoms/playlistAtom.js b/atoms/playlistAtom.js
new file mode 100644
index 0000000..13386c8
--- /dev/null
+++ b/atoms/playlistAtom.js
@@ -0,0 +1,11 @@
+import { atom } from 'recoil'
+
+export const playlistState = atom({
+ key: 'playlistState',
+ default: null,
+})
+
+export const playlistIdState = atom({
+ key: 'playlistIdState',
+ default: '37i9dQZF1EUMDoJuT8yJsl',
+})
diff --git a/components/Center.jsx b/components/Center.jsx
new file mode 100644
index 0000000..79c301c
--- /dev/null
+++ b/components/Center.jsx
@@ -0,0 +1,80 @@
+import { useSession } from 'next-auth/react'
+import { ChevronDownIcon } from '@heroicons/react/outline'
+import { useEffect, useState } from 'react'
+import { shuffle } from 'lodash'
+import { useRecoilState, useRecoilValue } from 'recoil'
+import { playlistIdState, playlistState } from '../atoms/playlistAtom'
+import useSpotify from '../hooks/useSpotify'
+import Songs from './Songs'
+
+const colors = [
+ 'from-indigo-500',
+ 'from-blue-500',
+ 'from-green-500',
+ 'from-red-500',
+ 'from-yellow-500',
+ 'from-pink-500',
+ 'from-purple-500',
+]
+
+function Center() {
+ const spotifyApi = useSpotify()
+ const { data: session } = useSession()
+ const [color, setColor] = useState(null)
+ const playlistId = useRecoilValue(playlistIdState)
+ const [playlist, setPlaylist] = useRecoilState(playlistState)
+
+ console.log('Playlist - ', playlist)
+
+ useEffect(() => {
+ setColor(shuffle(colors).pop())
+ }, [playlistId])
+
+ useEffect(() => {
+ spotifyApi
+ .getPlaylist(playlistId)
+ .then((data) => setPlaylist(data.body))
+ .catch((error) => console.log(error))
+ }, [spotifyApi, playlistId])
+
+ return (
+
+
{/* Playlist */}
-
Playlist name
-
Playlist name
-
Playlist name
-
Playlist name
-
Playlist name
-
Playlist name
-
Playlist name
-
Playlist name
-
Playlist name
-
Playlist name
+ {playlist.map((playlist) => (
+
setPlaylistId(playlist.id)}
+ >
+ {playlist.name}
+
+ ))}
)
diff --git a/components/Song.jsx b/components/Song.jsx
new file mode 100644
index 0000000..856b973
--- /dev/null
+++ b/components/Song.jsx
@@ -0,0 +1,30 @@
+import { millisToMinutesAndSeconds } from '../lib/time'
+
+function Song({ order, track }) {
+ // console.log(track)
+ return (
+
+
+
{order + 1}
+
+
+
{track.track.name}
+
{track.track.artists[0].name}
+
+
+
+
{track.track.album.name}
+
{millisToMinutesAndSeconds(track.track.duration_ms)}
+
+
+ )
+}
+
+export default Song
diff --git a/components/Songs.jsx b/components/Songs.jsx
new file mode 100644
index 0000000..6084f30
--- /dev/null
+++ b/components/Songs.jsx
@@ -0,0 +1,17 @@
+import { useRecoilValue } from 'recoil'
+import { playlistState } from '../atoms/playlistAtom'
+import Song from './Song'
+
+function Songs() {
+ const playlist = useRecoilValue(playlistState)
+
+ return (
+
+ {playlist?.tracks.items.map((track, index) => (
+
+ ))}
+
+ )
+}
+
+export default Songs
diff --git a/hooks/useSpotify.js b/hooks/useSpotify.js
new file mode 100644
index 0000000..5654645
--- /dev/null
+++ b/hooks/useSpotify.js
@@ -0,0 +1,27 @@
+import { signIn, useSession } from 'next-auth/react'
+import { useEffect } from 'react'
+import SpotifyWebApi from 'spotify-web-api-node'
+// import spotifyApi from '../lib/spotify'
+
+const spotifyApi = new SpotifyWebApi({
+ clientId: process.env.NEXT_PUBLIC_CLIENT_ID,
+ clientSecret: process.env.NEXT_PUBLIC_CLIENT_SECRET,
+})
+
+function useSpotify() {
+ const { data: session, status } = useSession()
+
+ useEffect(() => {
+ if (session) {
+ // If refresh token attempt fails, direct user to login
+ if (session.error === 'RefreshAccessTokenError') {
+ signIn()
+ }
+
+ spotifyApi.setAccessToken(session.user.accessToken)
+ }
+ }, [session])
+ return spotifyApi
+}
+
+export default useSpotify
diff --git a/lib/time.js b/lib/time.js
new file mode 100644
index 0000000..31c33c9
--- /dev/null
+++ b/lib/time.js
@@ -0,0 +1,10 @@
+import { constSelector } from 'recoil'
+
+export const millisToMinutesAndSeconds = (millis) => {
+ const minutes = Math.floor(millis / 60000)
+ const seconds = ((millis % 60000) / 1000).toFixed(0)
+
+ return seconds == 60
+ ? minutes + 1 + ':00'
+ : minutes + ':' + (seconds < 10 ? '0' : '') + seconds
+}
diff --git a/package-lock.json b/package-lock.json
index b16bb91..73363b6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,11 +6,14 @@
"": {
"dependencies": {
"@heroicons/react": "^1.0.5",
+ "lodash": "^4.17.21",
"next": "latest",
"next-auth": "^4.0.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "spotify-web-api-node": "^5.0.2"
+ "recoil": "^0.5.2",
+ "spotify-web-api-node": "^5.0.2",
+ "tailwind-scrollbar-hide": "^1.1.7"
},
"devDependencies": {
"@types/node": "17.0.4",
@@ -2071,6 +2074,11 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
},
+ "node_modules/hamt_plus": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
+ "integrity": "sha1-4hwlKWjH4zsg9qGwlM2FeHomVgE="
+ },
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -2648,6 +2656,11 @@
"node": ">=8"
}
},
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
"node_modules/lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -3637,6 +3650,25 @@
"node": ">=8.10.0"
}
},
+ "node_modules/recoil": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.5.2.tgz",
+ "integrity": "sha512-Edibzpu3dbUMLy6QRg73WL8dvMl9Xqhp+kU+f2sJtXxsaXvAlxU/GcnDE8HXPkprXrhHF2e6SZozptNvjNF5fw==",
+ "dependencies": {
+ "hamt_plus": "1.0.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.13.1"
+ },
+ "peerDependenciesMeta": {
+ "react-dom": {
+ "optional": true
+ },
+ "react-native": {
+ "optional": true
+ }
+ }
+ },
"node_modules/regenerator-runtime": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz",
@@ -4040,6 +4072,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tailwind-scrollbar-hide": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/tailwind-scrollbar-hide/-/tailwind-scrollbar-hide-1.1.7.tgz",
+ "integrity": "sha512-X324n9OtpTmOMqEgDUEA/RgLrNfBF/jwJdctaPZDzB3mppxJk7TLIDmOreEDm1Bq4R9LSPu4Epf8VSdovNU+iA=="
+ },
"node_modules/tailwindcss": {
"version": "3.0.12",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.12.tgz",
@@ -5990,6 +6027,11 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
},
+ "hamt_plus": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/hamt_plus/-/hamt_plus-1.0.2.tgz",
+ "integrity": "sha1-4hwlKWjH4zsg9qGwlM2FeHomVgE="
+ },
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@@ -6374,6 +6416,11 @@
"p-locate": "^4.1.0"
}
},
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -7066,6 +7113,14 @@
"picomatch": "^2.2.1"
}
},
+ "recoil": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/recoil/-/recoil-0.5.2.tgz",
+ "integrity": "sha512-Edibzpu3dbUMLy6QRg73WL8dvMl9Xqhp+kU+f2sJtXxsaXvAlxU/GcnDE8HXPkprXrhHF2e6SZozptNvjNF5fw==",
+ "requires": {
+ "hamt_plus": "1.0.2"
+ }
+ },
"regenerator-runtime": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz",
@@ -7359,6 +7414,11 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
+ "tailwind-scrollbar-hide": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/tailwind-scrollbar-hide/-/tailwind-scrollbar-hide-1.1.7.tgz",
+ "integrity": "sha512-X324n9OtpTmOMqEgDUEA/RgLrNfBF/jwJdctaPZDzB3mppxJk7TLIDmOreEDm1Bq4R9LSPu4Epf8VSdovNU+iA=="
+ },
"tailwindcss": {
"version": "3.0.12",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.0.12.tgz",
diff --git a/package.json b/package.json
index ff027a3..0bbc6e0 100644
--- a/package.json
+++ b/package.json
@@ -7,11 +7,14 @@
},
"dependencies": {
"@heroicons/react": "^1.0.5",
+ "lodash": "^4.17.21",
"next": "latest",
"next-auth": "^4.0.6",
"react": "^17.0.2",
"react-dom": "^17.0.2",
- "spotify-web-api-node": "^5.0.2"
+ "recoil": "^0.5.2",
+ "spotify-web-api-node": "^5.0.2",
+ "tailwind-scrollbar-hide": "^1.1.7"
},
"devDependencies": {
"@types/node": "17.0.4",
diff --git a/pages/_app.jsx b/pages/_app.jsx
index 7a61480..0861324 100644
--- a/pages/_app.jsx
+++ b/pages/_app.jsx
@@ -1,10 +1,14 @@
import '../styles/globals.css'
import { SessionProvider } from 'next-auth/react'
+import { RecoilBridge, RecoilRoot } from 'recoil'
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
+ // console.log(`session _app - `, session)
return (
-
+
+
+
)
}
diff --git a/pages/_middleware.jsx b/pages/_middleware.jsx
index a6022d9..9f35a9a 100644
--- a/pages/_middleware.jsx
+++ b/pages/_middleware.jsx
@@ -8,7 +8,7 @@ export async function middleware(req) {
const token = await getToken({ req, secret })
const { pathname } = req.nextUrl
- console.log(pathname)
+ //console.log(pathname)
if (token && pathname === '/login') {
return NextResponse.redirect('/')
diff --git a/pages/index.jsx b/pages/index.jsx
index 294cfef..86e84c5 100644
--- a/pages/index.jsx
+++ b/pages/index.jsx
@@ -1,14 +1,14 @@
import { getSession } from 'next-auth/react'
import Head from 'next/head'
import Sidebar from '../components/Sidebar'
+import Center from '../components/Center'
export default function Home() {
return (
-
- {/* Side bar */}
+
- {/* Center */}
+
{/* Player */}
@@ -16,10 +16,10 @@ export default function Home() {
)
}
-// export async function getServerSideProps(context) {
-// return {
-// props: {
-// session: await getSession(context),
-// },
-// }
-// }
+export async function getServerSideProps(context) {
+ return {
+ props: {
+ session: await getSession(context),
+ },
+ }
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index 4cd6138..880e5e7 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,10 +1,10 @@
module.exports = {
- content: [
- './pages/**/*.{js,ts,jsx,tsx}',
- './components/**/*.{js,ts,jsx,tsx}',
- ],
- theme: {
- extend: {},
- },
- plugins: [],
+ content: [
+ './pages/**/*.{js,ts,jsx,tsx}',
+ './components/**/*.{js,ts,jsx,tsx}',
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [require('tailwind-scrollbar-hide')],
}