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

Protected route #16

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
semi: ["error", "never"],
"arrow-parens": ["error", "as-needed"],
"react/jsx-filename-extension": ["warn", { "extensions": [".js"] }],
"react/prop-types": "warn",
"react/prop-types": "error",
"jsx-a11y/label-has-for": ["error", {
"components": ["Label"],
"required": {
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
"homepage": "https://tatomyr.github.io/estimate-it/",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build && npm run analyze",
"build": "react-scripts build",
"lint": "eslint src/",
"test": "react-scripts test --env=jsdom --coverage",
"precommit": "npm run lint && npm run test",
"predeploy": "npm run build",
"precommit": "git status && npm run lint && npm run test",
"predeploy": "npm run build && npm run analyze",
"deploy": "gh-pages -d build",
"analyze": "source-map-explorer build/static/js/main.*",
"eject": "react-scripts eject"
Expand Down
32 changes: 32 additions & 0 deletions src/components/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react'
import { Switch } from 'react-router-dom'
import Route from './ProtectedRoute'
import Home from './Home'
import Private from './Private'
import Redirector from './Redirector'
import Estimate from './Estimate'
import Dashboard from './Dashboard'
import AuthScreen from './AuthScreen'
import Spinner from './Spinner'
import Toastr from './Toastr'

const App = () => (
<div>
<Redirector />
<Switch>
<Route exact path="/" component={Home} />
<Private>
<Switch>
<Route path="/estimate/new" component={Estimate} />
<Route isProtected path="/estimate/:estimateId" component={Estimate} />
<Route path="/dashboard" component={Dashboard} />
<Route path="/auth" component={AuthScreen} />
</Switch>
</Private>
</Switch>
<Spinner />
<Toastr />
</div>
)

export default App
42 changes: 0 additions & 42 deletions src/components/App/App.js

This file was deleted.

20 changes: 0 additions & 20 deletions src/components/App/index.js

This file was deleted.

Empty file removed src/components/App/styles.css
Empty file.
47 changes: 26 additions & 21 deletions src/components/AuthScreen/Anonymous.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { Fragment } from 'react'
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types'
import {
Button,
Expand All @@ -9,18 +10,30 @@ import {
} from 'reactstrap'
import FA from 'react-fontawesome'
import * as api from '../../helpers/api'
import { locationType } from '../../helpers/propTypes'

const AlertAccessingEstimate = ({ from }) => ((from
&& from.pathname
&& from.pathname.startsWith('/estimate/')
&& from.pathname !== '/estimate/new'
)
? (
<Alert color="warning">
Please enter a valid credentials to get access to this estimate
</Alert>
)
: null)

AlertAccessingEstimate.propTypes = {
from: locationType.isRequired,
}

const Anonymous = ({
match: { url, params },
checkCreds,
openGuestSession,
from,
}) => (
<Fragment>
{(url.startsWith('/estimate/') && params.estimateId !== 'new') ? (
<Alert color="warning">
Please enter a valid credentials to get access to this estimate
</Alert>
) : null}
<AlertAccessingEstimate from={from} />
<form
onSubmit={e => {
e.preventDefault()
Expand Down Expand Up @@ -67,25 +80,17 @@ const Anonymous = ({
</form>
Or
<br />
<Button
color="primary"
outline
onClick={openGuestSession}
>
Guest Session
</Button>
<Link to="/estimate/new">
<Button color="primary" outline>
Guest Session
</Button>
</Link>
</Fragment>
)

Anonymous.propTypes = {
match: PropTypes.shape({
url: PropTypes.string.isRequired,
params: PropTypes.shape({
estimateId: PropTypes.string,
}).isRequired,
}).isRequired,
checkCreds: PropTypes.func.isRequired,
openGuestSession: PropTypes.func.isRequired,
from: locationType.isRequired,
}

export default Anonymous
26 changes: 18 additions & 8 deletions src/components/AuthScreen/AuthScreen.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
import React from 'react'
import PropTypes from 'prop-types'
import Header from '../Header'
import Authorized from './Authorized'
import Anonymous from './Anonymous'
import CredsCheckingScreen from './CredsCheckingScreen'
import { locationType, credsType } from '../../helpers/propTypes'

const AuthScreen = ({
username,
checkingCreds,
creds: {
haveBeenChecked,
username,
},
location: { state },
...rest
}) => (
<div className="overlay auth-screen">
<Header />
<div className="panel">
{(checkingCreds && 'Checking permissions. Please wait…')
|| (username && <Authorized username={username} {...rest} />)
|| <Anonymous {...rest} />}
{(!haveBeenChecked && <CredsCheckingScreen />)
|| (username && (
<Authorized
username={username}
from={state ? state.from : '/'}
redirectToReferrer={state && state.redirectToReferrer}
{...rest}
/>))
|| <Anonymous from={state ? state.from : '/'} {...rest} />}
</div>
</div>
)

AuthScreen.propTypes = {
username: PropTypes.string.isRequired,
checkingCreds: PropTypes.bool.isRequired,
creds: credsType.isRequired,
location: locationType.isRequired,
}

export default AuthScreen
67 changes: 45 additions & 22 deletions src/components/AuthScreen/AuthScreen.test.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,74 @@
/* globals describe, it, expect */

import React from 'react'
import { HashRouter as Router } from 'react-router-dom'
import renderer from 'react-test-renderer'
import AuthScreen from './AuthScreen'

const mockedFunctions = {
const commons = {
location: { pathname: '/', state: { from: '/' } },
match: { url: '/estimate/new', params: { estimateId: 'new' } },
checkCreds: () => null,
resetCreds: () => null,
cleanEstimate: () => null,
closeAuthScreen: () => null,
openGuestSession: () => null,
cleanAllEstimates: () => null,
redirect: () => null,
history: { goBack: () => null },
}

describe('AuthScreen', () => {
it('renders correctly for authorized user', () => {
const tree = renderer
.create(<AuthScreen
match={{ url: '/estimate/new', params: { estimateId: 'new' } }}
username="Test User"
checkingCreds={false}
{...mockedFunctions}
/>)
.create(
<Router>
<AuthScreen
creds={{
haveBeenChecked: true,
username: 'Test User',
dbName: 'dbName',
apiKey: 'apiKey',
}}
{...commons}
/>
</Router> // eslint-disable-line comma-dangle
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('renders correctly for anonymous user', () => {
const tree = renderer
.create(<AuthScreen
match={{ url: '/estimate/new', params: { estimateId: 'new' } }}
username=""
checkingCreds={false}
{...mockedFunctions}
/>)
.create(
<Router>
<AuthScreen
creds={{
haveBeenChecked: true,
username: '',
dbName: '',
apiKey: '',
}}
{...commons}
/>
</Router> // eslint-disable-line comma-dangle
)
.toJSON()
expect(tree).toMatchSnapshot()
})

it('renders correctly when checking credentials', () => {
const tree = renderer
.create(<AuthScreen
match={{ url: '/estimate/new', params: { estimateId: 'new' } }}
username=""
checkingCreds
{...mockedFunctions}
/>)
.create(
<Router>
<AuthScreen
creds={{
haveBeenChecked: false,
username: '',
dbName: '',
apiKey: '',
}}
{...commons}
/>
</Router> // eslint-disable-line comma-dangle
)
.toJSON()
expect(tree).toMatchSnapshot()
})
Expand Down
Loading