Skip to content

Commit

Permalink
Fixed #20
Browse files Browse the repository at this point in the history
  • Loading branch information
Jovert Lota Palonpon committed Mar 31, 2019
1 parent 3c4dc65 commit ce6e9df
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 275 deletions.
4 changes: 1 addition & 3 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ public function boot()
*/
public function register()
{
app()->bind('uploader', function () {
return new \App\Utils\Uploader;
});
//
}
}
167 changes: 25 additions & 142 deletions resources/js/Backoffice.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,11 @@ import { Loading } from './views';
class Backoffice extends Component {
state = {
loading: true,
retrying: false,
navigating: true,
authenticated: false,
nightMode: false,
token: {},
user: {},
username: '',

errorResponse: {},
successfulResponse: {},
responseInterceptor: null,
};

/**
* Refresh the user's session.
*
* @return {undefined}
*/
refresh = async () => {
this.setState({ navigating: true });

try {
const response = await axios.post('/api/v1/auth/refresh');
const token = response.data;

this.setToken(token, true);

this.setState(prevState => {
return {
navigating: false,
token,

// Update the user's auth_token after refreshing it in the API
user: {
...prevState.user,
auth_token: token.auth_token,
},
};
});
} catch (error) {}
};

/**
Expand All @@ -62,11 +27,13 @@ class Backoffice extends Component {
authenticate = async tokenString => {
const token = JSON.parse(tokenString);

if (token) {
this.setToken(token);

await this.fetchUser();
if (token === {}) {
return;
}

this.setToken(token);

await this.fetchUser();
};

/**
Expand Down Expand Up @@ -173,26 +140,23 @@ class Backoffice extends Component {
* Store the authentication object as string into a persistent storage.
*
* @param {object} token
* @param {boolean} updateExpiry
*
* @return {undefined}
*/
setToken = (token, updateExpiry = false) => {
setToken = token => {
// We will set a default Authorization header, this will
// eliminate the need to include the Authorization header
// for almost every AJAX requests.
window.axios.defaults.headers.common['Authorization'] = `Bearer ${
token.auth_token
}`;

if (updateExpiry) {
// Add an expired_at timestamp based in the expired_in property in the token.
// A client defined expiry time makes sense here since a server time is
// not what we should depend on.
token.expired_at = moment()
.add(token.expires_in, 'seconds')
.format('YYYY-MM-DD hh:mm:ss');
}
// Add an expired_at timestamp based in the expired_in property in the token.
// A client defined expiry time makes sense here since a server time is
// not what we should depend on.
token.expired_at = moment()
.add(token.expires_in, 'seconds')
.format('YYYY-MM-DD hh:mm:ss');

// Store it locally for the authentication token to persist.
window.localStorage.setItem('token', JSON.stringify(token));
Expand All @@ -201,103 +165,29 @@ class Backoffice extends Component {
/**
* Fetch the authenticated user.
*
* @return {undefined}
* @return {any}
*/
fetchUser = async () => {
this.setState({ loading: true });

try {
const response = await axios.post('/api/v1/auth/user');

if (response.status === 200) {
this.setState({
loading: false,
authenticated: true,
user: response.data,
});
if (response.status !== 200) {
return;
}
} catch (error) {}
};

/**
* Remove the response interceptor.
*
* @param {any} interceptor
*
* @param {undefined}
*/
removeResponseInterceptor = interceptor => {
axios.interceptors.response.eject(interceptor);
};

/**
* Record API responses & do something.
*
* @param {any} interceptor
*
* @param {undefined}
*/
addResponseInterceptor = () => {
const responseInterceptor = axios.interceptors.response.use(
response => {
return response;
},

async error => {
// In occasions of Unauthorized requests (401),
// Retry (if authenticated earlier).
if (error.response.status === 401 && this.state.authenticated) {
this.setState({
retrying: true,
});

// Request options
const {
url,
method,
headers,
params: data,
} = error.response.config;

const response = await axios({
url,
method,
headers: {
...headers,

// This is an override of the Authorization header
// to fix the 401 errors when we retry.
Authorization:
window.axios.defaults.headers.common[
'Authorization'
],
},
data,
});

// If the request returns 200 or 201 (Resource created),
// Treat it as successful response.
if ([200, 201].indexOf(response.status) > -1) {
this.setState({
retrying: false,
successfulResponse: response,
});
}
}

return Promise.reject(error);
},
);
this.setState({
loading: false,
authenticated: true,
user: response.data,
});

this.setState({
responseInterceptor,
});
return response.data;
} catch (error) {}
};

async componentDidMount() {
// Listen for all API responses.
this.addResponseInterceptor();

// Setup Night Mode via Persistent Storage.
this.setNightMode();

Expand All @@ -306,20 +196,14 @@ class Backoffice extends Component {
let expired = true;

if (token.hasOwnProperty('expired_at')) {
expired = token.expired_at < moment().format('YYYY-MM-DD hh:mm:ss');
expired = moment(token.expired_at).unix() > moment().unix();
}

if (!expired) {
await this.authenticate(JSON.stringify(token));
}

this.setState({ loading: false, navigating: false });
}

componentWillUnmount() {
const { responseInterceptor } = this.state;

this.removeResponseInterceptor(responseInterceptor);
this.setState({ loading: false });
}

render() {
Expand All @@ -346,7 +230,6 @@ class Backoffice extends Component {
routes: ROUTES,
handleNightmodeToggled: this
.handleNightmodeToggled,
refresh: this.refresh,
authenticate: this.authenticate,
handleLock: this.handleLock,
handleSignout: this.handleSignout,
Expand Down
113 changes: 46 additions & 67 deletions resources/js/core/Navigator.js
Original file line number Diff line number Diff line change
@@ -1,82 +1,61 @@
import React, { Component } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter, Route, Switch, Redirect } from 'react-router-dom';

import * as NavigationUtils from '../utils/Navigation';
import * as UrlUtils from '../utils/URL';

class Navigator extends Component {
async componentDidUpdate(prevProps) {
const { location, pageProps } = this.props;
const Navigator = props => {
const { authenticated, username, environment, routes } = props.pageProps;

// notify the parent component that the user is navigating...
if (location.pathname !== prevProps.location.pathname) {
await pageProps.refresh();
}
}
return (
<Switch>
{routes.map((route, i) => {
const View = route.component;

render() {
const {
authenticated,
username,
environment,
routes,
} = this.props.pageProps;

return (
<Switch>
{routes.map((route, i) => {
const View = route.component;

return (
<Route
key={i}
path={route.path}
exact
render={routeProps => {
if (route.auth) {
if (!authenticated) {
return (
<Redirect
to={{
search: UrlUtils._queryString(
{
username,
},
),
pathname: NavigationUtils._route(
'auth.signin',
),
}}
/>
);
}
return (
<Route
key={i}
path={route.path}
exact
render={routeProps => {
if (route.auth) {
if (!authenticated) {
return (
<Redirect
to={{
search: UrlUtils._queryString({
username,
}),
pathname: NavigationUtils._route(
'auth.signin',
),
}}
/>
);
}
}

if (
!route.auth &&
route.hasOwnProperty('path')
) {
if (authenticated) {
return (
<Redirect
to={NavigationUtils._route(
`${environment}.home`,
)}
/>
);
}
if (!route.auth && route.hasOwnProperty('path')) {
if (authenticated) {
return (
<Redirect
to={NavigationUtils._route(
`${environment}.home`,
)}
/>
);
}
}

return <View {...this.props} {...routeProps} />;
}}
/>
);
})}
</Switch>
);
}
}
return <View {...props} {...routeProps} />;
}}
/>
);
})}
</Switch>
);
};

Navigator.propTypes = {
pageProps: PropTypes.object.isRequired,
Expand Down
Loading

0 comments on commit ce6e9df

Please sign in to comment.