Skip to content

Commit

Permalink
keyboard shortcuts
Browse files Browse the repository at this point in the history
  • Loading branch information
thomassth committed Jul 27, 2024
1 parent 0500fec commit f886522
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ class Comment extends React.Component {

render() {
return (
<Card sx={{ mb: [3], minWidth: '35em' }}>
<Card
sx={{
mb: [3],
width: '35em',
maxWidth: '100%',
boxShadow: this.props.currentItem ? 'lightseagreen 0px 0px 16px;' : ''
}}
className={this.props.currentItem ? 'current-item' : ''}>
<Box>
<Text sx={{ mb: [3] }}>{this.props.comment.txt}</Text>
<Flex
Expand Down Expand Up @@ -85,7 +92,8 @@ Comment.propTypes = {
comment: PropTypes.shape({
txt: PropTypes.string,
is_meta: PropTypes.bool
})
}),
currentItem: PropTypes.bool
}

export default Comment
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

import React from 'react'
import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {
Expand All @@ -9,47 +9,72 @@ import {
} from '../../../actions'
import Comment from './comment'

@connect((state) => state.mod_comments_accepted)
class ModerateCommentsAccepted extends React.Component {
onCommentRejected(comment) {
this.props.dispatch(changeCommentStatusToRejected(comment))
}
function ModerateCommentsAccepted({ dispatch, accepted_comments = [] }) {

toggleIsMetaHandler(comment, is_meta) {
this.props.dispatch(changeCommentCommentIsMeta(comment, is_meta))
}
const [currentItem, setCurrentItem] = useState(0)
useEffect(() => {
function handleKeyDown(e) {
if (e.code === 'KeyR') {
onCommentRejected(accepted_comments[currentItem])
}
if (e.code === 'KeyW') {
setCurrentItem(Math.max(0, currentItem - 1))
}
if (accepted_comments && e.code === 'KeyS') {
setCurrentItem(Math.min(accepted_comments.length - 1, currentItem + 1))
}
}
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [currentItem, accepted_comments]);

useEffect(() => {
if (accepted_comments && currentItem > accepted_comments.length - 1) {
setCurrentItem(Math.min(accepted_comments.length - 1, currentItem))
}
}, [accepted_comments?.length ?? 0])

createCommentMarkup() {
const comments = this.props.accepted_comments.map((comment, i) => {
function onCommentRejected(comment) {
dispatch(changeCommentStatusToRejected(comment))
}
function
toggleIsMetaHandler(comment, is_meta) {
dispatch(changeCommentCommentIsMeta(comment, is_meta))
}
function createCommentMarkup() {
const comments = accepted_comments.map((comment, i) => {
return (
<Comment
key={i}
rejectButton
rejectClickHandler={this.onCommentRejected.bind(this)}
rejectClickHandler={onCommentRejected.bind(this)}
rejectButtonText="reject"
isMetaCheckbox
toggleIsMetaHandler={this.toggleIsMetaHandler.bind(this)}
toggleIsMetaHandler={toggleIsMetaHandler.bind(this)}
comment={comment}
currentItem={currentItem === i}
/>
)
})
return comments
}

render() {
return (
<div>
{this.props.accepted_comments !== null
? this.createCommentMarkup()
: 'Loading accepted comments...'}
</div>
)
}
return (
<div>
{accepted_comments !== null
? createCommentMarkup()
: 'Loading accepted comments...'}
</div>
)
}

ModerateCommentsAccepted.propTypes = {
dispatch: PropTypes.func,
accepted_comments: PropTypes.arrayOf(PropTypes.object)
}

export default ModerateCommentsAccepted
const mapStateToProps = (state) => ({
dispatch: state.mod_comments_accepted.dispatch,
accepted_comments: state.mod_comments_accepted.accepted_comments,
});
export default connect(mapStateToProps)(ModerateCommentsAccepted)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

import React from 'react'
import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import {
changeCommentStatusToAccepted,
Expand All @@ -9,47 +9,72 @@ import {
import { connect } from 'react-redux'
import Comment from './comment'

@connect((state) => state.mod_comments_rejected)
class ModerateCommentsRejected extends React.Component {
onCommentAccepted(comment) {
this.props.dispatch(changeCommentStatusToAccepted(comment))
function ModerateCommentsRejected({ dispatch, rejected_comments = [] }) {
const [currentItem, setCurrentItem] = useState(0)
useEffect(() => {
function handleKeyDown(e) {
if (e.code === 'KeyA') {
onCommentAccepted(rejected_comments[currentItem])
}
if (e.code === 'KeyW') {
setCurrentItem(Math.max(0, currentItem - 1))
}
if (rejected_comments && e.code === 'KeyS') {
setCurrentItem(Math.min(rejected_comments.length - 1, currentItem + 1))
}
}
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [currentItem, rejected_comments]);

useEffect(() => {
if (rejected_comments && currentItem > rejected_comments.length - 1) {
setCurrentItem(Math.min(rejected_comments.length - 1, currentItem))
}
}, [rejected_comments?.length ?? 0])


function onCommentAccepted(comment) {
dispatch(changeCommentStatusToAccepted(comment))
}

toggleIsMetaHandler(comment, is_meta) {
this.props.dispatch(changeCommentCommentIsMeta(comment, is_meta))
function toggleIsMetaHandler(comment, is_meta) {
dispatch(changeCommentCommentIsMeta(comment, is_meta))
}

createCommentMarkup() {
const comments = this.props.rejected_comments.map((comment, i) => {
function createCommentMarkup() {
const comments = rejected_comments.map((comment, i) => {
return (
<Comment
key={i}
acceptButton
acceptButtonText="accept"
acceptClickHandler={this.onCommentAccepted.bind(this)}
acceptClickHandler={onCommentAccepted.bind(this)}
isMetaCheckbox
toggleIsMetaHandler={this.toggleIsMetaHandler.bind(this)}
toggleIsMetaHandler={toggleIsMetaHandler.bind(this)}
comment={comment}
currentItem={currentItem === i}
/>
)
})
return comments
}

render() {
return (
<div>
{this.props.rejected_comments !== null
? this.createCommentMarkup()
: 'Loading rejected comments...'}
</div>
)
}
return (
<div>
{rejected_comments !== null
? createCommentMarkup()
: 'Loading rejected comments...'}
</div>
)
}

ModerateCommentsRejected.propTypes = {
dispatch: PropTypes.func,
rejected_comments: PropTypes.arrayOf(PropTypes.object)
}

export default ModerateCommentsRejected
const mapStateToProps = (state) => ({
dispatch: state.mod_comments_rejected.dispatch,
rejected_comments: state.mod_comments_rejected.rejected_comments,
});
export default connect(mapStateToProps)(ModerateCommentsRejected)
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (C) 2012-present, The Authors. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License, version 3, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

import React from 'react'
import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {
Expand All @@ -10,59 +10,89 @@ import {
} from '../../../actions'
import Comment from './comment'

@connect((state) => state.mod_comments_unmoderated)
class ModerateCommentsTodo extends React.Component {
onCommentAccepted(comment) {
this.props.dispatch(changeCommentStatusToAccepted(comment))
function ModerateCommentsTodo({ dispatch, unmoderated_comments = [] }) {
const [currentItem, setCurrentItem] = useState(0)
useEffect(() => {
function handleKeyDown(e) {
if (e.code === 'KeyA') {
onCommentAccepted(unmoderated_comments[currentItem])
}
if (e.code === 'KeyR') {
onCommentRejected(unmoderated_comments[currentItem])
}
if (e.code === 'KeyW') {
setCurrentItem(Math.max(0, currentItem - 1))
}
if (unmoderated_comments && e.code === 'KeyS') {
setCurrentItem(Math.min(unmoderated_comments.slice(0, max).length - 1, currentItem + 1))
}
}
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [currentItem, unmoderated_comments]);

const max = 100;

useEffect(() => {
if (unmoderated_comments && currentItem > unmoderated_comments.slice(0, max).length - 1) {
setCurrentItem(Math.min(unmoderated_comments.slice(0, max).length - 1, currentItem))
}
}, [unmoderated_comments?.length ?? 0])

function onCommentAccepted(comment) {
dispatch(changeCommentStatusToAccepted(comment))
}

onCommentRejected(comment) {
this.props.dispatch(changeCommentStatusToRejected(comment))
function onCommentRejected(comment) {
dispatch(changeCommentStatusToRejected(comment))
}

toggleIsMetaHandler(comment, is_meta) {
this.props.dispatch(changeCommentCommentIsMeta(comment, is_meta))
function toggleIsMetaHandler(comment, is_meta) {
dispatch(changeCommentCommentIsMeta(comment, is_meta))
}

createCommentMarkup(max) {
function createCommentMarkup(max) {

return this.props.unmoderated_comments.slice(0,max).map((comment, i) => {
return unmoderated_comments.slice(0, max).map((comment, i) => {
return (
<Comment
key={i}
acceptButton
rejectButton
acceptClickHandler={this.onCommentAccepted.bind(this)}
rejectClickHandler={this.onCommentRejected.bind(this)}
acceptClickHandler={onCommentAccepted}
rejectClickHandler={onCommentRejected}
acceptButtonText="accept"
rejectButtonText="reject"
isMetaCheckbox
toggleIsMetaHandler={this.toggleIsMetaHandler.bind(this)}
toggleIsMetaHandler={toggleIsMetaHandler}
comment={comment}
currentItem={currentItem === i}
/>
)
})

}

render() {
const max = 100;
return (
return (
<div>
<div>
<div>
<p> Displays maximum {max} comments </p>
{this.props.unmoderated_comments !== null
? this.createCommentMarkup(max)
: 'Loading unmoderated comments...'}
</div>
<p> Displays maximum {max} comments </p>
{unmoderated_comments !== null
? createCommentMarkup(max)
: 'Loading unmoderated comments...'}
</div>
)
}
</div>
)
}

ModerateCommentsTodo.propTypes = {
dispatch: PropTypes.func,
unmoderated_comments: PropTypes.arrayOf(PropTypes.object)
}

export default ModerateCommentsTodo
const mapStateToProps = (state) => ({
dispatch: state.mod_comments_unmoderated.dispatch,
unmoderated_comments: state.mod_comments_unmoderated.unmoderated_comments,
});

export default connect(mapStateToProps)(ModerateCommentsTodo)

0 comments on commit f886522

Please sign in to comment.