Skip to content

Commit

Permalink
Comment thread added on solution source files page (hiding at the rig…
Browse files Browse the repository at this point in the history
…ht, revealing by clicking on its tab).
  • Loading branch information
krulis-martin committed Jul 25, 2023
1 parent e5ccc23 commit 9e9943e
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ class AssignmentsTable extends Component {
defaultMessage="(supervisors and students of this group)"
/>
}
inModal
displayAs="modal"
/>
)}
</Modal>
Expand Down
39 changes: 34 additions & 5 deletions src/components/widgets/Comments/CommentBox/CommentBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import { Modal } from 'react-bootstrap';
import classnames from 'classnames';

import Box from '../../Box';
import Icon, { ChatIcon } from '../../../icons';
import styles from '../comments.less';

class CommentBox extends Component {
state = { prevCount: 0 };
state = { prevCount: 0, panelOpen: false };

componentDidMount() {
setTimeout(() => this.scrollToBottom(), 10);
Expand All @@ -29,10 +30,17 @@ class CommentBox extends Component {
}
};

openPanel = () => this.setState({ panelOpen: true });
closePanel = () => this.setState({ panelOpen: false });

renderMessages() {
return (
<div
className={classnames({ 'direct-chat-messages': true, [styles.fullHeight]: this.props.inModal })}
className={classnames({
'direct-chat-messages': true,
[styles.body]: this.props.displayAs === 'panel',
[styles.modalHeight]: this.props.displayAs === 'modal',
})}
ref={c => {
this.commentsContainer = c;
}}>
Expand All @@ -45,10 +53,10 @@ class CommentBox extends Component {
const {
title = <FormattedMessage id="app.comments.title" defaultMessage="Comments and Notes" />,
footer,
inModal = false,
displayAs = 'box',
} = this.props;

return inModal ? (
return displayAs === 'modal' ? (
<>
<Modal.Header closeButton>
<Modal.Title>{title}</Modal.Title>
Expand All @@ -58,6 +66,27 @@ class CommentBox extends Component {
<div className="full-width">{footer}</div>
</Modal.Footer>
</>
) : displayAs === 'panel' ? (
<>
<div className={classnames({ [styles.panel]: true, [styles.panelOpen]: this.state.panelOpen })}>
<div>
<span className={styles.panelIcon}>
{this.state.panelOpen ? (
<Icon icon="angles-right" className="text-muted" onClick={this.closePanel} />
) : (
<ChatIcon className="text-primary" onClick={this.openPanel} />
)}
</span>
{this.state.panelOpen && (
<>
<div className={styles.header}>{title}</div>
{this.renderMessages()}
<div className={styles.footer}>{footer}</div>
</>
)}
</div>
</div>
</>
) : (
<Box title={title} noPadding={false} collapsable footer={footer} className="direct-chat">
{this.renderMessages()}
Expand All @@ -70,7 +99,7 @@ CommentBox.propTypes = {
title: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
commentsCount: PropTypes.number.isRequired,
footer: PropTypes.element,
inModal: PropTypes.bool,
displayAs: PropTypes.string,
children: PropTypes.element,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ const CommentThread = ({
setPrivacy,
refresh,
deleteComment,
inModal = false,
displayAs = 'box',
}) => (
<CommentBox
title={title}
commentsCount={comments.length}
footer={
addComment && <AddComment addComment={addComment} additionalPublicSwitchNote={additionalPublicSwitchNote} />
}
inModal={inModal}>
displayAs={displayAs}>
<div>
{comments.map((comment, i) =>
comment.user.id === currentUserId ? (
Expand Down Expand Up @@ -76,7 +76,7 @@ CommentThread.propTypes = {
setPrivacy: PropTypes.func,
refresh: PropTypes.func,
deleteComment: PropTypes.func,
inModal: PropTypes.bool,
displayAs: PropTypes.string,
};

export default CommentThread;
101 changes: 100 additions & 1 deletion src/components/widgets/Comments/comments.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.fullHeight {
.modalHeight {
height: calc(90vh - 200px) !important;
}

Expand All @@ -17,3 +17,102 @@
.iconButtonDelete {
color: #f88;
}

.panel {
position: fixed;
top: 66px;
bottom: 10px;
right: 0;
width: 0.25rem;
border-bottom-left-radius: 0.25rem;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
transition: width ease 0.2s;
z-index: 2;
}

.panel > div {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: white;
border: 1px solid rgba(0, 0, 0, 0.125);
border-right: 0;
border-bottom-left-radius: 0.25rem;
display: flex;
flex-direction: column;
}

.panelOpen {
width: 42vw;
min-width: 400px;
border-top-left-radius: 0.25rem;
}

.panelOpen > div {
border-top-left-radius: 0.25rem;
}

.panel span.panelIcon {
position: absolute;
top: -1px;
left: -3rem;
width: 3rem;
height: 3rem;
font-size: 1.3rem;
text-align: center;
line-height: 3rem;

background-color: white;
border: 1px solid rgba(0, 0, 0, 0.125);
border-right: 0;
border-top-left-radius: 1rem;
border-bottom-left-radius: 1rem;
z-index: 3;

transition: top ease 1s;
}

.panel::after {
position: absolute;
content: "";
top: 0;
left: calc(1px - 3rem);
width: 3rem;
height: 3rem;
background-color: white;
display: block;
border-top-left-radius: 1rem;
border-bottom-left-radius: 1rem;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
z-index: -1;
transition: top ease 1s;
}

.panelOpen span.panelIcon {
top: calc(50% - 1.5rem);
}

.panelOpen::after {
top: calc(50% - 1.5rem);
}

.panel span.panelIcon > * {
cursor: pointer;
}

.panel div.header {
font-size: 1.1rem;
padding: 0.75rem 1.25rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
}

.panel div.body {
flex-grow: 1;
}

.panel div.footer {
border-top: 1px solid rgba(0, 0, 0, 0.125);
padding: 0.75rem 1.25rem;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CommentThreadContainer extends Component {
setPrivacy,
refresh,
deleteComment,
inModal = false,
displayAs = 'box',
} = this.props;

return (
Expand All @@ -62,7 +62,7 @@ class CommentThreadContainer extends Component {
repostComment={repostComment}
refresh={refresh}
deleteComment={deleteComment}
inModal={inModal}
displayAs={displayAs}
/>
)}
</ResourceRenderer>
Expand All @@ -74,7 +74,7 @@ CommentThreadContainer.propTypes = {
threadId: PropTypes.string.isRequired,
title: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
additionalPublicSwitchNote: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),
inModal: PropTypes.bool,
displayAs: PropTypes.string,
thread: PropTypes.object,
user: PropTypes.object,
addComment: PropTypes.func.isRequired,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/AssignmentSolutions/AssignmentSolutions.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ class AssignmentSolutions extends Component {
defaultMessage="(supervisors and students of this group)"
/>
}
inModal
displayAs="modal"
/>
</Modal>
</Col>
Expand Down
25 changes: 23 additions & 2 deletions src/pages/SolutionSourceCodes/SolutionSourceCodes.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import {
StopIcon,
SwapIcon,
} from '../../components/icons';
import SolutionActionsContainer from '../../containers/SolutionActionsContainer';
import SourceCodeBox from '../../components/Solutions/SourceCodeBox';
import ReviewSummary from '../../components/Solutions/ReviewSummary';
import RecentlyVisited from '../../components/Solutions/RecentlyVisited';
import { registerSolutionVisit } from '../../components/Solutions/RecentlyVisited/functions';
import Callout from '../../components/widgets/Callout';
import SolutionActionsContainer from '../../containers/SolutionActionsContainer';
import CommentThreadContainer from '../../containers/CommentThreadContainer';

import { fetchRuntimeEnvironments } from '../../redux/modules/runtimeEnvironments';
import { fetchAssignmentIfNeeded } from '../../redux/modules/assignments';
Expand Down Expand Up @@ -67,7 +68,13 @@ const wrapInArray = defaultMemoize(entry => [entry]);
const localStorageDiffMappingsKey = 'SolutionSourceCodes.diffMappings.';

class SolutionSourceCodes extends Component {
state = { diffDialogOpen: false, mappingDialogOpenFile: null, mappingDialogDiffWith: null, diffMappings: {} };
state = {
diffDialogOpen: false,
mappingDialogOpenFile: null,
mappingDialogDiffWith: null,
diffMappings: {},
commentsOpen: false,
};

static loadAsync = ({ solutionId, assignmentId, secondSolutionId }, dispatch) =>
Promise.all([
Expand Down Expand Up @@ -147,6 +154,9 @@ class SolutionSourceCodes extends Component {
this.setState({ diffDialogOpen: false, mappingDialogOpenFile: null, mappingDialogDiffWith: null });
};

openComments = () => this.setState({ commentsOpen: true });
closeComments = () => this.setState({ commentsOpen: false });

selectDiffSolution = id => {
const {
match: {
Expand Down Expand Up @@ -593,6 +603,17 @@ class SolutionSourceCodes extends Component {
)}
</ResourceRenderer>

<CommentThreadContainer
threadId={solution.id}
additionalPublicSwitchNote={
<FormattedMessage
id="app.solutionDetail.comments.additionalSwitchNote"
defaultMessage="(author of the solution and supervisors of this group)"
/>
}
displayAs="panel"
/>

<Modal show={this.state.diffDialogOpen} backdrop="static" onHide={this.closeDialogs} size="xl">
<Modal.Header closeButton>
<Modal.Title>
Expand Down

0 comments on commit 9e9943e

Please sign in to comment.