-
Notifications
You must be signed in to change notification settings - Fork 108
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
57 changed files
with
2,397 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# See editorconfig.org | ||
|
||
root = true | ||
|
||
[*] | ||
end_of_line = lf | ||
charset = utf-8 | ||
trim_trailing_whitespace = true | ||
insert_final_newline = true | ||
|
||
[**.js] | ||
indent_style = space | ||
indent_size = 2 | ||
|
||
[**.json] | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
.next | ||
node_modules | ||
queue.json | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
web: npm run build && npm run start |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,25 @@ | ||
# c | ||
A collaborative listening room using Spotify | ||
# C - A collaborative listening room using Spotify | ||
|
||
This project is a site where multiple users can propose songs and vote for them, having them played in a synchronised way through Spotify. | ||
|
||
## Setting up | ||
|
||
The server can be run locally and also deployed to Heroku. You will need to register your own Spotify app and set the credentials in a couple of config files. For that: | ||
|
||
1. Create an application on [Spotify's Developer Site](https://developer.spotify.com/my-applications/). | ||
|
||
2. Add as redirect uris both http://localhost:3000/auth/callback (for development) and <production_domain>/auth/callback (if you want to deploy your app somewhere). | ||
|
||
3. Set your HOST in `config/app.js`. | ||
|
||
4. Set your CLIENT_ID and CLIENT_SECRET in `config/auth.js`. | ||
|
||
## Dependencies | ||
|
||
Install the dependencies running `npm install`. | ||
|
||
## Running | ||
|
||
During development, run `npm run dev`. | ||
|
||
When running on production, run `web: npm run build && npm run start`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import * as types from '../constants/ActionTypes'; | ||
|
||
export const fetchAvailableDevices = () => ({ | ||
type: types.FETCH_AVAILABLE_DEVICES | ||
}); | ||
export const fetchAvailableDevicesSuccess = list => ({ | ||
type: types.FETCH_AVAILABLE_DEVICES_SUCCESS, | ||
list | ||
}); | ||
export const fetchAvailableDevicesError = error => ({ | ||
type: types.FETCH_AVAILABLE_DEVICES_ERROR, | ||
error | ||
}); | ||
|
||
export const transferPlaybackToDevice = deviceId => ({ | ||
type: types.TRANSFER_PLAYBACK_TO_DEVICE, | ||
deviceId | ||
}); | ||
export const transferPlaybackToDeviceSuccess = list => ({ | ||
type: types.TRANSFER_PLAYBACK_TO_DEVICE_SUCCESS | ||
}); | ||
export const transferPlaybackToDeviceError = list => ({ | ||
type: types.TRANSFER_PLAYBACK_TO_DEVICE_ERROR, | ||
error | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import fetch from 'isomorphic-unfetch'; | ||
|
||
import Config from '../config/app'; | ||
import * as types from '../constants/ActionTypes'; | ||
|
||
// playback | ||
export const playTrack = (track, user, position) => ({ | ||
type: types.PLAY_TRACK, | ||
track, | ||
user, | ||
position | ||
}); | ||
export const playTrackSuccess = (track, user, position) => ({ | ||
type: types.PLAY_TRACK_SUCCESS, | ||
track, | ||
user, | ||
position | ||
}); | ||
|
||
export const mutePlayback = () => ({ type: types.MUTE_PLAYBACK }); | ||
export const unmutePlayback = () => ({ type: types.UNMUTE_PLAYBACK }); | ||
|
||
export const fetchPlayingContextSuccess = playingContext => ({ | ||
type: types.FETCH_PLAYING_CONTEXT_SUCCESS, | ||
playingContext | ||
}); | ||
|
||
export const fetchPlayingContext = () => dispatch => | ||
fetch(`${Config.HOST}/api/now-playing`) | ||
.then(res => res.json()) | ||
.then(res => dispatch(fetchPlayingContextSuccess(res))); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import fetch from 'isomorphic-unfetch'; | ||
|
||
import Config from '../config/app'; | ||
import * as types from '../constants/ActionTypes'; | ||
|
||
export const queueTrack = id => ({ type: types.QUEUE_TRACK, id }); | ||
export const updateQueue = queue => ({ type: types.UPDATE_QUEUE, data: queue }); | ||
export const queueEnded = () => ({ type: types.QUEUE_ENDED }); | ||
export const queueRemoveTrack = id => ({ | ||
type: types.QUEUE_REMOVE_TRACK, | ||
id | ||
}); | ||
|
||
export const fetchQueue = () => dispatch => | ||
fetch(`${Config.HOST}/api/queue`).then(res => res.json()).then(res => dispatch(updateQueue(res))); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import * as types from '../constants/ActionTypes'; | ||
|
||
export const searchTracks = query => ({ type: types.SEARCH_TRACKS, query }); | ||
export const searchTracksSuccess = (query, results) => ({ | ||
type: types.SEARCH_TRACKS_SUCCESS, | ||
query, | ||
results | ||
}); | ||
export const searchTracksReset = () => ({ type: types.SEARCH_TRACKS_RESET }); | ||
export const fetchTrack = id => ({ type: types.FETCH_TRACK, id }); | ||
export const fetchTrackSuccess = (id, track) => ({ | ||
type: types.FETCH_TRACK_SUCCESS, | ||
id | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import * as types from '../constants/ActionTypes'; | ||
|
||
export const load = () => ({ type: types.LOAD }); | ||
export const login = () => ({ type: types.LOGIN }); | ||
export const loginSuccess = () => ({ | ||
type: types.LOGIN_SUCCESS | ||
}); | ||
export const loginFailure = refresh_token => ({ | ||
type: types.LOGIN_FAILURE, | ||
refresh_token | ||
}); | ||
export const updateToken = refreshToken => ({ | ||
type: types.UPDATE_TOKEN, | ||
refreshToken | ||
}); | ||
export const updateTokenSuccess = access_token => ({ | ||
type: types.UPDATE_TOKEN_SUCCESS, | ||
access_token | ||
}); | ||
export const updateCurrentUser = user => ({ | ||
type: types.UPDATE_CURRENT_USER, | ||
user | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import fetch from 'isomorphic-unfetch'; | ||
|
||
import Config from '../config/app'; | ||
import * as types from '../constants/ActionTypes'; | ||
|
||
export const updateUsers = users => ({ type: types.UPDATE_USERS, data: users }); | ||
|
||
export const fetchUsers = () => dispatch => | ||
fetch(`${Config.HOST}/api/users`).then(res => res.json()).then(res => dispatch(updateUsers(res))); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import * as types from '../constants/ActionTypes'; | ||
|
||
export const voteUp = id => ({ | ||
type: types.VOTE_UP, | ||
id | ||
}); | ||
|
||
export const voteUpSuccess = () => ({ | ||
type: types.VOTE_UP_SUCCESS | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
import React, { Component } from 'react'; | ||
import { connect } from 'react-redux'; | ||
import { injectIntl } from 'react-intl'; | ||
|
||
import { searchTracks, searchTracksReset } from '../actions/searchActions'; | ||
import { queueTrack } from '../actions/queueActions'; | ||
|
||
class ResultsList extends Component { | ||
render() { | ||
const { results, focus } = this.props; | ||
return ( | ||
<ul className="add-to-queue__search-results"> | ||
<style jsx>{` | ||
.add-to-queue__search-results { | ||
border: 1px solid #999; | ||
list-style: none; | ||
margin: 0; | ||
padding: 0; | ||
} | ||
.add-to-queue__search-results-item { | ||
padding: 5px 0 5px 5px; | ||
} | ||
.add-to-queue__search-results-item--focused { | ||
background-color: #eee; | ||
} | ||
`}</style> | ||
{results.map((r, index) => { | ||
const isFocused = focus === index; | ||
const className = | ||
'add-to-queue__search-results-item' + (isFocused ? ' add-to-queue__search-results-item--focused' : ''); | ||
return ( | ||
<li key={r.id} className={className} onClick={() => this.props.onSelect(r.id)}> | ||
{r.name} - {r.artists[0].name} | ||
</li> | ||
); | ||
})} | ||
</ul> | ||
); | ||
} | ||
} | ||
|
||
class AddToQueue extends Component { | ||
state = { | ||
text: this.props.text || '', | ||
focus: -1 | ||
}; | ||
|
||
handleChange = e => { | ||
const text = e.target.value; | ||
this.setState({ text: text }); | ||
if (text !== '') { | ||
this.props.searchTracks(text); | ||
} else { | ||
this.setState({ focus: -1 }); | ||
this.props.searchTracksReset(); | ||
} | ||
}; | ||
|
||
handleSelectElement = id => { | ||
this.setState({ text: '' }); | ||
this.props.queueTrack(id); | ||
this.props.searchTracksReset(); | ||
}; | ||
|
||
handleBlur = e => { | ||
// todo: this happens before the item from the list is selected, hiding the | ||
// list of results. We need to do this in a different way. | ||
/* this.setState({ focus: -1 }); | ||
this.props.searchTracksReset(); */ | ||
}; | ||
|
||
handleFocus = e => { | ||
if (e.target.value !== '') { | ||
this.props.searchTracks(e.target.value); | ||
} | ||
}; | ||
|
||
handleKeyDown = e => { | ||
switch (e.keyCode) { | ||
case 38: // up | ||
this.setState({ focus: this.state.focus - 1 }); | ||
break; | ||
case 40: // down | ||
this.setState({ focus: this.state.focus + 1 }); | ||
break; | ||
case 13: { | ||
let correct = false; | ||
if (this.state.focus !== -1) { | ||
this.props.queueTrack(this.props.search.results[this.state.focus].id); | ||
correct = true; | ||
} else { | ||
const text = e.target.value.trim(); | ||
if (text.length !== 0) { | ||
this.props.queueTrack(text); | ||
correct = true; | ||
} | ||
} | ||
if (correct) { | ||
this.setState({ text: '' }); | ||
this.props.searchTracksReset(); | ||
this.setState({ focus: -1 }); | ||
} | ||
break; | ||
} | ||
} | ||
}; | ||
|
||
render() { | ||
const placeholder = this.props.intl.formatMessage({id: 'queue.add'}); | ||
const results = this.props.search.results; | ||
return ( | ||
<div className="add-to-queue" onBlur={this.handleBlur}> | ||
<style jsx>{` | ||
.add-to-queue__input { | ||
padding: 5px; | ||
width: 400px; | ||
} | ||
`}</style> | ||
<input | ||
className="add-to-queue__input" | ||
placeholder={placeholder} | ||
value={this.state.text} | ||
onChange={this.handleChange} | ||
onKeyDown={this.handleKeyDown} | ||
onFocus={this.handleFocus} | ||
/> | ||
{results && <ResultsList results={results} onSelect={this.handleSelectElement} focus={this.state.focus} />} | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
const mapDispatchToProps = dispatch => ({ | ||
queueTrack: text => dispatch(queueTrack(text)), | ||
searchTracks: query => dispatch(searchTracks(query)), | ||
searchTracksReset: () => dispatch(searchTracksReset()) | ||
}); | ||
|
||
const mapStateToProps = state => ({ | ||
search: state.search | ||
}); | ||
|
||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(AddToQueue)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export const ButtonStyle = `.btn { | ||
background-color: transparent; | ||
border: 1px solid #666; | ||
border-radius: 50px; | ||
color: #666; | ||
cursor: pointer; | ||
line-height: 28px; | ||
padding: 0 15px; | ||
}`; | ||
|
||
export const ButtonDarkStyle = `.btn--dark { | ||
background-color: #bbc8d5; | ||
border: 1px solid #bbc8d5; | ||
color: #333; | ||
}`; |
Oops, something went wrong.