diff --git a/package-lock.json b/package-lock.json
index fd7ce49..6173d45 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3297,12 +3297,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -3317,17 +3319,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -3444,7 +3449,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -3456,6 +3462,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -3470,6 +3477,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -3483,6 +3491,7 @@
"version": "2.3.5",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -3581,7 +3590,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -3593,6 +3603,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3714,6 +3725,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
diff --git a/server/api/comments.js b/server/api/comments.js
index c0b9c7c..fa31563 100755
--- a/server/api/comments.js
+++ b/server/api/comments.js
@@ -1,13 +1,13 @@
const router = require('express').Router()
-const { Vote, Comment } = require('../db/models')
-const Sequelize = require('sequelize')
+const { Comment } = require('../db/models')
+
module.exports = router
+
router.get('/', async (req, res, next) => {
try {
const comments = await Comment.findAll({
- attributes: ['id', 'secs', 'text'],
- })
+ attributes: ['id', 'secs', 'text']})
res.send(comments)
} catch (err) {
next(err)
@@ -17,8 +17,7 @@ router.get('/', async (req, res, next) => {
router.get('/:id', async (req, res, next) => {
try {
const comment = await Comment.findByPk(req.params.id, {
- attributes: ['id', 'secs', 'text'],
- })
+ attributes: ['id', 'secs', 'text']})
res.json(comment)
} catch (err) {
next(err)
diff --git a/server/api/index.js b/server/api/index.js
index 9bfc4ce..3e01f11 100755
--- a/server/api/index.js
+++ b/server/api/index.js
@@ -2,7 +2,9 @@ const router = require('express').Router()
module.exports = router
const ascii = require('../ascii')
+router.use('/users', require('./users'))
router.use('/comments', require('./comments'))
+router.use('/votes', require('./votes'))
router.get('/', async (req, res, next) => {
try {
diff --git a/server/api/users.js b/server/api/users.js
new file mode 100644
index 0000000..3c9fcd1
--- /dev/null
+++ b/server/api/users.js
@@ -0,0 +1,38 @@
+const router = require('express').Router()
+const { User, Vote } = require('../db/models')
+module.exports = router
+
+router.get('/', async (req, res, next) => {
+ try {
+ const users = await User.findAll({
+ attributes: ['id', 'name']
+ })
+ res.send(users)
+ } catch (err) {
+ next(err)
+ }
+})
+
+router.get('/:id', async (req, res, next) => {
+ try {
+ const user = await User.findByPk(req.params.id,
+ {attributes: ['id', 'name'],
+ include: {model: Vote,
+ attributes: ['id', 'userId','commentId', 'upvote', 'downvote']}})
+ res.json(user)
+ } catch (err) {
+ next(err)
+ }
+})
+
+router.get('/:id/votes', async (req, res, next) => {
+ try {
+ const user = await User.findByPk(req.params.id,
+ {attributes: ['id', 'name'],
+ include: {model: Vote,
+ attributes: ['id', 'userId','commentId', 'upvote', 'downvote']}})
+ res.json(user.votes)
+ } catch (err) {
+ next(err)
+ }
+})
diff --git a/server/api/votes.js b/server/api/votes.js
new file mode 100644
index 0000000..0768c0f
--- /dev/null
+++ b/server/api/votes.js
@@ -0,0 +1,53 @@
+const router = require('express').Router()
+const { Vote } = require('../db/models')
+module.exports = router
+
+router.get('/', async (req, res, next) => {
+ try {
+ const votes = await Vote.findAll()
+ res.send(votes)
+ } catch (err) {
+ next(err)
+ }
+})
+
+router.post('/', async (req, res, next) => {
+ const {userId, commentId, upvote, downvote} = req.body
+ try {
+ const votes = await Vote.create({userId, commentId, upvote, downvote})
+ res.send(votes)
+ } catch (err) {
+ next(err)
+ }
+})
+
+router.get('/:id', async (req, res, next) => {
+ try {
+ const vote = await Vote.findByPk(+req.params.id)
+ res.json(vote)
+ } catch (err) {
+ next(err)
+ }
+})
+
+router.post('/:id/delete', async (req, res, next) => {
+ try {
+ const vote = await Vote.findByPk(+req.params.id)
+ await vote.destroy()
+ res.json(vote)
+ } catch (err) {
+ next(err)
+ }
+})
+
+router.put('/:id/update', async (req, res, next) => {
+ const upvote = req.body.downvote
+ const downvote = req.body.upvote
+ try {
+ const vote = await Vote.findByPk(+req.params.id)
+ await vote.update({upvote, downvote})
+ res.json(vote)
+ } catch (err) {
+ next(err)
+ }
+})
diff --git a/server/db/models/index.js b/server/db/models/index.js
index 23ac366..2b06bbb 100755
--- a/server/db/models/index.js
+++ b/server/db/models/index.js
@@ -1,3 +1,13 @@
const Comment = require('./comment')
+const Vote = require('./vote')
+const User = require('./user')
-module.exports = { Comment }
+Vote.belongsTo(Comment)
+Comment.hasMany(Vote)
+
+Vote.belongsTo(User)
+User.hasMany(Vote)
+
+Comment.belongsTo(User)
+User.hasMany(Comment)
+module.exports = { Comment, Vote, User }
diff --git a/server/db/models/user.js b/server/db/models/user.js
new file mode 100644
index 0000000..21cefe6
--- /dev/null
+++ b/server/db/models/user.js
@@ -0,0 +1,9 @@
+const Sequelize = require('sequelize')
+const db = require('../db')
+
+const User = db.define('users', {
+ name: Sequelize.STRING,
+
+})
+
+module.exports = User
diff --git a/server/db/models/vote.js b/server/db/models/vote.js
new file mode 100644
index 0000000..820b8e9
--- /dev/null
+++ b/server/db/models/vote.js
@@ -0,0 +1,9 @@
+const Sequelize = require('sequelize')
+const db = require('../db')
+
+const Vote = db.define('votes', {
+ upvote: Sequelize.INTEGER,
+ downvote: Sequelize.INTEGER,
+})
+
+module.exports = Vote
diff --git a/src/components/waveform/CommentList.js b/src/components/waveform/CommentList.js
index 8f87cca..de51eca 100644
--- a/src/components/waveform/CommentList.js
+++ b/src/components/waveform/CommentList.js
@@ -4,15 +4,22 @@ import { connect } from 'react-redux'
import { ListGroup } from 'react-bootstrap'
const CommentList = props => {
+
return (
{props.comments.map(comment => (
-
+ vote.commentId===comment.id && vote.userId===props.user.id)}
+ updateSongPos={props.updateSongPos}
+ comment={comment}
+ />
))}
)
}
-const mapState = state => ({ ...state })
+const mapState = state => ({...state})
export default connect(mapState)(CommentList)
diff --git a/src/components/waveform/CommentRow.js b/src/components/waveform/CommentRow.js
index d92881b..afbbf49 100644
--- a/src/components/waveform/CommentRow.js
+++ b/src/components/waveform/CommentRow.js
@@ -1,5 +1,6 @@
import React from 'react'
import { Row, Col, Media } from 'react-bootstrap'
+import CommentVotes from './CommentVotes'
const parseTime = secs => {
var hours = Math.floor(secs / 3600)
@@ -18,6 +19,22 @@ const parseTime = secs => {
return minutes + ':' + seconds
}
+// const toggleVote = (vote) => {
+// const userVote = this.props.user.votes.find(vote=>vote.commentId===this.props.id)
+// userVote.upvote = vote === 'up' ? (userVote.upvote === 1 ? 0 : 1) : 0
+// userVote.downvote = vote === 'down' ? (userVote.downvote === 1 ? 0 : 1) : 0
+// const sendThisToBackend = {
+// userId: this.props.user.id,
+// commentId: this.props.id,
+// userUpvote: userVote.upvote,
+// userDownvote: userVote.downvote,
+// prevUpvote: userVote.upvote,
+// prevDownvote: userVote.downvote
+// }
+//
+// this.props.saveVote(sendThisToBackend)
+// }
+
const CommentRow = props => {
console.log(props)
@@ -32,6 +49,11 @@ const CommentRow = props => {
{parseTime(props.comment.secs)}
+
{props.comment.text}
@@ -40,4 +62,16 @@ const CommentRow = props => {
)
}
+
+// const mapState = state => {
+// return {
+// user: state.user
+// }
+// }
+// const mapDispatch = dispatch => {
+// return {
+// saveVote: vote => dispatch(addVote(vote))
+// }
+// }
+//export default connect(mapState)(CommentRow)
export default CommentRow
diff --git a/src/components/waveform/CommentRowClass.js b/src/components/waveform/CommentRowClass.js
deleted file mode 100644
index b22ab5d..0000000
--- a/src/components/waveform/CommentRowClass.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react'
-import { Row, Col, Media } from 'react-bootstrap'
-import { connect } from 'react-redux'
-import { addVote } from '../../store'
-const parseTime = secs => {
- var hours = Math.floor(secs / 3600)
- var minutes = Math.floor((secs - hours * 3600) / 60)
- var seconds = secs - hours * 3600 - minutes * 60
-
- if (hours < 10) {
- hours = '0' + hours
- }
- if (minutes < 10) {
- minutes = '0' + minutes
- }
- if (seconds < 10) {
- seconds = '0' + seconds
- }
- return minutes + ':' + seconds
-}
-
-class CommentRow extends React.Component {
- constructor() {
- super()
- }
-
- render() {
- return (
-
-
-
-
-
- Anon at{' '}
- this.props.updateSongPos(this.props.secs)}>
- {parseTime(this.props.secs)}
-
-
-
-
- {this.props.text}
-
-
-
- )
- }
-}
-
-const mapState = state => ({ user: { id: 1 }, ...state })
-// const mapDispatch = dispatch => {
-// return {
-// saveVote: vote => dispatch(addVote(vote)),
-// }
-// }
-export default connect(
- mapState,
- mapDispatch,
-)(CommentRow)
diff --git a/src/components/waveform/CommentVotes.js b/src/components/waveform/CommentVotes.js
new file mode 100644
index 0000000..8bf8cc8
--- /dev/null
+++ b/src/components/waveform/CommentVotes.js
@@ -0,0 +1,68 @@
+import React from 'react'
+import { Row, Col } from 'react-bootstrap'
+import { connect } from 'react-redux'
+import { destroyVote, updateVote, addUpvote, addDownvote } from '../../store'
+
+const CommentVotes = props => {
+ const {commentId, userId, userVote} = props
+
+ const upvote = () => {
+ console.log('userVote',userVote)
+ userVote
+ ? userVote.upvote===1
+ ? props.deleteVote(userVote.id)
+ : props.editVote(userVote)
+ : props.upvote(userId, commentId)
+ }
+
+ const downvote = () => {
+ userVote
+ ? userVote.downvote===1
+ ? props.deleteVote(userVote.id)
+ : props.editVote(userVote)
+ : props.downvote(userId, commentId)
+ }
+
+ return (
+
+
+
+
+ ⏶
+
+
+
+
+
+
+ ⏷
+
+
+
+
+ )
+}
+
+const mapDispatch = dispatch => {
+ return {
+ deleteVote: userVote => dispatch(destroyVote(userVote)),
+ editVote: userVote => dispatch(updateVote(userVote)),
+ upvote: (userId, commentId) => dispatch(addUpvote(userId, commentId)),
+ downvote: (userId, commentId) => dispatch(addDownvote(userId, commentId)),
+ }
+}
+export default connect(null, mapDispatch)(CommentVotes)
diff --git a/src/components/waveform/index.js b/src/components/waveform/index.js
index b3aafd9..0968bbe 100644
--- a/src/components/waveform/index.js
+++ b/src/components/waveform/index.js
@@ -2,11 +2,10 @@ import React, { Component } from 'react'
import Waveform from 'react-audio-waveform'
import { connect } from 'react-redux'
import ReactAudioPlayer from 'react-audio-player'
-import CommentPopup from './CommentPopup'
import Comment from './Comment'
import CommentList from './CommentList'
-import { fetchAllComments, addComment } from '../../store'
-import { Media, Form, Button, Container, Row, Col } from 'react-bootstrap'
+import { getUser, fetchAllComments, addComment, getAllVotes } from '../../store'
+import { Media, Form, Container, Row, Col } from 'react-bootstrap'
const config = require('./audio/loneDigger.json')
const parseTime = secs => {
@@ -48,7 +47,9 @@ class Player extends Component {
}
async fetchData() {
+ await this.props.fetchUser()
await this.props.fetchComments()
+ await this.props.fetchAllVotes()
await this.setState({ loading: false })
}
@@ -81,7 +82,6 @@ class Player extends Component {
updateSongPos(secs) {
this.setState({ songPos: secs })
this.rap.audioEl.currentTime = secs
- this.rap.audioEl.play()
}
render() {
@@ -158,6 +158,8 @@ const mapState = state => ({ ...state })
const mapDispatch = dispatch => {
return {
fetchComments: () => dispatch(fetchAllComments()),
+ fetchUser: () => dispatch(getUser()),
+ fetchAllVotes: userId => dispatch(getAllVotes(userId)),
postComment: comment => dispatch(addComment(comment)),
}
}
diff --git a/src/store/index.js b/src/store/index.js
index f176446..81ffb74 100644
--- a/src/store/index.js
+++ b/src/store/index.js
@@ -5,8 +5,11 @@ import { composeWithDevTools } from 'redux-devtools-extension'
import episodes from './reducers/episodes'
import captions from './reducers/captions'
import comments from './reducers/comments'
+import user from './reducers/users'
+import votes from './reducers/votes'
-const reducer = combineReducers({ episodes, captions, comments })
+
+const reducer = combineReducers({episodes, captions, comments, user, votes})
const middleware = composeWithDevTools(
applyMiddleware(thunkMiddleware, createLogger({ collapsed: true })),
)
@@ -16,3 +19,5 @@ export default store
export * from './reducers/episodes'
export * from './reducers/captions'
export * from './reducers/comments'
+export * from './reducers/users'
+export * from './reducers/votes'
diff --git a/src/store/reducers/comments.js b/src/store/reducers/comments.js
index 357b09d..8b16999 100644
--- a/src/store/reducers/comments.js
+++ b/src/store/reducers/comments.js
@@ -1,8 +1,11 @@
import axios from 'axios'
+import {addedVote} from './votes'
// ACTION TYPES
const GOT_ALL_COMMENTS = 'GOT_ALL_COMMENTS'
const ADD_COMMENT = 'ADD_COMMENT'
+const UPVOTED_COMMENT = 'UPVOTED_COMMENT'
+const DOWNVOTED_COMMENT = 'DOWNVOTED_COMMENT'
const initialComments = []
// ACTION CREATORS
@@ -16,6 +19,15 @@ export const addedComment = comment => ({
comment,
})
+export const upvotedComment = comment => ({
+ type: UPVOTED_COMMENT,
+ comment,
+})
+
+export const downvotedComment = comment => ({
+ type: DOWNVOTED_COMMENT,
+ comment,
+})
// THUNK CREATORS
export const fetchAllComments = () => async dispatch => {
try {
@@ -36,6 +48,28 @@ export const addComment = comment => async dispatch => {
}
}
+export const upvoteComment = (userId, commentId) => async dispatch => {
+ console.log('REDUCER UPVOTECOMMENT', userId, commentId)
+ try {
+ const {data} = await axios.post(`/api/comments/${commentId}/upvote`, {userId})
+ console.log('the votesum should have changed', data)
+ dispatch(upvotedComment(data.comment))
+ dispatch(addedVote(data.vote))
+ } catch (err) {
+ console.error(err)
+ }
+}
+
+export const downvoteComment = (userId, commentId) => async dispatch => {
+ try {
+ const {data} = await axios.post(`/api/comments/${commentId}/downvote`, {userId})
+ console.log('the votesum should have changed', data)
+ dispatch(downvotedComment(data.comment))
+ dispatch(addedVote(data.vote))
+ } catch (err) {
+ console.error(err)
+ }
+}
// export const addVote = vote => async dispatch => {
//
// try {
@@ -53,6 +87,10 @@ const commentReducer = (comments = initialComments, action) => {
return action.comments
case ADD_COMMENT:
return comments.concat(action.comment)
+ case UPVOTED_COMMENT: {
+ const oldComments = comments.filter(comment=>comment.id !== action.comment.id)
+ return oldComments.concat(action.comment)
+ }
default:
return comments
}
diff --git a/src/store/reducers/users.js b/src/store/reducers/users.js
new file mode 100644
index 0000000..1409c5c
--- /dev/null
+++ b/src/store/reducers/users.js
@@ -0,0 +1,34 @@
+import axios from 'axios'
+
+const initialUser = {}
+
+// ACTION TYPES
+const GOT_USER = 'GOT_USER'
+
+export const gotUser = user => ({
+ type: GOT_USER,
+ user,
+})
+
+export const getUser = () => async dispatch => {
+ try {
+ const {data} = await axios.get(`/api/users/${1}`)
+ const user = {id: data.id, name: data.name}
+ dispatch(gotUser(user))
+ } catch (err) {
+ console.error(err)
+ }
+}
+
+
+// REDUCER
+const userReducer = (user = initialUser, action) => {
+ switch (action.type) {
+ case GOT_USER:
+ return action.user
+ default:
+ return user
+ }
+}
+
+export default userReducer
diff --git a/src/store/reducers/votes.js b/src/store/reducers/votes.js
new file mode 100644
index 0000000..30e5b17
--- /dev/null
+++ b/src/store/reducers/votes.js
@@ -0,0 +1,102 @@
+import axios from 'axios'
+
+const initialUserVotes = []
+
+// ACTION TYPES
+const GOT_ALL_VOTES = 'GOT_ALL_VOTES'
+const DELETED_VOTE = 'DELETED_VOTE'
+const UPVOTED = 'UPVOTED'
+const DOWNVOTED = 'DOWNVOTED'
+const UPDATED_VOTE = 'UPDATED_VOTE'
+
+export const gotAllVotes = votes => ({
+ type: GOT_ALL_VOTES,
+ votes
+})
+
+export const deletedVote = oldVote => ({
+ type: DELETED_VOTE,
+ oldVote
+})
+
+export const upvoted = newVote => ({
+ type: UPVOTED,
+ newVote
+})
+export const downvoted = newVote => ({
+ type: DOWNVOTED,
+ newVote
+})
+export const updatedVote = newVote => ({
+ type: UPDATED_VOTE,
+ newVote
+})
+
+export const addUpvote = (userId, commentId) => async dispatch => {
+ try {
+ const {data} = await axios.post('/api/votes', {upvote: 1, downvote: 0, userId, commentId})
+ dispatch(upvoted(data))
+ } catch(e) {
+ console.log(e)
+ }
+}
+
+export const addDownvote = (userId, commentId) => async dispatch => {
+ try {
+ const {data} = await axios.post('/api/votes', {upvote: 0, downvote: 1, userId, commentId})
+ dispatch(downvoted(data))
+ } catch(e) {
+ console.log(e)
+ }
+}
+export const destroyVote = id => async dispatch => {
+ try {
+ const {data} = await axios.post(`/api/votes/${id}/delete`)
+ dispatch(deletedVote(data))
+ } catch(e) {
+ console.log(e)
+ }
+}
+
+export const updateVote = userVote => async dispatch => {
+ try {
+ const {data} = await axios.put(`/api/votes/${userVote.id}/update`, userVote)
+ dispatch(updatedVote(data))
+ } catch(e) {
+ console.log(e)
+ }
+}
+
+export const getAllVotes = () => async dispatch => {
+ try {
+ const {data} = await axios.get('/api/votes')
+ dispatch(gotAllVotes(data))
+ } catch(e) {
+ console.log(e)
+ }
+}
+// REDUCER
+const voteReducer = (votes = initialUserVotes, action) => {
+ switch (action.type) {
+ case GOT_ALL_VOTES:
+ return action.votes
+ case DELETED_VOTE: {
+ const newVotes = votes.filter(vote => vote.id !== action.oldVote.id)
+ return newVotes
+ }
+ case UPDATED_VOTE: {
+ const newVotes = votes.filter(vote => vote.id !== action.newVote.id)
+ return newVotes.concat(action.newVote)
+ }
+ case UPVOTED: {
+ return votes.concat(action.newVote)
+ }
+ case DOWNVOTED: {
+ return votes.concat(action.newVote)
+ }
+ default:
+ return votes
+ }
+}
+
+export default voteReducer