Skip to content

Commit c6ba2cd

Browse files
committed
Fixing bugs, improving error reporting.
1 parent 08fdca5 commit c6ba2cd

File tree

3 files changed

+77
-16
lines changed

3 files changed

+77
-16
lines changed

src/helpers/groups.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
export const isExam = ({ privateData: { examBegin, examEnd } }) => {
1+
import { safeGet } from './common';
2+
3+
export const isExam = group => {
4+
const examBegin = safeGet(group, ['privateData', 'examBegin']);
5+
const examEnd = safeGet(group, ['privateData', 'examEnd']);
26
const now = Date.now() / 1000;
37
return examBegin && examEnd && examEnd > now && examBegin <= now;
48
};

src/pages/GroupExams/GroupExams.js

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,19 @@ import { groupExamLocksSelector } from '../../redux/selectors/groupExamLocks';
2525
import { lockedStudentsOfGroupSelector } from '../../redux/selectors/usersGroups';
2626
import { loggedInUserIdSelector } from '../../redux/selectors/auth';
2727
import { isLoggedAsSuperAdmin, loggedInUserSelector } from '../../redux/selectors/users';
28+
import { getJsData } from '../../redux/helpers/resourceManager';
2829

2930
import withLinks from '../../helpers/withLinks';
3031
import { hasPermissions, safeGet } from '../../helpers/common';
3132
import ResourceRenderer from '../../components/helpers/ResourceRenderer';
3233
import { isExam } from '../../helpers/groups';
3334

35+
const REFRESH_INTERVAL = 1; // [s]
36+
3437
class GroupExams extends Component {
38+
state = { examInProgress: false };
39+
intervalHandler = null;
40+
3541
static loadAsync = ({ groupId }, dispatch) =>
3642
Promise.all([
3743
dispatch(fetchGroupIfNeeded(groupId)).then(({ value: group }) =>
@@ -41,11 +47,31 @@ class GroupExams extends Component {
4147
),
4248
]);
4349

50+
static getDerivedStateFromProps({ group }) {
51+
const groupJs = getJsData(group);
52+
const examInProgress = Boolean(groupJs && isExam(groupJs));
53+
return { examInProgress };
54+
}
55+
56+
periodicRefresh = () => {
57+
const newState = GroupExams.getDerivedStateFromProps(this.props, this.state);
58+
if (newState.examInProgress !== this.state.examInProgress) {
59+
this.setState(newState);
60+
}
61+
};
62+
4463
componentDidMount() {
4564
this.props.loadAsync();
4665
if (this.props.params.examId) {
4766
this.props.loadGroupExamLocks();
4867
}
68+
69+
if (window && 'setInterval' in window) {
70+
if (this.intervalHandler) {
71+
window.clearInterval(this.intervalHandler);
72+
}
73+
this.intervalHandler = window.setInterval(this.periodicRefresh, REFRESH_INTERVAL * 1000);
74+
}
4975
}
5076

5177
componentDidUpdate(prevProps) {
@@ -57,6 +83,13 @@ class GroupExams extends Component {
5783
}
5884
}
5985

86+
componentWillUnmount() {
87+
if (this.intervalHandler) {
88+
window.clearInterval(this.intervalHandler);
89+
this.intervalHandler = null;
90+
}
91+
}
92+
6093
linkFactory = id => {
6194
const {
6295
params: { groupId, examId = null },
@@ -114,19 +147,19 @@ class GroupExams extends Component {
114147
unlimitedHeight>
115148
<GroupExamsTable
116149
exams={group.privateData.exams}
117-
selected={isExam(group) ? null : examId}
118-
linkFactory={isExam(group) ? null : this.linkFactory}
150+
selected={this.state.examInProgress ? null : examId}
151+
linkFactory={this.state.examInProgress ? null : this.linkFactory}
119152
/>
120153
</Box>
121154
</Col>
122155
</Row>
123156

124-
{(examId || isExam(group)) && hasPermissions(group, 'viewStudents', 'setExamPeriod') && (
157+
{(examId || this.state.examInProgress) && hasPermissions(group, 'viewStudents', 'setExamPeriod') && (
125158
<Row>
126159
<Col xs={12}>
127160
<Box
128161
title={
129-
isExam(group) ? (
162+
this.state.examInProgress ? (
130163
<FormattedMessage
131164
id="app.groupExams.studentsBoxTitle"
132165
defaultMessage="Participating students"
@@ -140,7 +173,7 @@ class GroupExams extends Component {
140173
}
141174
noPadding
142175
unlimitedHeight>
143-
{isExam(group) ? (
176+
{this.state.examInProgress ? (
144177
<LockedStudentsTable
145178
groupId={group.id}
146179
lockedStudents={lockedStudents}

src/pages/Login/Login.js

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ import PageContent from '../../components/layout/PageContent';
1212
import LoginForm from '../../components/forms/LoginForm';
1313
import ExternalLoginBox from '../../containers/ExternalLogin';
1414
import Callout from '../../components/widgets/Callout';
15+
import Button from '../../components/widgets/TheButton';
16+
import Icon from '../../components/icons';
1517

16-
import { login } from '../../redux/modules/auth';
18+
import { login, logout } from '../../redux/modules/auth';
1719
import { isLoggedIn, selectedInstanceId } from '../../redux/selectors/auth';
1820
import { loggedInUserSelector } from '../../redux/selectors/users';
21+
22+
import { getError } from '../../redux/helpers/resourceManager';
23+
1924
import { getConfigVar, getConfigVarLocalized } from '../../helpers/config';
2025
import { getErrorMessage } from '../../locales/apiErrorMessages';
2126

@@ -95,24 +100,41 @@ class Login extends Component {
95100
render() {
96101
const {
97102
isLoggedIn,
103+
loggedInUser,
104+
logout,
98105
params: { redirect = null },
99106
links: { RESET_PASSWORD_URI },
100-
intl: { locale },
107+
intl: { locale, formatMessage },
101108
} = this.props;
102109

103110
const external = EXTERNAL_AUTH_URL && EXTERNAL_AUTH_SERVICE_ID;
111+
const userError = getError(loggedInUser);
104112

105113
return (
106114
<PageContent icon="sign-in-alt" title={<FormattedMessage id="app.login.title" defaultMessage="Sign In" />}>
107115
<>
108116
{isLoggedIn ? (
109-
<Row>
110-
<Col sm={12}>
111-
<Callout variant="success">
112-
<FormattedMessage id="app.login.alreadyLoggedIn" defaultMessage="You are already logged in." />
113-
</Callout>
114-
</Col>
115-
</Row>
117+
userError ? (
118+
<Row>
119+
<Col sm={12}>
120+
<Callout variant="danger">
121+
<p>{getErrorMessage(formatMessage)(userError)}</p>
122+
<Button variant="danger" onClick={logout}>
123+
<Icon icon="sign-out-alt" gapRight />
124+
<FormattedMessage id="app.logout" defaultMessage="Logout" />
125+
</Button>
126+
</Callout>
127+
</Col>
128+
</Row>
129+
) : (
130+
<Row>
131+
<Col sm={12}>
132+
<Callout variant="success">
133+
<FormattedMessage id="app.login.alreadyLoggedIn" defaultMessage="You are already logged in." />
134+
</Callout>
135+
</Col>
136+
</Row>
137+
)
116138
) : (
117139
<>
118140
{redirect && (
@@ -171,13 +193,14 @@ class Login extends Component {
171193
}
172194

173195
Login.propTypes = {
174-
login: PropTypes.func.isRequired,
175196
params: PropTypes.shape({
176197
redirect: PropTypes.string,
177198
}),
178199
isLoggedIn: PropTypes.bool.isRequired,
179200
instanceId: PropTypes.string,
180201
loggedInUser: ImmutablePropTypes.map,
202+
login: PropTypes.func.isRequired,
203+
logout: PropTypes.func.isRequired,
181204
reset: PropTypes.func.isRequired,
182205
links: PropTypes.object.isRequired,
183206
intl: PropTypes.object,
@@ -193,6 +216,7 @@ export default withLinks(
193216
}),
194217
dispatch => ({
195218
login: ({ email, password }) => dispatch(login(email, password)),
219+
logout: () => dispatch(logout()),
196220
reset: () => {
197221
dispatch(reset('login'));
198222
},

0 commit comments

Comments
 (0)