Skip to content

Commit

Permalink
Creating group exam notification bar with locking button.
Browse files Browse the repository at this point in the history
  • Loading branch information
krulis-martin committed Mar 31, 2024
1 parent 9d8f997 commit 7497ab5
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 4 deletions.
149 changes: 149 additions & 0 deletions src/components/Groups/GroupExamPending/GroupExamPending.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl } from 'react-intl';
import { Modal } from 'react-bootstrap';

Check failure on line 4 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'Modal' is defined but never used

import ExamForm, {

Check failure on line 6 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'ExamForm' is defined but never used
prepareInitValues as prepareExamInitValues,

Check failure on line 7 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'prepareExamInitValues' is defined but never used
transformSubmittedData as transformExamData,

Check failure on line 8 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'transformExamData' is defined but never used
} from '../../forms/ExamForm';
import Button, { TheButtonGroup } from '../../widgets/TheButton';

Check failure on line 10 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'Button' is defined but never used

Check failure on line 10 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'TheButtonGroup' is defined but never used
import Callout from '../../widgets/Callout';
import Icon, { BanIcon, ClockIcon, EditIcon, GroupExamsIcon, LoadingIcon } from '../../icons';

Check failure on line 12 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'Icon' is defined but never used

Check failure on line 12 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'BanIcon' is defined but never used

Check failure on line 12 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'EditIcon' is defined but never used

Check failure on line 12 in src/components/Groups/GroupExamPending/GroupExamPending.js

View workflow job for this annotation

GitHub Actions / lint (18)

'LoadingIcon' is defined but never used
import DateTime from '../../widgets/DateTime';
import Explanation from '../../widgets/Explanation';
import { getErrorMessage } from '../../../locales/apiErrorMessages';

import { hasPermissions } from '../../../helpers/common';

const REFRESH_INTERVAL = 1; // [s]

class GroupExamPending extends Component {
state = {};
intervalHandler = null;

static getDerivedStateFromProps({ privateData: { examBegin, examEnd } }, state) {
const now = Date.now() / 1000;
const isExam = examBegin && examEnd && examEnd > now && examBegin <= now;
const nextChange = isExam ? examEnd - now : null;
const changeImminent = nextChange && nextChange <= 5; // s
return { isExam, changeImminent };
}

periodicRefresh = () => {
if (!this.props.archived) {
this.setState(GroupExamPending.getDerivedStateFromProps(this.props, this.state));
}
};

componentDidMount() {
if (!this.props.archived && window && 'setInterval' in window) {
if (this.intervalHandler) {
window.clearInterval(this.intervalHandler);
}
this.intervalHandler = window.setInterval(this.periodicRefresh, REFRESH_INTERVAL * 1000);
}
}

componentWillUnmount() {
if (this.intervalHandler) {
window.clearInterval(this.intervalHandler);
this.intervalHandler = null;
}
}

render() {
const {
privateData: { examBegin, examEnd, examLockStrict },
currentUser,
} = this.props;

//console.log(currentUser);
return (
this.state.isExam && (
<Callout
variant={this.state.examInProgress ? 'danger' : this.state.hasExam ? 'warning' : 'secondary'}
icon={
this.state.examInProgress ? (
<GroupExamsIcon className="fa-beat" />
) : this.state.hasExam ? (
<ClockIcon />
) : null
}>
TODO
{this.state.hasExam && (
<table>
<tbody>
<tr>
<td className="text-bold p-2">
<FormattedMessage id="app.groupExams.beginAt" defaultMessage="Begins at" />:
</td>
<td>
<DateTime unixts={examBegin} showRelative />
</td>
</tr>
<tr>
<td className="text-bold p-2">
<FormattedMessage id="app.groupExams.endAt" defaultMessage="Ends at" />:
</td>
<td>
<DateTime unixts={examEnd} showRelative />
</td>
</tr>
<tr>
<td className="text-bold p-2">
<FormattedMessage id="app.groupExams.locking" defaultMessage="Lock type" />:
</td>
<td>
<em>
{examLockStrict ? (
<FormattedMessage id="app.groupExams.lockStrict" defaultMessage="strict" />
) : (
<FormattedMessage id="app.groupExams.lockRegular" defaultMessage="regular" />
)}
</em>
<Explanation
id="lock-explain"
title={
examLockStrict ? (
<FormattedMessage id="app.groupExams.lockStrictTitle" defaultMessage="Strict lock" />
) : (
<FormattedMessage id="app.groupExams.lockRegularTitle" defaultMessage="Regular lock" />
)
}>
{examLockStrict ? (
<FormattedMessage
id="app.groupExams.lockStrictExplanation"
defaultMessage="Users taking the exam will not be allowed to access any other group, not even for reading (so thet are cut of source codes they submitted before the exam)."
/>
) : (
<FormattedMessage
id="app.groupExams.lockRegularExplanation"
defaultMessage="Users taking the exam will be able to access other groups in read-only mode (for instance to utilize pieces of previously submitted code)."
/>
)}
</Explanation>
</td>
</tr>
</tbody>
</table>
)}
</Callout>
)
);
}
}

GroupExamPending.propTypes = {
privateData: PropTypes.shape({
examBegin: PropTypes.number,
examEnd: PropTypes.number,
examLockStrict: PropTypes.bool,
}).isRequired,
archived: PropTypes.bool,
currentUser: PropTypes.object,
//addNotification: PropTypes.func.isRequired,
intl: PropTypes.object,
};

export default injectIntl(GroupExamPending);
2 changes: 2 additions & 0 deletions src/components/Groups/GroupExamPending/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import GroupExamPending from './GroupExamPending';
export default GroupExamPending;
14 changes: 10 additions & 4 deletions src/pages/GroupExams/GroupExams.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import { formValueSelector } from 'redux-form';
import Page from '../../components/layout/Page';
import { GroupNavigation } from '../../components/layout/Navigation';
import Box from '../../components/widgets/Box';
import GroupArchivedWarning from '../../components/Groups/GroupArchivedWarning/GroupArchivedWarning';
import GroupArchivedWarning from '../../components/Groups/GroupArchivedWarning';
import GroupExamPending from '../../components/Groups/GroupExamPending';
import { GroupExamsIcon } from '../../components/icons';

import { fetchGroup, fetchGroupIfNeeded, setExamPeriod, removeExamPeriod } from '../../redux/modules/groups';
import { addNotification } from '../../redux/modules/notifications';
import { groupSelector, groupDataAccessorSelector, groupTypePendingChange } from '../../redux/selectors/groups';
import { loggedInUserIdSelector } from '../../redux/selectors/auth';
import { isLoggedAsSuperAdmin } from '../../redux/selectors/users';
import { isLoggedAsSuperAdmin, loggedInUserSelector } from '../../redux/selectors/users';

import withLinks from '../../helpers/withLinks';
import GroupExamStatus from '../../components/Groups/GroupExamStatus';
Expand All @@ -35,6 +36,7 @@ class GroupExams extends Component {
render() {
const {
group,
currentUser,
groupsAccessor,
examBeginImmediately,
examEndRelative,
Expand All @@ -46,15 +48,17 @@ class GroupExams extends Component {

return (
<Page
resource={group}
resource={[group, currentUser]}
icon={<GroupExamsIcon />}
title={<FormattedMessage id="app.groupExams.title" defaultMessage="Group Exam Terms" />}>
{group => (
{(group, currentUser) => (
<div>
<GroupNavigation group={group} />

<GroupArchivedWarning {...group} groupsDataAccessor={groupsAccessor} linkFactory={GROUP_EDIT_URI_FACTORY} />

<GroupExamPending {...group} currentUser={currentUser} />

<Row>
<Col xs={12} xl={6}>
<GroupExamStatus
Expand Down Expand Up @@ -97,6 +101,7 @@ GroupExams.propTypes = {
groupId: PropTypes.string.isRequired,
}).isRequired,
group: ImmutablePropTypes.map,
currentUser: ImmutablePropTypes.map,
groupsAccessor: PropTypes.func.isRequired,
isSuperAdmin: PropTypes.bool,
examBeginImmediately: PropTypes.bool,
Expand All @@ -115,6 +120,7 @@ export default withLinks(
group: groupSelector(state, groupId),
groupsAccessor: groupDataAccessorSelector(state),
userId: loggedInUserIdSelector(state),
currentUser: loggedInUserSelector(state),
isSuperAdmin: isLoggedAsSuperAdmin(state),
examBeginImmediately: examFormSelector(state, 'beginImmediately'),
examEndRelative: examFormSelector(state, 'endRelative'),
Expand Down

0 comments on commit 7497ab5

Please sign in to comment.