From 86660641885eb08dde70b83223d465b52caf86f8 Mon Sep 17 00:00:00 2001 From: Saagar Arya <51128536+skarya22@users.noreply.github.com> Date: Thu, 24 Aug 2023 14:03:00 -0400 Subject: [PATCH] [bvl_feedback] Edit comment section (#8790) Fix display of bvl_feedback on mobile devices. - Switched Add Comment button from Pencil to a Comment (Original was confusing) - Set threads to be shown automatically for open threads as having them hidden made the UI confusing. - Added an Edit and Delete button for comments of which the author is the user viewing them - Flipped the order of comments around so that the newer comments show up below. Makes more sense when reading the comments - Made New Comment TextArea section show up below the thread, as that is where the new comment will appear - Changed panel width to work on mobile devices --- .../ajax/close_bvl_feedback_thread.php | 3 +- .../delete_thread_comment_bvl_feedback.php | 26 +++ .../ajax/get_thread_entry_data.php | 8 + .../ajax/open_bvl_feedback_thread.php | 3 +- .../update_thread_comment_bvl_feedback.php | 37 +++ .../bvl_feedback/css/bvl_feedback_panel.css | 53 +++++ .../jsx/react.behavioural_feedback_panel.js | 212 +++++++++++++----- modules/bvl_feedback/test/TestPlan.md | 10 +- php/libraries/NDB_BVL_Feedback.class.inc | 4 +- 9 files changed, 293 insertions(+), 63 deletions(-) create mode 100644 modules/bvl_feedback/ajax/delete_thread_comment_bvl_feedback.php create mode 100644 modules/bvl_feedback/ajax/update_thread_comment_bvl_feedback.php create mode 100644 modules/bvl_feedback/css/bvl_feedback_panel.css diff --git a/modules/bvl_feedback/ajax/close_bvl_feedback_thread.php b/modules/bvl_feedback/ajax/close_bvl_feedback_thread.php index 2ba84fb7384..0153807de2f 100644 --- a/modules/bvl_feedback/ajax/close_bvl_feedback_thread.php +++ b/modules/bvl_feedback/ajax/close_bvl_feedback_thread.php @@ -60,7 +60,8 @@ exit; } -header("HTTP/1.1 204 No Content"); +header("content-type:application/json"); +echo json_encode(['success' => true]); exit; diff --git a/modules/bvl_feedback/ajax/delete_thread_comment_bvl_feedback.php b/modules/bvl_feedback/ajax/delete_thread_comment_bvl_feedback.php new file mode 100644 index 00000000000..18e9dbd197c --- /dev/null +++ b/modules/bvl_feedback/ajax/delete_thread_comment_bvl_feedback.php @@ -0,0 +1,26 @@ + + * @license GPLv3 + * @link https://www.github.com/aces/Loris/ + */ +header("content-type:application/json"); +ini_set('default_charset', 'utf-8'); + +require "bvl_panel_ajax.php"; + +$db =& NDB_Factory::singleton()->database(); + +// DELETE the thread entries +$db->delete('feedback_bvl_entry', ["ID" => $_POST['entryID']]); + +print json_encode('success'); + +exit(); \ No newline at end of file diff --git a/modules/bvl_feedback/ajax/get_thread_entry_data.php b/modules/bvl_feedback/ajax/get_thread_entry_data.php index 6f7289ec0bb..0781fa2c998 100644 --- a/modules/bvl_feedback/ajax/get_thread_entry_data.php +++ b/modules/bvl_feedback/ajax/get_thread_entry_data.php @@ -15,8 +15,16 @@ header("content-type:application/json"); require "bvl_panel_ajax.php"; +$user =& User::singleton(); +$username = $user->getUsername(); + if (isset($_GET['feedbackID']) && !Empty($_GET['feedbackID'])) { $threadEntries = NDB_BVL_Feedback::getThreadEntries($_GET['feedbackID']); + // add username to threadentries + foreach ($threadEntries as $key => $value) { + $threadEntries[$key]['current_user'] = $username; + $threadEntries[$key]['editComment'] = false; + } print json_encode($threadEntries); } diff --git a/modules/bvl_feedback/ajax/open_bvl_feedback_thread.php b/modules/bvl_feedback/ajax/open_bvl_feedback_thread.php index 3fb83b1588c..10a22762f62 100644 --- a/modules/bvl_feedback/ajax/open_bvl_feedback_thread.php +++ b/modules/bvl_feedback/ajax/open_bvl_feedback_thread.php @@ -38,6 +38,7 @@ exit; } -header("HTTP/1.1 204 No Content"); +header("content-type:application/json"); +echo json_encode(['success' => true]); exit; diff --git a/modules/bvl_feedback/ajax/update_thread_comment_bvl_feedback.php b/modules/bvl_feedback/ajax/update_thread_comment_bvl_feedback.php new file mode 100644 index 00000000000..9fbf2262eaa --- /dev/null +++ b/modules/bvl_feedback/ajax/update_thread_comment_bvl_feedback.php @@ -0,0 +1,37 @@ + + * @license GPLv3 + * @link https://www.github.com/aces/Loris-Trunk/ + */ +header("content-type:application/json"); +ini_set('default_charset', 'utf-8'); + +require "bvl_panel_ajax.php"; + +if (isset($_POST['entryID']) && isset($_POST['newComment'])) { + $db =& NDB_Factory::singleton()->database(); + + $db->update( + 'feedback_bvl_entry', + [ + 'Comment' => $_POST['newComment'], + 'TestDate' => $_POST['date'] + ], + ['ID' => $_POST['entryID']] + ); + + print json_encode('success'); +} else { + print json_encode('error'); + exit(); +} + +exit(); \ No newline at end of file diff --git a/modules/bvl_feedback/css/bvl_feedback_panel.css b/modules/bvl_feedback/css/bvl_feedback_panel.css new file mode 100644 index 00000000000..3b9012b8f14 --- /dev/null +++ b/modules/bvl_feedback/css/bvl_feedback_panel.css @@ -0,0 +1,53 @@ +/* Based on "loris/htdocs/css/panel.css" */ + +#bvl_panel_wrapper .navmenu { + width: 800px; + position: fixed; + z-index: 1040; + top: 0; + bottom: 0; +} + +#bvl_panel_wrapper .panel-wrapper { + margin-right: -800px; + right: 0; + width: 800px; + background: #F5F5F5; + height: 100%; + border-color: #064785; + border-left: 2px solid; + border-top: 2px solid; + overflow-y: scroll; + z-index: 998; + transition: all 0.4s ease 0s; + padding-bottom: 50px; +} + +#bvl_panel_wrapper .bvl_panel { + padding-right: 800px; + transition: all 0.4s ease 0s; +} + +#bvl_panel_wrapper .active_panel_footer { + padding-right: 800px; +} + +#bvl_panel_wrapper .active_panel { + right: 800px; +} + +@media (max-width: 884px) { + #bvl_panel_wrapper .panel-wrapper { + margin-right: -100%; + width: 100%; + } + + #bvl_panel_wrapper .active_panel { + right: 100%; + } +} + +#comment_author { + color: gray; + font-size: 12px +} \ No newline at end of file diff --git a/modules/bvl_feedback/jsx/react.behavioural_feedback_panel.js b/modules/bvl_feedback/jsx/react.behavioural_feedback_panel.js index 94837bf149e..1bfdfdbbf2b 100644 --- a/modules/bvl_feedback/jsx/react.behavioural_feedback_panel.js +++ b/modules/bvl_feedback/jsx/react.behavioural_feedback_panel.js @@ -3,6 +3,8 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; +import '../css/bvl_feedback_panel.css'; + /** * Slider panel component */ @@ -173,7 +175,7 @@ FeedbackPanelContent.propTypes = { candID: PropTypes.string, commentID: PropTypes.string, sessionID: PropTypes.string, - commentToggled: PropTypes.func, + commentToggled: PropTypes.bool, }; @@ -188,12 +190,13 @@ class FeedbackPanelRow extends Component { constructor(props) { super(props); this.state = { - threadEntriesToggled: false, + threadEntriesToggled: this.props.status === 'opened' ? true : false, threadEntriesLoaded: [], }; this.loadServerState = this.loadServerState.bind(this); this.toggleEntries = this.toggleEntries.bind(this); this.newThreadEntry = this.newThreadEntry.bind(this); + this.updateThreadEntry = this.updateThreadEntry.bind(this); } /** @@ -235,11 +238,11 @@ class FeedbackPanelRow extends Component { /** * Toggle entries * - * @param {boolean} newComment + * @param {boolean} result */ - toggleEntries(newComment) { + toggleEntries(result) { let toggle = false; - if (newComment) { + if (result) { toggle = true; } else { toggle = !this.state.threadEntriesToggled; @@ -279,6 +282,42 @@ class FeedbackPanelRow extends Component { }); } + updateThreadEntry(entryID, newComment, date) { + const formData = new FormData(); + formData.append('entryID', entryID); + formData.append('newComment', newComment); + formData.append('date', date); + fetch( + loris.BaseURL + + '/bvl_feedback/ajax/update_thread_comment_bvl_feedback.php', + { + method: 'POST', + body: formData, + } + ).then(() => { + this.loadServerState(); + }).catch((error) => { + console.error(error); + }); + } + + deleteThreadEntry(entryID) { + const formData = new FormData(); + formData.append('entryID', entryID); + fetch( + loris.BaseURL + + '/bvl_feedback/ajax/delete_thread_comment_bvl_feedback.php', + { + method: 'POST', + body: formData, + } + ).then(() => { + this.loadServerState(); + }).catch((error) => { + console.error(error); + }); + } + /** * Renders the React component. * @@ -295,14 +334,54 @@ class FeedbackPanelRow extends Component { if (this.state.threadEntriesToggled) { arrow = 'glyphicon glyphicon-chevron-down glyphs'; - threadEntries = this.state.threadEntriesLoaded.map(function(entry, key) { + threadEntries = this.state.threadEntriesLoaded.map((entry, key) => { + let toggleEditComment = () => { + let tempThreadEntriesLoaded = [...this.state.threadEntriesLoaded]; + tempThreadEntriesLoaded.forEach((threadEntry, index) => { + if (index == key) { + threadEntry.editComment = !threadEntry.editComment; + } else { + threadEntry.editComment = false; + } + }); + this.setState({threadEntriesLoaded: tempThreadEntriesLoaded}); + }; return ( - - - {entry.UserID} on {entry.TestDate} commented:
- {entry.Comment} - - + + + + + {entry.Date} {entry.UserID}:{' '} + + {entry.Comment} + + {entry.UserID === entry.current_user && <> + {' '} { + toggleEditComment(); + }} + > + + {' '} + { + this.deleteThreadEntry(entry.EntryID); + }}> + + + } + + + + {entry.editComment ? + + : null} + ); }); } @@ -312,44 +391,47 @@ class FeedbackPanelRow extends Component { buttonClass = 'btn btn-danger dropdown-toggle btn-sm'; dropdown = (
  • Close
  • ); commentButton = ( - + ); } return ( - - {this.props.fieldname ? - {this.props.fieldname}
    {this.props.type} : - {this.props.type}} - {this.props.author} on:
    {this.props.date} - -
    - -
      - {dropdown} -
    -
    - - {commentButton} - - - {this.props.commentToggled ? - () : - null - } - {threadEntries} + + {this.props.fieldname ? + {this.props.fieldname}
    {this.props.type} : + {this.props.type}} + {this.props.author} on:
    {this.props.date} + +
    + +
      + {dropdown} +
    +
    + + {commentButton} + + + + {threadEntries} + {this.props.commentToggled ? + () : + null + } ); } @@ -367,10 +449,9 @@ FeedbackPanelRow.propTypes = { onClickClose: PropTypes.func, commentToggle: PropTypes.func, user: PropTypes.string, - commentToggled: PropTypes.func, + commentToggled: PropTypes.bool, }; - /** * Comment entry form component */ @@ -382,18 +463,31 @@ class CommentEntryForm extends Component { constructor(props) { super(props); this.state = { - value: '', - message: '', + value: props.value ? props.value : '', + entryID: -1, + date: '', }; this.sendComment = this.sendComment.bind(this); this.handleChange = this.handleChange.bind(this); + if (props.entryID) { + this.state.entryID = props.entryID; + this.state.date = props.date; + } } /** * Send comment */ sendComment() { - this.props.onCommentSend(this.state.value); + if (this.state.entryID < 0) { + this.props.onCommentSend(this.state.value); + } else { + this.props.onCommentSend( + this.state.entryID, + this.state.value, + this.state.date + ); + } this.setState({ value: '', message: 'Comment added!', @@ -418,7 +512,12 @@ class CommentEntryForm extends Component { render() { return ( - Add a thread entry: + + { + this.state.entryID < 0 ? + Add a comment: : + Update comment: + }