Skip to content

Commit

Permalink
Final Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rishonkumar committed Sep 27, 2022
1 parent 8c1d76f commit a8472bd
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/components/MusicPlayer/Track.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

const Track = ({ isPlaying, isActive, activeSong }) => (
<div className="flex-1 flex items-center justify-start">
<div className={`${isPlaying && isActive ? 'animate-[spin_3s_linear_infinite]' : ''} hidden sm:block h-16 w-16 mr-4`}>
<img src={activeSong?.images?.coverart} alt="cover art" className="rounded-full" />
</div>
<div className="w-[50%]">
<p className="truncate text-white font-bold text-lg">
{activeSong?.title ? activeSong?.title : 'No active Song'}
</p>
<p className="truncate text-gray-300">
{activeSong?.subtitle ? activeSong?.subtitle : 'No active Song'}
</p>
</div>
</div>
);

export default Track;
96 changes: 96 additions & 0 deletions src/components/MusicPlayer/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';

import { nextSong, prevSong, playPause } from '../../redux/features/playerSlice';
import Controls from './Controls';
import Player from './Player';
import Seekbar from './Seekbar';
import Track from './Track';
import VolumeBar from './VolumeBar';

const MusicPlayer = () => {
const { activeSong, currentSongs, currentIndex, isActive, isPlaying } = useSelector((state) => state.player);
const [duration, setDuration] = useState(0);
const [seekTime, setSeekTime] = useState(0);
const [appTime, setAppTime] = useState(0);
const [volume, setVolume] = useState(0.3);
const [repeat, setRepeat] = useState(false);
const [shuffle, setShuffle] = useState(false);
const dispatch = useDispatch();

useEffect(() => {
if (currentSongs.length) dispatch(playPause(true));
}, [currentIndex]);

const handlePlayPause = () => {
if (!isActive) return;

if (isPlaying) {
dispatch(playPause(false));
} else {
dispatch(playPause(true));
}
};

const handleNextSong = () => {
dispatch(playPause(false));

if (!shuffle) {
dispatch(nextSong((currentIndex + 1) % currentSongs.length));
} else {
dispatch(nextSong(Math.floor(Math.random() * currentSongs.length)));
}
};

const handlePrevSong = () => {
if (currentIndex === 0) {
dispatch(prevSong(currentSongs.length - 1));
} else if (shuffle) {
dispatch(prevSong(Math.floor(Math.random() * currentSongs.length)));
} else {
dispatch(prevSong(currentIndex - 1));
}
};

return (
<div className="relative sm:px-12 px-8 w-full flex items-center justify-between">
<Track isPlaying={isPlaying} isActive={isActive} activeSong={activeSong} />
<div className="flex-1 flex flex-col items-center justify-center">
<Controls
isPlaying={isPlaying}
isActive={isActive}
repeat={repeat}
setRepeat={setRepeat}
shuffle={shuffle}
setShuffle={setShuffle}
currentSongs={currentSongs}
handlePlayPause={handlePlayPause}
handlePrevSong={handlePrevSong}
handleNextSong={handleNextSong}
/>
<Seekbar
value={appTime}
min="0"
max={duration}
onInput={(event) => setSeekTime(event.target.value)}
setSeekTime={setSeekTime}
appTime={appTime}
/>
<Player
activeSong={activeSong}
volume={volume}
isPlaying={isPlaying}
seekTime={seekTime}
repeat={repeat}
currentIndex={currentIndex}
onEnded={handleNextSong}
onTimeUpdate={(event) => setAppTime(event.target.currentTime)}
onLoadedData={(event) => setDuration(event.target.duration)}
/>
</div>
<VolumeBar value={volume} min="0" max="1" onChange={(event) => setVolume(event.target.value)} setVolume={setVolume} />
</div>
);
};

export default MusicPlayer;
59 changes: 59 additions & 0 deletions src/pages/Discover.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from "react";
import { useDispatch, useSelector } from "react-redux";

import { Error, Loader, SongCard } from "../components";
import { selectGenreListId } from "../redux/features/playerSlice";
import { useGetSongsByGenreQuery } from "../redux/services/shazamCore";
import { genres } from "../assets/constants";

const Discover = () => {
const dispatch = useDispatch();
const { genreListId } = useSelector((state) => state.player);
const { activeSong, isPlaying } = useSelector((state) => state.player);
const { data, isFetching, error } = useGetSongsByGenreQuery(
genreListId || "POP"
);

if (isFetching) return <Loader title="Loading songs..." />;

if (error) return <Error />;

const genreTitle = genres.find(({ value }) => value === genreListId)?.title;

return (
<div className="flex flex-col">
<div className="w-full flex justify-between items-center sm:flex-row flex-col mt-4 mb-10">
<h2 className="font-bold text-3xl text-white text-left">
Discover {genreTitle}
</h2>

<select
onChange={(e) => dispatch(selectGenreListId(e.target.value))}
value={genreListId || "pop"}
className="bg-black text-gray-300 p-3 text-sm rounded-lg outline-none sm:mt-0 mt-5"
>
{genres.map((genre) => (
<option key={genre.value} value={genre.value}>
{genre.title}
</option>
))}
</select>
</div>

<div className="flex flex-wrap sm:justify-start justify-center gap-8">
{data?.map((song, i) => (
<SongCard
key={song.key}
song={song}
isPlaying={isPlaying}
activeSong={activeSong}
data={data}
i={i}
/>
))}
</div>
</div>
);
};

export default Discover;
17 changes: 17 additions & 0 deletions src/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Discover from './Discover';
import TopArtists from './TopArtists';
import ArtistDetails from './ArtistDetails';
import SongDetails from './SongDetails';
import Search from './Search';
import TopCharts from './TopCharts';
import AroundYou from './AroundYou';

export {
Discover,
Search,
TopArtists,
ArtistDetails,
SongDetails,
TopCharts,
AroundYou,
};
65 changes: 65 additions & 0 deletions src/redux/features/playerSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
currentSongs: [],
currentIndex: 0,
isActive: false,
isPlaying: false,
activeSong: {},
genreListId: '',
};

const playerSlice = createSlice({
name: 'player',
initialState,
reducers: {
setActiveSong: (state, action) => {
state.activeSong = action.payload.song;

if (action.payload?.data?.tracks?.hits) {
state.currentSongs = action.payload.data.tracks.hits;
} else if (action.payload?.data?.properties) {
state.currentSongs = action.payload?.data?.tracks;
} else {
state.currentSongs = action.payload.data;
}

state.currentIndex = action.payload.i;
state.isActive = true;
},

nextSong: (state, action) => {
if (state.currentSongs[action.payload]?.track) {
state.activeSong = state.currentSongs[action.payload]?.track;
} else {
state.activeSong = state.currentSongs[action.payload];
}

state.currentIndex = action.payload;
state.isActive = true;
},

prevSong: (state, action) => {
if (state.currentSongs[action.payload]?.track) {
state.activeSong = state.currentSongs[action.payload]?.track;
} else {
state.activeSong = state.currentSongs[action.payload];
}

state.currentIndex = action.payload;
state.isActive = true;
},

playPause: (state, action) => {
state.isPlaying = action.payload;
},

selectGenreListId: (state, action) => {
state.genreListId = action.payload;
},
},
});

export const { setActiveSong, nextSong, prevSong, playPause, selectGenreListId } = playerSlice.actions;

export default playerSlice.reducer;

0 comments on commit a8472bd

Please sign in to comment.