diff --git a/remark.rest b/remark.rest index 72fd9132..bc69368a 100644 --- a/remark.rest +++ b/remark.rest @@ -30,7 +30,7 @@ Content-Type: application/json } ### pin comment -PUT {{host}}/api/v1/admin/pin/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&pin=0 +PUT {{host}}/api/v1/admin/pin/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&pin=1 ### vote for comment PUT {{host}}/api/v1/vote/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/&vote=1 @@ -55,3 +55,9 @@ GET {{host}}/api/v1/list?site=remark ### get config GET {{host}}/api/v1/config + +### block user +PUT {{host}}/api/v1/admin/user/username?site=remark&block=1 + +### delete comment by id +DELETE {{host}}/api/v1/admin/comment/3665976683?site=remark&url=https://radio-t.com/p/2017/12/16/podcast-576/ diff --git a/web/app/common/api.js b/web/app/common/api.js index 97b1b9a8..1b84d372 100644 --- a/web/app/common/api.js +++ b/web/app/common/api.js @@ -2,11 +2,13 @@ import { siteId, url } from './settings'; import fetcher from './fetcher' +/* common */ + export const find = ({ url }) => fetcher.get(`/find?url=${url}&sort=-score&format=tree`); export const getComment = ({ id }) => fetcher.get(`/id/${id}?url=${url}`); -export const getUser = () => fetcher.get('/user'); +export const vote = ({ id, url, value }) => fetcher.put(`/vote/${id}?url=${url}&vote=${value}`); export const send = ({ text, pid }) => fetcher.post('/comment', { text, @@ -17,12 +19,28 @@ export const send = ({ text, pid }) => fetcher.post('/comment', { ...(pid ? { pid } : {}), }); -export const vote = ({ id, url, value }) => fetcher.put(`/vote/${id}?url=${url}&vote=${value}`); +export const getUser = () => fetcher.get('/user'); + +/* admin */ +export const pin = ({ id, url }) => fetcher.put(`/admin/pin/${id}?url=${url}&pin=1`); + +export const unpin = ({ id, url }) => fetcher.put(`/admin/pin/${id}?url=${url}&pin=0`); + +export const remove = ({ id }) => fetcher.delete(`/admin/comment/${id}?url=${url}`); + +export const blockUser = ({ id }) => fetcher.put(`/admin/user/${id}?&block=1`); + +export const unblockUser = ({ id }) => fetcher.put(`/admin/user/${id}?&block=0`); export default { find, getComment, - send, vote, + send, getUser, + pin, + unpin, + remove, + blockUser, + unblockUser, }; diff --git a/web/app/components/comment/__action/comment__action.scss b/web/app/components/comment/__action/comment__action.scss new file mode 100644 index 00000000..d9703a9c --- /dev/null +++ b/web/app/components/comment/__action/comment__action.scss @@ -0,0 +1,4 @@ +.comment__action { + margin-left: 8px; + cursor: pointer; +} diff --git a/web/app/components/comment/__controls/_view/_admin/comment__controls_view_admin.scss b/web/app/components/comment/__controls/_view/_admin/comment__controls_view_admin.scss new file mode 100644 index 00000000..75ada7bb --- /dev/null +++ b/web/app/components/comment/__controls/_view/_admin/comment__controls_view_admin.scss @@ -0,0 +1,3 @@ +.comment__controls_view_admin { + color: #ff4700; +} diff --git a/web/app/components/comment/__controls/comment__controls.scss b/web/app/components/comment/__controls/comment__controls.scss index ebd3eb42..0b0f164c 100644 --- a/web/app/components/comment/__controls/comment__controls.scss +++ b/web/app/components/comment/__controls/comment__controls.scss @@ -1,7 +1,7 @@ .comment__controls { display: inline-block; - margin-left: 8px; color: #06c5c5; + user-select: none; @media (hover: hover) { margin-left: 0; diff --git a/web/app/components/comment/__reply/comment__reply.scss b/web/app/components/comment/__reply/comment__reply.scss deleted file mode 100644 index 31696d41..00000000 --- a/web/app/components/comment/__reply/comment__reply.scss +++ /dev/null @@ -1,3 +0,0 @@ -.comment__reply { - cursor: pointer; -} diff --git a/web/app/components/comment/_pinned/comment_pinned.scss b/web/app/components/comment/_pinned/comment_pinned.scss new file mode 100644 index 00000000..f21be6bc --- /dev/null +++ b/web/app/components/comment/_pinned/comment_pinned.scss @@ -0,0 +1,7 @@ +.comment_pinned { + &, &.comment_view_admin { + .comment__username { + color: #FFD700; + } + } +} diff --git a/web/app/components/comment/comment.jsx b/web/app/components/comment/comment.jsx index b1159b7d..5509a54c 100644 --- a/web/app/components/comment/comment.jsx +++ b/web/app/components/comment/comment.jsx @@ -14,24 +14,31 @@ export default class Comment extends Component { isInputVisible: false, }; - this.updateScoreState(props); + this.updateState(props); this.decreaseScore = this.decreaseScore.bind(this); this.increaseScore = this.increaseScore.bind(this); this.onReplyClick = this.onReplyClick.bind(this); this.onReply = this.onReply.bind(this); + this.onPinClick = this.onPinClick.bind(this); + this.onUnpinClick = this.onUnpinClick.bind(this); + this.onBlockClick = this.onBlockClick.bind(this); + this.onUnblockClick = this.onUnblockClick.bind(this); + this.onDeleteClick = this.onDeleteClick.bind(this); } componentWillReceiveProps(nextProps) { - this.updateScoreState(nextProps); + this.updateState(nextProps); } - updateScoreState(props) { - const { score = 0, votes = [] } = props.data; + updateState(props) { + const { pin, score = 0, votes = [] } = props.data; const userId = store.get('user').id; this.setState({ score: score, + pinned: !!pin, + userBlocked: !!store.get('user').block, scoreIncreased: userId in votes && votes[userId], scoreDecreased: userId in votes && !votes[userId], }); @@ -43,6 +50,52 @@ export default class Comment extends Component { this.setState({ isInputVisible: !isInputVisible }); } + onPinClick() { + const { id } = this.props.data; + + this.setState({ pinned: true }); + + api.pin({ id, url }).then(() => { + api.getComment({ id }).then(comment => store.replaceComment(comment)); + }); + } + + onUnpinClick() { + const { id } = this.props.data; + + this.setState({ pinned: false }); + + api.pin({ id, url }).then(() => { + api.getComment({ id }).then(comment => store.replaceComment(comment)); + }); + } + + onBlockClick() { + const { user: { id } } = this.props.data; + + this.setState({ userBlocked: true }); + + api.blockUser({ id }); + } + + onUnblockClick() { + const { user: { id } } = this.props.data; + + this.setState({ userBlocked: false }); + + api.unblockUser({ id }); + } + + onDeleteClick() { + const { id } = this.props.data; + + api.remove({ id }).then(() => { + if (this.props.onDelete) { + this.props.onDelete(); + } + }); + } + increaseScore() { const { score, scoreIncreased, scoreDecreased } = this.state; const { id } = this.props.data; @@ -82,8 +135,9 @@ export default class Comment extends Component { this.setState({ isInputVisible: false }); } - render(props, { score, scoreIncreased, scoreDecreased, isInputVisible }) { + render(props, { userBlocked, pinned, score, scoreIncreased, scoreDecreased, isInputVisible }) { const { data, mix, mods = {} } = props; + const isAdmin = store.get('user').admin; const time = new Date(data.time); // TODO: which format for datetime should we choose? @@ -100,9 +154,14 @@ export default class Comment extends Component { }, }; - return ( + const defaultMods = { + pinned, // TODO: add default view mod or don't? -