Compare commits
2 Commits
77eeea605f
...
e00aa1717f
Author | SHA1 | Date | |
---|---|---|---|
e00aa1717f | |||
72ebae6067 |
709
package-lock.json
generated
709
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,12 +18,15 @@
|
||||
"@babel/preset-env": "^7.4.2",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"babel-loader": "^8.0.5",
|
||||
"eslint-plugin-react": "^7.12.4",
|
||||
"webpack": "^4.29.6",
|
||||
"webpack-cli": "^3.3.0",
|
||||
"webpack-dev-server": "^3.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"eslint": "^5.16.0",
|
||||
"history": "^4.9.0",
|
||||
"http-proxy-middleware": "^0.19.1",
|
||||
"morgan": "^1.9.1",
|
||||
@ -40,4 +43,4 @@
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-thunk": "^2.3.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
const router = require('express').Router()
|
||||
const { Comment } = require('../db/models')
|
||||
|
||||
module.exports = router
|
||||
|
||||
|
||||
router.get('/', async (req, res, next) => {
|
||||
try {
|
||||
const comments = await Comment.findAll()
|
||||
res.status(201).send(comments)
|
||||
const comments = await Comment.findAll({
|
||||
attributes: ['id', 'secs', 'text']})
|
||||
res.send(comments)
|
||||
} catch (err) {
|
||||
next(err)
|
||||
}
|
||||
@ -13,7 +16,8 @@ router.get('/', async (req, res, next) => {
|
||||
|
||||
router.get('/:id', async (req, res, next) => {
|
||||
try {
|
||||
const comment = await Comment.findByPk(req.params.id)
|
||||
const comment = await Comment.findByPk(req.params.id, {
|
||||
attributes: ['id', 'secs', 'text']})
|
||||
res.json(comment)
|
||||
} catch (err) {
|
||||
next(err)
|
||||
|
@ -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 {
|
||||
|
38
server/api/users.js
Normal file
38
server/api/users.js
Normal file
@ -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)
|
||||
}
|
||||
})
|
53
server/api/votes.js
Normal file
53
server/api/votes.js
Normal file
@ -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)
|
||||
}
|
||||
})
|
@ -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 }
|
||||
|
9
server/db/models/user.js
Normal file
9
server/db/models/user.js
Normal file
@ -0,0 +1,9 @@
|
||||
const Sequelize = require('sequelize')
|
||||
const db = require('../db')
|
||||
|
||||
const User = db.define('users', {
|
||||
name: Sequelize.STRING,
|
||||
|
||||
})
|
||||
|
||||
module.exports = User
|
9
server/db/models/vote.js
Normal file
9
server/db/models/vote.js
Normal file
@ -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
|
@ -1,17 +1,58 @@
|
||||
const db = require('../db')
|
||||
const { Comment } = require('./models')
|
||||
const { Vote, Comment, User } = require('./models')
|
||||
|
||||
const comment = {
|
||||
const testComment = {
|
||||
secs: 82,
|
||||
text: 'this is a great song!',
|
||||
}
|
||||
|
||||
const tsvote = {
|
||||
upvote: 1,
|
||||
downvote: 0,
|
||||
userId: 1
|
||||
}
|
||||
|
||||
const downvote = {
|
||||
upvote: 0,
|
||||
downvote: 1,
|
||||
userId: 3
|
||||
}
|
||||
|
||||
const upvote = {
|
||||
upvote: 0,
|
||||
downvote: 1,
|
||||
userId: 4
|
||||
}
|
||||
const nnvote = {
|
||||
upvote: 1,
|
||||
downvote: 0,
|
||||
userId: 2
|
||||
}
|
||||
const testUser = {
|
||||
name: 'tsr'
|
||||
}
|
||||
|
||||
const testUser2 = {
|
||||
name: 'notnull'
|
||||
}
|
||||
|
||||
const testUser3 = {
|
||||
name: 'anon'
|
||||
}
|
||||
|
||||
const testUser4 = {
|
||||
name: 'm'
|
||||
}
|
||||
async function runSeed() {
|
||||
await db.sync({ force: true })
|
||||
console.log('db synced!')
|
||||
console.log('seeding...')
|
||||
try {
|
||||
await Comment.create(comment)
|
||||
await User.bulkCreate([testUser, testUser2, testUser3, testUser4])
|
||||
await Vote.bulkCreate([upvote, downvote, tsvote, nnvote])
|
||||
const comment = await Comment.create(testComment)
|
||||
await comment.setUser(2)
|
||||
await comment.addVotes([1,2,3,4])
|
||||
console.log('seeded successfully')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
218
server/package-lock.json
generated
218
server/package-lock.json
generated
@ -4,6 +4,113 @@
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
|
||||
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
|
||||
"requires": {
|
||||
"@babel/highlight": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.0.tgz",
|
||||
"integrity": "sha512-/v5I+a1jhGSKLgZDcmAUZ4K/VePi43eRkUs3yePW1HB1iANOD5tqJXwGSG4BZhSksP8J9ejSlwGeTiiOFZOrXQ==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.4.0",
|
||||
"jsesc": "^2.5.1",
|
||||
"lodash": "^4.17.11",
|
||||
"source-map": "^0.5.0",
|
||||
"trim-right": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"@babel/helper-function-name": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
|
||||
"integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
|
||||
"requires": {
|
||||
"@babel/helper-get-function-arity": "^7.0.0",
|
||||
"@babel/template": "^7.1.0",
|
||||
"@babel/types": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-get-function-arity": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
|
||||
"integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/helper-split-export-declaration": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz",
|
||||
"integrity": "sha512-7Cuc6JZiYShaZnybDmfwhY4UYHzI6rlqhWjaIqbsJGsIqPimEYy5uh3akSRLMg65LSdSEnJ8a8/bWQN6u2oMGw==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.4.0"
|
||||
}
|
||||
},
|
||||
"@babel/highlight": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
|
||||
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
|
||||
"requires": {
|
||||
"chalk": "^2.0.0",
|
||||
"esutils": "^2.0.2",
|
||||
"js-tokens": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.3.tgz",
|
||||
"integrity": "sha512-gxpEUhTS1sGA63EGQGuA+WESPR/6tz6ng7tSHFCmaTJK/cGK8y37cBTspX+U2xCAue2IQVvF6Z0oigmjwD8YGQ=="
|
||||
},
|
||||
"@babel/template": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.0.tgz",
|
||||
"integrity": "sha512-SOWwxxClTTh5NdbbYZ0BmaBVzxzTh2tO/TeLTbF6MO6EzVhHTnff8CdBXx3mEtazFBoysmEM6GU/wF+SuSx4Fw==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"@babel/parser": "^7.4.0",
|
||||
"@babel/types": "^7.4.0"
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.3.tgz",
|
||||
"integrity": "sha512-HmA01qrtaCwwJWpSKpA948cBvU5BrmviAief/b3AVw936DtcdsTexlbyzNuDnthwhOQ37xshn7hvQaEQk7ISYQ==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"@babel/generator": "^7.4.0",
|
||||
"@babel/helper-function-name": "^7.1.0",
|
||||
"@babel/helper-split-export-declaration": "^7.4.0",
|
||||
"@babel/parser": "^7.4.3",
|
||||
"@babel/types": "^7.4.0",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0",
|
||||
"lodash": "^4.17.11"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.0.tgz",
|
||||
"integrity": "sha512-aPvkXyU2SPOnztlgo8n9cEiXW755mgyvueUPcpStqdzoSPm0fjO0vQBjLkt3JKJW7ufikfcnMTTPsN1xaTsBPA==",
|
||||
"requires": {
|
||||
"esutils": "^2.0.2",
|
||||
"lodash": "^4.17.11",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@types/geojson": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-1.0.6.tgz",
|
||||
@ -107,6 +214,19 @@
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"babel-eslint": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz",
|
||||
"integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"@babel/parser": "^7.0.0",
|
||||
"@babel/traverse": "^7.0.0",
|
||||
"@babel/types": "^7.0.0",
|
||||
"eslint-scope": "3.7.1",
|
||||
"eslint-visitor-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
@ -655,6 +775,38 @@
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
|
||||
"integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||
"integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ=="
|
||||
},
|
||||
"esrecurse": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
|
||||
"integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
|
||||
"requires": {
|
||||
"estraverse": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
|
||||
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
|
||||
},
|
||||
"esutils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
@ -975,8 +1127,7 @@
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
@ -994,13 +1145,11 @@
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
@ -1013,18 +1162,15 @@
|
||||
},
|
||||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
@ -1127,8 +1273,7 @@
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
@ -1138,7 +1283,6 @@
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
@ -1151,20 +1295,17 @@
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "2.3.5",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.1.2",
|
||||
"yallist": "^3.0.0"
|
||||
@ -1181,7 +1322,6 @@
|
||||
"mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
@ -1254,8 +1394,7 @@
|
||||
},
|
||||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
@ -1265,7 +1404,6 @@
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
@ -1341,8 +1479,7 @@
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
@ -1372,7 +1509,6 @@
|
||||
"string-width": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
@ -1390,7 +1526,6 @@
|
||||
"strip-ansi": {
|
||||
"version": "3.0.1",
|
||||
"bundled": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
@ -1429,13 +1564,11 @@
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "3.0.3",
|
||||
"bundled": true,
|
||||
"optional": true
|
||||
"bundled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1489,6 +1622,11 @@
|
||||
"ini": "^1.3.4"
|
||||
}
|
||||
},
|
||||
"globals": {
|
||||
"version": "11.11.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz",
|
||||
"integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw=="
|
||||
},
|
||||
"got": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
|
||||
@ -1841,6 +1979,16 @@
|
||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
|
||||
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"jsesc": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
|
||||
"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
@ -3111,6 +3259,11 @@
|
||||
"resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
|
||||
"integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
|
||||
},
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
|
||||
},
|
||||
"to-object-path": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
|
||||
@ -3167,6 +3320,11 @@
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz",
|
||||
"integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q=="
|
||||
},
|
||||
"trim-right": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
|
||||
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||
|
@ -5,6 +5,7 @@
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"babel-eslint": "^10.0.1",
|
||||
"concurrently": "^4.0.1",
|
||||
"express": "^4.16.4",
|
||||
"http-proxy-middleware": "^0.19.0",
|
||||
|
@ -19,7 +19,7 @@ class Comment extends React.Component {
|
||||
<div
|
||||
className="comment_icon"
|
||||
ref={this.attachRef}
|
||||
style={{ position: 'absolute', top: 180, left: this.props.commentLoc - 1 + '%' }}
|
||||
style={{ position: 'absolute', top: 80, left: this.props.commentLoc - 1 + '%' }}
|
||||
onMouseEnter={this.toggleShow}
|
||||
onMouseLeave={this.toggleShow}
|
||||
>
|
||||
|
25
src/components/waveform/CommentList.js
Normal file
25
src/components/waveform/CommentList.js
Normal file
@ -0,0 +1,25 @@
|
||||
import React from 'react'
|
||||
import CommentRow from './CommentRow'
|
||||
import { connect } from 'react-redux'
|
||||
import { ListGroup } from 'react-bootstrap'
|
||||
|
||||
const CommentList = props => {
|
||||
|
||||
return (
|
||||
<ListGroup>
|
||||
{props.comments.map(comment => (
|
||||
<CommentRow
|
||||
key={comment.id}
|
||||
userId={props.user.id}
|
||||
userVote={props.votes.find(vote=>vote.commentId===comment.id && vote.userId===props.user.id)}
|
||||
updateSongPos={props.updateSongPos}
|
||||
comment={comment}
|
||||
/>
|
||||
))}
|
||||
</ListGroup>
|
||||
)
|
||||
}
|
||||
|
||||
const mapState = state => ({...state})
|
||||
|
||||
export default connect(mapState)(CommentList)
|
77
src/components/waveform/CommentRow.js
Normal file
77
src/components/waveform/CommentRow.js
Normal file
@ -0,0 +1,77 @@
|
||||
import React from 'react'
|
||||
import { Row, Col, Media } from 'react-bootstrap'
|
||||
import CommentVotes from './CommentVotes'
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
return (
|
||||
<Media style={{ borderStyle: 'solid' }}>
|
||||
<img width={36} height={36} className="mr-1" src="/img/anarchybang.jpg" />
|
||||
<Media.Body>
|
||||
<Row>
|
||||
<Col>
|
||||
Anon at{' '}
|
||||
<a href="#" onClick={() => props.updateSongPos(props.comment.secs)}>
|
||||
{parseTime(props.comment.secs)}
|
||||
</a>
|
||||
</Col>
|
||||
<CommentVotes
|
||||
commentId={props.comment.id}
|
||||
userId={props.userId}
|
||||
userVote={props.userVote}
|
||||
/>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>{props.comment.text}</Col>
|
||||
</Row>
|
||||
</Media.Body>
|
||||
</Media>
|
||||
)
|
||||
}
|
||||
|
||||
// const mapState = state => {
|
||||
// return {
|
||||
// user: state.user
|
||||
// }
|
||||
// }
|
||||
// const mapDispatch = dispatch => {
|
||||
// return {
|
||||
// saveVote: vote => dispatch(addVote(vote))
|
||||
// }
|
||||
// }
|
||||
//export default connect(mapState)(CommentRow)
|
||||
export default CommentRow
|
68
src/components/waveform/CommentVotes.js
Normal file
68
src/components/waveform/CommentVotes.js
Normal file
@ -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 (
|
||||
<Col className="mr-3 float-right text-right">
|
||||
<Row>
|
||||
<Col>
|
||||
<a
|
||||
className={
|
||||
userVote && userVote.upvote === 1
|
||||
? 'text-danger' : 'text-muted'
|
||||
}
|
||||
href="#"
|
||||
onClick={upvote}
|
||||
>
|
||||
⏶
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<a
|
||||
className={
|
||||
userVote && userVote.downvote === 1
|
||||
? 'text-primary' : 'text-muted'
|
||||
}
|
||||
href="#"
|
||||
onClick={downvote}
|
||||
>
|
||||
⏷
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
@ -2,10 +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 { fetchAllComments, addComment } from '../../store'
|
||||
import { Media, Form, Button, Container, Row, Col } from 'react-bootstrap'
|
||||
import CommentList from './CommentList'
|
||||
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 => {
|
||||
@ -47,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 })
|
||||
}
|
||||
|
||||
@ -79,7 +81,7 @@ class Player extends Component {
|
||||
|
||||
updateSongPos(secs) {
|
||||
this.setState({ songPos: secs })
|
||||
console.log((this.rap.audioEl.currentTime = secs))
|
||||
this.rap.audioEl.currentTime = secs
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -95,7 +97,7 @@ class Player extends Component {
|
||||
}}
|
||||
barWidth={1}
|
||||
peaks={config.data}
|
||||
height={200}
|
||||
height={100}
|
||||
pos={this.state.songPos}
|
||||
duration={this.state.duration}
|
||||
onClick={this.updateSongPos}
|
||||
@ -142,15 +144,22 @@ class Player extends Component {
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<CommentList updateSongPos={this.updateSongPos} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapState = state => state
|
||||
const mapState = state => ({ ...state })
|
||||
const mapDispatch = dispatch => {
|
||||
return {
|
||||
fetchComments: () => dispatch(fetchAllComments()),
|
||||
fetchUser: () => dispatch(getUser()),
|
||||
fetchAllVotes: userId => dispatch(getAllVotes(userId)),
|
||||
postComment: comment => dispatch(addComment(comment)),
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,17 @@
|
||||
import {createStore, combineReducers, applyMiddleware} from 'redux'
|
||||
import {createLogger} from 'redux-logger'
|
||||
import { createStore, combineReducers, applyMiddleware } from 'redux'
|
||||
import { createLogger } from 'redux-logger'
|
||||
import thunkMiddleware from 'redux-thunk'
|
||||
import {composeWithDevTools} from 'redux-devtools-extension'
|
||||
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}))
|
||||
applyMiddleware(thunkMiddleware, createLogger({ collapsed: true })),
|
||||
)
|
||||
const store = createStore(reducer, middleware)
|
||||
|
||||
@ -17,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'
|
||||
|
@ -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,8 +19,16 @@ export const addedComment = comment => ({
|
||||
comment,
|
||||
})
|
||||
|
||||
// THUNK CREATORS
|
||||
export const upvotedComment = comment => ({
|
||||
type: UPVOTED_COMMENT,
|
||||
comment,
|
||||
})
|
||||
|
||||
export const downvotedComment = comment => ({
|
||||
type: DOWNVOTED_COMMENT,
|
||||
comment,
|
||||
})
|
||||
// THUNK CREATORS
|
||||
export const fetchAllComments = () => async dispatch => {
|
||||
try {
|
||||
const res = await axios.get('/api/comments')
|
||||
@ -37,15 +48,51 @@ 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 {
|
||||
// const res = await axios.get(`/api/comments/${id}`)
|
||||
// dispatch(addedVote(res.data))
|
||||
// } catch (err) {
|
||||
// console.error(err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// REDUCER
|
||||
const commentReducer = (comments = initialComments, action) => {
|
||||
switch (action.type) {
|
||||
case GOT_ALL_COMMENTS:
|
||||
return action.comments
|
||||
case ADD_COMMENT:
|
||||
return comments.concat(action.comment)
|
||||
default:
|
||||
return comments
|
||||
case GOT_ALL_COMMENTS:
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
34
src/store/reducers/users.js
Normal file
34
src/store/reducers/users.js
Normal file
@ -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
|
102
src/store/reducers/votes.js
Normal file
102
src/store/reducers/votes.js
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user