Skip to content

Commit 364e4ca

Browse files
committed
feat: auth hooks
refactor: Routes and Layouts refactor: useAppForm hook feat: DevVIew
1 parent 848b473 commit 364e4ca

32 files changed

+522
-112
lines changed

.env.sample

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,9 @@
1+
2+
# Debug mode
3+
REACT_APP_DEBUG = true
4+
5+
# API/Backend basic URL
6+
REACT_APP_URL_API = http://localhost:3030/api
7+
8+
# Runtime helpers
19
REACT_APP_VERSION = $npm_package_version
2-
REACT_APP_URL_API = http://localhost:3030/api

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
"url": "put your repo url here..."
2020
},
2121
"scripts": {
22+
"start": "react-scripts start",
2223
"build": "react-scripts build",
23-
"dev": "npm i && react-scripts start",
24+
"dev": "react-scripts start",
25+
"dev:update": "npm i && react-scripts start",
2426
"format": "prettier ./src --write",
2527
"format:all": "prettier . --write",
2628
"lint": "eslint ./src --ext .js,.ts,.tsx",
27-
"start": "react-scripts start",
2829
"type": "tsc",
2930
"test": "react-scripts test"
3031
},

src/App.tsx

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
1-
import { AppStore } from './store';
21
import { AppThemeProvider } from './theme';
3-
import Routes from './routes';
4-
import Layout from './layout';
2+
import { AppStore } from './store';
53
import { ErrorBoundary } from './components';
6-
import { BrowserRouter } from 'react-router-dom';
4+
import Routes from './routes';
75

86
/**
97
* Root Application Component
8+
* @component MainApp
109
*/
11-
const App = () => {
10+
const MainApp = () => {
1211
return (
1312
<ErrorBoundary name="App">
1413
<AppStore>
1514
<AppThemeProvider>
16-
<BrowserRouter>
17-
<Layout>
18-
<Routes />
19-
</Layout>
20-
</BrowserRouter>
15+
<Routes />
2116
</AppThemeProvider>
2217
</AppStore>
2318
</ErrorBoundary>
2419
);
2520
};
2621

27-
export default App;
22+
export default MainApp;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { FunctionComponent } from 'react';
2+
import { CircularProgress, CircularProgressProps, LinearProgress, Stack, StackProps } from '@mui/material';
3+
import { APP_LOADING_COLOR, APP_LOADING_SIZE, APP_LOADING_TYPE } from '../config';
4+
5+
interface Props extends StackProps {
6+
color?: CircularProgressProps['color'];
7+
size?: number | string;
8+
type?: 'circular' | 'linear';
9+
value?: number;
10+
}
11+
12+
/**
13+
* Renders MI circular progress centered inside Stack
14+
* @component AppLoading
15+
* @prop {string} [size] - size of the progress component. Numbers means pixels, string can be '2.5rem'
16+
*/
17+
const AppLoading: FunctionComponent<Props> = ({
18+
color = APP_LOADING_COLOR,
19+
size = APP_LOADING_SIZE,
20+
type = APP_LOADING_TYPE,
21+
value,
22+
...restOfProps
23+
}) => {
24+
const alignItems = type === 'linear' ? undefined : 'center';
25+
return (
26+
<Stack my={2} alignItems={alignItems} {...restOfProps}>
27+
{type === 'linear' ? (
28+
<LinearProgress color={color} value={value} />
29+
) : (
30+
<CircularProgress color={color} size={size} value={value} />
31+
)}
32+
</Stack>
33+
);
34+
};
35+
36+
export default AppLoading;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import AppLoading from './AppLoading';
2+
3+
export { AppLoading as default, AppLoading };

src/components/AppView/AppView.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { FunctionComponent, PropsWithChildren } from 'react';
2+
import { Stack, StackProps, useMediaQuery, useTheme } from '@mui/material';
3+
import { CONTENT_MAX_WIDTH, CONTENT_MIN_WIDTH } from '../config';
4+
5+
/**
6+
* Renders View container composition with limited width
7+
* @component AppView
8+
*/
9+
const AppView: FunctionComponent<PropsWithChildren<StackProps>> = ({ children, minWidth, ...restOfProps }) => {
10+
const theme = useTheme();
11+
const onSmallScreens = useMediaQuery(theme.breakpoints.down('sm'));
12+
const minWidthToRender = onSmallScreens ? '100%' : minWidth ?? CONTENT_MIN_WIDTH;
13+
14+
return (
15+
<Stack alignSelf="center" gap={2} maxWidth={CONTENT_MAX_WIDTH} minWidth={minWidthToRender} {...restOfProps}>
16+
{children}
17+
</Stack>
18+
);
19+
};
20+
21+
export default AppView;

src/components/AppView/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import AppView from './AppView';
2+
3+
export { AppView as default, AppView as ViewContainer };

src/components/config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* Components configuration
33
*/
4+
export const CONTENT_MAX_WIDTH = 800;
5+
export const CONTENT_MIN_WIDTH = 320; // CONTENT_MAX_WIDTH - Sidebar width
46

57
/**
68
* AppAlert and AppSnackBarAlert components
@@ -25,6 +27,13 @@ export const APP_ICON_SIZE = 24;
2527
export const APP_LINK_COLOR = 'textSecondary'; // 'primary' // 'secondary'
2628
export const APP_LINK_UNDERLINE = 'hover'; // 'always
2729

30+
/**
31+
* AppLoading component
32+
*/
33+
export const APP_LOADING_COLOR = 'primary'; // 'secondary'
34+
export const APP_LOADING_SIZE = '3rem'; // 40
35+
export const APP_LOADING_TYPE = 'circular'; // 'linear'; // 'circular'
36+
2837
/**
2938
* AppSection component
3039
*/

src/components/index.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import ErrorBoundary from './ErrorBoundary';
2-
import AppLink from './AppLink';
1+
import AppAlert from './AppAlert';
32
import AppButton from './AppButton';
3+
import AppForm from './AppForm';
44
import AppIcon from './AppIcon';
55
import AppIconButton from './AppIconButton';
6-
import AppAlert from './AppAlert';
7-
import AppForm from './AppForm';
6+
import AppLink from './AppLink';
7+
import AppLoading from './AppLoading';
8+
import AppView from './AppView';
9+
import ErrorBoundary from './ErrorBoundary';
810

9-
export { ErrorBoundary, AppLink, AppButton, AppIcon, AppIconButton, AppAlert, AppForm };
11+
export { ErrorBoundary, AppAlert, AppForm, AppButton, AppIcon, AppIconButton, AppLink, AppLoading, AppView };

src/hooks/auth.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
1-
import { useCallback } from 'react';
1+
import { useCallback, useEffect } from 'react';
2+
import { useNavigate } from 'react-router-dom';
23
import { useAppStore } from '../store';
34

5+
type CurrentUser = {
6+
id?: string;
7+
email?: string;
8+
phone?: string;
9+
avatar?: string;
10+
name?: string;
11+
};
12+
13+
/**
14+
* Hook to get currently logged user
15+
* @returns {object | undefined} user data as object or undefined if user is not logged in
16+
*/
17+
export function useCurrentUser(): CurrentUser | undefined {
18+
const [state] = useAppStore();
19+
return state.currentUser;
20+
}
21+
422
/**
523
* Hook to detect is current user authenticated or not
624
* @returns {boolean} true if user is authenticated, false otherwise
@@ -20,12 +38,31 @@ export function useIsAuthenticated() {
2038
* @returns {function} calling this event logs out current user
2139
*/
2240
export function useEventLogout() {
41+
const navigate = useNavigate();
2342
const [, dispatch] = useAppStore();
2443

2544
return useCallback(() => {
2645
// TODO: AUTH: add auth and tokens cleanup here
2746
// sessionStorageDelete('access_token');
2847

2948
dispatch({ type: 'LOG_OUT' });
30-
}, [dispatch]);
49+
navigate('/', { replace: true }); // Redirect to home page by reloading the App
50+
}, [dispatch, navigate]);
51+
}
52+
53+
/**
54+
* Adds watchdog and calls different callbacks on user login and logout
55+
* @param {function} afterLogin callback to call after user login
56+
* @param {function} afterLogout callback to call after user logout
57+
*/
58+
export function useAuthWatchdog(afterLogin: () => void, afterLogout: () => void) {
59+
const [state, dispatch] = useAppStore();
60+
61+
useEffect(() => {
62+
if (state.isAuthenticated) {
63+
afterLogin?.();
64+
} else {
65+
afterLogout?.();
66+
}
67+
}, [state.isAuthenticated, dispatch, afterLogin, afterLogout]);
3168
}

0 commit comments

Comments
 (0)