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,11 +13,9 @@ import MessagesPage from './pages/messages';
import ProfilePage from './pages/profile'; import ProfilePage from './pages/profile';
import AuthPage from './pages/auth'; import AuthPage from './pages/auth';
import NotFoundPage from './pages/404'; import NotFoundPage from './pages/404';
import { ErrorBoundary } from 'react-error-boundary';
const App = () => { const App = () => {
return ( return (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<Router> <Router>
<Switch> <Switch>
<PrivateRoute exact path='/' component={MainPage} title='Main' /> <PrivateRoute exact path='/' component={MainPage} title='Main' />
@ -28,7 +26,6 @@ const App = () => {
<Route component={NotFoundPage} /> <Route component={NotFoundPage} />
</Switch> </Switch>
</Router> </Router>
</ErrorBoundary>
); );
}; };

View File

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

View File

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

View File

@ -5,6 +5,8 @@ import { Route, Redirect } from 'react-router-dom';
import { IPrivateRouteProps } from '../../interfaces'; import { IPrivateRouteProps } from '../../interfaces';
import { useRootStore } from '../../hooks/useRootStore'; import { useRootStore } from '../../hooks/useRootStore';
import { observer } from 'mobx-react'; 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, * 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} {...options}
render={props => render={props =>
authStore.isLoggedIn ? ( authStore.isLoggedIn ? (
<ErrorBoundary FallbackComponent={ErrorFallback}>
<Layout> <Layout>
<Helmet> <Helmet>
<title>{title} • App </title> <title>{title} • App </title>
</Helmet> </Helmet>
<Component {...props} title={title} /> <Component {...props} title={title} />
</Layout> </Layout>
</ErrorBoundary>
) : ( ) : (
<Redirect to={{ pathname: '/auth', state: { from: props.location } }} /> <Redirect to={{ pathname: '/auth', state: { from: props.location } }} />
) )

View File

@ -12,12 +12,36 @@ export interface IAppConfig {
links: LinkType[]; links: LinkType[];
} }
export interface IUserRole {
id: number;
name: string;
slug: string;
}
export interface IDataResult { export interface IDataResult {
data: any; data: any;
message: string; message: string;
status: number; 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 { export interface IPageProps extends RouteComponentProps {
title?: string; title?: string;
} }

View File

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

View File

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

View File

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

View File

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