diff --git a/.DS_Store b/.DS_Store
index 6831926..aeafcdb 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/app/.DS_Store b/app/.DS_Store
index 8734399..bede5b0 100644
Binary files a/app/.DS_Store and b/app/.DS_Store differ
diff --git a/app/assets/.DS_Store b/app/assets/.DS_Store
index ceaebf1..23eab17 100644
Binary files a/app/assets/.DS_Store and b/app/assets/.DS_Store differ
diff --git a/app/assets/circular (1).otf b/app/assets/circular (1).otf
new file mode 100644
index 0000000..9b61395
Binary files /dev/null and b/app/assets/circular (1).otf differ
diff --git a/app/assets/images/face.jpg b/app/assets/images/face.jpg
new file mode 100644
index 0000000..e28d260
Binary files /dev/null and b/app/assets/images/face.jpg differ
diff --git a/app/assets/stylesheets/components/main_content.scss b/app/assets/stylesheets/components/main_content.scss
index 3a37711..f60a109 100644
--- a/app/assets/stylesheets/components/main_content.scss
+++ b/app/assets/stylesheets/components/main_content.scss
@@ -1,7 +1,10 @@
.main-container {
- height: 1000px;
- background-color: red; /* For browsers that do not support gradients */
- background-image: linear-gradient(#8D200A, #6D1A08, #451005, #150501);
+ height: 100vh;
+ background: #34e89e; /* fallback for old browsers */
+ background: -webkit-linear-gradient(to top, #0f3443, #34e89e); /* Chrome 10-25, Safari 5.1-6 */
+ background: linear-gradient(to top, #0f3443, #34e89e); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
+ display: flex;
+ font-family: Circular,Helvetica,Arial,sans-serif;
}
.main-container .nav-bar {
@@ -13,7 +16,6 @@
background-color: black;
opacity: .8;
box-sizing: border-box;
- position: fixed;
top: 0;
}
@@ -68,10 +70,50 @@
.nav-bar .logout{
color: white;
- margin-top: 500px;
align-self: end;
+ position: absolute;
+ bottom: 30px;
+ left: 70px;
}
.nav-bar .active-link{
color: green;
+ background-color: green;
+}
+
+.grid ul {
+ display: flex;
+ align-items: flex-start;
+ flex-wrap: wrap;
+}
+
+.playlist-item {
+ padding: 20px;
+ flex-basis: 15%;
+ box-sizing: border-box;
+}
+
+.playlist-item-image {
+ min-width: 150px;
+ min-height: 150px;
+ max-height: 241px;
+ max-width: 241px;
+}
+.playlist-subtext {
+ padding-top: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.playlist-subtext p {
+ color:white;
+ padding-bottom: 5px;
+ font-size: 14px;
+ font-family: Circular,Helvetica,Arial,sans-serif;
+}
+.playlist-subtext span {
+ color: lightgray;
+ font-weight: 100;
+ font-size: 14px;
+ font-family: Circular,Helvetica,Arial,sans-serif;
}
diff --git a/app/assets/stylesheets/components/show_box_content.scss b/app/assets/stylesheets/components/show_box_content.scss
new file mode 100644
index 0000000..1e185c7
--- /dev/null
+++ b/app/assets/stylesheets/components/show_box_content.scss
@@ -0,0 +1,37 @@
+.playlist-show-item {
+ display: flex;
+ flex-direction: column;
+ padding-left: 50px;
+ padding-top: 30px;
+}
+
+.playlist-show-item-image {
+ min-width: 180px;
+ min-height: 180px;
+ max-height: 260px;
+ max-width: 260px;
+}
+.playlist-show-subtext {
+ padding-top: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.playlist-show-subtext p {
+ color: white;
+ padding-bottom: 5px;
+ font-size: 14px;
+ font-family: Circular,Helvetica,Arial,sans-serif;
+}
+.playlist-show-subtext span {
+ color: lightgray;
+ font-weight: 100;
+ font-size: 14px;
+ font-family: Circular,Helvetica,Arial,sans-serif;
+}
+
+.loading {
+ width: 60px;
+ margin: auto;
+ margin-top: 160px;
+}
diff --git a/app/assets/stylesheets/components/splash.scss b/app/assets/stylesheets/components/splash.scss
index eb8ead8..213d34a 100644
--- a/app/assets/stylesheets/components/splash.scss
+++ b/app/assets/stylesheets/components/splash.scss
@@ -1,7 +1,8 @@
.splash-page-contain{
width:100%;
- height:1000px;
+ height:100vh;
overflow:hidden;
+ min-width: 800px;
}
.splash-page{
@@ -29,6 +30,7 @@
right: 0;
left: 0;
z-index: 2;
+ min-width: 800px;
}
.splash-page .logo {
diff --git a/app/controllers/api/playlists_controller.rb b/app/controllers/api/playlists_controller.rb
index dcbed40..b0ee5b9 100644
--- a/app/controllers/api/playlists_controller.rb
+++ b/app/controllers/api/playlists_controller.rb
@@ -1,6 +1,11 @@
class Api::PlaylistsController < ApplicationController
+ def show
+ @playlist = Playlist.includes(:songs, :author).find(params[:id])
+ render :show
+ end
+
def index
- @playlists = Playlist.all
+ @playlists = Playlist.all.includes(:songs, :author)
render :index
end
diff --git a/app/controllers/api/song_playlists_controller.rb b/app/controllers/api/song_playlists_controller.rb
index 44c34d4..baa10da 100644
--- a/app/controllers/api/song_playlists_controller.rb
+++ b/app/controllers/api/song_playlists_controller.rb
@@ -1,4 +1,16 @@
class Api::SongPlaylistsController < ApplicationController
+ def create
+ @song_playlists = SongPlaylists.new(song_playlist_params)
+ @playlist_song.save
+ end
+
+ def destroy
+ end
+
+ private
+ def song_playlist_params
+ params.require(:song_playlist).permit(:song_id, :playlist_id)
+ end
end
# class Api::PlaylistSongsController < ApplicationController
diff --git a/app/models/playlist.rb b/app/models/playlist.rb
index 05c6886..1e83a90 100644
--- a/app/models/playlist.rb
+++ b/app/models/playlist.rb
@@ -20,6 +20,10 @@ class Playlist < ApplicationRecord
foreign_key: :playlist_id,
class_name: :Song_playlist
+ has_many :songs,
+ through: :song_playlists,
+ source: :song
+
has_one_attached :photo
has_one_attached :track
end
diff --git a/app/models/song.rb b/app/models/song.rb
index 090be79..4135084 100644
--- a/app/models/song.rb
+++ b/app/models/song.rb
@@ -27,4 +27,8 @@ class Song < ApplicationRecord
has_many :arists,
through: :song_artists,
source: :artist
+
+ has_many :playlists,
+ through: :song_playlists,
+ source: :playlist
end
diff --git a/app/views/api/playlists/index.json.jbuilder b/app/views/api/playlists/index.json.jbuilder
index 79bd566..794eebb 100644
--- a/app/views/api/playlists/index.json.jbuilder
+++ b/app/views/api/playlists/index.json.jbuilder
@@ -1,5 +1,22 @@
-json.array! @playlists do |playlist|
- json.extract! playlist, :id, :title
- json.photoUrl url_for(playlist.photo)
- json.trackUrl url_for(playlist.track)
+@playlists.each do |playlist|
+ json.set! playlist.id do
+ json.extract! playlist, :id, :title, :author_id
+ json.author playlist.author.username
+
+ json.song_ids playlist.songs.pluck(:id)
+
+ if playlist.songs[0]
+ json.photoUrl url_for(playlist.songs[0].album.photo);
+ else
+ json.photoUrl image_path("face.jpg")
+ end
+ end
end
+
+# json.photoUrl url_for(playlist.photo)
+# json.trackUrl url_for(playlist.track)
+
+
+# json.songs playlist.songs.each do |song|
+# json.set! song.id
+# end
diff --git a/app/views/api/playlists/show.json.jbuilder b/app/views/api/playlists/show.json.jbuilder
index e69de29..818b3ac 100644
--- a/app/views/api/playlists/show.json.jbuilder
+++ b/app/views/api/playlists/show.json.jbuilder
@@ -0,0 +1,18 @@
+json.songs do
+ @playlist.songs.each do |song|
+ json.set! song.id do
+ json.extract! song, :id, :title
+ json.trackUrl url_for(song.track)
+ end
+ end
+end
+
+json.playlist do
+ json.extract! @playlist, :id, :title, :song_ids, :author_id
+ if @playlist.songs[0]
+ json.photoUrl url_for(@playlist.songs[0].album.photo);
+ else
+ json.photoUrl image_path("face.jpg")
+ end
+ json.author @playlist.author.username
+end
diff --git a/app/views/api/songs/index.json.jbuilder b/app/views/api/songs/index.json.jbuilder
index 1d8ee4d..4796105 100644
--- a/app/views/api/songs/index.json.jbuilder
+++ b/app/views/api/songs/index.json.jbuilder
@@ -1,4 +1,11 @@
-json.array! @songs do |song|
- json.extract! song, :id, :title, :album_id
- json.trackUrl url_for(song.track)
+@songs.each do |song|
+ json.set! song.id do
+ json.extract! song, :id, :title
+ json.trackUrl url_for(song.track)
+ end
end
+
+# json.array! @songs do |song|
+# json.extract! song, :id, :title, :album_id
+# json.trackUrl url_for(song.track)
+# end
diff --git a/db/migrate/20181118235623_change_songs.rb b/db/migrate/20181118235623_change_songs.rb
new file mode 100644
index 0000000..30e9ab9
--- /dev/null
+++ b/db/migrate/20181118235623_change_songs.rb
@@ -0,0 +1,5 @@
+class ChangeSongs < ActiveRecord::Migration[5.2]
+ def change
+ remove_index :songs, :album_id
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index fc4016a..9312314 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2018_11_18_002319) do
+ActiveRecord::Schema.define(version: 2018_11_18_235623) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -84,7 +84,6 @@
t.string "title", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
- t.index ["album_id"], name: "index_songs_on_album_id", unique: true
t.index ["title"], name: "index_songs_on_title", unique: true
end
diff --git a/db/seeds.rb b/db/seeds.rb
index ac0b257..be3343b 100644
--- a/db/seeds.rb
+++ b/db/seeds.rb
@@ -12,7 +12,99 @@
User.destroy_all
Playlist.destroy_all
-def create_album(params, filename)
- album = Album.new(params)
- file = EzDownload.open("")
-end
+l = Album.create!(title: "Chilis")
+m = Album.create!(title: "Corbys")
+n = Album.create!(title: "Samms")
+o = Album.create!(title: "Vibes")
+q = Album.create!(title: "Redemption")
+r = Album.create!(title: "Epic")
+s = Album.create!(title: "Yebbz")
+t = Album.create!(title: "Gambining")
+u = Album.create!(title: "Dragons")
+
+l.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/chilipeppers.jpg"), filename: "chilipeppers.jpg")
+m.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/corby.jpg"), filename: "corby.jpg")
+n.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/samm.jpg"), filename: "samm.jpg")
+o.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/Wave.jpg"), filename: "Wave.jpg")
+q.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/matisyahu.jpg"), filename: "matisyahu.jpg")
+r.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/whirl.jpg"), filename: "whirl.jpg")
+s.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/yebba.jpg"), filename: "yebba.jpg")
+t.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/gambino.jpg"), filename: "gambino.jpg")
+u.photo.attach(io: File.open("/Users/avichaivazana/Desktop/Photos/face.jpg"), filename: "face.jpg")
+
+c.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/Monday.mp3"), filename: "Monday.mp3")
+
+a.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/ Californication.mp3"), filename: "Californication.mp3")
+b.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/ Snow.mp3"), filename: "Snow.mp3")
+d.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/King Without a Crown.mp3"), filename: "King Without a Crown.mp3")
+e.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/Redbone.mp3"), filename: "Redbone.mp3")
+f.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/YEBBA.mp3"), filename: "YEBBA.mp3")
+g.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/Corporate_Innovative.mp3"), filename: "Corporate_Innovative.mp3")
+h.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/Corporate_Presentation.mp3"), filename: "Corporate_Presentation.mp3")
+i.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/Corporate_Success.mp3"), filename: "Corporate_Success.mp3")
+j.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/Smooth.mp3"), filename: "Smooth.mp3")
+k.track.attach(io: File.open("/Users/avichaivazana/Desktop/Songs/the-battle.mp3"), filename: "the-battle.mp3")
+
+a = Song.second
+b = Song.find_by(id: 14)
+d = Song.find_by(id: 5)
+e = Song.find_by(id: 6)
+f = Song.find_by(id: 7)
+g = Song.find_by(id: 8)
+h = Song.find_by(id: 15)
+i = Song.find_by(id: 16)
+j = Song.find_by(id: 11)
+k = Song.find_by(id: 12)
+
+a = Song.create!(album_id: 2, title: "Californication")
+b = Song.create!(album_id: 2, title: "Snow")
+c = Song.create!(album_id: 3, title: "Monday")
+d = Song.create!(album_id: 4, title: "King Without a Crown")
+e = Song.create!(album_id: 5, title: "Redbone")
+f = Song.create!(album_id: 6, title: "Evergreen")
+g = Song.create!(album_id: 7, title: "Corporate Innovation")
+h = Song.create!(album_id: 7, title: "Corporate Presentation")
+i = Song.create!(album_id: 7, title: "Corporate Success")
+j = Song.create!(album_id: 8, title: "Smooth")
+k = Song.create!(album_id: 9, title: "The Battle")
+
+
+
+Playlist.create!(author_id: 22, title: "Chill Vibes")
+Playlist.create!(author_id: 22, title: "Summer Stuff")
+Playlist.create!(author_id: 22, title: "Sleepy Time")
+Playlist.create!(author_id: 22, title: "Study Music")
+Playlist.create!(author_id: 22, title: "Party")
+Playlist.create!(author_id: 22, title: "Random Mix")
+Playlist.create!(author_id: 22, title: "Shower")
+Playlist.create!(author_id: 22, title: "Walking")
+Playlist.create!(author_id: 22, title: "Shower while walking")
+
+
+Song_playlist.create!(4, 3)
+Song_playlist.create!(4, 4)
+Song_playlist.create!(4, 5)
+Song_playlist.create!(5, 3)
+Song_playlist.create!(5, 4)
+Song_playlist.create!(5, 5)
+Song_playlist.create!(5, 6)
+Song_playlist.create!(6, 7)
+Song_playlist.create!(6, 8)
+Song_playlist.create!(6, 9)
+Song_playlist.create!(6, 10)
+Song_playlist.create!(7, 5)
+Song_playlist.create!(7, 3)
+Song_playlist.create!(7, 7)
+Song_playlist.create!(7, 4)
+Song_playlist.create!(8, 4)
+Song_playlist.create!(8, 5)
+Song_playlist.create!(11, 5)
+Song_playlist.create!(11, 7)
+Song_playlist.create!(11, 4)
+Song_playlist.create!(11, 3)
+Song_playlist.create!(12, 8)
+Song_playlist.create!(12, 7)
+Song_playlist.create!(15, 9)
+Song_playlist.create!(16, 10)
+Song_playlist.create!(14, 4)
+Song_playlist.create!(2, 3)
diff --git a/frontend/actions/playlist_actions.js b/frontend/actions/playlist_actions.js
index 31fd612..6d869b0 100644
--- a/frontend/actions/playlist_actions.js
+++ b/frontend/actions/playlist_actions.js
@@ -1,4 +1,4 @@
-import * as APIUtil from '../util/playlist_api_util'
+import * as APIUtil from '../util/playlist_api_util';
export const RECEIVE_ALL_PLAYLISTS = 'RECEIVE_ALL_PLAYLISTS';
export const RECEIVE_SINGLE_PLAYLIST = 'RECEIVE_SINGLE_PLAYLIST';
@@ -11,10 +11,11 @@ const receivePlaylists = (playlists) => {
};
};
-const receivePlaylist = (playlist) => {
+const receivePlaylist = ({playlist, songs}) => {
return {
type: RECEIVE_SINGLE_PLAYLIST,
- playlist
+ playlist,
+ songs
};
};
@@ -22,8 +23,8 @@ const removePlaylist = playlistId => {
return {
type: DELETE_PLAYLIST,
playlistId
- }
-}
+ };
+};
export const fetchPlaylists = () => dispatch => {
return (
@@ -34,8 +35,10 @@ export const fetchPlaylists = () => dispatch => {
export const fetchPlaylist = (id) => dispatch => {
return (
- APIUtil.fetchPlaylist(id).then(
- res => dispatch(receivePlaylist(res))
+ APIUtil.fetchPlaylist(id).then(res => {
+
+ dispatch(receivePlaylist(res));
+ }
));
};
diff --git a/frontend/actions/song_actions.js b/frontend/actions/song_actions.js
new file mode 100644
index 0000000..3032249
--- /dev/null
+++ b/frontend/actions/song_actions.js
@@ -0,0 +1,32 @@
+import * as APIUtil from '../util/song_api_util';
+
+export const RECEIVE_ALL_SONGS = 'RECEIVE_ALL_SONGS';
+export const RECEIVE_SINGLE_SONG = 'RECEIVE_SINGLE_SONG';
+
+const receiveSongs = (songs) => {
+ return {
+ type: RECEIVE_ALL_SONGS,
+ songs
+ };
+};
+
+const receiveSong = (song) => {
+ return {
+ type: RECEIVE_SINGLE_SONG,
+ song
+ };
+};
+
+export const fetchSongs = () => dispatch => {
+ return (
+ APIUtil.fetchSongs().then(
+ res => dispatch(receiveSongs(res))
+ ));
+};
+
+export const fetchSong = (id) => dispatch => {
+ return (
+ APIUtil.fetchSong(id).then(
+ res => dispatch(receiveSong(res))
+ ));
+};
diff --git a/frontend/components/App.jsx b/frontend/components/App.jsx
index 00f78ae..6d4c88c 100644
--- a/frontend/components/App.jsx
+++ b/frontend/components/App.jsx
@@ -7,28 +7,27 @@ import SplashContainer from './splash/splash_container';
import BrowseContainer from './main/browse_container';
import SearchContainer from './main/search_container';
import CollectionContainer from './main/collection_container';
+import PlaylistShowContainer from './main/playlist_show_container';
const App = () => {
return (
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-)
+);
};
export default App;
-
//
//
//
diff --git a/frontend/components/main/browse_container.js b/frontend/components/main/browse_container.js
index a57f23d..856feb3 100644
--- a/frontend/components/main/browse_container.js
+++ b/frontend/components/main/browse_container.js
@@ -3,13 +3,15 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { logout } from '../../actions/session_actions';
import { fetchPlaylists } from '../../actions/playlist_actions';
-import { selectAllPlaylists } from '../../reducers/selectors';
-import MainContent from './main_content'
+import { selectAllUnauthoredPlaylists } from '../../reducers/selectors';
+import MainContent from './main_content';
+
+const mapStateToProps = (state, ownProps) => {
-const mapStateToProps = state => {
return {
- playlists: selectAllPlaylists(state),
- navpath: "browse"
+ playlists: selectAllUnauthoredPlaylists(state),
+ navpath: "browse",
+ path: ownProps.location.pathname
};
};
diff --git a/frontend/components/main/collection_container.js b/frontend/components/main/collection_container.js
index c25c1b7..13691e2 100644
--- a/frontend/components/main/collection_container.js
+++ b/frontend/components/main/collection_container.js
@@ -3,11 +3,11 @@ import React from 'react';
import { Link } from 'react-router-dom';
import { logout } from '../../actions/session_actions';
import { fetchPlaylists } from '../../actions/playlist_actions';
-import { selectAllPlaylists } from '../../reducers/selectors';
-import MainContent from './main_content'
+import { selectAllAuthoredPlaylists } from '../../reducers/selectors';
+import MainContent from './main_content';
const mapStateToProps = state => ({
- playlists: selectAllPlaylists(state),
+ playlists: selectAllAuthoredPlaylists(state),
navpath: "collection"
});
diff --git a/frontend/components/main/header.jsx b/frontend/components/main/header.jsx
new file mode 100644
index 0000000..c97192a
--- /dev/null
+++ b/frontend/components/main/header.jsx
@@ -0,0 +1,57 @@
+// import React from 'react';
+// import { NavLink, withRouter } from 'react-router-dom';
+// import { connect } from 'react-redux';
+// import { openModal } from '../../actions/modal_actions';
+//
+// const mapDispatchToProps = dispatch => ({
+// openModal: (modal) => dispatch(openModal(modal))
+// });
+//
+// class Header extends React.Component {
+//
+// constructor(props) {
+// super(props);
+// }
+//
+// render() {
+//
+// return (
+//
+// )
+// }
+//
+// }
+//
+// export default withRouter(connect(null, mapDispatchToProps)(Header));
diff --git a/frontend/components/main/main_content.jsx b/frontend/components/main/main_content.jsx
index 8793f4f..bf47793 100644
--- a/frontend/components/main/main_content.jsx
+++ b/frontend/components/main/main_content.jsx
@@ -3,14 +3,15 @@ import PlaylistIndexItem from './playlist_index_item';
// import PlaylistIndex from './playlist_index_item';
import { NavLink, Redirect } from 'react-router-dom';
import NavBar from './navbar';
+import Header from './header';
class MainContent extends React.Component {
constructor(props) {
super(props);
- this.state = {
- playlists: []
- };
+ // this.state = {
+ // headerpath: props.headerpath
+ // };
this.fetchPlaylists = props.fetchPlaylists.bind(this);
this.logout = props.logout.bind(this);
}
@@ -20,15 +21,29 @@ class MainContent extends React.Component {
}
render() {
- const {playlists} = this.props;
+ const {playlists, navpath, show} = this.props;
+
+ const index = (
+
+
+ {playlists.map(playlist => )}
+
+
+ );
+
+
+ let redirect = "";
+ if (this.props.path === '/browse' || this.props.path === '/browse/'){
+ redirect = ;
+ }
return (
-
- Image Goes Here:
- {playlists.map(playlist => )}
-
-
+
+
+ {show ? show : index}
+
+ {redirect}
);
}
@@ -36,4 +51,16 @@ class MainContent extends React.Component {
export default MainContent;
+//
+//
+// {songs.map(song => )}
+//
+//
+//
+//
+// {artists.map(song => )}
+//
+//
+
+//
//
diff --git a/frontend/components/main/playlist_index_item.jsx b/frontend/components/main/playlist_index_item.jsx
index 9e3ad16..0a4a208 100644
--- a/frontend/components/main/playlist_index_item.jsx
+++ b/frontend/components/main/playlist_index_item.jsx
@@ -1,12 +1,17 @@
import React from 'react';
- const PlaylistIndexItem = ({ playlist }) => (
-
-
+import { Link } from 'react-router-dom';
+
+ const PlaylistIndexItem = ({ playlist, navpath}) => (
+
+
+
+

+
+
+
{playlist.title}
+
{playlist.author}
+
+
);
export default PlaylistIndexItem;
-
-
-//
diff --git a/frontend/components/main/playlist_show_container.js b/frontend/components/main/playlist_show_container.js
new file mode 100644
index 0000000..89463c9
--- /dev/null
+++ b/frontend/components/main/playlist_show_container.js
@@ -0,0 +1,30 @@
+import React from 'react';
+import { fetchPlaylist } from '../../actions/playlist_actions';
+import { connect } from 'react-redux';
+import ShowBoxContent from './show_box_content';
+import { logout } from '../../actions/session_actions';
+import { selectPlaylistSongs } from '../../reducers/selectors';
+
+
+const mapStateToProps = (state, ownProps) => {
+ const playlist = state.entities.playlists[ownProps.match.params.playlistId] || { title: "", song_ids: [], photoUrl: "" };
+
+ const songs = selectPlaylistSongs(state, playlist);
+ return {
+ playlist,
+ playlistId: ownProps.match.params.playlistId,
+ songs
+ };
+};
+
+const mapDipatchToProps = (dispatch) => {
+ return {
+ fetchPlaylist: (id) => dispatch(fetchPlaylist(id)),
+ logout: () => dispatch(logout())
+ };
+};
+
+export default connect(
+ mapStateToProps,
+ mapDipatchToProps
+)(ShowBoxContent);
diff --git a/frontend/components/main/show_box_content.jsx b/frontend/components/main/show_box_content.jsx
new file mode 100644
index 0000000..1c496fb
--- /dev/null
+++ b/frontend/components/main/show_box_content.jsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import NavBar from './navbar';
+import { PulseLoader } from 'react-spinners';
+
+
+class ShowBoxContent extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { loading: true };
+ }
+
+ componentDidMount(){
+ this.props.fetchPlaylist(this.props.playlistId)
+ .then( () => setTimeout(() => this.setState({loading: false}), 100));
+ }
+
+ render () {
+ const {playlist, logout, songs} = this.props;
+
+ let tracks = '';
+ if(songs[0]){
+ tracks = songs.map( (song) => {
+ return (
+
+ );
+ });
+ }
+
+ if (this.state.loading) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
+
+

+
+
+
{playlist.title}
+
{playlist.author}
+
+
+
+ {tracks}
+
+
+
+ );
+ }
+}
+export default ShowBoxContent;
diff --git a/frontend/reducers/entities/entities_reducer.js b/frontend/reducers/entities/entities_reducer.js
index 87774f8..fa7cfc1 100644
--- a/frontend/reducers/entities/entities_reducer.js
+++ b/frontend/reducers/entities/entities_reducer.js
@@ -1,7 +1,9 @@
import { combineReducers } from 'redux';
import playlistsReducer from './playlists_reducer';
+import songsReducer from './songs_reducer';
export default combineReducers({
- playlists: playlistsReducer
+ playlists: playlistsReducer,
+ songs: songsReducer
});
diff --git a/frontend/reducers/entities/playlists_reducer.js b/frontend/reducers/entities/playlists_reducer.js
index d393fe5..e72653e 100644
--- a/frontend/reducers/entities/playlists_reducer.js
+++ b/frontend/reducers/entities/playlists_reducer.js
@@ -4,11 +4,12 @@ import merge from 'lodash/merge';
const playlistsReducer = (state = {}, action) => {
Object.freeze(state);
let newState;
+ let playlist;
switch(action.type){
case RECEIVE_ALL_PLAYLISTS:
- return action.playlists;
+ return merge({}, state, action.playlists );
case RECEIVE_SINGLE_PLAYLIST:
- return merge({}, state, {[action.playlist.id]: action.playlist});
+ return merge({}, state, {[action.playlist.id]: action.playlist} );
case DELETE_PLAYLIST:
newState = merge({}, state);
delete newState[action.playlistId];
diff --git a/frontend/reducers/entities/songs_reducer.js b/frontend/reducers/entities/songs_reducer.js
new file mode 100644
index 0000000..4cc7992
--- /dev/null
+++ b/frontend/reducers/entities/songs_reducer.js
@@ -0,0 +1,20 @@
+import { RECEIVE_ALL_SONGS } from '../../actions/song_actions';
+import { RECEIVE_SINGLE_PLAYLIST } from '../../actions/playlist_actions';
+import merge from 'lodash/merge';
+
+const songsReducer = (state = {}, action) => {
+
+ Object.freeze(state);
+ let songs;
+ switch(action.type){
+ case RECEIVE_ALL_SONGS:
+ return merge({}, state, action.songs );
+ case RECEIVE_SINGLE_PLAYLIST:
+ songs = action.songs;
+ return merge({}, state, songs);
+ default:
+ return state;
+ }
+};
+
+export default songsReducer;
diff --git a/frontend/reducers/selectors.js b/frontend/reducers/selectors.js
index cbf0544..2ff9efe 100644
--- a/frontend/reducers/selectors.js
+++ b/frontend/reducers/selectors.js
@@ -1,3 +1,34 @@
import values from 'lodash/values';
export const selectAllPlaylists = state => Object.values(state.entities.playlists);
+
+export const selectAllAuthoredPlaylists = state => {
+ let authoredPlaylists = [];
+ let playlists = state.entities.playlists;
+ Object.values(playlists).forEach((playlist) => {
+ debugger
+ if (playlist.author_id === state.session.currentUser.id){
+ authoredPlaylists.push(playlist);
+ }
+ });
+ return authoredPlaylists;
+};
+
+export const selectAllUnauthoredPlaylists = state => {
+ let unauthoredPlaylists = [];
+ let playlists = state.entities.playlists;
+ Object.values(playlists).forEach((playlist) => {
+ debugger
+ if (playlist.author_id != state.session.currentUser.id){
+ unauthoredPlaylists.push(playlist);
+ }
+ });
+ return unauthoredPlaylists;
+};
+
+export const selectPlaylistSongs = (state, playlist) => {
+
+ return playlist ? playlist.song_ids.map(id => state.entities.songs[id]) : [];
+};
+
+export const selectAllSongs = state => Object.values(state.entities.songs);
diff --git a/frontend/util/playlist_api_util.jsx b/frontend/util/playlist_api_util.jsx
index 781b893..d91bbf6 100644
--- a/frontend/util/playlist_api_util.jsx
+++ b/frontend/util/playlist_api_util.jsx
@@ -2,22 +2,22 @@ export const fetchPlaylists = () => {
return $.ajax({
method: 'GET',
url: '/api/playlists'
- })
+ });
};
export const fetchPlaylist = (id) => {
return $.ajax({
method: 'GET',
url: `/api/playlists/${id}`
- })
+ });
};
export const createPlaylist = (playlist) => {
return $.ajax({
method: 'POST',
url: `/api/playlists`,
- data: { playlist }
- })
+ data: { playlist }
+ });
};
export const updatePlaylist = (playlist) => {
@@ -25,12 +25,12 @@ export const updatePlaylist = (playlist) => {
method: 'PATCH',
url: `/api/playlists/${playlist.id}`,
data: { playlist }
- })
+ });
};
export const deletePlaylist = (id) => {
return $.ajax({
method: 'DELETE',
url: `/api/playlists/${id}`
- })
+ });
};
diff --git a/frontend/util/song_api_util.jsx b/frontend/util/song_api_util.jsx
new file mode 100644
index 0000000..3f134dc
--- /dev/null
+++ b/frontend/util/song_api_util.jsx
@@ -0,0 +1,13 @@
+export const fetchSongs = () => {
+ return $.ajax({
+ method: 'GET',
+ url: '/api/songs'
+ });
+};
+
+export const fetchSong = (id) => {
+ return $.ajax({
+ method: 'GET',
+ url: `/api/songs/${id}`
+ });
+};
diff --git a/package-lock.json b/package-lock.json
index 11fc52a..5fb63e2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -721,6 +721,70 @@
"to-fast-properties": "2.0.0"
}
},
+ "@emotion/babel-utils": {
+ "version": "0.6.10",
+ "resolved": "https://registry.npmjs.org/@emotion/babel-utils/-/babel-utils-0.6.10.tgz",
+ "integrity": "sha512-/fnkM/LTEp3jKe++T0KyTszVGWNKPNOUJfjNKLO17BzQ6QPxgbg3whayom1Qr2oLFH3V92tDymU+dT5q676uow==",
+ "requires": {
+ "@emotion/hash": "0.6.6",
+ "@emotion/memoize": "0.6.6",
+ "@emotion/serialize": "0.9.1",
+ "convert-source-map": "1.6.0",
+ "find-root": "1.1.0",
+ "source-map": "0.7.3"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
+ }
+ }
+ },
+ "@emotion/hash": {
+ "version": "0.6.6",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.6.6.tgz",
+ "integrity": "sha512-ojhgxzUHZ7am3D2jHkMzPpsBAiB005GF5YU4ea+8DNPybMk01JJUM9V9YRlF/GE95tcOm8DxQvWA2jq19bGalQ=="
+ },
+ "@emotion/is-prop-valid": {
+ "version": "0.6.8",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.6.8.tgz",
+ "integrity": "sha512-IMSL7ekYhmFlILXcouA6ket3vV7u9BqStlXzbKOF9HBtpUPMMlHU+bBxrLOa2NvleVwNIxeq/zL8LafLbeUXcA==",
+ "requires": {
+ "@emotion/memoize": "0.6.6"
+ }
+ },
+ "@emotion/memoize": {
+ "version": "0.6.6",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.6.tgz",
+ "integrity": "sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ=="
+ },
+ "@emotion/serialize": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.9.1.tgz",
+ "integrity": "sha512-zTuAFtyPvCctHBEL8KZ5lJuwBanGSutFEncqLn/m9T1a6a93smBStK+bZzcNPgj4QS8Rkw9VTwJGhRIUVO8zsQ==",
+ "requires": {
+ "@emotion/hash": "0.6.6",
+ "@emotion/memoize": "0.6.6",
+ "@emotion/unitless": "0.6.7",
+ "@emotion/utils": "0.8.2"
+ }
+ },
+ "@emotion/stylis": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.7.1.tgz",
+ "integrity": "sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ=="
+ },
+ "@emotion/unitless": {
+ "version": "0.6.7",
+ "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.6.7.tgz",
+ "integrity": "sha512-Arj1hncvEVqQ2p7Ega08uHLr1JuRYBuO5cIvcA+WWEQ5+VmkOE3ZXzl04NbQxeQpWX78G7u6MqxKuNX3wvYZxg=="
+ },
+ "@emotion/utils": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.8.2.tgz",
+ "integrity": "sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw=="
+ },
"@webassemblyjs/ast": {
"version": "1.7.11",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz",
@@ -885,6 +949,11 @@
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz",
"integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g=="
},
+ "abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
+ },
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
@@ -941,6 +1010,14 @@
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "requires": {
+ "sprintf-js": "1.0.3"
+ }
+ },
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@@ -961,6 +1038,11 @@
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
},
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
"asn1.js": {
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
@@ -1020,6 +1102,55 @@
"util.promisify": "1.0.0"
}
},
+ "babel-plugin-emotion": {
+ "version": "9.2.11",
+ "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz",
+ "integrity": "sha512-dgCImifnOPPSeXod2znAmgc64NhaaOjGEHROR/M+lmStb3841yK1sgaDYAYMnlvWNz8GnpwIPN0VmNpbWYZ+VQ==",
+ "requires": {
+ "@babel/helper-module-imports": "7.0.0",
+ "@emotion/babel-utils": "0.6.10",
+ "@emotion/hash": "0.6.6",
+ "@emotion/memoize": "0.6.6",
+ "@emotion/stylis": "0.7.1",
+ "babel-plugin-macros": "2.4.2",
+ "babel-plugin-syntax-jsx": "6.18.0",
+ "convert-source-map": "1.6.0",
+ "find-root": "1.1.0",
+ "mkdirp": "0.5.1",
+ "source-map": "0.5.7",
+ "touch": "2.0.2"
+ }
+ },
+ "babel-plugin-macros": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.4.2.tgz",
+ "integrity": "sha512-NBVpEWN4OQ/bHnu1fyDaAaTPAjnhXCEPqr1RwqxrU7b6tZ2hypp+zX4hlNfmVGfClD5c3Sl6Hfj5TJNF5VG5aA==",
+ "requires": {
+ "cosmiconfig": "5.0.7",
+ "resolve": "1.8.1"
+ }
+ },
+ "babel-plugin-syntax-jsx": {
+ "version": "6.18.0",
+ "resolved": "http://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
+ "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
+ },
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "2.5.7",
+ "regenerator-runtime": "0.11.1"
+ },
+ "dependencies": {
+ "regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+ }
+ }
+ },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -1284,6 +1415,27 @@
"unset-value": "1.0.0"
}
},
+ "caller-callsite": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
+ "requires": {
+ "callsites": "2.0.0"
+ }
+ },
+ "caller-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
+ "requires": {
+ "caller-callsite": "2.0.0"
+ }
+ },
+ "callsites": {
+ "version": "2.0.0",
+ "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
+ },
"camelcase": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
@@ -1304,6 +1456,11 @@
"supports-color": "5.5.0"
}
},
+ "change-emitter": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz",
+ "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU="
+ },
"chokidar": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
@@ -1474,11 +1631,27 @@
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
},
+ "core-js": {
+ "version": "2.5.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
+ "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
+ },
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
+ "cosmiconfig": {
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.0.7.tgz",
+ "integrity": "sha512-PcLqxTKiDmNT6pSpy4N6KtuPwb53W+2tzNvwOZw0WH9N6O0vLIBq0x8aj8Oj75ere4YcGi48bDFCL+3fRJdlNA==",
+ "requires": {
+ "import-fresh": "2.0.0",
+ "is-directory": "0.3.1",
+ "js-yaml": "3.12.0",
+ "parse-json": "4.0.0"
+ }
+ },
"create-ecdh": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
@@ -1488,6 +1661,28 @@
"elliptic": "6.4.1"
}
},
+ "create-emotion": {
+ "version": "9.2.12",
+ "resolved": "https://registry.npmjs.org/create-emotion/-/create-emotion-9.2.12.tgz",
+ "integrity": "sha512-P57uOF9NL2y98Xrbl2OuiDQUZ30GVmASsv5fbsjF4Hlraip2kyAvMm+2PoYUvFFw03Fhgtxk3RqZSm2/qHL9hA==",
+ "requires": {
+ "@emotion/hash": "0.6.6",
+ "@emotion/memoize": "0.6.6",
+ "@emotion/stylis": "0.7.1",
+ "@emotion/unitless": "0.6.7",
+ "csstype": "2.5.7",
+ "stylis": "3.5.4",
+ "stylis-rule-sheet": "0.0.10"
+ }
+ },
+ "create-emotion-styled": {
+ "version": "9.2.8",
+ "resolved": "https://registry.npmjs.org/create-emotion-styled/-/create-emotion-styled-9.2.8.tgz",
+ "integrity": "sha512-2LrNM5MREWzI5hZK+LyiBHglwE18WE3AEbBQgpHQ1+zmyLSm/dJsUZBeFAwuIMb+TjNZP0KsMZlV776ufOtFdg==",
+ "requires": {
+ "@emotion/is-prop-valid": "0.6.8"
+ }
+ },
"create-hash": {
"version": "1.2.0",
"resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
@@ -1543,6 +1738,11 @@
"randomfill": "1.0.4"
}
},
+ "csstype": {
+ "version": "2.5.7",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.5.7.tgz",
+ "integrity": "sha512-Nt5VDyOTIIV4/nRFswoCKps1R5CD1hkiyjBE9/thNaNZILLEviVw9yWQw15+O+CpNjQKB/uvdcxFFOrSflY3Yw=="
+ },
"cyclist": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
@@ -1683,6 +1883,23 @@
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
},
+ "emotion": {
+ "version": "9.2.12",
+ "resolved": "https://registry.npmjs.org/emotion/-/emotion-9.2.12.tgz",
+ "integrity": "sha512-hcx7jppaI8VoXxIWEhxpDW7I+B4kq9RNzQLmsrF6LY8BGKqe2N+gFAQr0EfuFucFlPs2A9HM4+xNj4NeqEWIOQ==",
+ "requires": {
+ "babel-plugin-emotion": "9.2.11",
+ "create-emotion": "9.2.12"
+ }
+ },
+ "encoding": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "requires": {
+ "iconv-lite": "0.4.24"
+ }
+ },
"end-of-stream": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
@@ -1709,6 +1926,14 @@
"prr": "1.0.1"
}
},
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "requires": {
+ "is-arrayish": "0.2.1"
+ }
+ },
"es-abstract": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz",
@@ -1745,6 +1970,11 @@
"estraverse": "4.2.0"
}
},
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ },
"esrecurse": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
@@ -1924,6 +2154,27 @@
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
+ "fbjs": {
+ "version": "0.8.17",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
+ "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.4.0",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.19"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ }
+ }
+ },
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
@@ -1955,6 +2206,11 @@
"pkg-dir": "2.0.0"
}
},
+ "find-root": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+ "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
+ },
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@@ -2715,6 +2971,14 @@
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
},
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": "2.1.2"
+ }
+ },
"ieee754": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz",
@@ -2725,6 +2989,15 @@
"resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
"integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
},
+ "import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+ "requires": {
+ "caller-path": "2.0.0",
+ "resolve-from": "3.0.0"
+ }
+ },
"import-local": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
@@ -2842,6 +3115,11 @@
}
}
},
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+ },
"is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
@@ -2900,6 +3178,11 @@
}
}
},
+ "is-directory": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
+ },
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
@@ -2990,6 +3273,15 @@
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
+ "isomorphic-fetch": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+ "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
+ "requires": {
+ "node-fetch": "1.7.3",
+ "whatwg-fetch": "3.0.0"
+ }
+ },
"js-levenshtein": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz",
@@ -3000,6 +3292,15 @@
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
+ "js-yaml": {
+ "version": "3.12.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
+ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
+ "requires": {
+ "argparse": "1.0.10",
+ "esprima": "4.0.1"
+ }
+ },
"jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
@@ -3295,6 +3596,15 @@
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
+ "node-fetch": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+ "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+ "requires": {
+ "encoding": "0.1.12",
+ "is-stream": "1.1.0"
+ }
+ },
"node-libs-browser": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz",
@@ -3340,6 +3650,14 @@
"semver": "5.6.0"
}
},
+ "nopt": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
+ "requires": {
+ "abbrev": "1.1.1"
+ }
+ },
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
@@ -3510,6 +3828,15 @@
"pbkdf2": "3.0.17"
}
},
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+ "requires": {
+ "error-ex": "1.3.2",
+ "json-parse-better-errors": "1.0.2"
+ }
+ },
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@@ -3598,6 +3925,14 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "requires": {
+ "asap": "2.0.6"
+ }
+ },
"promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@@ -3708,6 +4043,15 @@
"scheduler": "0.11.2"
}
},
+ "react-emotion": {
+ "version": "9.2.12",
+ "resolved": "https://registry.npmjs.org/react-emotion/-/react-emotion-9.2.12.tgz",
+ "integrity": "sha512-qt7XbxnEKX5sZ73rERJ92JMbEOoyOwG3BuCRFRkXrsJhEe+rFBRTljRw7yOLHZUCQC4GBObZhjXIduQ8S0ZpYw==",
+ "requires": {
+ "babel-plugin-emotion": "9.2.11",
+ "create-emotion-styled": "9.2.8"
+ }
+ },
"react-is": {
"version": "16.6.3",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.3.tgz",
@@ -3766,6 +4110,17 @@
"warning": "4.0.2"
}
},
+ "react-spinners": {
+ "version": "0.4.7",
+ "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.4.7.tgz",
+ "integrity": "sha512-+XPY9HkcNshu8+zZ5VomK+dWSkGTycEWH41OJnqItm7ooopLCXngJIh80OTBYZReLQ9gFwLjVsjfZz2sV+14Tg==",
+ "requires": {
+ "emotion": "9.2.12",
+ "prop-types": "15.6.2",
+ "react-emotion": "9.2.12",
+ "recompose": "0.27.1"
+ }
+ },
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
@@ -3797,6 +4152,26 @@
"readable-stream": "2.3.6"
}
},
+ "recompose": {
+ "version": "0.27.1",
+ "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.27.1.tgz",
+ "integrity": "sha512-p7xsyi/rfNjHfdP7vPU02uSFa+Q1eHhjKrvO+3+kRP4Ortj+MxEmpmd+UQtBGM2D2iNAjzNI5rCyBKp9Ob5McA==",
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "change-emitter": "0.1.6",
+ "fbjs": "0.8.17",
+ "hoist-non-react-statics": "2.5.5",
+ "react-lifecycles-compat": "3.0.4",
+ "symbol-observable": "1.2.0"
+ },
+ "dependencies": {
+ "hoist-non-react-statics": {
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
+ "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
+ }
+ }
+ },
"redux": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz",
@@ -3986,6 +4361,11 @@
"ret": "0.1.15"
}
},
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
"scheduler": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.11.2.tgz",
@@ -4217,6 +4597,11 @@
"extend-shallow": "3.0.2"
}
},
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
"ssri": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz",
@@ -4309,6 +4694,16 @@
"resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
"integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
},
+ "stylis": {
+ "version": "3.5.4",
+ "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz",
+ "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q=="
+ },
+ "stylis-rule-sheet": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz",
+ "integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw=="
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -4392,6 +4787,14 @@
"repeat-string": "1.6.1"
}
},
+ "touch": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-2.0.2.tgz",
+ "integrity": "sha512-qjNtvsFXTRq7IuMLweVgFxmEuQ6gLbRs2jQxL80TtZ31dEKWYIxRXquij6w6VimyDek5hD3PytljHmEtAs2u0A==",
+ "requires": {
+ "nopt": "1.0.10"
+ }
+ },
"trim-right": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
@@ -4412,6 +4815,11 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
+ "ua-parser-js": {
+ "version": "0.7.19",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz",
+ "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ=="
+ },
"uglify-es": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
@@ -4724,6 +5132,11 @@
}
}
},
+ "whatwg-fetch": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
+ "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q=="
+ },
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
diff --git a/package.json b/package.json
index 3864961..215abe3 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"react-dom": "^16.6.3",
"react-redux": "^5.1.1",
"react-router-dom": "^4.3.1",
+ "react-spinners": "^0.4.7",
"redux": "^4.0.1",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0",