Skip to content

Commit

Permalink
Adding accept action buttons to assignment solutions overview.
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Krulis committed May 3, 2019
1 parent cdb9459 commit 4fb72ea
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 35 deletions.
11 changes: 9 additions & 2 deletions src/components/Assignments/SolutionsTable/SolutionsTableRow.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, FormattedNumber } from 'react-intl';
import { FormattedMessage, FormattedNumber, injectIntl, intlShape } from 'react-intl';
import { Link } from 'react-router';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import classnames from 'classnames';
Expand All @@ -9,6 +9,8 @@ import AssignmentStatusIcon, { getStatusDesc } from '../Assignment/AssignmentSta
import Points from './Points';
import EnvironmentsListItem from '../../helpers/EnvironmentsList/EnvironmentsListItem';
import DeleteSolutionButtonContainer from '../../../containers/DeleteSolutionButtonContainer/DeleteSolutionButtonContainer';
import AcceptSolutionContainer from '../../../containers/AcceptSolutionContainer';

import CommentsIcon from './CommentsIcon';
import { SendIcon } from '../../icons';
import DateTime from '../../widgets/DateTime';
Expand Down Expand Up @@ -36,6 +38,7 @@ const SolutionsTableRow = ({
noteMaxlen = null,
compact = false,
links: { SOLUTION_DETAIL_URI_FACTORY },
intl: { locale },
}) => {
const trimmedNote = note && note.trim();
const hasNote = Boolean(trimmedNote);
Expand Down Expand Up @@ -118,6 +121,9 @@ const SolutionsTableRow = ({
<FormattedMessage id="generic.detail" defaultMessage="Detail" />
</Link>
)}
{permissionHints && permissionHints.setAccepted && (
<AcceptSolutionContainer id={id} locale={locale} shortLabel bsSize="xs" />
)}
{permissionHints && permissionHints.delete && <DeleteSolutionButtonContainer id={id} bsSize="xs" />}
</td>
</tr>
Expand Down Expand Up @@ -162,6 +168,7 @@ SolutionsTableRow.propTypes = {
noteMaxlen: PropTypes.number,
compact: PropTypes.bool.isRequired,
links: PropTypes.object,
intl: intlShape,
};

export default withLinks(SolutionsTableRow);
export default withLinks(injectIntl(SolutionsTableRow));
20 changes: 15 additions & 5 deletions src/components/buttons/AcceptSolution/AcceptSolution.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@ import { FormattedMessage } from 'react-intl';
import Button from '../../widgets/FlatButton';
import Icon from '../../icons';

const AcceptSolution = ({ accepted, acceptPending, accept, unaccept }) =>
const AcceptSolution = ({ accepted, acceptPending, accept, unaccept, shortLabel = false, bsSize = undefined }) =>
accepted === true ? (
<Button bsStyle="info" onClick={unaccept} disabled={acceptPending}>
<Button bsStyle="info" bsSize={bsSize} onClick={unaccept} disabled={acceptPending}>
<Icon icon="check-circle" gapRight />
<FormattedMessage id="app.acceptSolution.accepted" defaultMessage="Revoke as Final" />
{shortLabel ? (
<FormattedMessage id="app.acceptSolution.acceptedShort" defaultMessage="Revoke" />
) : (
<FormattedMessage id="app.acceptSolution.accepted" defaultMessage="Revoke as Final" />
)}
</Button>
) : (
<Button bsStyle="primary" onClick={accept} disabled={acceptPending}>
<Button bsStyle="primary" bsSize={bsSize} onClick={accept} disabled={acceptPending}>
<Icon icon={['far', 'check-circle']} gapRight />
<FormattedMessage id="app.acceptSolution.notAccepted" defaultMessage="Accept as Final" />
{shortLabel ? (
<FormattedMessage id="app.acceptSolution.notAcceptedShort" defaultMessage="Accept" />
) : (
<FormattedMessage id="app.acceptSolution.notAccepted" defaultMessage="Accept as Final" />
)}
</Button>
);

Expand All @@ -22,6 +30,8 @@ AcceptSolution.propTypes = {
acceptPending: PropTypes.bool.isRequired,
accept: PropTypes.func.isRequired,
unaccept: PropTypes.func.isRequired,
shortLabel: PropTypes.bool,
bsSize: PropTypes.string,
};

export default AcceptSolution;
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import AcceptSolution from '../../components/buttons/AcceptSolution';
import { acceptSolution, unacceptSolution } from '../../redux/modules/solutions';
import { isAccepted, isAcceptPending } from '../../redux/selectors/solutions';

const AcceptSolutionContainer = ({ accepted, acceptPending, accept, unaccept }) => {
return <AcceptSolution accepted={accepted} acceptPending={acceptPending} accept={accept} unaccept={unaccept} />;
const AcceptSolutionContainer = ({ accepted, acceptPending, accept, unaccept, ...props }) => {
return (
<AcceptSolution accepted={accepted} acceptPending={acceptPending} accept={accept} unaccept={unaccept} {...props} />
);
};

AcceptSolutionContainer.propTypes = {
Expand Down
8 changes: 6 additions & 2 deletions src/pages/AssignmentStats/AssignmentStats.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { Row, Col } from 'react-bootstrap';
import { connect } from 'react-redux';
import { injectIntl, FormattedMessage, FormattedNumber } from 'react-intl';
import { injectIntl, FormattedMessage, FormattedNumber, intlShape } from 'react-intl';
import { LinkContainer } from 'react-router-bootstrap';
import { Link } from 'react-router';
import { defaultMemoize } from 'reselect';
Expand Down Expand Up @@ -40,6 +40,7 @@ import DateTime from '../../components/widgets/DateTime';
import Points from '../../components/Assignments/SolutionsTable/Points';
import EnvironmentsListItem from '../../components/helpers/EnvironmentsList/EnvironmentsListItem';
import DeleteSolutionButtonContainer from '../../containers/DeleteSolutionButtonContainer/DeleteSolutionButtonContainer';
import AcceptSolutionContainer from '../../containers/AcceptSolutionContainer';

import { safeGet, identity } from '../../helpers/common';
import { createUserNameComparator } from '../../components/helpers/users';
Expand Down Expand Up @@ -161,6 +162,9 @@ const prepareTableColumnDescriptors = defaultMemoize((loggedUserId, assignmentId
<FormattedMessage id="generic.detail" defaultMessage="Detail" />
</Link>
)}
{solution.permissionHints && solution.permissionHints.setAccepted && (
<AcceptSolutionContainer id={solution.id} locale={locale} shortLabel bsSize="xs" />
)}
{solution.permissionHints && solution.permissionHints.delete && (
<DeleteSolutionButtonContainer id={solution.id} bsSize="xs" />
)}
Expand Down Expand Up @@ -442,7 +446,7 @@ AssignmentStats.propTypes = {
loadAsync: PropTypes.func.isRequired,
downloadBestSolutionsArchive: PropTypes.func.isRequired,
fetchManyStatus: PropTypes.string,
intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired,
intl: intlShape,
links: PropTypes.object.isRequired,
};

Expand Down
62 changes: 38 additions & 24 deletions src/redux/modules/solutions.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,37 +164,51 @@ const reducer = handleActions(
[additionalActionTypes.ACCEPT_REJECTED]: (state, { meta: { id } }) =>
state.setIn(['resources', id, 'data', 'accepted-pending'], false),

[additionalActionTypes.ACCEPT_FULFILLED]: (state, { meta: { id } }) =>
state.update('resources', resources =>
resources.map((item, itemId) =>
item.get('data') !== null
? item.update('data', data =>
itemId === id
? data.set('accepted', true).set('accepted-pending', false)
: data.set('accepted', false).set('accepted-pending', false)
)
: item
)
),
[additionalActionTypes.ACCEPT_FULFILLED]: (state, { meta: { id } }) => {
const assignmentId = state.getIn(['resources', id, 'data', 'exerciseAssignmentId']);
const userId = state.getIn(['resources', id, 'data', 'solution', 'userId']);
return !assignmentId || !userId
? state
: state
// Accepted solution needs to be updated
.updateIn(['resources', id, 'data'], data =>
data
.set('accepted', true)
.set('isBestSolution', true) // accepted also becomes best solution
.set('accepted-pending', false)
)
// All other solutions from the same assignment by the same author needs to be updated
.update('resources', resources =>
resources.map((item, itemId) => {
const aId = item.getIn(['data', 'exerciseAssignmentId']);
const uId = item.getIn(['data', 'solution', 'userId']);
return itemId === id || aId !== assignmentId || uId !== userId
? item // no modification (either it is accepted solution, or it is solution from another assignment/by another user)
: item.update('data', data => data.set('accepted', false).set('isBestSolution', false)); // no other solution can be accepted nor best
})
);
},

[additionalActionTypes.UNACCEPT_PENDING]: (state, { meta: { id } }) =>
state.setIn(['resources', id, 'data', 'accepted-pending'], true),

[additionalActionTypes.UNACCEPT_REJECTED]: (state, { meta: { id } }) =>
state.setIn(['resources', id, 'data', 'accepted-pending'], false),

[additionalActionTypes.UNACCEPT_FULFILLED]: (state, { meta: { id } }) =>
state.update('resources', resources =>
resources.map((item, itemId) =>
item.get('data') !== null
? item.update('data', data =>
itemId === id
? data.set('accepted', false).set('accepted-pending', false)
: data.set('accepted', true).set('accepted-pending', false)
)
: item
)
),
[additionalActionTypes.UNACCEPT_FULFILLED]: (state, { payload: { assignments }, meta: { id } }) => {
const assignmentId = state.getIn(['resources', id, 'data', 'exerciseAssignmentId']);
const assignmentStats = assignments.find(a => a.id === assignmentId);
const newBestSolutionId = assignmentStats && assignmentStats.bestSolutionId;
state = state.updateIn(['resources', id, 'data'], data =>
data
.set('accepted', false)
.set('isBestSolution', false)
.set('accepted-pending', false)
);
return newBestSolutionId && state.hasIn(['resources', newBestSolutionId, 'data', 'isBestSolution'])
? state.setIn(['resources', newBestSolutionId, 'data', 'isBestSolution'], true)
: state;
},

[submissionEvaluationActionTypes.REMOVE_FULFILLED]: (state, { meta: { solutionId, id: evaluationId } }) => {
if (!solutionId || !evaluationId) {
Expand Down

0 comments on commit 4fb72ea

Please sign in to comment.