Skip to content

Commit

Permalink
Merge pull request #10 from graasp/9/login
Browse files Browse the repository at this point in the history
9/login
  • Loading branch information
pyphilia authored Dec 4, 2020
2 parents 33b7aa0 + 0d52b38 commit bcdf11f
Show file tree
Hide file tree
Showing 15 changed files with 2,231 additions and 1,696 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
# graasp-compose

## How to use the api

- add following hosts using `sudo vim /etc/hosts` with
- `127.0.01 web.graasp.org`
- `128.178.242.202 api.graasp.org`
- add in your `.env.local` file

```
REACT_APP_API_HOST=http://api.graasp.org:3111
PORT=3111
HOST=web.graasp.org
```
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,23 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"js-cookie": "2.2.1",
"node-fetch": "2.6.1",
"prop-types": "15.7.2",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router": "5.2.0",
"react-router-dom": "5.2.0",
"react-scripts": "3.4.3"
},
"scripts": {
"start": "react-scripts start",
"start": "env-cmd -f ./.env.local react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"test": "env-cmd -f ./.env.test react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint .",
"prettier:check": "prettier --check 'src/**/*.js'",
"prettier:write": "prettier --write 'src/**/*.js'",
"prettier:check": "prettier --check src/**/*.js",
"prettier:write": "prettier --write src/**/*.js",
"hooks:uninstall": "node node_modules/husky/husky.js uninstall",
"hooks:install": "node node_modules/husky/husky.js install"
},
Expand All @@ -44,6 +47,7 @@
"devDependencies": {
"@commitlint/cli": "11.0.0",
"@commitlint/config-conventional": "11.0.0",
"env-cmd": "10.1.0",
"eslint-config-airbnb": "18.2.0",
"eslint-config-prettier": "6.11.0",
"eslint-plugin-import": "2.22.0",
Expand Down
25 changes: 25 additions & 0 deletions src/api/authentication.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { API_HOST } from '../config/constants';
import { DEFAULT_GET, DEFAULT_POST } from './utils';

// payload = {email}
export const signIn = async (payload) => {
const req = await fetch(`${API_HOST}/login`, {
...DEFAULT_POST,
body: JSON.stringify(payload),
});
return req.status === 204;
};

export const signOut = async () => {
const req = await fetch(`${API_HOST}/logout`, DEFAULT_GET);
return req.status === 204;
};

// payload = {name, mail}
export const signUp = async (payload) => {
const req = await fetch(`${API_HOST}/register`, {
...DEFAULT_POST,
body: JSON.stringify(payload),
});
return req.status === 204;
};
25 changes: 25 additions & 0 deletions src/api/item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { API_HOST } from '../config/constants';
import { DEFAULT_GET, DEFAULT_POST } from './utils';

// payload = {email}
export const getOwnItems = async () => {
const req = await fetch(`${API_HOST}/own`, {
...DEFAULT_GET,
});
// eslint-disable-next-line no-console
console.log(req);
};

// payload = {email}
export const createItem = async () => {
const req = await fetch(`${API_HOST}/items`, {
...DEFAULT_POST,
body: JSON.stringify({ name: 'myitem' }),
});
// eslint-disable-next-line no-console
console.log(await req.json());
};

// we need this function for navigation purposes: when you click on an item, you want to see its 'immediate' children
// eslint-disable-next-line import/prefer-default-export
export const fetchItemImmediateChildren = () => {};
10 changes: 10 additions & 0 deletions src/api/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const DEFAULT_GET = {
credentials: 'include',
method: 'GET',
};

export const DEFAULT_POST = {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
};
20 changes: 19 additions & 1 deletion src/components/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import {
BrowserRouter as Router,
Switch,
Route,
Redirect,
} from 'react-router-dom';
import { makeStyles } from '@material-ui/core/styles';
import Header from './layout/Header';
import Items from './main/Items';
import items from '../data/sample';
import SignUp from './SignUp';
import { SIGN_UP_PATH, SIGN_IN_PATH } from '../config/paths';
import SignIn from './SignIn';

const useStyles = makeStyles((theme) => ({
root: {
Expand All @@ -25,6 +33,16 @@ function App() {
<Route path="/items/:itemId">
<Items items={items} />
</Route>
<Route path={SIGN_IN_PATH} exact>
<SignIn />
</Route>
<Route path={SIGN_UP_PATH} exact>
<SignUp />
</Route>
<Route path="/" exact>
<Redirect to="/items" />
</Route>
<Redirect to="/items" />
</Switch>
</main>
</div>
Expand Down
149 changes: 149 additions & 0 deletions src/components/SignIn.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 { withRouter } from 'react-router';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import Divider from '@material-ui/core/Divider';
import FormControl from '@material-ui/core/FormControl';
import { Alert } from '@material-ui/lab';
import { SIGN_UP_PATH } from '../config/paths';
import { signIn, signOut } from '../api/authentication';
import { isSignedIn } from '../utils/common';

const styles = (theme) => ({
fullScreen: {
margin: 'auto',
textAlign: 'center',
},
input: {
margin: theme.spacing(1),
},
form: {
width: '50%',
minWidth: '200px',
margin: 'auto',
},
divider: {
margin: theme.spacing(2),
},
});

class SignIn extends Component {
static propTypes = {
classes: PropTypes.shape({
fullScreen: PropTypes.string.isRequired,
divider: PropTypes.string.isRequired,
form: PropTypes.string.isRequired,
input: PropTypes.string.isRequired,
}).isRequired,
history: PropTypes.shape({
push: PropTypes.func.isRequired,
replace: PropTypes.func.isRequired,
}).isRequired,
};

state = {
isSuccess: null,
email: '',
isAuthenticated: false,
};

componentDidMount() {
const isAuthenticated = isSignedIn();
this.setState({ isAuthenticated });
}

handleOnRegister = () => {
const {
history: { push },
} = this.props;
push(SIGN_UP_PATH);
};

signIn = async () => {
const { email } = this.state;
const isSuccess = await signIn({ email });
this.setState({ isSuccess });
};

signOut = async () => {
const isSuccess = await signOut();
this.setState({ isSuccess });
};

handleOnChange = (e) => {
this.setState({ email: e.target.value });
};

renderMessage = () => {
const { isSuccess } = this.state;
if (isSuccess) {
return <Alert severity="success">Success!</Alert>;
}
// is not triggered for null (initial case)
if (isSuccess === false) {
return <Alert severity="error">An error occured.</Alert>;
}
return null;
};

renderSignOutButton = () => {
return (
<>
<Typography variant="subtitle1">You are already signed in.</Typography>
<Button variant="text" color="primary" onClick={this.signOut}>
Click here to sign out
</Button>
</>
);
};

renderSignInForm = () => {
const { email } = this.state;
const { classes } = this.props;
return (
<>
<FormControl>
<TextField
className={classes.input}
required
label="email"
variant="outlined"
value={email}
onChange={this.handleOnChange}
/>
<Button variant="contained" color="primary" onClick={this.signIn}>
Sign In
</Button>
</FormControl>

<Divider variant="middle" className={classes.divider} />
<Button variant="text" color="primary" onClick={this.handleOnRegister}>
Not registered? Click here to register
</Button>
</>
);
};

render() {
const { classes } = this.props;
const { isAuthenticated } = this.state;

return (
<div className={classes.fullScreen}>
{this.renderMessage()}
<Typography variant="h2" component="h2">
Sign In
</Typography>
{!isAuthenticated && this.renderSignInForm()}
{isAuthenticated && this.renderSignOutButton()}
</div>
);
}
}

const StyledComponent = withStyles(styles, { withTheme: true })(SignIn);

export default withRouter(StyledComponent);
Loading

0 comments on commit bcdf11f

Please sign in to comment.