-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
remy727
committed
Jan 14, 2021
1 parent
4211c07
commit c4610d5
Showing
20 changed files
with
507 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
[{"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reportWebVitals.js":"1","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/App.js":"2","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/index.js":"3","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/store/index.js":"4","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/index.js":"5","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/alert.reducer.js":"6","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/authentication.reducer.js":"7","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/users.reducer.js":"8","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/index.js":"9","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/alert.constants.js":"10"},{"size":354,"mtime":1610628389225,"results":"11","hashOfConfig":"12"},{"size":93,"mtime":1610628310066,"results":"13","hashOfConfig":"12"},{"size":531,"mtime":1610632564902,"results":"14","hashOfConfig":"12"},{"size":513,"mtime":1610632616964,"results":"15","hashOfConfig":"12"},{"size":283,"mtime":1610632295949,"results":"16","hashOfConfig":"12"},{"size":435,"mtime":1610633233420,"results":"17","hashOfConfig":"12"},{"size":606,"mtime":1610633371356,"results":"18","hashOfConfig":"12"},{"size":418,"mtime":1610633463017,"results":"19","hashOfConfig":"12"},{"size":66,"mtime":1610633043021,"results":"20","hashOfConfig":"12"},{"size":145,"mtime":1610632986395,"results":"21","hashOfConfig":"12"},{"filePath":"22","messages":"23","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"gwrit2",{"filePath":"24","messages":"25","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"26","messages":"27","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"28","messages":"29","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"30","messages":"31","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"32","messages":"33","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"34","messages":"35","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"36","messages":"37","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"38","messages":"39","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"40","messages":"41","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reportWebVitals.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/App.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/store/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/alert.reducer.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/authentication.reducer.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/users.reducer.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/alert.constants.js",[]] | ||
[{"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reportWebVitals.js":"1","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/App.js":"2","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/index.js":"3","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/store/index.js":"4","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/index.js":"5","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/alert.reducer.js":"6","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/authentication.reducer.js":"7","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/users.reducer.js":"8","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/index.js":"9","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/alert.constants.js":"10","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/helpers/history.js":"11","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/actions/index.js":"12","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/actions/user.actions.js":"13","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/route/PrivateRoute.js":"14","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/pages/home/index.jsx":"15","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/pages/login/index.jsx":"16","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/services/user.service.js":"17","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/helpers/auth-header.js":"18","/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/helpers/fake-backend.js":"19"},{"size":354,"mtime":1610628389225,"results":"20","hashOfConfig":"21"},{"size":1320,"mtime":1610636587367,"results":"22","hashOfConfig":"21"},{"size":630,"mtime":1610637085102,"results":"23","hashOfConfig":"21"},{"size":513,"mtime":1610632616964,"results":"24","hashOfConfig":"21"},{"size":283,"mtime":1610632295949,"results":"25","hashOfConfig":"21"},{"size":435,"mtime":1610633233420,"results":"26","hashOfConfig":"21"},{"size":606,"mtime":1610633371356,"results":"27","hashOfConfig":"21"},{"size":417,"mtime":1610633692257,"results":"28","hashOfConfig":"21"},{"size":66,"mtime":1610633043021,"results":"29","hashOfConfig":"21"},{"size":145,"mtime":1610632986395,"results":"30","hashOfConfig":"21"},{"size":93,"mtime":1610633762502,"results":"31","hashOfConfig":"21"},{"size":62,"mtime":1610634014769,"results":"32","hashOfConfig":"21"},{"size":1363,"mtime":1610634870997,"results":"33","hashOfConfig":"21"},{"size":356,"mtime":1610635268369,"results":"34","hashOfConfig":"21"},{"size":1231,"mtime":1610637277674,"results":"35","hashOfConfig":"21"},{"size":3373,"mtime":1610636623295,"results":"36","hashOfConfig":"21"},{"size":1389,"mtime":1610634600640,"results":"37","hashOfConfig":"21"},{"size":247,"mtime":1610634345658,"results":"38","hashOfConfig":"21"},{"size":2081,"mtime":1610637013709,"results":"39","hashOfConfig":"21"},{"filePath":"40","messages":"41","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"gwrit2",{"filePath":"42","messages":"43","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"44","messages":"45","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"46","messages":"47","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"48","messages":"49","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"50","messages":"51","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"52","messages":"53","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"54","messages":"55","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"56","messages":"57","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"58","messages":"59","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"60","messages":"61","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"62","messages":"63","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"64","messages":"65","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"66","messages":"67","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"68","messages":"69","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"70","messages":"71","errorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"72","messages":"73","errorCount":1,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":null},{"filePath":"74","messages":"75","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"76","messages":"77","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reportWebVitals.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/App.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/store/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/alert.reducer.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/authentication.reducer.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/reducers/users.reducer.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/constants/alert.constants.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/helpers/history.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/actions/index.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/actions/user.actions.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/route/PrivateRoute.js",["78"],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/pages/home/index.jsx",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/pages/login/index.jsx",["79"],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/services/user.service.js",["80"],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/helpers/auth-header.js",[],"/Users/admin/work/Norio.Umata/Own/react-redux-jwt-authentication/src/helpers/fake-backend.js",[],{"ruleId":"81","severity":1,"message":"82","line":1,"column":17,"nodeType":"83","messageId":"84","endLine":1,"endColumn":26},{"ruleId":"85","severity":1,"message":"86","line":67,"column":15,"nodeType":"87","endLine":67,"endColumn":950},{"ruleId":"88","severity":2,"message":"89","line":44,"column":9,"nodeType":"83","messageId":"90","endLine":44,"endColumn":17},"no-unused-vars","'Component' is defined but never used.","Identifier","unusedVar","jsx-a11y/alt-text","img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.","JSXOpeningElement","no-restricted-globals","Unexpected use of 'location'.","defaultMessage"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,52 @@ | ||
function App() { | ||
return ( | ||
<div className="App"> | ||
</div> | ||
) | ||
import React from 'react' | ||
import { Router, Route } from 'react-router-dom' | ||
import { connect } from 'react-redux' | ||
|
||
import { history } from './helpers' | ||
import { alertActions } from './actions' | ||
import { PrivateRoute } from './route' | ||
import { HomePage } from './pages/home' | ||
import { LoginPage } from './pages/login' | ||
|
||
class App extends React.Component { | ||
constructor(props) { | ||
super(props) | ||
|
||
const { dispatch } = this.props | ||
history.listen((location, action) => { | ||
// clear alert on location change | ||
dispatch(alertActions.clear()) | ||
}) | ||
} | ||
|
||
render() { | ||
const { alert } = this.props | ||
return ( | ||
<div className="jumbotron"> | ||
<div className="container"> | ||
<div className="col-sm-8 col-sm-offset-2"> | ||
{alert.message && | ||
<div className={`alert ${alert.type}`}>{alert.message}</div> | ||
} | ||
<Router history={history}> | ||
<div> | ||
<PrivateRoute exact path="/" component={HomePage} /> | ||
<Route path="/login" component={LoginPage} /> | ||
</div> | ||
</Router> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
function mapStateToProps(state) { | ||
const { alert } = state | ||
return { | ||
alert | ||
} | ||
} | ||
|
||
export default App | ||
const connectedApp = connect(mapStateToProps)(App) | ||
export { connectedApp as App } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { alertConstants } from '../constants' | ||
|
||
function success(message) { | ||
return { type: alertConstants.SUCCESS, message } | ||
} | ||
|
||
function error(message) { | ||
return { type: alertConstants.ERROR, message } | ||
} | ||
|
||
function clear() { | ||
return { type: alertConstants.CLEAR } | ||
} | ||
|
||
export const alertActions = { | ||
success, | ||
error, | ||
clear | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './alert.actions' | ||
export * from './user.actions' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { userConstants } from '../constants' | ||
import { userService } from '../services' | ||
import { alertActions } from './' | ||
import { history } from '../helpers' | ||
|
||
function login(username, password) { | ||
return dispatch => { | ||
dispatch(request({ username })) | ||
|
||
userService.login(username, password) | ||
.then( | ||
user => { | ||
dispatch(success(user)) | ||
history.push('/') | ||
}, | ||
error => { | ||
dispatch(failure(error)) | ||
dispatch(alertActions.error(error)) | ||
} | ||
) | ||
} | ||
|
||
function request(user) { return { type: userConstants.LOGIN_REQUEST, user } } | ||
function success(user) { return { type: userConstants.LOGIN_SUCCESS, user } } | ||
function failure(error) { return { type: userConstants.LOGIN_FAILURE, error } } | ||
} | ||
|
||
function logout() { | ||
userService.logout() | ||
return { type: userConstants.LOGOUT } | ||
} | ||
|
||
function getAll() { | ||
return dispatch => { | ||
dispatch(request()) | ||
|
||
userService.getAll() | ||
.then( | ||
users => dispatch(success(users)), | ||
error => dispatch(failure(error)) | ||
) | ||
} | ||
|
||
function request() { return { type: userConstants.GETALL_REQUEST } } | ||
function success(users) { return { type: userConstants.GETALL_SUCCESS, users } } | ||
function failure(error) { return { type: userConstants.GETALL_FAILURE, error } } | ||
} | ||
|
||
export const userActions = { | ||
login, | ||
logout, | ||
getAll | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export function authHeader() { | ||
// return authorization header with jwt token | ||
let user = JSON.parse(localStorage.getItem('user')) | ||
|
||
if (user && user.token) { | ||
return { 'Authorization': 'Bearer ' + user.token } | ||
} else { | ||
return {} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
export function configureFakeBackend() { | ||
let users = [{ id: 1, username: 'test', password: 'test', firstName: 'Test', lastName: 'User' }] | ||
let realFetch = window.fetch | ||
window.fetch = function (url, opts) { | ||
return new Promise((resolve, reject) => { | ||
// wrap in timeout to simulate server api call | ||
setTimeout(() => { | ||
|
||
// authenticate | ||
if (url.endsWith('/users/authenticate') && opts.method === 'POST') { | ||
// get parameters from post request | ||
let params = JSON.parse(opts.body) | ||
|
||
// find if any user matches login credentials | ||
let filteredUsers = users.filter(user => { | ||
return user.username === params.username && user.password === params.password | ||
}) | ||
|
||
if (filteredUsers.length) { | ||
// if login details are valid return user details and fake jwt token | ||
let user = filteredUsers[0] | ||
let responseJson = { | ||
id: user.id, | ||
username: user.username, | ||
firstName: user.firstName, | ||
lastName: user.lastName, | ||
token: 'fake-jwt-token' | ||
} | ||
resolve({ ok: true, text: () => Promise.resolve(JSON.stringify(responseJson)) }) | ||
} else { | ||
// else return error | ||
reject('Username or password is incorrect') | ||
} | ||
|
||
return | ||
} | ||
|
||
// get users | ||
if (url.endsWith('/users') && opts.method === 'GET') { | ||
// check for fake auth token in header and return users if valid, this security is implemented server side in a real application | ||
if (opts.headers && opts.headers.Authorization === 'Bearer fake-jwt-token') { | ||
resolve({ ok: true, text: () => Promise.resolve(JSON.stringify(users))}) | ||
} else { | ||
// return 401 not authorised if token is null or invalid | ||
reject('Unauthorised') | ||
} | ||
|
||
return | ||
} | ||
|
||
// pass through any requests not handled above | ||
realFetch(url, opts).then(response => resolve(response)) | ||
|
||
}, 500) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { createBrowserHistory } from 'history' | ||
|
||
export const history = createBrowserHistory() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './history' | ||
export * from './auth-header' | ||
export * from './fake-backend' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import React from 'react' | ||
import { Link } from 'react-router-dom' | ||
import { connect } from 'react-redux' | ||
|
||
import { userActions } from '../../actions' | ||
|
||
class HomePage extends React.Component { | ||
componentDidMount() { | ||
this.props.dispatch(userActions.getAll()) | ||
} | ||
|
||
render() { | ||
const { user, users } = this.props | ||
return ( | ||
<div className="col-md-6 col-md-offset-3"> | ||
<h1>Hi {user.firstName}!</h1> | ||
<p>You're logged in with React & JWT!!</p> | ||
<h3>Users from secure api end point:</h3> | ||
{users.loading && <em>Loading users...</em>} | ||
{users.error && <span className="text-danger">ERROR: {users.error}</span>} | ||
{users.items && | ||
<ul> | ||
{users.items.map((user, index) => | ||
<li key={user.id}> | ||
{user.firstName + ' ' + user.lastName} | ||
</li> | ||
)} | ||
</ul> | ||
} | ||
<p> | ||
<Link to="/login">Logout</Link> | ||
</p> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
function mapStateToProps(state) { | ||
const { users, authentication } = state | ||
const { user } = authentication | ||
return { | ||
user, | ||
users | ||
} | ||
} | ||
|
||
const connectedHomePage = connect(mapStateToProps)(HomePage) | ||
export { connectedHomePage as HomePage } |
Oops, something went wrong.