Skip to content

Commit

Permalink
Merge pull request #275 from graasp/267/displayDataInClassrooms
Browse files Browse the repository at this point in the history
267/display data in classrooms
  • Loading branch information
pyphilia authored Jun 5, 2020
2 parents c79e909 + 044be2a commit bc1c052
Show file tree
Hide file tree
Showing 28 changed files with 1,976 additions and 232 deletions.
30 changes: 28 additions & 2 deletions public/app/listeners/editClassroom.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
const { EDIT_CLASSROOM_CHANNEL } = require('../config/channels');
const { ERROR_GENERAL } = require('../config/errors');
const { CLASSROOMS_COLLECTION } = require('../db');
const {
CLASSROOMS_COLLECTION,
SPACES_COLLECTION,
ACTIONS_COLLECTION,
APP_INSTANCE_RESOURCES_COLLECTION,
} = require('../db');
const logger = require('../logger');

const editClassroom = (mainWindow, db) => async (event, { name, id }) => {
const editClassroom = (mainWindow, db) => async (
event,
{ name, id, deleteSelection }
) => {
logger.debug('editing classroom');

try {
Expand All @@ -15,6 +23,24 @@ const editClassroom = (mainWindow, db) => async (event, { name, id }) => {
mainWindow.webContents.send(EDIT_CLASSROOM_CHANNEL, ERROR_GENERAL);
}

// delete selected space and their resources
Object.entries(deleteSelection).forEach(([spaceId, selected]) => {
if (selected) {
classroom
.get(SPACES_COLLECTION)
.remove({ id: spaceId })
.write();
classroom
.get(ACTIONS_COLLECTION)
.remove({ spaceId })
.write();
classroom
.get(APP_INSTANCE_RESOURCES_COLLECTION)
.remove({ spaceId })
.write();
}
});

// update data
const now = new Date();
classroom.assign({ name, updatedAt: now }).write();
Expand Down
32 changes: 24 additions & 8 deletions public/app/listeners/editUserInClassroom.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
const { EDIT_USER_IN_CLASSROOM_CHANNEL } = require('../config/channels');
const { ERROR_GENERAL } = require('../config/errors');
const { CLASSROOMS_COLLECTION, USERS_COLLECTION } = require('../db');
const {
CLASSROOMS_COLLECTION,
USERS_COLLECTION,
ACTIONS_COLLECTION,
APP_INSTANCE_RESOURCES_COLLECTION,
} = require('../db');
const logger = require('../logger');

/**
* @param {Object<string,boolean>} deleteSelection : object mapping space id to whether the space data should be deleted
*/
const editUserInClassroom = (mainWindow, db) => async (
event,
{ username, userId, classroomId }
{ username, userId, classroomId, deleteSelection }
) => {
logger.debug('editing user in classroom');

try {
const user = db
.get(CLASSROOMS_COLLECTION)
.find({ id: classroomId })
.get(USERS_COLLECTION)
.find({ id: userId });
const classroom = db.get(CLASSROOMS_COLLECTION).find({ id: classroomId });

const user = classroom.get(USERS_COLLECTION).find({ id: userId });

// check user exists
const found = user.value();
Expand All @@ -25,9 +31,19 @@ const editUserInClassroom = (mainWindow, db) => async (
);
}

// delete space data related to user if selected
const actions = classroom.get(ACTIONS_COLLECTION);
const resources = classroom.get(APP_INSTANCE_RESOURCES_COLLECTION);
Object.entries(deleteSelection).forEach(([spaceId, selected]) => {
if (selected) {
actions.remove({ spaceId, user: userId }).write();
resources.remove({ spaceId, user: userId }).write();
}
});

// update data
const now = new Date();
user.assign({ username, lastUpdatedAt: now }).write();
user.assign({ username, updatedAt: now }).write();

mainWindow.webContents.send(EDIT_USER_IN_CLASSROOM_CHANNEL);
} catch (err) {
Expand Down
40 changes: 31 additions & 9 deletions public/app/listeners/loadSpaceInClassroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,35 @@ const loadSpaceInClassroom = (mainWindow, db) => async (
try {
const classroom = db.get(CLASSROOMS_COLLECTION).find({ id: classroomId });

// add user if doesn't exist
let user = classroom
.get(USERS_COLLECTION)
.find({ username })
.value();
if (!user) {
user = addUserInClassroomDatabase(db, { username, id: classroomId });
// username should be defined if add resources or actions
if (isResourcesSelected || isActionsSelected) {
if (!username) {
logger.debug('username not specified');
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
ERROR_GENERAL
);
}
}

// add user
let user = null;
if (username) {
user = classroom
.get(USERS_COLLECTION)
.find({ username })
.value();
if (!user) {
try {
user = addUserInClassroomDatabase(db, { username, id: classroomId });
} catch (err) {
logger.debug(err);
return mainWindow.webContents.send(
LOAD_SPACE_IN_CLASSROOM_CHANNEL,
err
);
}
}
}

// todo: check teacher can write in classroom
Expand Down Expand Up @@ -101,8 +123,6 @@ const loadSpaceInClassroom = (mainWindow, db) => async (
clean(extractPath);
}

const { id: userId } = user;

// write resources to database if selected
if (isResourcesSelected) {
if (_.isEmpty(appInstanceResources)) {
Expand All @@ -113,6 +133,7 @@ const loadSpaceInClassroom = (mainWindow, db) => async (
);
}

const { id: userId } = user;
const savedResources = classroom.get(APP_INSTANCE_RESOURCES_COLLECTION);

// remove previous corresponding resources
Expand All @@ -138,6 +159,7 @@ const loadSpaceInClassroom = (mainWindow, db) => async (
);
}

const { id: userId } = user;
const savedActions = classroom.get(ACTIONS_COLLECTION);

// remove previous corresponding actions
Expand Down
25 changes: 19 additions & 6 deletions src/actions/classroom.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import {
} from '../types';
import {
ERROR_GENERAL,
ERROR_ACCESS_DENIED_CLASSROOM,
ERROR_DUPLICATE_CLASSROOM_NAME,
ERROR_LOADING_MESSAGE,
ERROR_INVALID_USERNAME,
ERROR_DUPLICATE_USERNAME_IN_CLASSROOM,
ERROR_NO_USER_TO_DELETE,
Expand Down Expand Up @@ -67,6 +67,8 @@ import {
ERROR_GETTING_SPACE_IN_CLASSROOM_MESSAGE,
ERROR_INVALID_USERNAME_MESSAGE,
SUCCESS_SPACE_LOADED_MESSAGE,
ERROR_LOADING_MESSAGE,
ERROR_ACCESS_DENIED_CLASSROOM_MESSAGE,
} from '../config/messages';
import { createFlag } from './common';
import { createExtractFile, createClearLoadSpace } from './loadSpace';
Expand All @@ -88,10 +90,14 @@ export const getClassrooms = () => dispatch => {
// create listener
window.ipcRenderer.once(GET_CLASSROOMS_CHANNEL, (event, classrooms) => {
// dispatch that the getter has succeeded
dispatch({
type: GET_CLASSROOMS_SUCCEEDED,
payload: classrooms,
});
if (classrooms === ERROR_ACCESS_DENIED_CLASSROOM) {
toastr.error(ERROR_MESSAGE_HEADER, ERROR_ACCESS_DENIED_CLASSROOM_MESSAGE);
} else {
dispatch({
type: GET_CLASSROOMS_SUCCEEDED,
payload: classrooms,
});
}
dispatch(flagGettingClassrooms(false));
});
};
Expand All @@ -110,6 +116,12 @@ export const getClassroom = async payload => async dispatch => {
}

switch (response) {
case ERROR_ACCESS_DENIED_CLASSROOM:
toastr.error(
ERROR_MESSAGE_HEADER,
ERROR_ACCESS_DENIED_CLASSROOM_MESSAGE
);
break;
case ERROR_GENERAL:
toastr.error(ERROR_MESSAGE_HEADER, ERROR_GETTING_CLASSROOM_MESSAGE);
break;
Expand Down Expand Up @@ -206,7 +218,8 @@ export const editClassroom = payload => dispatch => {
if (response === ERROR_GENERAL) {
toastr.error(ERROR_MESSAGE_HEADER, ERROR_EDITING_CLASSROOM_MESSAGE);
} else {
// update saved classrooms in state
// update saved classrooms and current classroom in state
dispatch(getClassroom(payload));
dispatch(getClassrooms());

toastr.success(SUCCESS_MESSAGE_HEADER, SUCCESS_EDITING_CLASSROOM_MESSAGE);
Expand Down
36 changes: 20 additions & 16 deletions src/components/classrooms/AddClassroomButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/Button';
import { withTranslation } from 'react-i18next';
import TextField from '@material-ui/core/TextField';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import { addClassroom } from '../../actions';
import {
ADD_CLASSROOM_BUTTON_ID,
ADD_CLASSROOM_NAME_INPUT_ID,
ADD_CLASSROOM_VALIDATE_BUTTON_ID,
ADD_CLASSROOM_CANCEL_BUTTON_ID,
} from '../../config/selectors';
import ClassroomNameTextField from './ClassroomNameTextField';

const styles = theme => ({
fab: {
Expand All @@ -41,18 +40,25 @@ class AddClassroomButton extends Component {

state = (() => {
const { t } = this.props;
const defaultName = t('New Classroom');
return {
open: false,
name: t('New Classroom'),
name: defaultName,
};
})();

isClassroomNameValid = () => {
const { name } = this.state;
// todo: check for special characters
return name.trim().length;
};

handleClickOpen = () => {
this.setState({ open: true });
};

close = () => {
this.setState({ name: '', open: false });
this.setState({ open: false });
};

handleCancel = () => {
Expand All @@ -62,11 +68,14 @@ class AddClassroomButton extends Component {
handleValidate = () => {
const { name } = this.state;
const { userId, dispatchAddClassroom } = this.props;
dispatchAddClassroom({ name, userId });
this.close();
if (this.isClassroomNameValid()) {
const trimmedName = name.trim();
dispatchAddClassroom({ name: trimmedName, userId });
this.close();
}
};

handleChange = event => {
handleNameChange = event => {
const { target } = event;
this.setState({ name: target.value });
};
Expand Down Expand Up @@ -96,15 +105,9 @@ class AddClassroomButton extends Component {
{t('Enter a name for your new classroom')}
</DialogTitle>
<DialogContent>
<TextField
id={ADD_CLASSROOM_NAME_INPUT_ID}
autoFocus
margin="dense"
label={t("Classroom's Name")}
type="text"
fullWidth
value={name}
onChange={this.handleChange}
<ClassroomNameTextField
name={name}
handleChange={this.handleNameChange}
/>
</DialogContent>
<DialogActions>
Expand All @@ -119,6 +122,7 @@ class AddClassroomButton extends Component {
onClick={this.handleValidate}
color="primary"
id={ADD_CLASSROOM_VALIDATE_BUTTON_ID}
disabled={!this.isClassroomNameValid()}
>
{t('Validate')}
</Button>
Expand Down
43 changes: 43 additions & 0 deletions src/components/classrooms/ClassroomNameTextField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import TextField from '@material-ui/core/TextField';
import { CLASSROOM_NAME_INPUT_ID } from '../../config/selectors';
import { isClassroomNameValid } from '../../utils/classroom';

const ClassroomNameTextField = ({ name, t, handleChange }) => {
const isValid = isClassroomNameValid(name);
let errorProps = {};
if (!isValid) {
errorProps = {
...errorProps,
helperText: t(`Classroom's name is not valid`),
error: true,
};
}

return (
<TextField
id={CLASSROOM_NAME_INPUT_ID}
autoFocus
margin="dense"
label={t("Classroom's Name")}
type="text"
fullWidth
value={name}
onChange={handleChange}
// eslint-disable-next-line react/jsx-props-no-spreading
{...errorProps}
/>
);
};

ClassroomNameTextField.propTypes = {
name: PropTypes.string.isRequired,
handleChange: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
};

const TranslatedComponent = withTranslation()(ClassroomNameTextField);

export default TranslatedComponent;
Loading

0 comments on commit bc1c052

Please sign in to comment.