Skip to content

Commit

Permalink
added: playlist page & api functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
NayanUnni95 committed Oct 18, 2024
1 parent 13dee0a commit 3a1ec6c
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 9 deletions.
28 changes: 28 additions & 0 deletions Genres List.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Music /genre/0JQ5DAqbMKFSi39LMRT0Cy
Made for you /genre/0JQ5DAt0tbjZptfcdMSKl3
Explore all category /genre/0JQ5DArNBzkmxXHCqFLx3c
Daily mix /genre/section0JQ5DACFo5h0jxzOyHOsIo
Your artist mixes /genre/section0JQ5DACFo5h0jxzOyHOsIa
Featured playlist /genre/section0JQ5DAzQHECxDlYNI6xD1g
Uniquely yours /genre/section0JQ5DACFo5h0jxzOyHOsIe
Handpicked new release /genre/section0JQ5IMCbQBLAlPhkJ41ypw
New release /genre/0JQ5DAqbMKFz6FAsUtgAab
Your genre mixes /genre/section0JQ5DACFo5h0jxzOyHOsI9
Your decade mixes /genre/section0JQ5DACFo5h0jxzOyHOsIb
Your mood mixes /genre/section0JQ5DACFo5h0jxzOyHOsIc
Your niche mixes /genre/section0JQ5DATaxswzruE2nWp3Lr
The best new release /genre/section0JQ5IMCbQBLiGLtWsAvnNG
Recently played /genre/recently-played
Popular equal playlist /genre/section0JQ5IMCbQBLmdV4K4hLrHt
Playlist from our editors /genre/0JQ5DAqbMKFSi39LMRT0Cy
Jump back in /section/0JQ5DAIiKWzVFULQfUm85X
Popular album /section/0JQ5DAnM3wGh0gz1MXnu3B
Today's biggest hits /section/0JQ5DAnM3wGh0gz1MXnu3M
More of what you like /section/0JQ5DAnM3wGh0gz1MXnu3J
India's best /section/0JQ5DAuChZYPe9iDhh2mJz
Charts /section/0JQ5DAnM3wGh0gz1MXnu5g
Popular radio /section/0JQ5DAnM3wGh0gz1MXnu4h
Popular artist /section/0JQ5DAnM3wGh0gz1MXnu3C
For that 'pasandida insaan' /section/0JQ5IMCbQBLkvpuwqL2UWr
Spotify playlist /section/0JQ5DAuChZYPe9iDhh2mJz
Featured charts /section/0JQ5DAzQHECxDlYNI6xD1g
17 changes: 16 additions & 1 deletion src/constants/constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ const Base_URL = 'https://api.spotify.com/v1';
const Liked_Songs = '/me/tracks?limit=50';
const Albums = '/me/albums';
const Playlist = '/me/playlists';
const Artists = '/me/following?type=artist';
const PlaylistWithId = '/playlists';
const Artists = '/me/following?type=artist&limit=50';
const Several_Category = 'browse/categories';
const Several_Albums = '/albums/{id}';
const New_Release = '/browse/new-releases';
Expand All @@ -16,13 +17,21 @@ const Several_Artists = '/artists/{id}';
const Several_BrowserCategory = '/browse/categories';
const Search_Item = '/search';
const Profile = '/me';
const Recently_Played = '/me/player/recently-played';
const Recommendation =
'/recommendations?seed_artists={artist_id}&seed_genres={genre}&seed_tracks={track_id}';
const Today_Hits = '/search?q=playlist:"Today\'s Biggest Hits"&type=playlist';
const Charts = '/search?q=charts&type=playlist';
const County_Best = `/browse/categories?country=`;
const User = '/users';

export {
Token_URL,
Base_URL,
Liked_Songs,
Albums,
Playlist,
PlaylistWithId,
Artists,
Several_Category,
Several_Albums,
Expand All @@ -36,4 +45,10 @@ export {
Several_BrowserCategory,
Search_Item,
Profile,
Recently_Played,
Recommendation,
Today_Hits,
Charts,
County_Best,
User,
};
6 changes: 5 additions & 1 deletion src/pages/Collection/Collection.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { IoPlay } from 'react-icons/io5';
import NavBar from '../../components/NavBar/NavBar';
import { Link, useNavigate } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
import { Liked_Songs } from '../../constants/constant';
import { Liked_Songs, User } from '../../constants/constant';
import equ from '../../assets/images/equaliser-animated-green.gif';
import { DataContext } from '../../context/DataCacheContext';
import { ThreeDots } from 'react-loader-spinner';
Expand Down Expand Up @@ -112,6 +112,10 @@ function Collection() {
</div>
<div className={styles.desc}>
<h5 className={styles.name}>
<img
src={profileData && profileData.images[0].url}
alt={profileData && profileData.display_name}
/>
<Link to={profileData ? `/user/${profileData.id}` : ``}>
{profileData ? profileData.display_name : 'user'}
</Link>
Expand Down
27 changes: 27 additions & 0 deletions src/pages/Collection/Collection.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@
display: flex;
align-items: center;
}
.name {
display: flex;
align-items: center;
justify-content: center;
}
.name img {
width: 2rem;
height: 2rem;
border-radius: 3rem;
margin-right: 0.5rem;
}
.songManageSection {
display: flex;
align-items: center;
Expand Down Expand Up @@ -92,6 +103,10 @@ button {
.desc {
font-size: medium;
}
.desc h4 {
font-weight: 400;
color: #b8b8b8e0;
}
.desc h5 {
color: #000000;
}
Expand Down Expand Up @@ -255,6 +270,9 @@ button {
.songAddedTime {
display: none;
}
.name img {
display: none;
}
}
@media only screen and (min-width: 768px) {
.innerSection {
Expand All @@ -268,6 +286,15 @@ button {
font-size: 3rem;
}
}
@media only screen and (min-width: 1024px) {
.imgSection div img {
width: 200px;
height: 200px;
}
.title h1 {
font-size: 4rem;
}
}
@keyframes scroll {
0% {
transform: translateX(0%);
Expand Down
6 changes: 3 additions & 3 deletions src/pages/Login/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function Login() {
const clientId = import.meta.env.VITE_CLIENT_ID;
const redirectUri = import.meta.env.VITE_HOME_URL;
const scope =
'user-read-private user-read-email playlist-modify-private playlist-modify-public playlist-read-private user-top-read user-library-read user-follow-read';
'user-read-private user-read-email playlist-modify-private playlist-modify-public playlist-read-private user-top-read user-library-read user-follow-read user-read-recently-played';
let url = 'https://accounts.spotify.com/authorize';
url += '?response_type=token';
url += '&client_id=' + encodeURIComponent(clientId);
Expand All @@ -32,8 +32,8 @@ function Login() {
</div>
<div className={styles.contentSection}>
<div>
<span>Get Started,</span>to your musical journey with spotify,
simply log in with your existing account or <br />
<span>Get Started,</span>to your musical journey with spotify
client, simply log in with your existing account or <br />
<a href="https://accounts.spotify.com/en/login">
create a new one.
</a>
Expand Down
207 changes: 203 additions & 4 deletions src/pages/Playlist/Playlist.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,213 @@
import React from 'react';
import styles from './Playlist.module.css';
import React, { useState, useEffect } from 'react';
import styles from '../Collection/Collection.module.css';
import { Icon } from '../../Icons';
import { FaArrowLeft } from 'react-icons/fa6';
import { RiMore2Line } from 'react-icons/ri';
import { LuClock3 } from 'react-icons/lu';
import { IoPlay } from 'react-icons/io5';
import NavBar from '../../components/NavBar/NavBar';
import { Link } from 'react-router-dom';
import { Link, useNavigate, useParams } from 'react-router-dom';
import { useAuth } from '../../hooks/useAuth';
import { PlaylistWithId, User } from '../../constants/constant';
import equ from '../../assets/images/equaliser-animated-green.gif';
import { ThreeDots } from 'react-loader-spinner';

function Playlist() {
return <></>;
const navigate = useNavigate();
const [cardHover, setCardHover] = useState(false);
const [playlistData, setPlaylistData] = useState(null);
const [playlistOwner, setPlaylistOwner] = useState(null);
const { fetchData } = useAuth();
const { playlistId } = useParams();

const DateConverter = (zuluTime) => {
const date = new Date(zuluTime);
const months = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
];
const day = String(date.getUTCDate()).padStart(2, '0');
const month = months[date.getUTCMonth()];
const year = date.getUTCFullYear();
return `${day} ${month} ${year}`;
};

const msToTime = (milliseconds) => {
const totalSeconds = Math.floor(milliseconds / 1000);

const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;

const formattedMinutes = String(minutes).padStart(2, '0');
const formattedSeconds = String(seconds).padStart(2, '0');

return `${formattedMinutes}:${formattedSeconds}`;
};
useEffect(() => {
// do {
fetchData(`${PlaylistWithId}/${playlistId}`)
.then((res) => {
setPlaylistData(res);
fetchData(`${User}/${res.owner.id}`)
.then((res) => {
setPlaylistOwner(res);
})
.catch((err) => {
console.log(err);
});
})
.catch((err) => {
console.log(err);
});
// } while (savedTracks != null);
}, [playlistId]);

return (
<div className={styles.collectionSection}>
{playlistData ? (
<div className={styles.innerSection}>
<div className={styles.navigationBar}>
<NavBar />
</div>
<nav>
<div className={styles.navigationBtn}>
<button onClick={() => navigate(-1)}>
<FaArrowLeft size={20} color="black" />
</button>
</div>
<div className={styles.songManageSection}>
<div className={styles.searchBar}>
<button>
<Icon name="search" size={15} />
</button>
<input type="text" placeholder="Find in liked songs" />
</div>
<div className={styles.sortBtn}>
<button>sort</button>
</div>
</div>
</nav>
<header>
<div className={styles.imgSection}>
<div>
<img
src={playlistData && playlistData.images[0].url}
alt={playlistData && playlistData.name}
/>
</div>
</div>
<div className={styles.detailsSection}>
<div className={styles.type}>
<span>{playlistData && playlistData.type}</span>
</div>
<div className={styles.title}>
<h1>{playlistData && playlistData.name}</h1>
</div>
<div className={styles.desc}>
<h4>{playlistData && playlistData.description}</h4>
</div>
<div className={styles.desc}>
<h5 className={styles.name}>
<img
src={playlistOwner && playlistOwner.images[0].url}
alt={playlistOwner && playlistOwner.display_name}
/>
<Link to={playlistOwner && `/user/${playlistOwner.id}`}>
<h3>{playlistOwner && playlistOwner.display_name}</h3>
</Link>
</h5>
<span className={styles.songCount}>
&nbsp;• {playlistData.tracks.total} songs
</span>
</div>
</div>
</header>
<div className={styles.tableContainer}>
<hr />
<table>
<thead>
<tr>
<th className={styles.tableSongNoLabel}>#</th>
<th className={styles.tableSongTitleLabel}>title</th>
<th className={styles.tableSongAlbumLabel}>album</th>
<th className={styles.tableSongDateLabel}>date added</th>
<th className={styles.tableSongDurationLabel}>
<LuClock3 />
</th>
</tr>
</thead>
<tbody>
{playlistData.tracks.items.map((data, index) => {
return (
<tr key={index} style={{ cursor: 'pointer' }}>
<td className={styles.songNo}>
{cardHover ? <IoPlay /> : <span>{index + 1}</span>}
{/* <img
src={equ}
style={{ width: '15px', height: '15px' }}
/> */}
</td>
<td className={styles.songMainData}>
<div className={styles.songAvatar}>
<img src={data.track.album.images[1].url} />
</div>
<div className={styles.songDetails}>
<div className={styles.songName}>
<Link to={`/track/${data.track.id}`}>
<span>{data.track.name}</span>
</Link>
</div>
<div className={styles.artistName}>
{data.track.artists.map((obj, index) => {
return (
<Link to={`/artist/${obj.id}`} key={index}>
<span>{obj.name},</span>
</Link>
);
})}
</div>
</div>
</td>
<td className={styles.songAlbumName}>
<div className={styles.albumNameSection}>
<Link to={`/album/${data.track.album.id}`}>
<span>{data.track.album.name}</span>
</Link>
</div>
</td>
<td className={styles.songAddedTime}>
<span>{DateConverter(data.added_at)}</span>
</td>
<td className={styles.songDuration}>
<span>{msToTime(data.track.duration_ms)}</span>
</td>
<td className={styles.moreBtn}>
<RiMore2Line style={{ cursor: 'not-allowed' }} />
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
) : (
<div className={styles.loaderSection}>
<ThreeDots visible={true} height="50" width="50" color="gray" />
</div>
)}
</div>
);
}

export default Playlist;
Empty file.

0 comments on commit 3a1ec6c

Please sign in to comment.