├── App.css
├── App.js
├── Credentials.js
├── Detail.js
├── Dropdown.js
├── Listbox.js
├── index.css
├── index.js
└── package.json
/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | height: 40vmin;
7 | pointer-events: none;
8 | }
9 |
10 | @media (prefers-reduced-motion: no-preference) {
11 | .App-logo {
12 | animation: App-logo-spin infinite 20s linear;
13 | }
14 | }
15 |
16 | .App-header {
17 | background-color: #282c34;
18 | min-height: 100vh;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 | font-size: calc(10px + 2vmin);
24 | color: white;
25 | }
26 |
27 | .App-link {
28 | color: #61dafb;
29 | }
30 |
31 | @keyframes App-logo-spin {
32 | from {
33 | transform: rotate(0deg);
34 | }
35 | to {
36 | transform: rotate(360deg);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import Dropdown from './Dropdown';
3 | import Listbox from './Listbox';
4 | import Detail from './Detail';
5 | import { Credentials } from './Credentials';
6 | import axios from 'axios';
7 |
8 | const App = () => {
9 |
10 | const spotify = Credentials();
11 |
12 | console.log('RENDERING APP.JS');
13 |
14 | const data = [
15 | {value: 1, name: 'A'},
16 | {value: 2, name: 'B'},
17 | {value: 3, name: 'C'},
18 | ];
19 |
20 | const [token, setToken] = useState('');
21 | const [genres, setGenres] = useState({selectedGenre: '', listOfGenresFromAPI: []});
22 | const [playlist, setPlaylist] = useState({selectedPlaylist: '', listOfPlaylistFromAPI: []});
23 | const [tracks, setTracks] = useState({selectedTrack: '', listOfTracksFromAPI: []});
24 | const [trackDetail, setTrackDetail] = useState(null);
25 |
26 | useEffect(() => {
27 |
28 | axios('https://accounts.spotify.com/api/token', {
29 | headers: {
30 | 'Content-Type' : 'application/x-www-form-urlencoded',
31 | 'Authorization' : 'Basic ' + btoa(spotify.ClientId + ':' + spotify.ClientSecret)
32 | },
33 | data: 'grant_type=client_credentials',
34 | method: 'POST'
35 | })
36 | .then(tokenResponse => {
37 | setToken(tokenResponse.data.access_token);
38 |
39 | axios('https://api.spotify.com/v1/browse/categories?locale=sv_US', {
40 | method: 'GET',
41 | headers: { 'Authorization' : 'Bearer ' + tokenResponse.data.access_token}
42 | })
43 | .then (genreResponse => {
44 | setGenres({
45 | selectedGenre: genres.selectedGenre,
46 | listOfGenresFromAPI: genreResponse.data.categories.items
47 | })
48 | });
49 |
50 | });
51 |
52 | }, [genres.selectedGenre, spotify.ClientId, spotify.ClientSecret]);
53 |
54 | const genreChanged = val => {
55 | setGenres({
56 | selectedGenre: val,
57 | listOfGenresFromAPI: genres.listOfGenresFromAPI
58 | });
59 |
60 | axios(`https://api.spotify.com/v1/browse/categories/${val}/playlists?limit=10`, {
61 | method: 'GET',
62 | headers: { 'Authorization' : 'Bearer ' + token}
63 | })
64 | .then(playlistResponse => {
65 | setPlaylist({
66 | selectedPlaylist: playlist.selectedPlaylist,
67 | listOfPlaylistFromAPI: playlistResponse.data.playlists.items
68 | })
69 | });
70 |
71 | console.log(val);
72 | }
73 |
74 | const playlistChanged = val => {
75 | console.log(val);
76 | setPlaylist({
77 | selectedPlaylist: val,
78 | listOfPlaylistFromAPI: playlist.listOfPlaylistFromAPI
79 | });
80 | }
81 |
82 | const buttonClicked = e => {
83 | e.preventDefault();
84 |
85 | axios(`https://api.spotify.com/v1/playlists/${playlist.selectedPlaylist}/tracks?limit=10`, {
86 | method: 'GET',
87 | headers: {
88 | 'Authorization' : 'Bearer ' + token
89 | }
90 | })
91 | .then(tracksResponse => {
92 | setTracks({
93 | selectedTrack: tracks.selectedTrack,
94 | listOfTracksFromAPI: tracksResponse.data.items
95 | })
96 | });
97 | }
98 |
99 | const listboxClicked = val => {
100 |
101 | const currentTracks = [...tracks.listOfTracksFromAPI];
102 |
103 | const trackInfo = currentTracks.filter(t => t.track.id === val);
104 |
105 | setTrackDetail(trackInfo[0].track);
106 |
107 |
108 |
109 | }
110 |
111 |
112 |
113 |
114 | return (
115 |
130 |
131 |
132 | );
133 | }
134 |
135 | export default App;
--------------------------------------------------------------------------------
/Credentials.js:
--------------------------------------------------------------------------------
1 | const Credentials = () => {
2 |
3 | return {
4 | ClientId: 'ENTER YOUR CLIENT ID',
5 | ClientSecret: 'ENTER YOUR CLIENT SECRET'
6 | }
7 | }
8 |
9 | export { Credentials };
--------------------------------------------------------------------------------
/Detail.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Detail = ({album, artists, name}) => {
4 |
5 | return (
6 |
7 |
8 |

11 |
12 |
13 |
14 |
17 |
18 |
19 |
22 |
23 |
24 | );
25 | }
26 |
27 | export default Detail;
--------------------------------------------------------------------------------
/Dropdown.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Dropdown = props => {
4 |
5 | const dropdownChanged = e => {
6 | props.changed(e.target.value);
7 |
8 | }
9 |
10 | return (
11 |
12 |
13 |
17 |
18 | );
19 | }
20 |
21 | export default Dropdown;
--------------------------------------------------------------------------------
/Listbox.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Listbox = props => {
4 |
5 | const clicked = e => {
6 | e.preventDefault();
7 | props.clicked(e.target.id);
8 | }
9 |
10 | return (
11 |
12 |
13 | {
14 | props.items.map((item, idx) =>
15 | )
22 | }
23 |
24 |
25 |
26 |
27 | );
28 | }
29 |
30 | export default Listbox;
--------------------------------------------------------------------------------
/index.css:
--------------------------------------------------------------------------------
1 | .btn.dropdown-toggle {
2 | width:150px;
3 | text-align:left;
4 | }
5 |
6 | span.caret {
7 | position: absolute;
8 | left: 90%;
9 | top: 45%;
10 | }
11 |
12 | label {
13 | padding-top:5px;
14 | }
15 |
16 | .form-label {
17 | padding-left:0px !important;
18 | }
19 |
20 | img {
21 | width:140px;
22 | height:140px;
23 | }
24 |
25 | .btn-success {
26 | background-color: #3b7d4a!important;
27 | }
28 |
29 | .btn-success:hover {
30 | background-color: #4daf64!important;
31 | }
32 |
33 | img.track {
34 | border: 1px solid #8a8a8a;
35 | }
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import 'bootstrap/dist/css/bootstrap.min.css';
2 | import $ from 'jquery';
3 | import Popper from 'popper.js';
4 | import 'bootstrap/dist/js/bootstrap.bundle.min';
5 | import React from 'react';
6 | import ReactDOM from 'react-dom';
7 | import './index.css';
8 | import App from './App';
9 |
10 |
11 |
12 | ReactDOM.render(
13 |
14 |
15 | ,
16 | document.getElementById('root')
17 | );
18 |
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "spotify-api",
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 | "axios": "^0.20.0",
10 | "bootstrap": "^4.5.2",
11 | "jquery": "^3.5.1",
12 | "popper.js": "^1.16.1",
13 | "react": "^16.13.1",
14 | "react-dom": "^16.13.1",
15 | "react-scripts": "3.4.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 |
--------------------------------------------------------------------------------