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 & Assignments Mk2 - Part 1 #107

Merged
merged 10 commits into from
Dec 8, 2017
11 changes: 11 additions & 0 deletions src/components/darien/Darien401.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import GenericStatusPage from '../../components/common/GenericStatusPage';

const Darien401 = (props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been switching to writing functional components using declaration rather than expression: function MyComponent() {}. React will correctly use the function name as the component display name this way. For some reason, React won't use it if it's an expression. It really helps with debugging using the React Dev Tools to see the correct names.

return (
<GenericStatusPage status="warning" message="Please login to view this page." />
);
};

export default Darien401;
11 changes: 11 additions & 0 deletions src/components/darien/Darien404.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import GenericStatusPage from '../../components/common/GenericStatusPage';

const Darien404 = (props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about declaration vs expression for ease of debugging purposes.

return (
<GenericStatusPage status="warning" message="Page not found." />
);
};

export default Darien404;
14 changes: 14 additions & 0 deletions src/components/darien/DarienEducators.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';
import PropTypes from 'prop-types';
import ClassroomsLayout from '../classrooms/ClassroomsLayout';

const DarienEducators = (props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about declaration.

return (
<ClassroomsLayout match={props.match} />
);
};

DarienEducators.defaultProps = {};
DarienEducators.propTypes = {};

export default DarienEducators;
85 changes: 47 additions & 38 deletions src/components/darien/DarienHome.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Actions } from 'jumpstate';

import Section from 'grommet/components/Section';
import Box from 'grommet/components/Box';
Expand All @@ -9,6 +10,7 @@ import Image from 'grommet/components/Image';
import Heading from 'grommet/components/Heading';
import Button from 'grommet/components/Button';
import Paragraph from 'grommet/components/Paragraph';
import Label from 'grommet/components/Label';

import ProgramHome from '../common/ProgramHome';
import NeedHelp from '../common/NeedHelp';
Expand All @@ -17,47 +19,54 @@ import {
PROGRAMS_INITIAL_STATE, PROGRAMS_PROPTYPES, PROGRAMS_STATUS
} from '../../ducks/programs';

class DarienHome extends React.Component {
constructor(props) {
super(props);
}
const DarienHome = (props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about using declaration.

const signedIn = (props.user && props.initialised);
const selectedProgramExists = (props.programsStatus === PROGRAMS_STATUS.SUCCESS && props.selectedProgram);
const name = (selectedProgramExists && props.selectedProgram.name) ? props.selectedProgram.name : '';

render() {
const selectedProgramExists = (this.props.programsStatus === PROGRAMS_STATUS.SUCCESS && this.props.selectedProgram);
const name = (selectedProgramExists && this.props.selectedProgram.name) ? this.props.selectedProgram.name : '';

return (
<ProgramHome className="darien-home">
<Hero
className="program-home__hero"
background={<Image src="https://placeimg.com/1000/1000/nature/any" fit="cover" />}
backgroundColorIndex="dark"
size="medium"
>
<Box align="center"><Heading className="program-home__header">{name}</Heading></Box>
</Hero>
<Section
className="program-home__section"
align="center"
colorIndex="accent-3"
direction="column"
margin={{ vertical: 'none', horizontal: 'none' }}
pad={{ vertical: 'none', horizontal: 'none' }}
justify="center"
>
<Box align="center" direction="column">
<Paragraph>Investigate ecological questions by exploring trail camera data using an interactive map. Filter and download data to perform analyses and test hypotheses. If you are an educator, you can set up private classrooms and invite your students to join. Curate data sets or let your students explore on their own. Guided activities and supporting educational resources are also available. If you are a student or you simply want to explore the data, click the Explorer button.</Paragraph>
<Paragraph>Are you an educator or a student/explorer? Make your selection to get started!</Paragraph>
return (
<ProgramHome className="darien-home">
<Hero
className="program-home__hero"
background={<Image src="https://placeimg.com/1000/1000/nature/any" fit="cover" />}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Darien team might want to pick an actual background image here rather than use this placeholder. Maybe something from the project?

I put the string for the background source into the program metadata for I2A just so it's consistent with referencing everything about the program from the database. Just so you know, the controllers for update hasn't been done for programs on the API, so you have to ask for someone update it via the Rails console.

backgroundColorIndex="dark"
size="medium"
>
<Box align="center"><Heading className="program-home__header">{name}</Heading></Box>
</Hero>
<Section
className="program-home__section"
align="center"
colorIndex="accent-3"
direction="column"
margin={{ vertical: 'none', horizontal: 'none' }}
pad={{ vertical: 'none', horizontal: 'none' }}
justify="center"
>
<Box align="center" direction="column">
<Paragraph>Investigate ecological questions by exploring trail camera data using an interactive map. Filter and download data to perform analyses and test hypotheses.</Paragraph>

<Box pad="medium" size="medium">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a minor styling comment, but perhaps the Box should be defined as a bigger size to allow for the paragraphs to be displaying inline? Even with a fairly high resolution screen, I still have to scroll to see both options for the lab to get started.

<Paragraph>If you are an educator, you can set up private classrooms and invite your students to join. Curate data sets or let your students explore on their own. Guided activities and supporting educational resources are also available. {(signedIn) ? null : '(Sign In required)'}</Paragraph>
{(signedIn)
? <Button path="/wildcam-darien-lab/educators/" label="Educator" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add className="button--secondary" here too?

: <Button type="button" className="button--secondary" onClick={Actions.auth.toggleOauthModal} label="Sign In" />
}
</Box>
<Box align="center" direction="row" justify="between" pad="medium" size="medium">
<Button path="/wildcam-darien-lab/educators/" label="Educator" />
<Button path="/wildcam-darien-lab/students/" label="Explorer" />

<Box pad="medium" size="medium">
<Paragraph> Alternatively, you can simply explore the data.</Paragraph>
<Button path="/wildcam-darien-lab/map/" label="Explorer" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add className="button--secondary" here so this button correctly gets hover/focus styles? I still have had a moment to figure out why Grommet is being inconsistent with the styles.

</Box>
</Section>
<NeedHelp />
</ProgramHome>
);
}
</Box>
<Box align="center" direction="row" justify="between" pad="medium" size="medium">


</Box>
</Section>
<NeedHelp />
</ProgramHome>
);
}

DarienHome.propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import PropTypes from 'prop-types';
import MapExplorer from '../../containers/maps/MapExplorer';
import mapConfig from '../../lib/wildcam-darien.mapConfig.js';

const DarienExplorer = (props) => {
const DarienMap = (props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about using declaration.

return (
<MapExplorer
mapConfig={props.mapConfig}
/>
);
};

DarienExplorer.defaultProps = {
DarienMap.defaultProps = {
mapConfig
};

DarienExplorer.propTypes = {
DarienMap.propTypes = {
mapConfig: PropTypes.object
};

export default DarienExplorer;
export default DarienMap;
4 changes: 2 additions & 2 deletions src/containers/common/ProgramHomeContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Actions } from 'jumpstate';
import { Switch, Route, Redirect } from 'react-router-dom';

import AstroHome from '../../components/astro/AstroHome';
import DarienRoutesContainer from '../darien/DarienRoutesContainer';
import DarienProgram from '../darien/DarienProgram';
import GenericStatusPage from '../../components/common/GenericStatusPage';

import {
Expand Down Expand Up @@ -61,7 +61,7 @@ export class ProgramHomeContainer extends React.Component {
<Switch>
<Route path="/astro-101-with-galaxy-zoo/educators" component={AstroHome} />
<Redirect from="/astro-101-with-galaxy-zoo" to="/astro-101-with-galaxy-zoo/educators/" />
<Route path="/wildcam-darien-lab" component={DarienRoutesContainer} />
<Route path="/wildcam-darien-lab" component={DarienProgram} />
</Switch>
);
}
Expand Down
70 changes: 70 additions & 0 deletions src/containers/darien/DarienProgram.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
Darien Program
--------------
This container is the "main parent" that oversees/organises the rest of the
components used by WildCam Darien Lab.

Currently, it has two concerns:
- Only allow non-logged-in users access to certain parts of the Lab.
- Route Teachers and Students to their correct components.

*/

import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Switch, Route } from 'react-router-dom';
import DarienHome from '../../components/darien/DarienHome';
import DarienEducators from '../../components/darien/DarienEducators';
import DarienMap from '../../components/darien/DarienMap';
import Darien401 from '../../components/darien/Darien401';
import Darien404 from '../../components/darien/Darien404';
import GenericStatusPage from '../../components/common/GenericStatusPage';

class DarienProgram extends React.Component {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can still use the higher order connect function with functional components, so I don't think this has to be a class, unless you have plans to add some lifecycle methods to handle something.

render() {
if (!this.props.initialised) { //User status unknown: wait.
return (<GenericStatusPage status="fetching" message="Loading" />);
} else {

if (this.props.user) { //User logged in: give access to all locations.
return (
<Switch>
<Route exact path={`${this.props.match.url}/`} component={DarienHome} />
<Route path={`${this.props.match.url}/educators`} component={DarienEducators} />
<Route path={`${this.props.match.url}/map`} component={DarienMap} />
<Route path="*" component={Darien404} />
</Switch>
);
} else { //User not logged in: give limited access.
return (
<Switch>
<Route exact path={`${this.props.match.url}/`} component={DarienHome} />
<Route path={`${this.props.match.url}/educators`} component={Darien401} />
<Route path={`${this.props.match.url}/map`} component={DarienMap} />
<Route path="*" component={Darien404} />
</Switch>
);
}
}
}
}

DarienProgram.propTypes = {
initialised: PropTypes.bool,
user: PropTypes.shape({ login: PropTypes.string }),
};

DarienProgram.defaultProps = {
initialised: false,
user: null,
};

function mapStateToProps(state) {
return {
initialised: state.auth.initialised,
user: state.auth.user,
};
}

export default connect(mapStateToProps)(DarienProgram);
18 changes: 0 additions & 18 deletions src/containers/darien/DarienRoutesContainer.jsx

This file was deleted.