Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Darien classrooms table #74

Merged
merged 7 commits into from
Oct 24, 2017
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 1 addition & 19 deletions src/components/classrooms/ClassroomsManager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
} from '../../ducks/classrooms';

import ClassroomFormContainer from '../../containers/classrooms/ClassroomFormContainer';
import ConfirmationDialog from '../common/ConfirmationDialog';
import ClassroomsTableContainer from '../../containers/classrooms/ClassroomsTableContainer';

const ClassroomsManager = (props) => {
Expand All @@ -24,14 +23,6 @@ const ClassroomsManager = (props) => {
<Paragraph align="start" size="small">{props.classroomInstructions}</Paragraph>
<Button type="button" primary={true} label="Create New Classroom" onClick={props.toggleFormVisibility} />
</Box>
<ConfirmationDialog
confirmationButtonLabel="Delete"
onConfirmation={props.deleteClassroom}
onClose={props.closeConfirmationDialog}
showConfirmationDialog={props.showConfirmationDialog}
>
<Paragraph size="small">Deleting a classroom will also delete the associated assignments.</Paragraph>
</ConfirmationDialog>
{props.showForm &&
<Layer closer={true} onClose={props.toggleFormVisibility}>
<ClassroomFormContainer heading="Create Classroom" submitLabel="Create" />
Expand All @@ -43,29 +34,20 @@ const ClassroomsManager = (props) => {
{props.classrooms.length === 0 && props.classroomsStatus === CLASSROOMS_STATUS.ERROR &&
<Paragraph>Error: Classrooms could not be loaded.</Paragraph>}
{(props.classrooms.length > 0 && props.classroomsStatus === CLASSROOMS_STATUS.SUCCESS) &&
<ClassroomsTableContainer
maybeDeleteClassroom={props.maybeDeleteClassroom}
match={props.match}
/>}
<ClassroomsTableContainer match={props.match} />}
</Box>
);
};

ClassroomsManager.defaultProps = {
classroomInstructions: 'First, make sure your students have set up a Zooniverse account. Then create a classroom and share the classroom\'s unique join URL with your students to keep track of their progress as they work through each assignment. Students must be logged in to their Zooniverse accounts first to be able to use the join link. Share the URL under View Project with your students for them to complete the assignment.',
closeConfirmationDialog: () => {},
deleteClassroom: () => {},
maybeDeleteClassroom: () => {},
showForm: false,
toggleFormVisibility: Actions.classrooms.toggleFormVisibility,
...CLASSROOMS_INITIAL_STATE
};

ClassroomsManager.propTypes = {
classroomInstructions: PropTypes.string,
closeConfirmationDialog: PropTypes.func,
deleteClassroom: PropTypes.func,
maybeDeleteClassroom: PropTypes.func,
showForm: PropTypes.bool,
toggleFormVisibility: PropTypes.func,
...CLASSROOMS_PROPTYPES
Expand Down
170 changes: 170 additions & 0 deletions src/components/darien/DarienClassroomsTable.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Actions } from 'jumpstate';
import CopyToClipboard from 'react-copy-to-clipboard';
import Box from 'grommet/components/Box';
import Table from 'grommet/components/Table';
import TableRow from 'grommet/components/TableRow';
import AddIcon from 'grommet/components/icons/base/Add';
import EditIcon from 'grommet/components/icons/base/Edit';
import CloseIcon from 'grommet/components/icons/base/Close';
import Anchor from 'grommet/components/Anchor';
import Button from 'grommet/components/Button';
import Paragraph from 'grommet/components/Paragraph';
import Spinning from 'grommet/components/icons/Spinning';
import Timestamp from 'grommet/components/Timestamp';

import { config } from '../../lib/config';
import {
ASSIGNMENTS_STATUS, ASSIGNMENTS_INITIAL_STATE, ASSIGNMENTS_PROPTYPES
} from '../../ducks/assignments';
import {
CLASSROOMS_INITIAL_STATE, CLASSROOMS_PROPTYPES
} from '../../ducks/classrooms';

const DarienClassroomsTable = (props) => {
return (
<Box>
<Table className="manager-table">
<thead className="manager-table__headers">
<TableRow>
<th id="assignments" scope="col" className="manager-table__caption">Your Classrooms</th>
<th id="completed" scope="col" className="headers__header">Completed</th>
<th id="export" scope="col" className="headers__header">Due Date</th>
<th id="view-project" scope="col" className="headers__header">View Project</th>
</TableRow>
</thead>
{props.classrooms.map((classroom) => {
// TODO update URL once we have staging/production hosts

const joinURL = `${window.location.host}/#/${props.selectedProgram.slug}/students/classrooms/${classroom.id}/join?token=${classroom.joinToken}`;
// Can we get linked assignments with classrooms in single get request?
// No, if we want this, then we need to open an issue with the API
// TODO replace classifications_target with calculated percentage

// The trailing slash is inconsistent in React Router 4's match.url property...
const editURL = (props.match.url[props.match.url.length - 1] === '/') ? props.match.url : `${props.match.url}/`;
return (
<tbody className="manager-table__body" key={classroom.id}>
<TableRow>
<th className="manager-table__row-header" id="classroom" colSpan="4" scope="colgroup">
<Box pad="none" margin="none" justify="between" direction="row">
<span>
<Button
className="manager-table__button--edit"
path={`${editURL}classrooms/${classroom.id}`}
onClick={() => { Actions.classrooms.selectClassroom(classroom); }}
icon={<EditIcon size="small" />}
/>
{' '}{classroom.name}{' '}
<CopyToClipboard text={joinURL} onCopy={() => { Actions.classrooms.setToastState({ status: 'ok', message: 'Copied join link.' }); }}>
<Button type="button" className="manager-table__button--as-link" plain={true} onClick={() => {}}>
Copy Join Link
</Button>
</CopyToClipboard>
</span>
<Button
className="manager-table__button--delete"
type="button"
onClick={props.maybeDeleteClassroom.bind(null, classroom.id)}
>
<CloseIcon size="small" />
</Button>
</Box>
</th>
</TableRow>
{((props.assignments[classroom.id] &&
props.assignments[classroom.id].length === 0 &&
props.assignmentsStatus === ASSIGNMENTS_STATUS.FETCHING) ||
(Object.keys(props.assignments).length === 0 &&
props.assignmentsStatus === ASSIGNMENTS_STATUS.FETCHING)) &&
<TableRow className="manager-table__row-data">
<td colSpan="4"><Spinning /></td>
</TableRow>}
{(props.assignments[classroom.id] &&
props.assignments[classroom.id].length === 0 &&
props.assignmentsStatus === ASSIGNMENTS_STATUS.SUCCESS) &&
<TableRow className="manager-table__row-data">
<td colSpan="4">
<Box pad="none" margin="none" justify="between" direction="row">
<Paragraph>No assignments have been created yet.</Paragraph>
<Button
className="manager-table__button--create"
onClick={props.toggleAssignmentForm}
type="button"
>
<AddIcon size="small" />
</Button>
</Box>
</td>
</TableRow>}
{(props.assignments[classroom.id] &&
props.assignmentsStatus === ASSIGNMENTS_STATUS.SUCCESS) &&
props.assignments[classroom.id].map((assignment) => {
return (
<TableRow className="manager-table__row-data" key={assignment.id}>
<td headers="classroom assignments">
{assignment.name}
<Button
className="manager-table__button--edit"
onClick={props.toggleAssignmentForm}
icon={<EditIcon size="small" />}
/>
</td>
<td headers="classroom completed">
{(assignment.metadata && assignment.metadata.classifications_target) ?
assignment.metadata.classifications_target : ''}
</td>
<td headers="classroom export">
<Timestamp value={assignment.metadata.duedate} />
</td>
<td headers="classroom view-project">
<Anchor
className="manager-table__link"
href={`${config.zooniverse}/projects/wildcam/wildcam-darien/classify?workflow=${assignment.workflow_id}`}
target="_blank"
rel="noopener noreferrer"
>
Project Page{' '}
<i className="fa fa-mail-forward" aria-hidden="true" />
<Button
className="manager-table__button--delete"
type="button"
onClick={props.maybeDeleteAssignment.bind(null, assignment.id)}
>
<CloseIcon size="small" />
</Button>
</Anchor>
</td>
</TableRow>
);
})}
</tbody>
);
})}
</Table>
</Box>
);
};

DarienClassroomsTable.defaultProps = {
closeConfirmationDialog: () => {},
maybeDeleteAssignment: () => {},
maybeDeleteClassroom: () => {},
selectClassroom: () => {},
toggleAssignmentForm: () => {},
...CLASSROOMS_INITIAL_STATE,
...ASSIGNMENTS_INITIAL_STATE
};

DarienClassroomsTable.propTypes = {
closeConfirmationDialog: PropTypes.func,
maybeDeleteAssignment: PropTypes.func,
maybeDeleteClassroom: PropTypes.func,
selectClassroom: PropTypes.func,
toggleAssignmentForm: PropTypes.func,
...CLASSROOMS_PROPTYPES,
...ASSIGNMENTS_PROPTYPES
};

export default DarienClassroomsTable;
2 changes: 1 addition & 1 deletion src/components/darien/DarienHome.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class DarienHome extends React.Component {
<Paragraph>Are you an educator or a student/explorer? Make your selection to get started!</Paragraph>
</Box>
<Box align="center" direction="row" justify="between" pad="medium" size="medium">
<Button path="/wildcam-darien-lab/eduactors/" label="Educator" />
<Button path="/wildcam-darien-lab/educators/" label="Educator" />
<Button path="/wildcam-darien-lab/students/" label="Explorer" />
</Box>
</Section>
Expand Down
47 changes: 47 additions & 0 deletions src/containers/astro/AstroClassroomTableContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { Actions } from 'jumpstate';
import AstroClassroomsTable from '../../components/astro/AstroClassroomsTable';

class AstroClassroomsTableContainer extends React.Component {
constructor() {
super();

this.state = {
toExport: {
assignment: {},
classroom: {}
}
};

this.onExportModalClose = this.onExportModalClose.bind(this);
this.showExportModal = this.showExportModal.bind(this);
}

onExportModalClose() {
this.setState({ toExport: { assignment: {}, classroom: {} } });

Actions.caesarExports.showModal();
}

showExportModal(assignment, classroom) {
this.setState({ toExport: { assignment, classroom } });

Actions.caesarExports.showModal();
Actions.getCaesarExport({ assignment, classroom });
}

render() {
return (
<AstroClassroomsTable
{...this.props}
assignmentToExport={this.state.toExport.assignment}
onExportModalClose={this.onExportModalClose}
showExportModal={this.showExportModal}
>
{this.props.children}
</AstroClassroomsTable>
);
}
}

export default AstroClassroomsTableContainer;
47 changes: 47 additions & 0 deletions src/containers/astro/AstroClassroomsTableContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { Actions } from 'jumpstate';
import AstroClassroomsTable from '../../components/astro/AstroClassroomsTable';

class AstroClassroomsTableContainer extends React.Component {
constructor() {
super();

this.state = {
toExport: {
assignment: {},
classroom: {}
}
};

this.onExportModalClose = this.onExportModalClose.bind(this);
this.showExportModal = this.showExportModal.bind(this);
}

onExportModalClose() {
this.setState({ toExport: { assignment: {}, classroom: {} } });

Actions.caesarExports.showModal();
}

showExportModal(assignment, classroom) {
this.setState({ toExport: { assignment, classroom } });

Actions.caesarExports.showModal();
Actions.getCaesarExport({ assignment, classroom });
}

render() {
return (
<AstroClassroomsTable
{...this.props}
assignmentToExport={this.state.toExport.assignment}
onExportModalClose={this.onExportModalClose}
showExportModal={this.showExportModal}
>
{this.props.children}
</AstroClassroomsTable>
);
}
}

export default AstroClassroomsTableContainer;
3 changes: 1 addition & 2 deletions src/containers/classrooms/ClassroomFormContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class ClassroomFormContainer extends React.Component {
const assignments = this.props.selectedProgram.metadata.assignments;
if (classroom) this.autoCreateAssignments(assignments, classroom);
}
})
}).then(Actions.classrooms.toggleFormVisibility());
}

updateClassroom() {
Expand Down Expand Up @@ -94,7 +94,6 @@ export class ClassroomFormContainer extends React.Component {

Actions.createAssignment(assignmentData);
})).then(() => {
Actions.classrooms.toggleFormVisibility();
Actions.getClassroomsAndAssignments(this.props.selectedProgram);
});
}
Expand Down
Loading