├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── index.html
├── manifest.json
├── robots.txt
└── webfonts
│ ├── fa-brands-400.eot
│ ├── fa-brands-400.svg
│ ├── fa-brands-400.ttf
│ ├── fa-brands-400.woff
│ ├── fa-brands-400.woff2
│ ├── fa-regular-400.eot
│ ├── fa-regular-400.svg
│ ├── fa-regular-400.ttf
│ ├── fa-regular-400.woff
│ ├── fa-regular-400.woff2
│ ├── fa-solid-900.eot
│ ├── fa-solid-900.svg
│ ├── fa-solid-900.ttf
│ ├── fa-solid-900.woff
│ └── fa-solid-900.woff2
└── src
├── App.css
├── App.js
├── Register.js
├── StateProvider.js
├── assets
├── images
│ ├── albumartwork
│ │ ├── 1.jpg
│ │ ├── 1.png
│ │ ├── 2.png
│ │ ├── 3.png
│ │ ├── 4.png
│ │ ├── 5.png
│ │ ├── 6.jpeg
│ │ ├── 7.png
│ │ ├── 8.png
│ │ └── 9.png
│ ├── site
│ │ └── email-logo.png
│ ├── songartwork
│ │ ├── download (1).jpg
│ │ ├── download (10).jpg
│ │ ├── download (11).jpg
│ │ ├── download (12).jpg
│ │ ├── download (13).jpg
│ │ ├── download (14).jpg
│ │ ├── download (2).jpg
│ │ ├── download (3).jpg
│ │ ├── download (4).jpg
│ │ ├── download (7).jpg
│ │ ├── download (8).jpg
│ │ ├── download (9).jpg
│ │ ├── download.jpg
│ │ ├── download1.jpg
│ │ ├── maxresdefault (1).jpg
│ │ └── maxresdefault.jpg
│ └── users
│ │ └── profile-images
│ │ └── unnamed.jpg
├── logo
│ └── spotify-icons-logos
│ │ ├── icons
│ │ ├── O1_RGB
│ │ │ └── O2_PNG
│ │ │ │ ├── Spotify_Icon_RGB_Black.png
│ │ │ │ ├── Spotify_Icon_RGB_Green.png
│ │ │ │ └── Spotify_Icon_RGB_White.png
│ │ └── O2_CMYK
│ │ │ └── O2_PNG
│ │ │ ├── Spotify_Icon_CMYK_Black.png
│ │ │ ├── Spotify_Icon_CMYK_Green.png
│ │ │ └── Spotify_Icon_CMYK_White.png
│ │ └── logos
│ │ ├── O1_RGB
│ │ └── O2_PNG
│ │ │ ├── Spotify_Logo_RGB_Black.png
│ │ │ ├── Spotify_Logo_RGB_Green.png
│ │ │ ├── Spotify_Logo_RGB_White.png
│ │ │ └── Spotify_Logo_RGB_nwe.png
│ │ └── O2_CMYK
│ │ └── O2_PNG
│ │ ├── Spotify_Logo_CMYK_Black.png
│ │ ├── Spotify_Logo_CMYK_Green.png
│ │ └── Spotify_Logo_CMYK_White.png
└── playlistIcon.svg
├── components
├── AddToPlaylistModel.js
├── Album.js
├── AlbumCart.js
├── AlbumHader.js
├── AlbumSongConatiner.js
├── Artist.js
├── ArtistCart.js
├── CreateAlbumPopup.js
├── GenreCart.js
├── GenreGridContainer.js
├── Hader.js
├── HomeGrid.js
├── Liked.js
├── NowPlayingBar.js
├── Playlist.js
├── PlylistCart.js
├── Search.js
├── Sidebar.js
├── SingleSong.js
└── SongPopupOptions.js
├── css
├── Register.css
└── components
│ ├── AddToPlaylistModel.css
│ ├── AlbumCart.css
│ ├── AlbumCartGrid.css
│ ├── AlbumHader.css
│ ├── AlbumSongConatiner.css
│ ├── ArtistCart.css
│ ├── CreateAlbumPopup.css
│ ├── GenreCart.css
│ ├── GenreGridContainer.css
│ ├── Hader.css
│ ├── NowPlayingBar.css
│ ├── PlaylistCart.css
│ ├── Sidebar.css
│ ├── SingleSong.css
│ └── SongPopupOptions.css
├── handlers
├── addSongToPlaylist.js
├── createPlaylist.js
├── getUserInfo.js
├── likeAlbum.js
├── likeSong.js
├── login.js
└── signup.js
├── helpers
├── baseUrl.js
├── formatTime.js
├── genreList.js
└── isBuffering.js
├── index.css
├── index.js
├── reducer.js
└── serviceWorker.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.firebase
6 | /.pnp
7 | /.vscode
8 | *.firebaserc
9 | /firebase.json
10 | .pnp.js
11 |
12 | # testing
13 | /coverage
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | .env.local
21 | .env.development.local
22 | .env.test.local
23 | .env.production.local
24 |
25 | npm-debug.log*
26 | yarn-debug.log*
27 | yarn-error.log*
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SPOTIFY CLONE
2 | ## Live Demo
3 |
4 | [spotify-clone](https://spotify-react-73.web.app/)
5 | ### the backend for this web app is available here [spotify-clone-backend-php](https://github.com/rana-shoaib/spotify-clone-backend-php)
6 | ###### run `npm i` to install all the dependencies
7 | ## Available Scripts
8 |
9 | In the project directory, you can run:
10 |
11 | ### `npm start`
12 |
13 | Runs the app in the development mode.
14 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
15 |
16 | The page will reload if you make edits.
17 | You will also see any lint errors in the console.
18 |
19 | 
20 | 
21 | 
22 | 
23 | 
24 | 
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "spotify-clone",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "randomcolor": "^0.6.2",
10 | "react": "^16.13.1",
11 | "react-dom": "^16.13.1",
12 | "react-router-dom": "^5.2.0",
13 | "react-scripts": "3.4.1",
14 | "react-toastify": "^6.0.8",
15 | "universal-cookie": "^4.0.3"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": "react-app"
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/public/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/public/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/public/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/public/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/public/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/public/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/public/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/public/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/public/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/public/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/public/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/public/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/public/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .button-green {
2 | background-color: #1db954;
3 | color: #ffffff;
4 | border-radius: 32px;
5 | border: none;
6 | }
7 | body {
8 | background-color: #121212;
9 | }
10 | .button-green:hover {
11 | background-color: #1ed760;
12 | cursor: pointer;
13 | }
14 | .silvery-text {
15 | color: #b3b3b3;
16 | }
17 | .white-text {
18 | color: #ffffff;
19 | }
20 | .rounded-paly-button {
21 | width: 55px;
22 | height: 55px;
23 | background-color: #1db954;
24 | display: flex;
25 | justify-content: center;
26 | align-items: center;
27 | border-radius: 50%;
28 | }
29 | .rounded-paly-button i {
30 | color: #ffffff;
31 | }
32 | .section-hading {
33 | color: #ffffff;
34 | margin-left: 20px;
35 | margin-bottom: 25px;
36 | font-size: 2rem;
37 | }
38 | .close:hover {
39 | transform: scale(1.1);
40 | cursor: pointer;
41 | }
42 | .close:before,
43 | .close:after {
44 | display: inline-block;
45 | content: " ";
46 | height: 45px;
47 | width: 2px;
48 | background-color: #b3b3b3;
49 | }
50 | .close:before {
51 | transform: rotate(45deg);
52 | }
53 | .close:after {
54 | transform: rotate(-45deg);
55 | }
56 | #main-content {
57 | background-color: #121212;
58 | width: 100%;
59 | height: 100vh;
60 | padding-bottom: 120px;
61 | padding-left: 240px;
62 | overflow-y: auto;
63 | padding-top: 60px;
64 | }
65 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import "./App.css";
3 | import Sidebar from "./components/Sidebar";
4 | import NowPlayingBar from "./components/NowPlayingBar";
5 | import HomeGrid from "./components/HomeGrid";
6 | import Hader from "./components/Hader";
7 | import Album from "./components/Album";
8 | import Search from "./components/Search";
9 | import Artist from "./components/Artist";
10 | import Register from "./Register";
11 | import Liked from "./components/Liked";
12 | import AddToPlaylistModel from "./components/AddToPlaylistModel";
13 | import CreateAlbumPopup from "./components/CreateAlbumPopup";
14 | import SongPopupOptions from "./components/SongPopupOptions";
15 | import Playlist from "./components/Playlist";
16 | import { Switch, Route } from "react-router-dom";
17 | import Cookies from "universal-cookie";
18 | import getUserInfo from "./handlers/getUserInfo";
19 | import { useStateValue } from "./StateProvider";
20 | import { ToastContainer } from "react-toastify";
21 |
22 | function App() {
23 | const cookies = new Cookies();
24 | const [{}, dispatch] = useStateValue();
25 | const [{ user, isLogin }] = useStateValue();
26 | const setUserInfo = async () => {
27 | const data = await getUserInfo(cookies.get("loginToken"));
28 | dispatch({
29 | type: "SET_USER",
30 | item: data,
31 | });
32 |
33 | dispatch({
34 | type: "LOGIN_STATUS",
35 | item: true,
36 | });
37 | };
38 | useEffect(() => {
39 | if (cookies.get("loginToken")) {
40 | setUserInfo();
41 | }
42 | }, [isLogin]);
43 | return (
44 | <>
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | >
69 | );
70 | }
71 |
72 | export default App;
73 |
--------------------------------------------------------------------------------
/src/Register.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import "./css/Register.css";
3 | import signup from "./handlers/signup";
4 | import login from "./handlers/login";
5 | import { ToastContainer, toast } from "react-toastify";
6 | import "react-toastify/dist/ReactToastify.css";
7 | import Cookies from "universal-cookie";
8 | import { useStateValue } from "./StateProvider";
9 |
10 | function Register({ history }) {
11 | const [showLoginForm, setShowLoginForm] = useState(true);
12 | const [signupErrors, setSignUpErrors] = useState({});
13 | const [loginError, setLoginError] = useState("");
14 | const cookies = new Cookies();
15 | const [{}, dispatch] = useStateValue();
16 |
17 | const toggleForms = () => {
18 | setShowLoginForm(!showLoginForm);
19 | };
20 |
21 | let signupData = {
22 | name: "",
23 | email: "",
24 | username: "",
25 | password: "",
26 | passwordAgain: "",
27 | };
28 |
29 | let loginData = {
30 | usernameOrEmail: "",
31 | password: "",
32 | };
33 |
34 | const submitSignup = async (e) => {
35 | e.preventDefault();
36 | var formEl = document.forms.SignupForm;
37 | var formData = new FormData(formEl);
38 |
39 | for (const [key] of Object.entries(signupData)) {
40 | signupData[key] = formData.get(key);
41 | }
42 |
43 | const result = await signup(signupData);
44 | if (typeof result === "object") {
45 | if (result.sucess) {
46 | toast.info("SignUp Sucessfull 😍");
47 |
48 | cookies.set("loginToken", result.loginToken, { path: "/" });
49 | dispatch({
50 | type: "LOGIN_STATUS",
51 | item: true,
52 | });
53 | history.push("/");
54 | } else {
55 | setSignUpErrors(result.errors);
56 | toast.error("Resolve the errors to continue");
57 | }
58 | } else {
59 | toast.error("Something went wrong try again later");
60 | }
61 | };
62 |
63 | const submitLogin = async (e) => {
64 | e.preventDefault();
65 | var formEl = document.forms.loginForm;
66 | var formData = new FormData(formEl);
67 |
68 | for (const [key] of Object.entries(loginData)) {
69 | loginData[key] = formData.get(key);
70 | }
71 | console.log(loginData);
72 | const result = await login(loginData);
73 | if (typeof result == "object") {
74 | if (result.sucess) {
75 | toast.info("Login Sucessfull 😍");
76 | cookies.set("loginToken", result.token, { path: "/" });
77 | dispatch({
78 | type: "LOGIN_STATUS",
79 | item: true,
80 | });
81 | history.push("/");
82 | } else {
83 | setLoginError(result.error);
84 | toast.error("Resolve the errors to continue");
85 | }
86 | } else {
87 | toast.error("Something went wrong try again later");
88 | }
89 | };
90 | return (
91 |
92 |
93 |
})
96 |
97 |
98 |
99 |
106 |
111 | Log In
{" "}
112 |
113 |
114 |
152 |
153 |
184 |
185 |
186 | );
187 | }
188 |
189 | export default Register;
190 |
--------------------------------------------------------------------------------
/src/StateProvider.js:
--------------------------------------------------------------------------------
1 | // setup data layer
2 | // We need this to track the basket
3 |
4 | import React, { createContext, useContext, useReducer } from "react";
5 |
6 | // THIS IS THE DATA LAYER
7 | export const StateContext = createContext();
8 |
9 | // BUILD A PROVIDER
10 | export const StateProvider = ({ reducer, initialState, children }) => (
11 |
12 | {children}
13 |
14 | );
15 |
16 | // This is how we use it inside of a component
17 | export const useStateValue = () => useContext(StateContext);
18 |
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/1.jpg
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/1.png
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/2.png
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/3.png
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/4.png
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/5.png
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/6.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/6.jpeg
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/7.png
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/8.png
--------------------------------------------------------------------------------
/src/assets/images/albumartwork/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/albumartwork/9.png
--------------------------------------------------------------------------------
/src/assets/images/site/email-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/site/email-logo.png
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (1).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (1).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (10).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (10).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (11).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (11).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (12).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (12).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (13).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (13).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (14).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (14).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (2).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (2).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (3).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (3).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (4).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (4).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (7).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (7).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (8).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (8).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download (9).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download (9).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download.jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/download1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/download1.jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/maxresdefault (1).jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/maxresdefault (1).jpg
--------------------------------------------------------------------------------
/src/assets/images/songartwork/maxresdefault.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/songartwork/maxresdefault.jpg
--------------------------------------------------------------------------------
/src/assets/images/users/profile-images/unnamed.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/images/users/profile-images/unnamed.jpg
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/icons/O1_RGB/O2_PNG/Spotify_Icon_RGB_Black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/icons/O1_RGB/O2_PNG/Spotify_Icon_RGB_Black.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/icons/O1_RGB/O2_PNG/Spotify_Icon_RGB_Green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/icons/O1_RGB/O2_PNG/Spotify_Icon_RGB_Green.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/icons/O1_RGB/O2_PNG/Spotify_Icon_RGB_White.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/icons/O1_RGB/O2_PNG/Spotify_Icon_RGB_White.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/icons/O2_CMYK/O2_PNG/Spotify_Icon_CMYK_Black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/icons/O2_CMYK/O2_PNG/Spotify_Icon_CMYK_Black.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/icons/O2_CMYK/O2_PNG/Spotify_Icon_CMYK_Green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/icons/O2_CMYK/O2_PNG/Spotify_Icon_CMYK_Green.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/icons/O2_CMYK/O2_PNG/Spotify_Icon_CMYK_White.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/icons/O2_CMYK/O2_PNG/Spotify_Icon_CMYK_White.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_Black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_Black.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_Green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_Green.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_White.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_White.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_nwe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/logos/O1_RGB/O2_PNG/Spotify_Logo_RGB_nwe.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/logos/O2_CMYK/O2_PNG/Spotify_Logo_CMYK_Black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/logos/O2_CMYK/O2_PNG/Spotify_Logo_CMYK_Black.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/logos/O2_CMYK/O2_PNG/Spotify_Logo_CMYK_Green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/logos/O2_CMYK/O2_PNG/Spotify_Logo_CMYK_Green.png
--------------------------------------------------------------------------------
/src/assets/logo/spotify-icons-logos/logos/O2_CMYK/O2_PNG/Spotify_Logo_CMYK_White.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/assets/logo/spotify-icons-logos/logos/O2_CMYK/O2_PNG/Spotify_Logo_CMYK_White.png
--------------------------------------------------------------------------------
/src/assets/playlistIcon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/AddToPlaylistModel.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../css/components/AddToPlaylistModel.css";
3 | import PlylistCart from "./PlylistCart";
4 | import { useStateValue } from "../StateProvider";
5 |
6 | function AddToPlaylistModel() {
7 | const [{}, dispatch] = useStateValue();
8 | const [
9 | { user, userPlaylists, showAddToPlaylistModel, songOptionnsData },
10 | ] = useStateValue();
11 |
12 | const closeModel = () => {
13 | dispatch({
14 | type: "SHOW_HIDE_ADD_TO_PLAYLIST_MODEL",
15 | item: false,
16 | });
17 | };
18 |
19 | return (
20 |
24 |
25 |
26 | Add to playlist
27 |
28 |
29 |
30 | {userPlaylists.map(({ title, id }) => {
31 | return ;
32 | })}
33 |
34 |
35 | );
36 | }
37 |
38 | export default AddToPlaylistModel;
39 |
--------------------------------------------------------------------------------
/src/components/Album.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import AlbumHader from "./AlbumHader";
3 | import AlbumSongConatiner from "./AlbumSongConatiner";
4 | import { useStateValue } from "../StateProvider";
5 | import Cookies from "universal-cookie";
6 | import BASE_URL from "../helpers/baseUrl";
7 |
8 | function Album({ match }) {
9 | const [album, setAlbum] = useState([]);
10 | const [song, setSong] = useState([]);
11 | const [{}, dispatch] = useStateValue();
12 | const [{ playlist, user, currentPlayingAlbumId }] = useStateValue();
13 | const cookies = new Cookies();
14 |
15 | useEffect(() => {
16 | fetch(
17 | `${BASE_URL}getAlbumInfo.php?id=${match.params.id}&token=${cookies.get(
18 | "loginToken"
19 | )}`
20 | )
21 | .then((respone) => respone.json())
22 | .then((data) => {
23 | //
24 | setAlbum([data.album]);
25 | setSong(data.songs);
26 | dispatch({
27 | type: "SET_TEMP_ALBUM_ID",
28 | item: data.album.id,
29 | });
30 | dispatch({
31 | type: "SET_TEMP_PALYLIST",
32 | item: data.songs,
33 | });
34 | dispatch({
35 | type: "SET_ALBUM_COLOR",
36 | item: data.album.albumColor,
37 | });
38 | });
39 |
40 | return () => {
41 | dispatch({
42 | type: "SET_ALBUM_COLOR",
43 | item: "#121212",
44 | });
45 |
46 | dispatch({
47 | type: "SET_TEMP_ALBUM_ID",
48 | item: currentPlayingAlbumId,
49 | });
50 | };
51 | }, []);
52 | return (
53 |
54 | {album.map((album) => {
55 | return (
56 |
70 | );
71 | })}
72 |
73 |
74 | );
75 | }
76 |
77 | export default Album;
78 |
--------------------------------------------------------------------------------
/src/components/AlbumCart.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../css/components/AlbumCart.css";
3 | import { Link } from "react-router-dom";
4 | import { useStateValue } from "../StateProvider";
5 | import Cookies from "universal-cookie";
6 | import BASE_URL from "../helpers/baseUrl";
7 |
8 | function AlbumCart({ img, title, discription, id, isArtist = false }) {
9 | const [
10 | { playlist, user, currentSongId, isPlaying, currentPlayingAlbumId },
11 | ] = useStateValue();
12 | const [{}, dispatch] = useStateValue();
13 | const cookies = new Cookies();
14 |
15 | const setPlayList = (id) => {
16 | if (playlist[currentSongId]?.albumId === id) {
17 | // if palylist is already set no need to set it agin just paly pause the song
18 | //console.log(isPlaying);
19 | dispatch({
20 | type: "UPDATE_SONG_STATUS",
21 | item: !isPlaying,
22 | });
23 | } else {
24 | fetch(
25 | `${BASE_URL}getAlbumInfo.php?id=${id}&token=${cookies.get(
26 | "loginToken"
27 | )}`
28 | )
29 | .then((respone) => respone.json())
30 | .then((data) => {
31 | dispatch({
32 | type: "SET_PLAYLIST",
33 | item: data.songs,
34 | });
35 | dispatch({
36 | type: "UPDATE_SONG_STATUS",
37 | item: true,
38 | });
39 |
40 | dispatch({
41 | type: "SET_CURRENT_ALBUM_ID",
42 | item: data.album.id,
43 | });
44 | });
45 | }
46 | };
47 |
48 | return (
49 |
54 |
59 |
62 |
65 | {
68 | e.preventDefault();
69 | setPlayList(id);
70 | }}
71 | style={{
72 | visibility: currentPlayingAlbumId == id ? "visible" : "",
73 | display: isArtist ? "none" : "flex",
74 | }}
75 | >
76 |
84 |
92 |
93 |
94 | );
95 | }
96 |
97 | export default AlbumCart;
98 |
--------------------------------------------------------------------------------
/src/components/AlbumHader.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import "../css/components/AlbumHader.css";
3 | import { useStateValue } from "../StateProvider";
4 | import likeAlbum from "../handlers/likeAlbum";
5 | import Cookies from "universal-cookie";
6 | import { toast } from "react-toastify";
7 | function AlbumHader({
8 | id,
9 | title,
10 | artist,
11 | discription,
12 | img,
13 | likes,
14 | isRoundedImg,
15 | songsList,
16 | albumId,
17 | showLikeButton = true,
18 | showOptionsButton = true,
19 | showNumOfLikes = true,
20 | showAlbumArt = true,
21 | isLikedByUser,
22 | type = "",
23 | }) {
24 | const [
25 | {
26 | isPlaying,
27 | albumColor,
28 | playlist,
29 | currentSong,
30 | currentPlayingAlbumId,
31 | tempAlbumId,
32 | },
33 | ] = useStateValue();
34 | const [{}, dispatch] = useStateValue();
35 | const [{ user }] = useStateValue();
36 | const cookies = new Cookies();
37 |
38 | const [isAlbumLiked, setIsAlbumLiked] = useState(isLikedByUser);
39 | const [albumLikes, setAlbumLikes] = useState(parseInt(likes));
40 |
41 | const like = async () => {
42 | if (user.name) {
43 | const response = await likeAlbum({
44 | token: cookies.get("loginToken"),
45 | albumId: id,
46 | });
47 | setIsAlbumLiked(response.isLikedAlbum);
48 | if (response.isLikedAlbum) {
49 | setAlbumLikes(albumLikes + 1);
50 | } else {
51 | setAlbumLikes(albumLikes + -1);
52 | }
53 | } else {
54 | toast.info("Login to like like this album");
55 | }
56 | };
57 | const setSong = () => {
58 | if (songsList.length > 0) {
59 | if (!isPlaying) {
60 | dispatch({
61 | type: "SET_PLAYLIST",
62 | item: songsList,
63 | });
64 | console.log(playlist);
65 |
66 | dispatch({
67 | type: "SET_CURRENT_ALBUM_ID",
68 | item: tempAlbumId,
69 | });
70 |
71 | dispatch({
72 | type: "UPDATE_SONG_STATUS",
73 | item: true,
74 | });
75 | } else {
76 | dispatch({
77 | type: "UPDATE_SONG_STATUS",
78 | item: false,
79 | });
80 | }
81 | }
82 | };
83 |
84 | return (
85 |
86 |
87 |
88 |

95 |
96 |
97 |
98 |
99 | {type}
100 |
101 |
102 | {title}
103 |
104 |
105 | {discription}
106 |
107 |
108 |
109 | {showLikeButton ? artist + " . " : ""}
110 |
111 |
116 | {albumLikes + " likes"}
117 |
118 |
119 |
120 |
121 |
122 |
123 |
128 |
137 |
146 |
147 |
148 |
153 |
157 |
158 |
159 |
163 |
164 |
165 |
166 |
167 | );
168 | }
169 |
170 | export default AlbumHader;
171 |
--------------------------------------------------------------------------------
/src/components/AlbumSongConatiner.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import "../css/components/AlbumSongConatiner.css";
3 | import SingleSong from "./SingleSong";
4 |
5 | function AlbumSongConatiner({ data, showSongArt, songsList }) {
6 | let songCount = 0;
7 | return (
8 |
9 | {data.map(({ title, artist, album, duration, id, artistId, artPath }) => {
10 | return (
11 |
24 | );
25 | })}
26 |
27 | );
28 | }
29 |
30 | export default AlbumSongConatiner;
31 |
--------------------------------------------------------------------------------
/src/components/Artist.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import AlbumHader from "./AlbumHader";
3 | import AlbumSongConatiner from "./AlbumSongConatiner";
4 | import AlbumCart from "./AlbumCart";
5 | import { useStateValue } from "../StateProvider";
6 | import Cookies from "universal-cookie";
7 | import randomcolor from "randomcolor";
8 | import BASE_URL from "../helpers/baseUrl";
9 |
10 | function Artist({ match }) {
11 | const [album, setAlbum] = useState([]);
12 | const [song, setSong] = useState([]);
13 | const [artistInfo, setArtistInfo] = useState({});
14 | const [{}, dispatch] = useStateValue();
15 | const [{ playlist, user }] = useStateValue();
16 | const cookies = new Cookies();
17 |
18 | useEffect(() => {
19 | fetch(
20 | `${BASE_URL}getArtistInfo.php?id=${match.params.id}&token=${cookies.get(
21 | "loginToken"
22 | )}`
23 | )
24 | .then((respone) => respone.json())
25 | .then((data) => {
26 | setAlbum(data.albums);
27 | setSong(data.songs);
28 | setArtistInfo(data.artist);
29 | // dispatch({
30 | // type: "SET_PLAYLIST",
31 | // item: data.songs,
32 | // });
33 | dispatch({
34 | type: "SET_TEMP_ALBUM_ID",
35 | item: 99,
36 | });
37 | dispatch({
38 | type: "SET_TEMP_PALYLIST",
39 | item: data.songs,
40 | });
41 |
42 | dispatch({
43 | type: "SET_ALBUM_COLOR",
44 | item: randomcolor(),
45 | });
46 | });
47 | }, []);
48 |
49 | useEffect(() => {
50 | return () => {
51 | dispatch({
52 | type: "SET_ALBUM_COLOR",
53 | item: "#121212",
54 | });
55 | };
56 | }, []);
57 | return (
58 |
59 |
71 |
Songs
72 |
;
73 |
Albums
74 |
78 | {album.map(({ id, title, discription, artPath }) => {
79 | return (
80 |
87 | );
88 | })}
89 |
90 |
91 | );
92 | }
93 |
94 | export default Artist;
95 |
--------------------------------------------------------------------------------
/src/components/ArtistCart.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../css/components/ArtistCart.css";
3 |
4 | function ArtistCart() {
5 | return
6 |
7 |
;
8 | }
9 |
10 | export default ArtistCart;
11 |
--------------------------------------------------------------------------------
/src/components/CreateAlbumPopup.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import "../css/components/CreateAlbumPopup.css";
3 | import { useStateValue } from "../StateProvider";
4 | import createPlaylist from "../handlers/createPlaylist";
5 | import Cookies from "universal-cookie";
6 | import { toast } from "react-toastify";
7 |
8 | function CreateAlbumPopup() {
9 | const [{}, dispatch] = useStateValue();
10 | const [{ showPopupPlaylistForm, userPlaylists }] = useStateValue();
11 | const [playlistName, setPlaylistName] = useState("");
12 | const cookies = new Cookies();
13 | useEffect(() => {
14 | setPlaylistName("");
15 | }, []);
16 | const closeForm = () => {
17 | dispatch({
18 | type: "SHOW_HIDE_PLAYLIST_POPUP_FORM",
19 | item: false,
20 | });
21 | setPlaylistName("");
22 | };
23 | const handelInputChange = (e) => {
24 | setPlaylistName(e.target.value);
25 | };
26 | const createPlaylist1 = async () => {
27 | dispatch({
28 | type: "SHOW_HIDE_PLAYLIST_POPUP_FORM",
29 | item: false,
30 | });
31 | const response = await createPlaylist({
32 | token: cookies.get("loginToken"),
33 | playlistName: playlistName,
34 | });
35 |
36 | if (response.isCreated) {
37 | let temp = userPlaylists;
38 | temp.push({
39 | id: response.id,
40 | title: response.title,
41 | });
42 | dispatch({
43 | type: "SET_USER_PLAYLISTS",
44 | item: temp,
45 | });
46 | toast.info(`Playlist ${response.title} has been created`);
47 | }
48 | };
49 | return (
50 |
54 |
55 |
56 |
Create new playlist
57 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | );
76 | }
77 |
78 | export default CreateAlbumPopup;
79 |
--------------------------------------------------------------------------------
/src/components/GenreCart.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../css/components/GenreCart.css";
3 |
4 | function GenreCart({ title = "", img, bgColor }) {
5 | return (
6 |
7 |
{title}
8 |

9 |
10 | );
11 | }
12 |
13 | export default GenreCart;
14 |
--------------------------------------------------------------------------------
/src/components/GenreGridContainer.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import GenreCart from "./GenreCart";
3 | import "../css/components/GenreGridContainer.css";
4 | import genreList from "../helpers/genreList";
5 |
6 | function GenreGridContainer() {
7 | return (
8 |
9 | {genreList.map(({ title, img, bgColor }) => {
10 | return (
11 |
12 | );
13 | })}
14 |
15 | );
16 | }
17 |
18 | export default GenreGridContainer;
19 |
--------------------------------------------------------------------------------
/src/components/Hader.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import "../css/components/Hader.css";
3 | import { useStateValue } from "../StateProvider";
4 | import { Link } from "react-router-dom";
5 | import Cookies from "universal-cookie";
6 |
7 | function Hader() {
8 | const [{}, dispatch] = useStateValue();
9 | const [{ showSearchBox, albumColor, user }] = useStateValue();
10 | const [showAccountOptions, setShowAccountAptions] = useState(false);
11 | const cookies = new Cookies();
12 | const handleSearch = (e) => {
13 | dispatch({
14 | type: "UPDATE_SEARCH_QUERY",
15 | item: e.target.value.trim(),
16 | });
17 | };
18 |
19 | const toggelShowAccountOptions = (e) => {
20 | setShowAccountAptions(!showAccountOptions);
21 | };
22 |
23 | const logout = () => {
24 | cookies.remove("loginToken");
25 | dispatch({
26 | type: "LOGIN_STATUS",
27 | item: false,
28 | });
29 | dispatch({
30 | type: "SET_USER",
31 | item: {},
32 | });
33 | };
34 |
35 | return (
36 |
102 | );
103 | }
104 |
105 | export default Hader;
106 |
--------------------------------------------------------------------------------
/src/components/HomeGrid.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import AlbumCart from "./AlbumCart";
3 | import "../css/components/AlbumCartGrid.css";
4 | import BASE_URL from "../helpers/baseUrl";
5 |
6 | function HomeGrid() {
7 | const [apiData, setapiData] = useState([]);
8 | const [artists, setArtists] = useState([]);
9 | useEffect(() => {
10 | fetch(`${BASE_URL}api.php`)
11 | .then((response) => response.json())
12 | .then((data) => {
13 | setapiData(data.albums);
14 | setArtists(data.artists);
15 | });
16 | }, []);
17 | return (
18 | <>
19 |
20 | Most Popular Albums
21 |
22 |
23 | {apiData.map(({ id, title, discription, artPath }) => {
24 | return (
25 |
32 | );
33 | })}
34 |
35 | Popular Artists
36 |
37 |
38 | {artists.map(({ id, name, img }) => {
39 | return (
40 |
48 | );
49 | })}
50 |
51 | >
52 | );
53 | }
54 |
55 | export default HomeGrid;
56 |
--------------------------------------------------------------------------------
/src/components/Liked.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import AlbumHader from "./AlbumHader";
3 | import AlbumSongConatiner from "./AlbumSongConatiner";
4 | import { useStateValue } from "../StateProvider";
5 | import Cookies from "universal-cookie";
6 | import BASE_URL from "../helpers/baseUrl";
7 |
8 | function Liked({ match }) {
9 | const [song, setSong] = useState([]);
10 | const [{}, dispatch] = useStateValue();
11 | const [{ playlist, user, currentPlayingAlbumId }] = useStateValue();
12 | const cookies = new Cookies();
13 |
14 | useEffect(() => {
15 | fetch(`${BASE_URL}getLikedSongs.php?token=${cookies.get("loginToken")}`)
16 | .then((respone) => respone.json())
17 | .then((data) => {
18 | setSong(data.songs);
19 | dispatch({
20 | type: "SET_TEMP_ALBUM_ID",
21 | item: 87,
22 | });
23 |
24 | dispatch({
25 | type: "SET_ALBUM_COLOR",
26 | item: "#393260",
27 | });
28 |
29 | dispatch({
30 | type: "SET_TEMP_PALYLIST",
31 | item: data.songs,
32 | });
33 | });
34 |
35 | return () => {
36 | dispatch({
37 | type: "SET_ALBUM_COLOR",
38 | item: "#121212",
39 | });
40 |
41 | dispatch({
42 | type: "SET_TEMP_ALBUM_ID",
43 | item: currentPlayingAlbumId,
44 | });
45 | };
46 | }, []);
47 | return (
48 |
62 | );
63 | }
64 |
65 | export default Liked;
66 |
--------------------------------------------------------------------------------
/src/components/NowPlayingBar.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import "../css/components/NowPlayingBar.css";
3 | import { useStateValue } from "../StateProvider";
4 | import formatTime from "../helpers/formatTime";
5 | import likeSong from "../handlers/likeSong";
6 | import Cookies from "universal-cookie";
7 | import isBuffering from "../helpers/isBuffering";
8 |
9 | function NowPlayingBar() {
10 | const [{ playlist, user, currentSongId, isPlaying }] = useStateValue();
11 | const [{}, dispatch] = useStateValue();
12 | const [songTimebarWidth, setSongTimebarWidth] = useState(0);
13 | const [songFormattedCurrentTime, setSongFormattedCurrentTime] = useState(
14 | "0:00"
15 | );
16 | const [isShuffelOn, setIsSuffelOn] = useState(false);
17 | const [isRpeatlOn, setIsRepeatOn] = useState(false);
18 | const cookies = new Cookies();
19 | const [showSongLoadingIndicator, setShowSongLoadingIndicator] = useState(
20 | false
21 | );
22 | const [volumePercentage, setVolumePercentage] = useState(100);
23 | const [isMuted, setIsMuted] = useState(false);
24 | const [volumeBeforeMuted, setVolumeBeforeMuted] = useState(1);
25 |
26 | let audio;
27 |
28 | const toggelSongStatus = () => {
29 | dispatch({
30 | type: "UPDATE_SONG_STATUS",
31 | item: !isPlaying,
32 | });
33 | };
34 |
35 | const previousSong = () => {
36 | dispatch({
37 | type: "SET_CURRENT_SONG_ID",
38 | item: currentSongId > 0 ? currentSongId - 1 : playlist.length - 1,
39 | });
40 | };
41 |
42 | const seekSong = (e) => {
43 | audio = document.getElementById("currentPlayingSong");
44 | let percentageClicked =
45 | (e.offsetX /
46 | document.getElementById("songTimeBarContainer").offsetWidth) *
47 | 100;
48 | audio.currentTime = (audio.duration * percentageClicked) / 100;
49 | };
50 |
51 | const toggelSuffelSong = () => {
52 | setIsSuffelOn(!isShuffelOn);
53 | setIsRepeatOn(false);
54 | };
55 |
56 | const toggelRepeatSong = () => {
57 | setIsRepeatOn(!isRpeatlOn);
58 | setIsSuffelOn(false);
59 | };
60 |
61 | useEffect(() => {
62 | audio = document.getElementById("currentPlayingSong");
63 | isPlaying ? audio.play() : audio.pause();
64 | }, [currentSongId, isPlaying, playlist]);
65 |
66 | useEffect(() => {
67 | setSongTimebarWidth(0);
68 |
69 | audio.addEventListener("timeupdate", () => {
70 | setSongTimebarWidth((audio.currentTime / audio.duration) * 100);
71 | setSongFormattedCurrentTime(formatTime(audio.currentTime));
72 | });
73 | }, [currentSongId]);
74 |
75 | useEffect(() => {
76 | audio = document.getElementById("currentPlayingSong");
77 | document
78 | .getElementById("songTimeBarContainer")
79 | .addEventListener("click", (e) => {
80 | seekSong(e);
81 | });
82 | }, []);
83 |
84 | const nextSong = (forceNext = false) => {
85 | const audio = document.getElementById("currentPlayingSong");
86 | if (!forceNext) {
87 | if (isShuffelOn) {
88 | let randomNumber = Math.floor(Math.random() * playlist.length);
89 | if (randomNumber != currentSongId) {
90 | dispatch({
91 | type: "SET_CURRENT_SONG_ID",
92 | item: randomNumber,
93 | });
94 | } else {
95 | audio.currentTime = 0;
96 | audio.play();
97 | }
98 | } else if (isRpeatlOn) {
99 | // dispatch({
100 | // type: "SET_CURRENT_SONG_ID",
101 | // item: currentSongId,
102 | // });
103 | audio.currentTime = 0;
104 | audio.play();
105 | } else {
106 | dispatch({
107 | type: "SET_CURRENT_SONG_ID",
108 | item: currentSongId < playlist.length - 1 ? currentSongId + 1 : 0,
109 | });
110 | }
111 | } else {
112 | dispatch({
113 | type: "SET_CURRENT_SONG_ID",
114 | item: currentSongId < playlist.length - 1 ? currentSongId + 1 : 0,
115 | });
116 | }
117 | };
118 | //like song
119 | const toggelLikeSong = async () => {
120 | if (cookies.get("loginToken")) {
121 | if (playlist[currentSongId].id) {
122 | const response = await likeSong({
123 | token: cookies.get("loginToken"),
124 | songId: playlist[currentSongId].id,
125 | });
126 |
127 | let temp = playlist;
128 | temp[currentSongId].isLikedByUser = response.isLikedSong;
129 | dispatch({
130 | type: "SET_PLAYLIST",
131 | item: temp,
132 | });
133 | }
134 | }
135 | };
136 | // loading indicator
137 | useEffect(() => {
138 | if (playlist[currentSongId].id) {
139 | setShowSongLoadingIndicator(true);
140 | }
141 | const audio = document.getElementById("currentPlayingSong");
142 | audio.addEventListener("canplay", () => {
143 | setShowSongLoadingIndicator(false);
144 | });
145 | }, [playlist, currentSongId]);
146 |
147 | const adgestVolume = (e) => {
148 | const audio = document.getElementById("currentPlayingSong");
149 | const ratio =
150 | e.nativeEvent.offsetX /
151 | document.getElementById("volumeBarContainer").offsetWidth;
152 | audio.volume = ratio;
153 | setVolumePercentage(ratio * 100);
154 |
155 | //if user try to change the volume and the song is muted it should unmute
156 | audio.muted = false;
157 | setIsMuted(false);
158 | };
159 |
160 | const toggelMute = () => {
161 | const audio = document.getElementById("currentPlayingSong");
162 | if (!isMuted) {
163 | setVolumeBeforeMuted(audio.volume);
164 | audio.muted = true;
165 | setVolumePercentage(0);
166 | setIsMuted(true);
167 | } else {
168 | audio.volume = volumeBeforeMuted;
169 | audio.muted = false;
170 | setVolumePercentage((volumeBeforeMuted / 1) * 100);
171 | setIsMuted(false);
172 | }
173 | };
174 |
175 | return (
176 |
177 |
178 |

182 |
183 |
184 | {playlist[currentSongId]?.title}
185 |
186 |
187 |
188 | {playlist[currentSongId]?.album}
189 |
190 |
200 |
201 |
202 |
203 |
204 |
210 |
215 |
219 |
225 |
231 |
{
235 | nextSong(true);
236 | }}
237 | >
238 |
244 |
245 |
246 |
247 | {songFormattedCurrentTime}
248 |
249 |
259 |
260 | {playlist[currentSongId]?.duration}
261 |
262 |
263 |
264 |
265 |
50 && !isMuted ? "block" : "none",
271 | }}
272 | >
273 |
284 |
290 |
297 |
303 |
304 |
311 |
312 | );
313 | }
314 |
315 | export default NowPlayingBar;
316 |
--------------------------------------------------------------------------------
/src/components/Playlist.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import AlbumHader from "./AlbumHader";
3 | import AlbumSongConatiner from "./AlbumSongConatiner";
4 | import { useStateValue } from "../StateProvider";
5 | import Cookies from "universal-cookie";
6 | import randomcolor from "randomcolor";
7 | import BASE_URL from "../helpers/baseUrl";
8 |
9 | function Playlist(props) {
10 | const [album, setAlbum] = useState([]);
11 | const [song, setSong] = useState([]);
12 | const [{}, dispatch] = useStateValue();
13 | const [{ playlist, user, currentPlayingAlbumId }] = useStateValue();
14 | const cookies = new Cookies();
15 |
16 | useEffect(() => {
17 | fetch(
18 | `${BASE_URL}getPlaylistInfo.php?playlistId=${
19 | props.match.params.id
20 | }&token=${cookies.get("loginToken")}`
21 | )
22 | .then((respone) => respone.json())
23 | .then((data) => {
24 | setAlbum([{ id: data.id, title: data.title }]);
25 | setSong(data.songs);
26 | dispatch({
27 | type: "SET_TEMP_ALBUM_ID",
28 | item: data.id,
29 | });
30 | dispatch({
31 | type: "SET_TEMP_PALYLIST",
32 | item: data.songs,
33 | });
34 | dispatch({
35 | type: "SET_ALBUM_COLOR",
36 | item: randomcolor(),
37 | });
38 | });
39 |
40 | return () => {
41 | dispatch({
42 | type: "SET_ALBUM_COLOR",
43 | item: "#121212",
44 | });
45 |
46 | dispatch({
47 | type: "SET_TEMP_ALBUM_ID",
48 | item: currentPlayingAlbumId,
49 | });
50 | };
51 | }, [props.match.params.id]);
52 | return (
53 |
54 | {album.map((album) => {
55 | return (
56 |
69 | );
70 | })}
71 |
72 |
73 | );
74 | }
75 |
76 | export default Playlist;
77 |
--------------------------------------------------------------------------------
/src/components/PlylistCart.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import palylistIcon from "../assets/playlistIcon.svg";
3 | import "../css/components/PlaylistCart.css";
4 | import { useStateValue } from "../StateProvider";
5 | import addSongToPlaylist from "../handlers/addSongToPlaylist";
6 | import Cookies from "universal-cookie";
7 | import { toast } from "react-toastify";
8 |
9 | function PlylistCart({ title, id }) {
10 | const [{}, dispatch] = useStateValue();
11 | const [
12 | { user, userPlaylists, showAddToPlaylistModel, addToPlaylistData },
13 | ] = useStateValue();
14 | const cookies = new Cookies();
15 |
16 | const addToPlaylist = async () => {
17 | const response = await addSongToPlaylist({
18 | token: cookies.get("loginToken"),
19 | songId: addToPlaylistData.songId,
20 | playlistId: id,
21 | });
22 |
23 | if (response.isCreated) {
24 | toast.info("Song Added to Your Playlist");
25 | } else {
26 | toast.info(" Unabel to add Song to Your Playlist");
27 | }
28 | };
29 |
30 | return (
31 |
32 |
33 |

34 |
35 |
36 |
{title}
37 |
38 | );
39 | }
40 |
41 | export default PlylistCart;
42 |
--------------------------------------------------------------------------------
/src/components/Search.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import { useStateValue } from "../StateProvider";
3 | import AlbumCart from "../components/AlbumCart";
4 | import "../css/components/AlbumCartGrid.css";
5 | import GenreGridContainer from "./GenreGridContainer";
6 | import BASE_URL from "../helpers/baseUrl";
7 |
8 | function Search({ history, match }) {
9 | const [{ searchQuery }] = useStateValue();
10 | const [{}, dispatch] = useStateValue();
11 | const [searchedAlbums, setSearchedAlbums] = useState([]);
12 | const [noSearchResults, setNoSearchResults] = useState(false);
13 |
14 | const getSarchResults = (param) => {
15 | fetch(`${BASE_URL}serach.php?query=${param}`)
16 | .then((response) => response.json())
17 | .then((data) => {
18 | setSearchedAlbums(data.albums);
19 | if (data.albums.length > 0) {
20 | setNoSearchResults(false);
21 | } else {
22 | setNoSearchResults(true);
23 | }
24 | // history.push(`/search/${searchQuery.trim()}`);
25 | });
26 | };
27 | useEffect(() => {
28 | if (searchQuery.trim() != "") {
29 | getSarchResults(searchQuery);
30 | }
31 | }, [searchQuery]);
32 | useEffect(() => {
33 | dispatch({
34 | type: "SHOW_HIDE_SEARCH_BOX",
35 | item: true,
36 | });
37 | return () => {
38 | dispatch({
39 | type: "SHOW_HIDE_SEARCH_BOX",
40 | item: false,
41 | });
42 | };
43 | }, []);
44 | return (
45 |
46 |
47 |
48 |
49 |
0 && searchQuery != "" ? "block" : "none",
54 | }}
55 | >
56 | Albums
57 |
58 |
64 | Nothing found agianst your searched term "{searchQuery}"
65 |
66 |
73 | {searchedAlbums.map(({ id, title, discription, artPath }) => {
74 | return (
75 |
82 | );
83 | })}
84 |
85 |
86 | );
87 | }
88 |
89 | export default Search;
90 |
--------------------------------------------------------------------------------
/src/components/Sidebar.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import "../css/components/Sidebar.css";
3 | import { NavLink, Link } from "react-router-dom";
4 | import { useStateValue } from "../StateProvider";
5 | import Cookies from "universal-cookie";
6 | import { toast } from "react-toastify";
7 | import BASE_URL from "../helpers/baseUrl";
8 |
9 | function Sidebar() {
10 | const [{}, dispatch] = useStateValue();
11 | const [{ userPlaylists, user }] = useStateValue();
12 | const cookies = new Cookies();
13 | const showForm = () => {
14 | if (user.name) {
15 | dispatch({
16 | type: "SHOW_HIDE_PLAYLIST_POPUP_FORM",
17 | item: true,
18 | });
19 | } else {
20 | toast.info("Login to start creating Playlists");
21 | }
22 | };
23 |
24 | useEffect(() => {
25 | fetch(`${BASE_URL}getUserPlaylists.php?token=${cookies.get("loginToken")}`)
26 | .then((responesen) => responesen.json())
27 | .then((data) => {
28 | dispatch({
29 | type: "SET_USER_PLAYLISTS",
30 | item: data.playlists,
31 | });
32 | });
33 | }, []);
34 | return (
35 |
36 |
})
40 |
46 |
47 | Home
48 |
49 |
55 |
56 | Search
57 |
58 |
62 | PLAYLISTS
63 |
64 |
65 |
66 |
67 | +
68 |
69 |
70 |
Create Playlist
71 |
72 |
73 |
74 |
75 |
76 | Liked Songs
77 |
78 |
79 |
80 | {/*
Playlist 1
81 |
Playlist 2
82 |
Playlist 3
*/}
83 | {userPlaylists.map(({ id, title }) => {
84 | return (
85 |
91 | {title}
92 |
93 | );
94 | })}
95 |
96 |
97 | );
98 | }
99 |
100 | export default Sidebar;
101 |
--------------------------------------------------------------------------------
/src/components/SingleSong.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import "../css/components/SingleSong.css";
3 | import { useStateValue } from "../StateProvider";
4 | import { Link } from "react-router-dom";
5 | import SongPopupOptions from "./SongPopupOptions";
6 |
7 | function SingleSong({
8 | id,
9 | title,
10 | artist,
11 | duration,
12 | artistId,
13 | artPath,
14 | showSongArt = false,
15 | songList,
16 | songId,
17 | }) {
18 | const [{}, dispatch] = useStateValue();
19 | const [
20 | { isPlaying, currentSongId, playlist, tempAlbumId, temPlaylist },
21 | ] = useStateValue();
22 |
23 | const setSong = (id) => {
24 | console.log(songList);
25 | dispatch({
26 | type: "SET_PLAYLIST",
27 | item: songList,
28 | });
29 | dispatch({
30 | type: "SET_CURRENT_SONG_ID",
31 | item: id,
32 | });
33 |
34 | dispatch({
35 | type: "UPDATE_SONG_STATUS",
36 | item: true,
37 | });
38 |
39 | dispatch({
40 | type: "SET_CURRENT_ALBUM_ID",
41 | item: tempAlbumId,
42 | });
43 | };
44 |
45 | const toggelSongStatus = () => {
46 | dispatch({
47 | type: "UPDATE_SONG_STATUS",
48 | item: !isPlaying,
49 | });
50 | };
51 |
52 | const showSongOption = (e, id) => {
53 | const x = e.nativeEvent.clientX;
54 | const y = e.nativeEvent.clientY;
55 | let data = {
56 | cordinates: {
57 | x: x,
58 | y: y,
59 | },
60 | };
61 | data.songId = id;
62 | /*finding wether song is already liked or not and we will check it from temp playlist
63 | because the use may or may not be listning to this album so we can't reference it from
64 | reagular playlist*/
65 | temPlaylist.map((obj) => {
66 | if (obj.id == id) {
67 | data.isLiked = obj.isLikedByUser;
68 | }
69 | });
70 |
71 | dispatch({
72 | type: "SONGS_OPTION_DATA",
73 | item: data,
74 | });
75 | };
76 |
77 | const hideSongOptions = (e) => {
78 | if (e.target.classList[0] != "option") {
79 | dispatch({
80 | type: "SONGS_OPTION_DATA",
81 | item: {},
82 | });
83 | }
84 | };
85 |
86 | useEffect(() => {
87 | document.body.addEventListener("click", hideSongOptions);
88 | }, []);
89 |
90 | return (
91 |
99 |
100 |
101 |
{
109 | setSong(id);
110 | }}
111 | >
112 |
123 | {showSongArt ?

: ""}
124 |
125 |
126 | {title}
127 |
128 |
133 | {artist}
134 |
135 |
136 |
137 |
138 |
{
141 | showSongOption(e, songId);
142 | }}
143 | >
144 |
145 |
146 |
147 | {duration}
148 |
149 |
150 |
151 | );
152 | }
153 |
154 | export default SingleSong;
155 |
--------------------------------------------------------------------------------
/src/components/SongPopupOptions.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import "../css/components/SongPopupOptions.css";
3 | import { useStateValue } from "../StateProvider";
4 | import likeSong from "../handlers/likeSong";
5 | import Cookies from "universal-cookie";
6 | import { toast } from "react-toastify";
7 |
8 | function SongPopupOptions() {
9 | const [{ songOptionnsData, playlist, temPlaylist }] = useStateValue();
10 | const [{}, dispatch] = useStateValue();
11 | const [{ user }] = useStateValue();
12 | const cookies = new Cookies();
13 |
14 | const toggelLikeSong = async () => {
15 | const songId = songOptionnsData.songId;
16 | dispatch({
17 | type: "SONGS_OPTION_DATA",
18 | item: {},
19 | });
20 | if (user.name) {
21 | const response = await likeSong({
22 | token: cookies.get("loginToken"),
23 | songId: songId,
24 | });
25 | /*Now we are going to update the staus liked or not by finding the the song in
26 | temp as well as well as in regular playlisr*/
27 | // let temp = playlist;
28 | // temp[currentSongId].isLikedByUser = response.isLikedSong;
29 | let temp = playlist;
30 | temp.map((obj, i) => {
31 | if (obj.id == songId) {
32 | temp[i].isLikedByUser = response.isLikedSong;
33 | dispatch({
34 | type: "SET_PLAYLIST",
35 | item: temp,
36 | });
37 | }
38 | });
39 |
40 | temp = temPlaylist;
41 | temp.map((obj, i) => {
42 | if (obj.id == songId) {
43 | temp[i].isLikedByUser = response.isLikedSong;
44 | }
45 | });
46 | dispatch({
47 | type: "SET_TEMP_PALYLISTT",
48 | item: temp,
49 | });
50 |
51 | //show status to user
52 | if (response.isLikedSong) {
53 | toast.info("Added to your Liked Songs 💚");
54 | } else {
55 | toast.info("Remove from your Liked Songs ");
56 | }
57 | } else {
58 | toast.info("Login to add this song to your Liked Songs ");
59 | }
60 | };
61 |
62 | const showAddToPlaylistModel = () => {
63 | if (user.name) {
64 | dispatch({
65 | type: "SHOW_HIDE_ADD_TO_PLAYLIST_MODEL",
66 | item: true,
67 | });
68 |
69 | dispatch({
70 | type: "ADD_TO_PLAYLIST_DATA",
71 | item: { songId: songOptionnsData.songId },
72 | });
73 | } else {
74 | toast.info("Login to start creating Playlists");
75 | }
76 | };
77 | return (
78 |
106 | );
107 | }
108 |
109 | export default SongPopupOptions;
110 |
--------------------------------------------------------------------------------
/src/css/Register.css:
--------------------------------------------------------------------------------
1 | body {
2 | overflow: auto !important;
3 | }
4 | .register-main-container {
5 | display: flex;
6 | }
7 | .register-main-container .right,
8 | .register-main-container .left {
9 | width: 50vw;
10 | height: 100vh;
11 | }
12 | .register-main-container .right {
13 | position: fixed;
14 | display: flex;
15 | justify-content: center;
16 | align-items: center;
17 | background-color: #1db954;
18 | }
19 | .register-main-container .right img {
20 | width: 60%;
21 | height: auto;
22 | }
23 | .register-main-container .left {
24 | padding-top: 35px;
25 | background-color: #191414;
26 | display: flex;
27 | align-items: center;
28 | flex-direction: column;
29 | margin-left: 50vw;
30 | /* height: 150vh;
31 | overflow: auto; */
32 | }
33 | .register-main-container .left .button-container {
34 | display: flex;
35 | width: 100%;
36 | justify-content: center;
37 | }
38 | #activate-signup-form,
39 | #activate-login-form {
40 | cursor: pointer;
41 | width: 30%;
42 | height: 40px;
43 | display: flex;
44 | justify-content: center;
45 | align-items: center;
46 | background-color: #ffffff;
47 | color: #1db954;
48 | }
49 |
50 | #activate-login-form {
51 | border-bottom-right-radius: 30px;
52 | border-top-right-radius: 30px;
53 | }
54 | #activate-signup-form {
55 | border-bottom-left-radius: 30px;
56 | border-top-left-radius: 30px;
57 | }
58 | #activate-login-form.active,
59 | #activate-signup-form.active {
60 | background-color: #1db954;
61 | color: #ffffff;
62 | }
63 | #SignupForm,
64 | #loginForm {
65 | margin-top: 20px;
66 | display: none;
67 | width: 45vw;
68 | flex-direction: column;
69 | justify-content: center;
70 | align-items: center;
71 | }
72 |
73 | #SignupForm p,
74 | #loginForm p {
75 | margin-top: 20px;
76 | margin-bottom: 20px;
77 | color: rgba(275, 275, 275, 0.9);
78 | width: 90%;
79 | }
80 | #loginForm a {
81 | margin-top: 20px;
82 | }
83 |
84 | #SignupForm input,
85 | #loginForm input {
86 | width: 90%;
87 | height: 40px;
88 | background-color: transparent;
89 | border: none;
90 | color: rgba(275, 275, 275, 0.9);
91 | border-bottom: 1px solid rgba(275, 275, 275, 0.4);
92 | }
93 | #SignupForm .show-error,
94 | #loginForm .show-error {
95 | color: red;
96 | width: 90%;
97 | }
98 | #SignupForm .signup-button,
99 | #loginForm .login-button {
100 | width: 25vw;
101 | height: 45px;
102 | margin-top: 30px;
103 | min-width: 200px;
104 | }
105 | @media only screen and (max-width: 800px) {
106 | .register-main-container .left {
107 | width: 100%;
108 |
109 | margin: 0px;
110 | }
111 | .register-main-container .right {
112 | position: absolute;
113 | display: none;
114 | }
115 | #SignupForm,
116 | #loginForm {
117 | width: 95vw;
118 | }
119 | #activate-signup-form,
120 | #activate-login-form {
121 | width: 45%;
122 | max-width: 200px;
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/css/components/AddToPlaylistModel.css:
--------------------------------------------------------------------------------
1 | #add-to-palylist-model {
2 | position: absolute;
3 | width: 100vw;
4 | height: 100vh;
5 | background-color: rgba(0, 0, 0, 0.9);
6 | z-index: 2000;
7 | display: flex;
8 | flex-direction: column;
9 | align-items: center;
10 | padding-top: 20px;
11 | z-index: 999;
12 | overflow-y: auto;
13 | overflow-x: hidden;
14 | }
15 | #add-to-palylist-model #hader {
16 | display: flex;
17 | flex-direction: column;
18 | align-items: center;
19 | }
20 | #add-to-palylist-model #hader h1 {
21 | font-size: 4rem;
22 | margin-bottom: 20px;
23 | }
24 | #add-to-palylist-model #hader button {
25 | width: 200px;
26 | height: 42px;
27 | border-radius: 32px;
28 | border: none;
29 | outline: none;
30 | background-color: #1ed760;
31 | text-transform: uppercase;
32 | }
33 | #add-to-palylist-model #hader button:hover {
34 | cursor: pointer;
35 | transform: scale(1.03);
36 | }
37 |
38 | #add-to-palylist-model #palylist-container {
39 | width: 100vw;
40 | margin-top: 40px;
41 | padding: 20px;
42 | display: flex;
43 | flex-wrap: wrap;
44 | }
45 |
--------------------------------------------------------------------------------
/src/css/components/AlbumCart.css:
--------------------------------------------------------------------------------
1 | .album-container {
2 | background-color: #282828;
3 | max-width: 240px;
4 | padding: 20px;
5 | position: relative;
6 | }
7 | .album-container .album-discription p {
8 | display: block;
9 | display: -webkit-box;
10 | width: 100%;
11 | max-height: 2.4rem;
12 | margin: 0 auto;
13 | font-size: 1rem;
14 | line-height: 1.2rem;
15 | -webkit-line-clamp: 2;
16 | -webkit-box-orient: vertical;
17 | overflow: hidden;
18 | text-overflow: ellipsis;
19 | margin-top: 10px;
20 | }
21 | .album-container .album-tittle p {
22 | margin-top: 10px;
23 | line-height: 1.2rem;
24 | white-space: nowrap;
25 | text-overflow: ellipsis;
26 | overflow: hidden;
27 | }
28 | .album-container img {
29 | object-fit: contain;
30 | width: 100%;
31 | box-shadow: 0 10px 30px 0 rgba(14, 13, 13, 0.3),
32 | 0 1px 2px 0 rgba(0, 0, 0, 0.2);
33 | }
34 | .album-container #circular-paly-button {
35 | background-color: #1db954;
36 | width: 40px;
37 | height: 40px;
38 | border-radius: 50%;
39 | color: #ffffff;
40 | position: absolute;
41 | justify-content: center;
42 | align-items: center;
43 | bottom: 20px;
44 | right: 20px;
45 | display: flex;
46 | visibility: hidden;
47 | }
48 | #album-floating-pause-button {
49 | display: none;
50 | }
51 | #album-container:hover #circular-paly-button {
52 | visibility: visible !important;
53 | }
54 |
--------------------------------------------------------------------------------
/src/css/components/AlbumCartGrid.css:
--------------------------------------------------------------------------------
1 | #album-cart-grid {
2 | display: grid;
3 | grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
4 | justify-items: stretch;
5 | grid-column-gap: 20px;
6 | grid-row-gap: 20px;
7 | padding: 20px;
8 | width: auto;
9 | }
10 |
--------------------------------------------------------------------------------
/src/css/components/AlbumHader.css:
--------------------------------------------------------------------------------
1 | #album-hader {
2 | display: flex;
3 | padding: 20px;
4 | background: linear-gradient(transparent, rgba(0, 0, 0, 0.5));
5 | /* background-color: #315a60; */
6 | }
7 | #controls {
8 | margin-bottom: 15px;
9 | /* background-color: #315a60; */
10 | background-image: linear-gradient(rgba(0, 0, 0, 0.6), rgb(18, 18, 18));
11 | }
12 | #album-hader #left {
13 | width: 25%;
14 | min-width: 200px;
15 | }
16 |
17 | #album-hader #left img {
18 | width: 100%;
19 | }
20 |
21 | #album-hader #right {
22 | display: flex;
23 | flex-direction: column;
24 | justify-content: flex-end;
25 | margin-left: 20px;
26 | width: 75%;
27 | }
28 | #album-hader #right #type {
29 | text-transform: uppercase;
30 | }
31 | #album-hader #right h1 {
32 | font-size: 5rem;
33 | margin-bottom: 7px;
34 | width: 90%;
35 | white-space: nowrap;
36 | overflow: hidden;
37 | text-overflow: ellipsis;
38 | }
39 |
40 | #album-hader #right p {
41 | margin-bottom: 7px;
42 | width: 90%;
43 | white-space: nowrap;
44 | overflow: hidden;
45 | text-overflow: ellipsis;
46 | }
47 |
48 | @media screen and (max-width: 1060px) {
49 | #album-hader #right h1 {
50 | font-size: 4rem;
51 | }
52 | }
53 |
54 | @media screen and (max-width: 950px) {
55 | #album-hader #right h1 {
56 | font-size: 3rem;
57 | }
58 | }
59 |
60 | #controls {
61 | display: flex;
62 | padding: 25px;
63 | align-items: center;
64 | }
65 |
66 | #controls #album-like-button i {
67 | font-size: 30px;
68 | color: #1db954;
69 | margin-left: 40px;
70 | }
71 |
72 | #album-options-button i {
73 | margin-left: 25px;
74 | }
75 |
--------------------------------------------------------------------------------
/src/css/components/AlbumSongConatiner.css:
--------------------------------------------------------------------------------
1 | #album-song-container {
2 | padding: 0px 20px;
3 | }
4 |
--------------------------------------------------------------------------------
/src/css/components/ArtistCart.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rana-shoaib/react-spotify-clone/022fcf24275ce2d8619d83b7e8eaa81a10ffc367/src/css/components/ArtistCart.css
--------------------------------------------------------------------------------
/src/css/components/CreateAlbumPopup.css:
--------------------------------------------------------------------------------
1 | #create-album-poup {
2 | position: absolute;
3 | width: 100vw;
4 | height: 100%;
5 | background-color: rgba(0, 0, 0, 0.9);
6 | z-index: 2000;
7 | }
8 | #create-album-poup #inner {
9 | position: absolute;
10 | top: 50%;
11 | left: 50%;
12 | transform: translate(-50%, -50%);
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | }
17 |
18 | #playlist-name-input-field {
19 | width: 100vw;
20 | height: 140px;
21 | background-color: #282828;
22 | margin-top: 10px;
23 | }
24 | #playlist-name-input-field #inner-input {
25 | width: 80%;
26 | margin-left: 20%;
27 | margin-top: 20px;
28 | }
29 | #playlist-name-input-field #inner-input input {
30 | width: 80%;
31 | background-color: transparent;
32 | height: 80px;
33 | border: none;
34 | outline: none;
35 | color: #ffffff;
36 | font-size: 30px;
37 | }
38 | #create-album-poup #inner #button-conatiner {
39 | margin-top: 20px;
40 | display: flex;
41 | }
42 | #create-album-poup #inner #button-conatiner button {
43 | width: 120px;
44 | height: 37px;
45 | border-radius: 32px;
46 | margin-left: 30px;
47 | color: #ffffff;
48 | display: flex;
49 | justify-content: center;
50 | align-items: center;
51 | cursor: pointer;
52 | }
53 | #create-album-poup #inner #button-conatiner button:hover {
54 | transform: scale(1.1);
55 | }
56 | #create-album-poup #inner #button-conatiner button:focus {
57 | outline: none;
58 | }
59 | #create-album-poup #inner #button-conatiner button:nth-child(2) {
60 | background-color: #1db954;
61 | border: none;
62 | }
63 | #create-album-poup #inner #button-conatiner button:nth-child(1) {
64 | background-color: transparent;
65 | border: 1px solid #ffffff;
66 | }
67 |
--------------------------------------------------------------------------------
/src/css/components/GenreCart.css:
--------------------------------------------------------------------------------
1 | #genre-cart {
2 | position: relative;
3 | max-width: 230px;
4 | height: 200px;
5 | border-radius: 10px;
6 | padding-top: 15px;
7 | overflow: hidden;
8 | }
9 | #genre-cart h6 {
10 | color: hsl(0, 0%, 100%);
11 | font-size: 1.5rem;
12 | margin-left: 20px;
13 | }
14 | #genre-cart #genre-img {
15 | position: absolute;
16 | bottom: 0px;
17 | right: 0px;
18 | width: 130px;
19 | transform: rotate(25deg) translate(18%, -2%);
20 | }
21 |
--------------------------------------------------------------------------------
/src/css/components/GenreGridContainer.css:
--------------------------------------------------------------------------------
1 | #genre-grid-container {
2 | display: grid;
3 | grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
4 | grid-column-gap: 20px;
5 | grid-row-gap: 20px;
6 | padding: 20px;
7 | width: auto;
8 | }
9 |
--------------------------------------------------------------------------------
/src/css/components/Hader.css:
--------------------------------------------------------------------------------
1 | #header-container {
2 | width: 100%;
3 | display: flex;
4 | justify-content: space-between;
5 | position: fixed;
6 | z-index: 999;
7 | height: 60px;
8 | /* background-color: #315a60; */
9 | top: 0px;
10 | left: 0px;
11 | align-items: center;
12 | padding-left: 285px;
13 | padding-right: 15px;
14 | }
15 | #back-and-forward-container {
16 | width: 100%;
17 | display: flex;
18 | }
19 | #back-button-circle,
20 | #forward-button-circle {
21 | width: 40px;
22 | height: 40px;
23 | border-radius: 20px;
24 | background-color: #050505;
25 | display: flex;
26 | justify-content: center;
27 | align-items: center;
28 | margin-right: 10px;
29 | cursor: pointer;
30 | }
31 | #back-button-circle i,
32 | #forward-button-circle i {
33 | color: #e1e1e1;
34 | }
35 | #user-avatar-container img {
36 | width: 30px;
37 | height: 30px;
38 | border-radius: 15px;
39 | }
40 | #user-avatar-container {
41 | /* width: 160px;*/
42 | height: 30px;
43 | border-radius: 20px;
44 | background-color: #050505;
45 | display: flex;
46 | align-items: center;
47 | cursor: pointer;
48 | padding-right: 10px;
49 | }
50 | #user-avatar-container span {
51 | margin-right: 10px;
52 | margin-left: 10px;
53 | white-space: nowrap;
54 | }
55 |
56 | #serch-box-container {
57 | width: 45%;
58 | height: 40px;
59 | border-radius: 32px;
60 | background-color: #ffffff;
61 | }
62 |
63 | #hader-search-box {
64 | width: 40%;
65 | height: 40px;
66 | background-color: #ffffff;
67 | min-width: 200px;
68 | border-radius: 22px;
69 | display: flex;
70 | align-items: center;
71 | overflow: hidden;
72 | }
73 | #hader-search-box input {
74 | height: 100%;
75 | width: 98%;
76 | border: none;
77 | padding: 0px 10px;
78 | outline-width: 0px;
79 | }
80 | #hader-search-box i {
81 | margin-left: 7px;
82 | }
83 |
84 | #hader-login-button a {
85 | display: block;
86 | width: 120px;
87 | height: 37px;
88 | margin-right: 30px;
89 | background-color: #ffffff;
90 | display: flex;
91 | justify-content: center;
92 | align-items: center;
93 | border-radius: 32px;
94 | text-transform: uppercase;
95 | color: #3b3b3b;
96 | font-weight: 600;
97 | }
98 | #hader-login-button a:hover {
99 | transform: scale(1.03);
100 | }
101 | #account-option-continer {
102 | width: 170px;
103 |
104 | background-color: #282828;
105 | position: absolute;
106 | top: 50px;
107 | right: 20px;
108 | padding: 5px;
109 | }
110 | #account-option-continer .menue {
111 | color: #b3b3b3;
112 | padding: 7px;
113 | }
114 | #account-option-continer .menue:hover {
115 | background-color: #3e3e3e;
116 | cursor: pointer;
117 | color: #ffffff;
118 | }
119 |
--------------------------------------------------------------------------------
/src/css/components/NowPlayingBar.css:
--------------------------------------------------------------------------------
1 | #nowplayingBarContainer {
2 | position: fixed;
3 | bottom: 0px;
4 | left: 0px;
5 | width: 100vw;
6 | min-height: 100px;
7 | display: flex;
8 | background-color: #282828;
9 | z-index: 999;
10 | min-width: 700px;
11 | }
12 | #nowplayingBarLeft,
13 | #nowplayingBarRight {
14 | display: flex;
15 | align-items: center;
16 | width: 30%;
17 | }
18 |
19 | #nowplayingBarLeft {
20 | position: relative;
21 | }
22 | #nowplayingBarLeft div {
23 | width: 95%;
24 | }
25 | #nowplayingBarRight {
26 | display: flex;
27 | justify-content: flex-end;
28 | padding-right: 20px;
29 | }
30 | #likeSongButton {
31 | position: absolute;
32 | left: 80%;
33 | padding-left: 20px;
34 | bottom: 2.7vh;
35 | color: #b3b3b3;
36 | font-size: 20px;
37 | cursor: pointer;
38 | }
39 | #nowplayingBarCenter {
40 | width: 40%;
41 | display: flex;
42 | flex-direction: column;
43 | justify-content: center;
44 | align-items: center;
45 | }
46 | #nowplayingSonAlbumArtwork {
47 | width: 80px;
48 | height: 65px;
49 | margin-right: 10px;
50 | margin-left: 10px;
51 | }
52 | #nowPlayingSongTittle,
53 | #nowPlayingSongAlbumName {
54 | height: 1.3rem;
55 | overflow: hidden;
56 | margin-bottom: 10px;
57 | white-space: nowrap;
58 | text-overflow: ellipsis;
59 | width: 50%;
60 | }
61 | .controlIcon {
62 | color: #b3b3b3;
63 | font-size: 14px;
64 | margin-right: 27px;
65 | cursor: pointer;
66 | }
67 | #songControlsConatiner {
68 | margin-bottom: 10px;
69 | display: flex;
70 | align-items: center;
71 | }
72 | #songTimeBarContainer {
73 | background-color: #535353;
74 | width: 90%;
75 | height: 4px;
76 | cursor: pointer;
77 | position: relative;
78 | }
79 | #songTimeBar {
80 | background-color: #b3b3b3;
81 | width: 50px;
82 | height: 4px;
83 | }
84 | #songTimeBarCircle,
85 | #circle {
86 | width: 12px;
87 | height: 12px;
88 | background-color: #ffffff;
89 | border-radius: 50%;
90 | position: absolute;
91 | top: -4px;
92 | display: none;
93 | margin-left: -6px;
94 | }
95 | #songTimeBarContainer:hover #songTimeBarCircle,
96 | #volumeBarContainer:hover #circle {
97 | display: block;
98 | }
99 | #songTimeBarContainer:hover #songTimeBar {
100 | background-color: #1db954;
101 | }
102 | #songCurrentTime {
103 | margin-right: 6px;
104 | font-size: 14px;
105 | }
106 | #songTotalTime {
107 | margin-left: 6px;
108 | font-size: 14px;
109 | }
110 | #play,
111 | #pause {
112 | font-size: 30px;
113 | }
114 | #pause {
115 | display: none;
116 | }
117 |
118 | #volumeBarContainer {
119 | cursor: pointer;
120 | width: 70px;
121 | height: 4px;
122 | max-width: 100px;
123 | min-width: 60px;
124 | background-color: #535353;
125 | position: relative;
126 | }
127 | #volumeBar {
128 | height: 4px;
129 | background-color: #b3b3b3;
130 | }
131 | #volumeBarContainer:hover #volumeBar {
132 | background-color: #1db954;
133 | }
134 | #volumeDown,
135 | #volumeMute,
136 | #volumeZero {
137 | display: none;
138 | }
139 | #loading-indicator {
140 | background-color: transparent;
141 | border-radius: 50%;
142 | width: 45px;
143 | height: 45px;
144 | display: flex;
145 | align-items: center;
146 | border: 4px solid transparent;
147 | border-top: 3px solid #ffffff;
148 | animation: loading 1s linear infinite;
149 | margin-right: -38px;
150 | z-index: -1;
151 | }
152 |
153 | @keyframes loading {
154 | 0% {
155 | transform: rotate(0deg);
156 | }
157 | 100% {
158 | transform: rotate(360deg);
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/css/components/PlaylistCart.css:
--------------------------------------------------------------------------------
1 | #palylist-cart {
2 | width: 200px;
3 | height: 230px;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | margin-right: 20px;
8 | }
9 | #playlist-iamge-conatiner {
10 | width: 100%;
11 | height: 99%;
12 | background-color: #282828;
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | margin-bottom: 10px;
17 | position: relative;
18 | }
19 | #playlist-iamge-conatiner i {
20 | font-size: 25px;
21 | position: absolute;
22 | left: 50%;
23 | right: 50%;
24 | transform: translate(-50%, -50%);
25 | display: none;
26 | }
27 |
28 | #playlist-iamge-conatiner:hover {
29 | background-color: #0c0c0c;
30 | }
31 | #playlist-iamge-conatiner:hover i {
32 | display: block;
33 | }
34 |
--------------------------------------------------------------------------------
/src/css/components/Sidebar.css:
--------------------------------------------------------------------------------
1 | #side-bar-container {
2 | height: 100vh;
3 | position: fixed;
4 | top: 0px;
5 | left: 0px;
6 | background-color: #040404;
7 | padding: 20px;
8 | min-width: 240px;
9 | z-index: 999;
10 | }
11 | #side-bar-logo {
12 | width: 130px;
13 | height: auto;
14 | }
15 | .side-bar-icons {
16 | font-size: 24px;
17 | color: #b3b3b3;
18 | margin-right: 20px;
19 | }
20 | .side-bar-menue {
21 | display: flex;
22 | margin-top: 20px;
23 | cursor: pointer;
24 | }
25 | .side-bar-menue:hover * {
26 | color: #ffffff;
27 | }
28 | .side-bar-menue-active {
29 | width: 110%;
30 | padding-left: 10px;
31 | margin-left: -12px;
32 | height: 45px;
33 | background-color: #282828;
34 | display: flex;
35 | align-items: center;
36 | border-radius: 5px;
37 | }
38 | .side-bar-menue-active * {
39 | color: #ffffff;
40 | }
41 | .create-new-playlist-icon,
42 | .liked-song-icon {
43 | width: 30px;
44 | height: 30px;
45 | background-color: #b3b3b3;
46 | display: flex;
47 | justify-content: center;
48 | align-items: center;
49 | margin-right: 16px;
50 | }
51 | .create-new-playlist-icon span {
52 | font-size: 30px;
53 | }
54 | #user-created-palylists-container {
55 | margin-top: 20px;
56 | }
57 | #user-created-palylists-container p {
58 | margin-top: 5px;
59 | }
60 | #user-created-palylists-container p:hover {
61 | color: #ffffff;
62 | }
63 | .straight-line {
64 | background-color: #191414;
65 | width: 100%;
66 | height: 2px;
67 | margin-top: 12px;
68 | }
69 |
--------------------------------------------------------------------------------
/src/css/components/SingleSong.css:
--------------------------------------------------------------------------------
1 | #single-song-container,
2 | #single-song-container-active {
3 | display: flex;
4 | justify-content: space-between;
5 | align-items: center;
6 | padding: 10px;
7 | margin-bottom: 5px;
8 | }
9 | #single-song-container:hover,
10 | #single-song-container-active {
11 | background-color: #282828;
12 | }
13 | #single-song-container #right,
14 | #single-song-container #left,
15 | #single-song-container-active #right,
16 | #single-song-container-active #left {
17 | display: flex;
18 | align-items: center;
19 | }
20 | #single-song-container #left #song-play-button,
21 | #single-song-container-active #left #song-play-button {
22 | display: none;
23 | }
24 | #single-song-container #left #song-details,
25 | #single-song-container-active #left #song-details {
26 | margin-left: 15px;
27 | }
28 | #single-song-container #left #art,
29 | #single-song-container-active #left #art {
30 | width: 50px;
31 | height: 40px;
32 | margin-left: 15px;
33 | }
34 |
35 | #single-song-container #right #song-options,
36 | #single-song-container-active #right #song-options {
37 | margin-right: 40px;
38 | display: none;
39 | }
40 |
41 | #single-song-container:hover #right #song-options,
42 | #single-song-container-active #right #song-options {
43 | display: block;
44 | }
45 |
46 | #single-song-container:hover #left #music-icon,
47 | #single-song-container-active #left #music-icon {
48 | display: none;
49 | }
50 |
51 | #single-song-container:hover #left #song-play-button,
52 | #single-song-container-active #left #song-play-button {
53 | display: block;
54 | }
55 |
--------------------------------------------------------------------------------
/src/css/components/SongPopupOptions.css:
--------------------------------------------------------------------------------
1 | #song-popup-options-conatiner {
2 | position: absolute;
3 | background-color: #282828;
4 | z-index: 9999999999;
5 | left: 50%;
6 | top: 50%;
7 | width: 200px;
8 | }
9 | #song-popup-options-conatiner * {
10 | font-size: 14px;
11 | }
12 | #song-popup-options-conatiner .option {
13 | width: 100%;
14 | padding: 7px 10px;
15 | cursor: pointer;
16 | }
17 | #song-popup-options-conatiner .option:hover {
18 | background-color: #333333;
19 | }
20 |
--------------------------------------------------------------------------------
/src/handlers/addSongToPlaylist.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "../helpers/baseUrl";
2 |
3 | const addSongToPlaylist = (data) => {
4 | let bodyCredientail = {
5 | data: data,
6 | };
7 | return fetch(`${BASE_URL}addSongToPlaylist.php`, {
8 | method: "POST",
9 | body: JSON.stringify(bodyCredientail),
10 | })
11 | .then((respone) => respone.json())
12 | .then((data) => {
13 | return data;
14 | })
15 | .catch((e) => console.log(e));
16 | };
17 |
18 | export default addSongToPlaylist;
19 |
--------------------------------------------------------------------------------
/src/handlers/createPlaylist.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "../helpers/baseUrl";
2 |
3 | const createPlaylist = (data) => {
4 | let bodyCredientail = {
5 | data: data,
6 | };
7 | return fetch(`${BASE_URL}createPlaylist.php`, {
8 | method: "POST",
9 |
10 | body: JSON.stringify(bodyCredientail),
11 | })
12 | .then((respone) => respone.json())
13 | .then((data) => {
14 | return data;
15 | })
16 | .catch((e) => console.log(e));
17 | };
18 |
19 | export default createPlaylist;
20 |
--------------------------------------------------------------------------------
/src/handlers/getUserInfo.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "../helpers/baseUrl";
2 |
3 | const getUserInfo = (token) => {
4 | return fetch(`${BASE_URL}getUserInfo.php?loginToken=${token}`)
5 | .then((response) => response.json())
6 | .then((data) => {
7 | return data;
8 | });
9 | };
10 |
11 | export default getUserInfo;
12 |
--------------------------------------------------------------------------------
/src/handlers/likeAlbum.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "../helpers/baseUrl";
2 |
3 | const likeAlbum = (data) => {
4 | let bodyCredientail = {
5 | data: data,
6 | };
7 | return fetch(`${BASE_URL}likeAlbum.php`, {
8 | method: "POST",
9 | body: JSON.stringify(bodyCredientail),
10 | })
11 | .then((respone) => respone.json())
12 | .then((data) => {
13 | return data;
14 | })
15 | .catch((e) => console.log(e));
16 | };
17 |
18 | export default likeAlbum;
19 |
--------------------------------------------------------------------------------
/src/handlers/likeSong.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "../helpers/baseUrl";
2 |
3 | const likeSong = (data) => {
4 | let bodyCredientail = {
5 | data: data,
6 | };
7 | return fetch(`${BASE_URL}likeSong.php`, {
8 | method: "POST",
9 | body: JSON.stringify(bodyCredientail),
10 | })
11 | .then((respone) => respone.json())
12 | .then((data) => {
13 | return data;
14 | })
15 | .catch((e) => console.log(e));
16 | };
17 |
18 | export default likeSong;
19 |
--------------------------------------------------------------------------------
/src/handlers/login.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "../helpers/baseUrl";
2 |
3 | const login = (data) => {
4 | let bodyCredientail = {
5 | loginData: data,
6 | };
7 | return fetch(`${BASE_URL}login.php`, {
8 | method: "POST",
9 | body: JSON.stringify(bodyCredientail),
10 | })
11 | .then((respone) => respone.json())
12 | .then((data) => {
13 | return data;
14 | })
15 | .catch((e) => console.error(e));
16 | };
17 |
18 | export default login;
19 |
--------------------------------------------------------------------------------
/src/handlers/signup.js:
--------------------------------------------------------------------------------
1 | import BASE_URL from "../helpers/baseUrl";
2 |
3 | const signup = (data) => {
4 | let bodyCredientail = {
5 | signupData: data,
6 | };
7 | return fetch(`${BASE_URL}signup.php`, {
8 | method: "POST",
9 | body: JSON.stringify(bodyCredientail),
10 | })
11 | .then((respone) => respone.json())
12 | .then((data) => {
13 | return data;
14 | })
15 | .catch((e) => console.log(e));
16 | };
17 |
18 | export default signup;
19 |
--------------------------------------------------------------------------------
/src/helpers/baseUrl.js:
--------------------------------------------------------------------------------
1 | const BASE_URL = "https://spotify-clone-backend.000.pe/";
2 | export default BASE_URL;
3 |
--------------------------------------------------------------------------------
/src/helpers/formatTime.js:
--------------------------------------------------------------------------------
1 | const formatTime = (sec) => {
2 | let min = Math.floor(sec / 60);
3 | sec = sec - min * 60;
4 | sec = Math.floor(sec);
5 |
6 | if (sec < 10) {
7 | sec = "0" + sec;
8 | }
9 |
10 | return min + ":" + sec;
11 | };
12 |
13 | export default formatTime;
14 |
--------------------------------------------------------------------------------
/src/helpers/genreList.js:
--------------------------------------------------------------------------------
1 | const genreList = [
2 | {
3 | title: "Hip-Hop",
4 | img: "https://t.scdn.co/images/9676cef74ec147a48607c737c4f93943.jpeg",
5 | bgColor: "#D9891F",
6 | },
7 |
8 | {
9 | title: "Summer",
10 | img: "https://t.scdn.co/images/a2a24668f16c4e9680233a0d7d244a4b.jpeg",
11 | bgColor: "#CDA050",
12 | },
13 |
14 | {
15 | title: "Country",
16 | img: "https://t.scdn.co/images/4afff64d33e74356905bc257646d476c.jpeg",
17 | bgColor: "#D1A452",
18 | },
19 |
20 | {
21 | title: "Higher Ground",
22 | img: "https://i.scdn.co/image/4f26db8239305bef29ef956b331b31407cbf51f9",
23 | bgColor: "#6A818B",
24 | },
25 |
26 | {
27 | title: "Latin",
28 | img: "https://t.scdn.co/images/1d7841c92c504343a391dfa0626fc22c.jpeg",
29 | bgColor: "#C94E2B",
30 | },
31 |
32 | {
33 | title: "Rock",
34 | img: "https://t.scdn.co/images/31c85ae6fec34a16927ef28a7a88e97b.jpeg",
35 | bgColor: "#D21A2C",
36 | },
37 |
38 | {
39 | title: "R&B",
40 | img: "https://t.scdn.co/images/92a6fd8aaffe403ba1967c70097f90f9.jpeg",
41 | bgColor: "#CC2E8C",
42 | },
43 |
44 | {
45 | title: "Romance",
46 | img: "https://t.scdn.co/images/f926c0d460ae4f1abd83ffc3c1affdf0.jpeg",
47 | bgColor: "#CA5F84",
48 | },
49 |
50 | {
51 | title: "Punk",
52 | img: "https://t.scdn.co/images/1383b2c0e0954accad7e7a05387c0c4e.jpeg",
53 | bgColor: "#616161",
54 | },
55 | ];
56 |
57 | export default genreList;
58 |
--------------------------------------------------------------------------------
/src/helpers/isBuffering.js:
--------------------------------------------------------------------------------
1 | var lastPlayPos = 0;
2 | var currentPlayPos = 0;
3 | var bufferingDetected = false;
4 | let checkInterval = 50.0;
5 | function isBuffering(audio) {
6 | let player = audio;
7 | currentPlayPos = player.currentTime;
8 |
9 | // checking offset should be at most the check interval
10 | // but allow for some margin
11 | var offset = (checkInterval - 20) / 1000;
12 |
13 | // if no buffering is currently detected,
14 | // and the position does not seem to increase
15 | // and the player isn't manually paused...
16 | if (
17 | !bufferingDetected &&
18 | currentPlayPos < lastPlayPos + offset &&
19 | !player.paused
20 | ) {
21 | bufferingDetected = true;
22 | }
23 |
24 | // if we were buffering but the player has advanced,
25 | // then there is no buffering
26 | if (
27 | bufferingDetected &&
28 | currentPlayPos > lastPlayPos + offset &&
29 | !player.paused
30 | ) {
31 | bufferingDetected = false;
32 | }
33 | lastPlayPos = currentPlayPos;
34 |
35 | return bufferingDetected;
36 | }
37 |
38 | export default isBuffering;
39 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 | body {
7 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
8 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
9 | sans-serif;
10 | -webkit-font-smoothing: antialiased;
11 | -moz-osx-font-smoothing: grayscale;
12 | overflow-y: hidden;
13 | }
14 |
15 | code {
16 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
17 | monospace;
18 | }
19 |
20 | a {
21 | text-decoration: none;
22 | }
23 |
24 | /*............Coustom Scroll Bar ................*/
25 | /* width */
26 | ::-webkit-scrollbar {
27 | width: 13px;
28 | position: absolute;
29 | }
30 |
31 | /* Track */
32 | ::-webkit-scrollbar-track {
33 | background: #121212;
34 | }
35 |
36 | /* Handle */
37 | ::-webkit-scrollbar-thumb {
38 | background: #5a5a5a;
39 | }
40 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 | import * as serviceWorker from "./serviceWorker";
6 | import { StateProvider } from "./StateProvider";
7 | import reducer, { initialState } from "./reducer";
8 | import { BrowserRouter } from "react-router-dom";
9 |
10 | ReactDOM.render(
11 |
12 |
13 |
14 |
15 |
16 |
17 | ,
18 | document.getElementById("root")
19 | );
20 |
21 | // If you want your app to work offline and load faster, you can change
22 | // unregister() to register() below. Note this comes with some pitfalls.
23 | // Learn more about service workers: https://bit.ly/CRA-PWA
24 | serviceWorker.unregister();
25 |
--------------------------------------------------------------------------------
/src/reducer.js:
--------------------------------------------------------------------------------
1 | export const initialState = {
2 | playlist: [{}],
3 | currentSongId: 0,
4 | isPlaying: false,
5 | searchQuery: "",
6 | showSearchBox: false,
7 | albumColor: "#121212",
8 | currentPlayingAlbumId: "",
9 | tempAlbumId: "",
10 | user: {},
11 | showPopupPlaylistForm: false,
12 | songOptionnsData: {},
13 | temPlaylist: [{}],
14 | userPlaylists: [{}],
15 | showAddToPlaylistModel: false,
16 | addToPlaylistData: {},
17 | isLogin: false,
18 | };
19 |
20 | const reducer = (state, action) => {
21 | //
22 | switch (action.type) {
23 | case "SET_USER":
24 | return {
25 | ...state,
26 | user: action.item,
27 | };
28 | case "SET_PLAYLIST":
29 | // Logic for adding item to basket
30 | return {
31 | ...state,
32 | playlist: action.item,
33 | };
34 |
35 | case "SET_CURRENT_SONG_ID":
36 | return {
37 | ...state,
38 | currentSongId: action.item,
39 | };
40 | case "UPDATE_SONG_STATUS":
41 | return {
42 | ...state,
43 | isPlaying: action.item,
44 | };
45 |
46 | case "UPDATE_SEARCH_QUERY":
47 | return {
48 | ...state,
49 | searchQuery: action.item,
50 | };
51 |
52 | case "SHOW_HIDE_SEARCH_BOX":
53 | return {
54 | ...state,
55 | showSearchBox: action.item,
56 | };
57 |
58 | case "SET_ALBUM_COLOR":
59 | return {
60 | ...state,
61 | albumColor: action.item,
62 | };
63 | case "SET_CURRENT_ALBUM_ID":
64 | return {
65 | ...state,
66 | currentPlayingAlbumId: action.item,
67 | };
68 | case "SET_TEMP_ALBUM_ID":
69 | return {
70 | ...state,
71 | tempAlbumId: action.item,
72 | };
73 | case "SHOW_HIDE_PLAYLIST_POPUP_FORM":
74 | return {
75 | ...state,
76 | showPopupPlaylistForm: action.item,
77 | };
78 |
79 | case "SONGS_OPTION_DATA":
80 | return {
81 | ...state,
82 | songOptionnsData: action.item,
83 | };
84 | case "SET_TEMP_PALYLIST":
85 | return {
86 | ...state,
87 | temPlaylist: action.item,
88 | };
89 |
90 | case "SET_USER_PLAYLISTS":
91 | return {
92 | ...state,
93 | userPlaylists: action.item,
94 | };
95 | case "SHOW_HIDE_ADD_TO_PLAYLIST_MODEL":
96 | return {
97 | ...state,
98 | showAddToPlaylistModel: action.item,
99 | };
100 |
101 | case "ADD_TO_PLAYLIST_DATA":
102 | return {
103 | ...state,
104 | addToPlaylistData: action.item,
105 | };
106 |
107 | case "LOGIN_STATUS":
108 | return {
109 | ...state,
110 | isLogin: action.item,
111 | };
112 | default:
113 | return state;
114 | }
115 | };
116 |
117 | export default reducer;
118 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' },
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------