52 |
Front End Masters Instructors
53 | { auth.isAuthenticated() && auth.isAdmin() &&
54 |
57 | }
58 |
59 | {instructorList}
60 |
61 |
62 | )
63 | }
64 | }
65 |
66 | export default Instructor
67 |
--------------------------------------------------------------------------------
/src/utils/AuthService.js:
--------------------------------------------------------------------------------
1 | import { EventEmitter } from 'events'
2 | import { isTokenExpired } from './jwtHelper'
3 | import { browserHistory } from 'react-router'
4 | import jwtDecode from 'jwt-decode'
5 |
6 | import { API_URL } from './constants'
7 |
8 | export default class AuthService extends EventEmitter {
9 | constructor() {
10 | super()
11 |
12 | // binds login functions to keep this context
13 | this.login = this.login.bind(this)
14 | }
15 |
16 | _doAuthentication(endpoint, values) {
17 | return this.fetch(`${API_URL}/${endpoint}`, {
18 | method: 'POST',
19 | body: JSON.stringify(values),
20 | headers: { 'Content-Type': 'application/json' }
21 | })
22 | }
23 |
24 | login(user, password) {
25 | return this._doAuthentication('users/authenticate', { user, password })
26 | }
27 |
28 | signup(username, email, password) {
29 | return this._doAuthentication('users', { username, email, password })
30 | }
31 |
32 | isAuthenticated() {
33 | // Checks if there is a saved token and it's still valid
34 | const token = localStorage.getItem('token')
35 | if (token) {
36 | return !isTokenExpired(token)
37 | } else {
38 | return false
39 | }
40 | }
41 |
42 | isAdmin() {
43 | return jwtDecode(this.getToken()).scope === 'admin'
44 | }
45 |
46 | finishAuthentication(token) {
47 | localStorage.setItem('token', token)
48 | }
49 |
50 | getToken() {
51 | // Retrieves the user token from localStorage
52 | return localStorage.getItem('token')
53 | }
54 |
55 | logout() {
56 | // Clear user token and profile data from localStorage
57 | localStorage.removeItem('token')
58 | }
59 |
60 | _checkStatus(response) {
61 | // raises an error in case response status is not a success
62 | if (response.status >= 200 && response.status < 300) {
63 | return response
64 | } else {
65 | var error = new Error(response.statusText)
66 | error.response = response
67 | return error
68 | }
69 | }
70 |
71 | fetch(url, options) {
72 | // performs api calls sending the required authentication headers
73 | const headers = {
74 | 'Accept': 'application/json',
75 | 'Content-Type': 'application/json'
76 | }
77 |
78 | if (this.isAuthenticated()) {
79 | headers['Authorization'] = 'Bearer ' + this.getToken()
80 | }
81 |
82 | return fetch(url, {
83 | headers,
84 | ...options
85 | })
86 | .then(response => response.json())
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "auth0-react-sample",
3 | "version": "1.0.0",
4 | "description": "A minimal reactJS sample application showing auth0 integration",
5 | "repository": "https://github.com/auth0-samples/auth0-react-sample",
6 | "license": "MIT",
7 | "scripts": {
8 | "start": "npm-run-all --parallel dev-server",
9 | "dev-server": "cross-env NODE_ENV=development hjs-dev-server",
10 | "clean": "rimraf dist",
11 | "build": "npm run clean && cross-env NODE_ENV=production webpack",
12 | "publish_pages": "gh-pages -d dist",
13 | "ghpages": "npm run build && npm run publish_pages",
14 | "test": "cross-env NODE_ENV=test karma start karma.conf.js",
15 | "test:watch": "npm run test -- --watch"
16 | },
17 | "devDependencies": {
18 | "autoprefixer": "^6.3.6",
19 | "babel-core": "^6.7.7",
20 | "babel-loader": "^6.2.4",
21 | "babel-plugin-transform-es2015-modules-umd": "^6.8.0",
22 | "babel-polyfill": "^6.7.4",
23 | "babel-preset-es2015": "^6.6.0",
24 | "babel-preset-react": "^6.5.0",
25 | "babel-preset-react-hmre": "^1.1.1",
26 | "babel-preset-stage-0": "^6.5.0",
27 | "babel-register": "^6.7.2",
28 | "chai": "^3.5.0",
29 | "chai-enzyme": "^0.4.2",
30 | "cheerio": "^0.20.0",
31 | "cross-env": "^1.0.8",
32 | "css-loader": "^0.23.1",
33 | "cssnano": "^3.5.2",
34 | "dotenv": "^2.0.0",
35 | "enzyme": "^2.2.0",
36 | "expect": "^1.18.0",
37 | "file-loader": "^0.8.5",
38 | "gh-pages": "^0.11.0",
39 | "hjs-webpack": "^8.1.0",
40 | "jasmine-core": "^2.4.1",
41 | "json-loader": "^0.5.4",
42 | "karma": "^0.13.22",
43 | "karma-chai": "^0.1.0",
44 | "karma-jasmine": "^0.3.8",
45 | "karma-mocha": "^1.0.1",
46 | "karma-phantomjs-launcher": "^1.0.0",
47 | "karma-sourcemap-loader": "^0.3.7",
48 | "karma-spec-reporter": "0.0.26",
49 | "karma-webpack": "^1.7.0",
50 | "mocha": "^2.4.5",
51 | "npm-run-all": "^2.3.0",
52 | "phantomjs-polyfill": "0.0.2",
53 | "phantomjs-prebuilt": "^2.1.7",
54 | "postcss-loader": "^0.9.1",
55 | "precss": "^1.4.0",
56 | "prettyjson": "^1.1.3",
57 | "react-addons-test-utils": "^15.0.2",
58 | "sinon": "^1.17.4",
59 | "style-loader": "^0.13.1",
60 | "transform-loader": "^0.2.3",
61 | "url-loader": "^0.5.7",
62 | "webpack": "^1.13.0",
63 | "yargs": "^4.7.1"
64 | },
65 | "dependencies": {
66 | "auth0-lock": "^11.27.0",
67 | "bootstrap": "^3.3.7",
68 | "classnames": "^2.2.5",
69 | "express-jwt": "^5.0.0",
70 | "jwt-decode": "^2.1.0",
71 | "md5": "^2.2.1",
72 | "react": "^15.3.1",
73 | "react-bootstrap": "^0.30.0-rc.1",
74 | "react-dom": "^15.3.1",
75 | "react-router": "^2.8.0",
76 | "react-router-bootstrap": "^0.23.1"
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/views/Main/NewInstructor/NewInstructor.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes as T } from 'react'
2 | import {Panel, Col, Button, FormGroup, FormControl, ControlLabel, Alert} from 'react-bootstrap'
3 | import styles from './styles.module.css'
4 | import jwtDecode from 'jwt-decode'
5 | import md5 from 'md5'
6 |
7 | import { API_URL } from './../../../utils/constants'
8 |
9 | export class NewInstructor extends React.Component {
10 | static contextTypes = {
11 | router: T.object
12 | }
13 |
14 | constructor(props, context) {
15 | super(props, context)
16 | this.state = {
17 | first_name: '',
18 | last_name: '',
19 | email: '',
20 | company: '',
21 | error: ''
22 | }
23 | }
24 |
25 | handleChange(event) {
26 | this.setState({ [event.target.name]: event.target.value })
27 | }
28 |
29 | onNewInstructorSubmit() {
30 | const { first_name, last_name, email, company } = this.state
31 | const data = { first_name, last_name, email, company }
32 | this.props.auth.fetch(`${API_URL}/instructors`, {
33 | method: 'POST',
34 | body: JSON.stringify(data)
35 | }).then(result => {
36 | if (result.error) {
37 | this.setState({ error: result })
38 | return
39 | }
40 | this.context.router.push('/instructor')
41 | })
42 | }
43 |
44 | render() {
45 | return (
46 |