feat: added typing for user result fetch & logout

This commit is contained in:
Sergey Yarkov 2021-08-24 12:58:13 +03:00
parent e7e98dd7ac
commit d4703b97d3
9 changed files with 70 additions and 51 deletions

View File

@ -13,22 +13,19 @@ import MessagesPage from './pages/messages';
import ProfilePage from './pages/profile';
import AuthPage from './pages/auth';
import NotFoundPage from './pages/404';
import { ErrorBoundary } from 'react-error-boundary';
const App = () => {
return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<Router>
<Switch>
<PrivateRoute exact path='/' component={MainPage} title='Main' />
<PrivateRoute path='/courses' component={CoursesPage} title='Courses' />
<PrivateRoute path='/messages' component={MessagesPage} title='Messages' />
<PrivateRoute path='/profile' component={ProfilePage} title='Profile' />
<Route path='/auth' component={AuthPage} />
<Route component={NotFoundPage} />
</Switch>
</Router>
</ErrorBoundary>
<Router>
<Switch>
<PrivateRoute exact path='/' component={MainPage} title='Main' />
<PrivateRoute path='/courses' component={CoursesPage} title='Courses' />
<PrivateRoute path='/messages' component={MessagesPage} title='Messages' />
<PrivateRoute path='/profile' component={ProfilePage} title='Profile' />
<Route path='/auth' component={AuthPage} />
<Route component={NotFoundPage} />
</Switch>
</Router>
);
};

View File

@ -11,14 +11,13 @@ import {
Box,
Avatar,
Text,
Link,
useToast,
Skeleton,
} from '@chakra-ui/react';
import { MdSettings, MdExitToApp } from 'react-icons/md';
import { observer } from 'mobx-react';
import { useRootStore } from '../../../hooks/useRootStore';
import { useHistory } from 'react-router-dom';
import { useHistory, Link } from 'react-router-dom';
const UserInfo: React.FC = () => {
const { authStore, userStore } = useRootStore();

View File

@ -12,15 +12,13 @@ import { useErrorHandler } from 'react-error-boundary';
* Сomponent for rendering the current page.
*/
const Layout: React.FC = ({ children }) => {
const { authStore } = useRootStore();
const { authStore, userStore } = useRootStore();
const handleError = useErrorHandler();
React.useEffect(() => {
if (authStore.isLoggedIn) {
authStore.root.userStore.loadCurrentUserData().catch(error => {
if (error.response && error.response.status === 401) {
handleError(error);
}
userStore.loadCurrentUserData().catch(error => {
handleError(error);
});
}
});

View File

@ -5,6 +5,8 @@ import { Route, Redirect } from 'react-router-dom';
import { IPrivateRouteProps } from '../../interfaces';
import { useRootStore } from '../../hooks/useRootStore';
import { observer } from 'mobx-react';
import { ErrorBoundary } from 'react-error-boundary';
import ErrorFallback from '../ErrorFallback';
/**
* Checks if the user is loggedIn by reactive variable and if not,
@ -18,12 +20,14 @@ const PrivateRoute: React.FC<IPrivateRouteProps> = ({ children, component: Compo
{...options}
render={props =>
authStore.isLoggedIn ? (
<Layout>
<Helmet>
<title>{title} • App </title>
</Helmet>
<Component {...props} title={title} />
</Layout>
<ErrorBoundary FallbackComponent={ErrorFallback}>
<Layout>
<Helmet>
<title>{title} • App </title>
</Helmet>
<Component {...props} title={title} />
</Layout>
</ErrorBoundary>
) : (
<Redirect to={{ pathname: '/auth', state: { from: props.location } }} />
)

View File

@ -12,12 +12,36 @@ export interface IAppConfig {
links: LinkType[];
}
export interface IUserRole {
id: number;
name: string;
slug: string;
}
export interface IDataResult {
data: any;
message: string;
status: number;
}
export interface ILoginResult extends IDataResult {
data: {
token: string;
type: string;
expires_at: string;
};
}
export interface IUserResult extends IDataResult {
data: {
id: string;
first_name: string;
last_name: string;
email: string;
roles: IUserRole[];
};
}
export interface IPageProps extends RouteComponentProps {
title?: string;
}

View File

@ -1,13 +1,5 @@
import { IDataResult } from '../interfaces';
import { AxiosInstance } from 'axios';
export interface ILoginResult extends IDataResult {
data: {
token: string;
type: string;
expires_at: string;
};
}
import { IDataResult, ILoginResult } from '../interfaces';
import { AxiosInstance, AxiosResponse } from 'axios';
export default class AuthService {
public api: AxiosInstance;
@ -24,22 +16,20 @@ export default class AuthService {
* @returns Login result
*/
public async requestLogin(login: string, password: string): Promise<ILoginResult> {
const result = await this.api.post('v1/auth/login', {
const result: AxiosResponse<any> = await this.api.post('v1/auth/login', {
login,
password,
});
return result.data;
}
/**
* Revoke token
*
* @returns Logout result
* @returns Data result
*/
public async requestLogout(): Promise<any> {
const result = await this.api.post('v1/auth/logout');
public async requestLogout(): Promise<IDataResult> {
const result: AxiosResponse<any> = await this.api.post('v1/auth/logout');
return result.data;
}
}

View File

@ -1,4 +1,5 @@
import { AxiosInstance } from 'axios';
import { IUserResult } from '../interfaces';
export default class UserService {
public api: AxiosInstance;
@ -12,7 +13,7 @@ export default class UserService {
*
* @returns User data
*/
public async fetchMe(): Promise<any> {
public async fetchMe(): Promise<IUserResult> {
const result = await this.api.get('v1/me');
return result.data;
}

View File

@ -3,6 +3,7 @@ import Cookies from 'js-cookie';
import RootStore from './RootStore';
import AuthService from '../services/AuthService';
import { AxiosInstance } from 'axios';
import { IDataResult, ILoginResult } from '../interfaces';
export default class AuthStore {
public root: RootStore;
@ -27,7 +28,7 @@ export default class AuthStore {
this.loading = value;
}
public async login(login: string, password: string) {
public async login(login: string, password: string): Promise<ILoginResult> {
try {
this.setLoading(true);
const result = await this.authService.requestLogin(login, password);
@ -43,7 +44,7 @@ export default class AuthStore {
}
}
public async logout() {
public async logout(): Promise<IDataResult> {
try {
this.setLoading(true);
const result = await this.authService.requestLogout();

View File

@ -1,5 +1,6 @@
import { AxiosInstance } from 'axios';
import { autorun, makeAutoObservable } from 'mobx';
import { IUserResult } from '../interfaces';
import UserService from '../services/UserService';
import RootStore from './RootStore';
@ -25,13 +26,17 @@ export default class UserStore {
makeAutoObservable(this);
}
public async loadCurrentUserData(): Promise<any> {
const result = await this.userService.fetchMe();
public async loadCurrentUserData(): Promise<IUserResult> {
try {
const result = await this.userService.fetchMe();
autorun(() => {
this.me = result.data;
});
autorun(() => {
this.me = result.data;
});
return result;
return result;
} catch (error) {
throw error;
}
}
}