diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx
index 77e2aa5..f9d735d 100644
--- a/src/components/Header/Header.tsx
+++ b/src/components/Header/Header.tsx
@@ -3,12 +3,14 @@ import { Flex, Box } from '@chakra-ui/react';
import AppName from './AppName';
import UserInfo from './User/UserInfo';
import UserNotifications from './User/UserNotifications';
-import useWindowDimensions from 'hooks/useWindowDimensions';
import NavMobile from '../Nav/Mobile/Nav';
import { observer } from 'mobx-react';
+import { useRootStore } from 'hooks/useRootStore';
const Header: React.FC = () => {
- const { isDesktop } = useWindowDimensions();
+ const {
+ uiStore: { isDesktop },
+ } = useRootStore();
return (
{
- const { authStore, userStore } = useRootStore();
- const history = useHistory();
- const toast = useToast();
+ const { userStore } = useRootStore();
+ const { logout } = useLogoutQuery();
- const onLogoutHandler = async (e: React.MouseEvent) => {
- try {
- await authStore.logout();
- history.push('/auth');
- toast({ title: 'You are logged out.', isClosable: true, status: 'info' });
- } catch (error) {
- console.error(error);
- }
- };
+ // const onLogoutHandler = async (e: React.MouseEvent) => {
+ // try {
+ // await authStore.logout();
+ // history.push('/auth');
+ // toast({ title: 'You are logged out.', isClosable: true, status: 'info' });
+ // } catch (error) {
+ // console.error(error);
+ // }
+ // };
if (userStore.me === null) {
return ;
@@ -60,7 +59,7 @@ const UserInfo: React.FC = () => {
My profile
-
) : (
diff --git a/src/components/PrivateRoute/PrivateRoute.tsx b/src/components/PrivateRoute/PrivateRoute.tsx
index b94d6a4..063e0fe 100644
--- a/src/components/PrivateRoute/PrivateRoute.tsx
+++ b/src/components/PrivateRoute/PrivateRoute.tsx
@@ -4,7 +4,6 @@ import Layout from '../Layout/Layout';
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';
import config from 'config';
@@ -39,4 +38,4 @@ const PrivateRoute: React.FC = ({ component: Component, titl
);
};
-export default observer(PrivateRoute);
+export default PrivateRoute;
diff --git a/src/components/User/UserBadge.tsx b/src/components/User/UserBadge.tsx
index 5848790..19fb6a7 100644
--- a/src/components/User/UserBadge.tsx
+++ b/src/components/User/UserBadge.tsx
@@ -2,14 +2,13 @@ import { Badge } from '@chakra-ui/react';
import React from 'react';
import { UserRoleEnum } from 'enums';
import { IUserRole } from 'interfaces';
+import { userHasRoles } from 'helpers';
/**
* Returns the badge for user based on roles
*/
const UserBadge: React.FC<{ roles: IUserRole[] }> = ({ roles }) => {
- const slugs = roles.map(role => role.slug);
-
- if (slugs.includes(UserRoleEnum.ADMIN)) {
+ if (userHasRoles(roles, [UserRoleEnum.ADMIN])) {
return (
Administrator
@@ -17,7 +16,7 @@ const UserBadge: React.FC<{ roles: IUserRole[] }> = ({ roles }) => {
);
}
- if (slugs.includes(UserRoleEnum.TEACHER)) {
+ if (userHasRoles(roles, [UserRoleEnum.TEACHER])) {
return (
Teacher
@@ -25,7 +24,7 @@ const UserBadge: React.FC<{ roles: IUserRole[] }> = ({ roles }) => {
);
}
- if (slugs.includes(UserRoleEnum.STUDENT)) {
+ if (userHasRoles(roles, [UserRoleEnum.STUDENT])) {
return Student;
}
diff --git a/src/hooks/useLogoutQuery.ts b/src/hooks/useLogoutQuery.ts
new file mode 100644
index 0000000..e630d1d
--- /dev/null
+++ b/src/hooks/useLogoutQuery.ts
@@ -0,0 +1,49 @@
+import React from 'react';
+import { useToast } from '@chakra-ui/react';
+import { useHistory } from 'react-router-dom';
+import { useRootStore } from './useRootStore';
+import { IDataResult } from 'interfaces';
+import { useErrorHandler } from 'react-error-boundary';
+
+type StateType = {
+ result: IDataResult | null;
+ error: any;
+ loading: boolean;
+ fetched: boolean;
+};
+
+const useLogoutQuery = () => {
+ const { authStore } = useRootStore();
+ const [state, setState] = React.useState({ result: null, error: null, loading: false, fetched: false });
+ const isMounted = React.useRef(true);
+ const history = useHistory();
+ const toast = useToast();
+ const handleError = useErrorHandler();
+ const request = React.useCallback(async () => {
+ setState(s => ({ ...s, loading: true }));
+ try {
+ const data = await authStore.logout();
+ history.push('/auth');
+
+ toast({ title: 'You are logged out.', isClosable: true, status: 'info' });
+ if (isMounted.current) setState(s => ({ ...s, result: data }));
+ } catch (error) {
+ handleError(error);
+ setState(s => ({ ...s, error }));
+ } finally {
+ if (isMounted.current) setState(s => ({ ...s, loading: false, fetched: true }));
+ }
+ }, [authStore, history, toast, handleError]);
+
+ const logout = () => request();
+
+ React.useEffect(() => {
+ return () => {
+ isMounted.current = false;
+ };
+ }, []);
+
+ return { ...state, logout };
+};
+
+export default useLogoutQuery;
diff --git a/src/hooks/useWindowDimensions.ts b/src/hooks/useWindowDimensions.ts
deleted file mode 100644
index f20b16b..0000000
--- a/src/hooks/useWindowDimensions.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react';
-
-const useWindowDimensions = () => {
- const [windowDimensions, setWindowDimensions] = React.useState({
- width: window.innerWidth,
- height: window.innerHeight,
- });
-
- React.useEffect(() => {
- /**
- * Update state on resize
- */
- const handleResize = () => {
- setWindowDimensions({ width: window.innerWidth, height: window.innerHeight });
- };
-
- window.addEventListener('resize', handleResize);
-
- return () => {
- window.removeEventListener('resize', handleResize);
- };
- }, []);
-
- return {
- windowDimensions,
- isDesktop: windowDimensions.width > 768,
- isTablet: windowDimensions.width < 768,
- isMobile: windowDimensions.width < 568,
- };
-};
-
-export default useWindowDimensions;
diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts
index 6a7b034..65e71d7 100644
--- a/src/interfaces/index.ts
+++ b/src/interfaces/index.ts
@@ -71,3 +71,8 @@ export interface IPublicRouteProps extends RouteProps {
component: React.FC;
title?: string;
}
+
+export interface IWindowDimensions {
+ width: number;
+ height: number;
+}
diff --git a/src/pages/courses.tsx b/src/pages/courses.tsx
index 0b669d2..541c11b 100644
--- a/src/pages/courses.tsx
+++ b/src/pages/courses.tsx
@@ -1,23 +1,12 @@
-import React, { useEffect } from 'react';
+import React from 'react';
import { Box, Heading, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Grid } from '@chakra-ui/react';
import { IPageProps } from 'interfaces';
-import { useRootStore } from 'hooks/useRootStore';
-import { useHistory } from 'react-router-dom';
/**
* Courses page
*/
const CoursesPage: React.FC = ({ title }) => {
- const { authStore } = useRootStore();
- const history = useHistory();
-
- useEffect(() => {
- if (!authStore.isLoggedIn) {
- history.push('/auth');
- }
- });
-
return (
<>
diff --git a/src/pages/messages.tsx b/src/pages/messages.tsx
index ac14eef..b638430 100644
--- a/src/pages/messages.tsx
+++ b/src/pages/messages.tsx
@@ -1,23 +1,12 @@
-import React, { useEffect } from 'react';
+import React from 'react';
import { Box, Heading, Breadcrumb, BreadcrumbItem, BreadcrumbLink, Grid } from '@chakra-ui/react';
import { IPageProps } from 'interfaces';
-import { useRootStore } from 'hooks/useRootStore';
-import { useHistory } from 'react-router-dom';
/**
* Messages page
*/
const MessagesPage: React.FC = ({ title }) => {
- const { authStore } = useRootStore();
- const history = useHistory();
-
- useEffect(() => {
- if (!authStore.isLoggedIn) {
- history.push('/auth');
- }
- });
-
return (
<>
diff --git a/src/stores/UIStore.ts b/src/stores/UIStore.ts
index 43d9d9c..c34b068 100644
--- a/src/stores/UIStore.ts
+++ b/src/stores/UIStore.ts
@@ -1,6 +1,7 @@
-import { makeAutoObservable } from 'mobx';
+import { makeAutoObservable, observable } from 'mobx';
import { createBrowserHistory } from 'history';
import RootStore from './RootStore';
+import { IWindowDimensions } from 'interfaces';
export default class UIStore {
public root: RootStore;
@@ -9,18 +10,43 @@ export default class UIStore {
public history: ReturnType;
+ public windowDimensions: IWindowDimensions = { width: window.innerWidth, height: window.innerHeight };
+
constructor(root: RootStore) {
this.root = root;
this.history = createBrowserHistory();
- makeAutoObservable(this);
+
+ makeAutoObservable(this, {
+ windowDimensions: observable.struct,
+ });
this.history.listen(({ pathname }) => {
console.log(`[history]: pathname changed to "${pathname}"`);
this.location = pathname;
});
+
+ window.onresize = () => {
+ this.windowDimensions = this.getWindowDimensions();
+ };
}
- public setLocation(location: string) {
+ public setLocation(location: string): void {
this.location = location;
}
+
+ private getWindowDimensions(): IWindowDimensions {
+ return { width: window.innerWidth, height: window.innerHeight };
+ }
+
+ get isDesktop() {
+ return this.windowDimensions.width > 768;
+ }
+
+ get isTablet() {
+ return this.windowDimensions.width < 768;
+ }
+
+ get isMobile() {
+ return this.windowDimensions.width < 568;
+ }
}