Commit b79c9ecc authored by Víctor Gallego Fontenla's avatar Víctor Gallego Fontenla 🏉

Added a few more examples

parent 436c6305
......@@ -5,6 +5,7 @@
"dependencies": {
"bootstrap": "^4.1.3",
"bootswatch": "^4.1.3",
"prop-types": "^15.6.2",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-icons": "^3.1.0",
......
......@@ -4,12 +4,15 @@ import 'bootswatch/dist/lux/bootstrap.css'
import './styles.css'
import { BrowserRouter as Router } from 'react-router-dom'
import Layout from './components/layout'
import { AuthenticatedApp } from "./components/authentication";
class App extends Component {
render() {
return <Router>
return <AuthenticatedApp>
<Router>
<Layout/>
</Router>
</AuthenticatedApp>
}
}
......
import React, { PureComponent as Component } from 'react'
import { Row } from 'reactstrap'
import { Link } from 'react-router-dom'
export class ArticlePreview extends Component {
render(){
return <Row tag = "article">
return <article>
<header>
<h1>{ this.props.title }</h1>
<h5 className = "text-muted">by {this.props.author} on { this.props.date } </h5>
<h5 className = "text-muted"><address className = "d-inline">by {this.props.author}</address> on <time className = "d-inline" dateTime = { this.props.date }>{ this.props.date }</time></h5>
</header>
<p>{this.props.resume}</p>
<footer className = "mb-3">
<Link to = {`/posts/${this.props.id}`}>View more...</Link>
</footer>
</Row>
</article>
}
}
......@@ -23,7 +22,7 @@ export class FullArticle extends Component {
this.state = {
author : "",
date: "",
date: "2018-05-17",
title: "",
body: "",
comments: []
......@@ -46,36 +45,32 @@ export class FullArticle extends Component {
}
render(){
return <>
<Row tag = "article">
return <article>
<header>
<h1>{ this.state.title }</h1>
<h5 className = "text-muted"><address className = "d-inline">by {this.state.author}</address> on <time className = "d-inline" dateTime = { this.state.date }>{ this.state.date }</time></h5>
</header>
{this.state.body.split("\n").map((paragraph, index) => <p key= {`p-${index}`}>{paragraph}</p>)}
<section>
<header>
<h1>{ this.state.title }</h1>
<h5 className = "text-muted">by {this.state.author} on { this.state.date } </h5>
</header>
{this.state.body.split("\n").map((paragraph, index) => <p key= {`p-${index}`}>{paragraph}</p>)}
</Row>
<Row tag = "aside">
<header className= "w-100">
<h3>Comments</h3>
<hr />
</header>
<section>
{this.state.comments.map(comment => <ArticleComment key = {comment.id} user = {comment.email} title = {comment.name} body = {comment.body}/>)}
</section>
</Row>
</>
{this.state.comments.map(comment => <ArticleComment key = {comment.id} user = {comment.email} title = {comment.name} body = {comment.body}/>)}
</section>
</article>
}
}
export class ArticleComment extends Component {
render() {
return <div>
return <article>
<header>
<h5>{this.props.title}</h5>
<h6>{this.props.user}</h6>
</header>
{ this.props.body.split("\n").map((paragraph, index) => <p key = {`c-${index}`}>{paragraph}</p>) }
</div>
</article>
}
}
......
import React, { Component } from "react"
import PropTypes from 'prop-types'
const USERS = {
test: {
name: "Test User",
id: "test",
roles: ["user"],
password: "1234"
},
admin: {
name: "Admin User",
id: "admin",
roles: ["admin"],
password: "1234"
}
}
const AuthContext = React.createContext()
export class AuthenticatedApp extends Component {
constructor(){
super()
this.state = {
authenticated: false,
user : {},
error: {}
}
}
login = (user, pass) => {
if(USERS[user] && USERS[user].password === pass)
this.setState(prev => ({...prev, authenticated: true, user: USERS[user]}))
else
this.setState(prev => ({...prev, error: { code: "INVALID_LOGIN", message: "Invalid user or password!" }}))
}
logout = () => {
this.setState(prev => ({...prev, authenticated: false, user: {}}))
}
render(){
const auth = {
authenticated: this.state.authenticated,
user: this.state.user,
error: this.state.error,
login: this.login,
logout: this.logout
}
return <AuthContext.Provider value = { auth } >
{ this.props.children }
</AuthContext.Provider>
}
}
export const Authentication = AuthContext.Consumer
export class AuthenticatedOnly extends Component {
static propTypes = {
requiredRole: PropTypes.string,
children: PropTypes.element.isRequired
}
static defaultProps = {
requiredRole : null
}
render(){
return <Authentication>
{
auth => {
if (auth.authenticated && (this.props.requiredRole === null || auth.user.roles.includes(this.props.requiredRole)))
return this.props.children
}
}
</Authentication>
}
}
export class UnauthenticatedOnly extends Component {
static propTypes = {
children: PropTypes.element.isRequired
}
render(){
return <Authentication>
{
auth => {
if (!auth.authenticated)
return this.props.children
}
}
</Authentication>
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@ import NavigationBar from "../navbar"
import { Container } from "reactstrap"
import {ArticleList, FullArticle} from "../article"
import Login from "../login"
import Logout from "../logout"
import { Switch, Route, Redirect } from "react-router-dom"
export default class Layout extends Component {
......@@ -11,9 +12,10 @@ export default class Layout extends Component {
<NavigationBar/>
<Container className = "pt-3" tag = "main">
<Switch>
<Route path = "/login" component = {Login} />
<Route path = "/posts/:id" component = { FullArticle }/>
<Route path = "/posts" component = {ArticleList} />
<Route path = "/posts" component = { ArticleList } />
<Route path = "/login" component = { Login } />
<Route path = "/logout" component = { Logout } />
<Redirect from = "/" to = "/posts"/>
</Switch>
</Container>
......
import React, { Component } from "react"
import {
Alert,
Button,
Row,
Col,
Card,
CardHeader,
CardBody,
CardTitle,
CardFooter,
CardTitle,
Form,
FormGroup,
Label,
Input
} from 'reactstrap'
import { Redirect } from "react-router-dom"
import { Authentication } from '../authentication'
export default class Login extends Component {
render() {
return <Authentication>
{ auth => {
if (auth.authenticated)
return <Redirect to ="/" />;
else
return <Row>
<Col xs="12" sm={{size: 6, offset: 3}}>
<LoginForm onLogin = {auth.login}/>
<LoginError error = { auth.error } />
</Col>
</Row>
}}
</Authentication>
}
}
class LoginForm extends Component {
constructor(){
super()
......@@ -29,38 +52,49 @@ export default class Login extends Component {
let value = event.target !== null ? event.target.value : ""
this.setState(prev => ({...prev, username: value}))
}
onPasswordChange = event => {
let value = event.target !== null ? event.target.value : ""
this.setState(prev => ({...prev, password: value}))
}
onLoginButtonClick = () => {
console.log(`${this.state.username}: ${this.state.password}`)
this.props.onLogin(this.state.username, this.state.password)
}
render() {
return <Row>
<Col xs="12" sm = {{size: 6, offset: 3}}>
<Card color = "primary">
<CardHeader>
<CardTitle>Login</CardTitle>
</CardHeader>
<CardBody>
<Form>
<FormGroup>
<Label>Username</Label>
<Input value = { this.state.username } onChange = { this.onUsernameChange }/>
</FormGroup>
<FormGroup>
<Label>Password</Label>
<Input type = "password" value = { this.state.password } onChange = { this.onPasswordChange }/>
</FormGroup>
</Form>
</CardBody>
<CardFooter>
<Button block onClick = { this.onLoginButtonClick }>Login</Button>
</CardFooter>
</Card>
</Col>
</Row>
return <Card color="primary">
<CardHeader>
<CardTitle>Login</CardTitle>
</CardHeader>
<CardBody>
<Form >
<FormGroup>
<Label>Username</Label>
<Input value = { this.state.username } onChange = { this.onUsernameChange }/>
</FormGroup>
<FormGroup>
<Label>Password</Label>
<Input type = "password" value = { this.state.password } onChange = { this.onPasswordChange }/>
</FormGroup>
</Form>
</CardBody>
<CardFooter>
<Button block onClick = { this.onLoginButtonClick }>Login</Button>
</CardFooter>
</Card>
}
}
class LoginError extends Component {
render(){
if(this.props.error.code)
return <Alert className = "mt-3" color="danger">
{this.props.error.message}
</Alert>
else return null
}
}
\ No newline at end of file
import React, { Component } from "react"
import { Redirect } from "react-router-dom"
import { Authentication } from '../authentication'
export default class Logout extends Component {
render() {
return <Authentication>
{ auth => {
if (auth.authenticated)
auth.logout()
else
return <Redirect to ="/" />
}}
</Authentication>
}
}
\ No newline at end of file
......@@ -16,6 +16,7 @@ import {
} from 'reactstrap'
import { Link } from 'react-router-dom'
import { AuthenticatedOnly, UnauthenticatedOnly } from "../authentication";
export default class NavigationBar extends Component {
onSearchButtonClick = () => {}
......@@ -27,9 +28,21 @@ export default class NavigationBar extends Component {
<NavItem>
<NavLink tag={Link} to="/">Post list</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} to="/login">Login</NavLink>
</NavItem>
<AuthenticatedOnly requiredRole = "admin">
<NavItem>
<NavLink tag={Link} to="/admin">Admin</NavLink>
</NavItem>
</AuthenticatedOnly>
<UnauthenticatedOnly>
<NavItem>
<NavLink tag={Link} to="/login">Login</NavLink>
</NavItem>
</UnauthenticatedOnly>
<AuthenticatedOnly>
<NavItem>
<NavLink tag={Link} to="/logout">Logout</NavLink>
</NavItem>
</AuthenticatedOnly>
</Nav>
<Form inline>
<FormGroup>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment