Browse Source

Router typescript 적용

master
김장현 8 months ago
parent
commit
b9b496e814
  1. 37
      package-lock.json
  2. 3
      package.json
  3. 56
      src/@core/layouts/components/layout-wrapper/index.js
  4. 194
      src/router/Router.tsx
  5. 15
      src/router/routes/type.ts

37
package-lock.json generated

@ -4081,6 +4081,43 @@
"redux": "^4.0.0"
}
},
"@types/react-router": {
"version": "5.1.20",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
"integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
"dev": true,
"requires": {
"@types/history": "^4.7.11",
"@types/react": "*"
},
"dependencies": {
"@types/history": {
"version": "4.7.11",
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
"dev": true
}
}
},
"@types/react-router-dom": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
"integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
"dev": true,
"requires": {
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router": "*"
},
"dependencies": {
"@types/history": {
"version": "4.7.11",
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
"dev": true
}
}
},
"@types/redux-debounced": {
"version": "0.2.19",
"resolved": "https://registry.npmjs.org/@types/redux-debounced/-/redux-debounced-0.2.19.tgz",

3
package.json

@ -132,6 +132,7 @@
"extends": "react-app"
},
"devDependencies": {
"@types/react-router-dom": "5.3.3",
"@types/sortablejs": "^1.10.6",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
@ -151,7 +152,7 @@
"react-app-rewired": "^2.1.6",
"react-snap": "1.23.0",
"sass-loader": "^8.0.2",
"typescript": "^4.3.5"
"typescript": "4.3.5"
},
"browserslist": {
"production": [

56
src/@core/layouts/components/layout-wrapper/index.js

@ -1,59 +1,64 @@
// ** React Imports
import { Fragment, useEffect } from 'react'
import { Fragment, useEffect } from 'react';
// ** Third Party Components
import classnames from 'classnames'
import classnames from 'classnames';
// ** Store & Actions
import { useSelector, useDispatch } from 'react-redux'
import { handleContentWidth, handleMenuCollapsed, handleMenuHidden } from '@store/actions/layout'
import { useSelector, useDispatch } from 'react-redux';
import {
handleContentWidth,
handleMenuCollapsed,
handleMenuHidden
} from '@store/actions/layout';
// ** Styles
import 'animate.css/animate.css'
import 'animate.css/animate.css';
const LayoutWrapper = props => {
// ** Props
const { layout, children, appLayout, wrapperClass, transition, routeMeta } = props
const { layout, children, appLayout, wrapperClass, transition, routeMeta } =
props;
// ** Store Vars
const dispatch = useDispatch()
const store = useSelector(state => state)
const navbarStore = store.navbar
const contentWidth = store.layout.contentWidth
const dispatch = useDispatch();
const store = useSelector(state => state);
const navbarStore = store.navbar;
const contentWidth = store.layout.contentWidth;
//** Vars
const Tag = layout === 'HorizontalLayout' && !appLayout ? 'div' : Fragment
const Tag = layout === 'HorizontalLayout' && !appLayout ? 'div' : Fragment;
// ** Clean Up Function
const cleanUp = () => {
if (routeMeta) {
if (routeMeta.contentWidth) {
dispatch(handleContentWidth('full'))
dispatch(handleContentWidth('full'));
}
if (routeMeta.menuCollapsed) {
dispatch(handleMenuCollapsed(!routeMeta.menuCollapsed))
dispatch(handleMenuCollapsed(!routeMeta.menuCollapsed));
}
if (routeMeta.menuHidden) {
dispatch(handleMenuHidden(!routeMeta.menuHidden))
}
dispatch(handleMenuHidden(!routeMeta.menuHidden));
}
}
};
// ** ComponentDidMount
useEffect(() => {
if (routeMeta) {
if (routeMeta.contentWidth) {
dispatch(handleContentWidth(routeMeta.contentWidth))
dispatch(handleContentWidth(routeMeta.contentWidth));
}
if (routeMeta.menuCollapsed) {
dispatch(handleMenuCollapsed(routeMeta.menuCollapsed))
dispatch(handleMenuCollapsed(routeMeta.menuCollapsed));
}
if (routeMeta.menuHidden) {
dispatch(handleMenuHidden(routeMeta.menuHidden))
dispatch(handleMenuHidden(routeMeta.menuHidden));
}
}
return () => cleanUp()
}, [])
return () => cleanUp();
}, []);
return (
<div
@ -69,21 +74,20 @@ const LayoutWrapper = props => {
'content-wrapper': !appLayout,
'content-area-wrapper': appLayout,
'container p-0': contentWidth === 'boxed',
[`animate__animated animate__${transition}`]: transition !== 'none' && transition.length
[`animate__animated animate__${transition}`]:
transition !== 'none' && transition.length
})}
>
<Tag
/*eslint-disable */
{...(layout === 'HorizontalLayout' && !appLayout
? { className: classnames({ 'content-body': !appLayout }) }
: {})}
/*eslint-enable */
>
{children}
</Tag>
</div>
</div>
)
}
);
};
export default LayoutWrapper
export default LayoutWrapper;

194
src/router/Router.tsx

@ -0,0 +1,194 @@
import { useCallback, lazy, Suspense, useEffect } from 'react';
import { useDispatch } from 'react-redux';
import {
BrowserRouter as AppRouter,
Redirect,
Route,
Switch,
RouteComponentProps
} from 'react-router-dom';
import { useLayout } from '@hooks/useLayout';
import { useRouterTransition } from '@hooks/useRouterTransition';
import LayoutWrapper from '@layouts/components/layout-wrapper';
import BlankLayout from '@layouts/BlankLayout';
import HeaderLayout from '@layouts/HeaderLayout';
import HorizontalLayout from '@src/layouts/HorizontalLayout';
import VerticalLayout from '@src/layouts/VerticalLayout';
import * as Actions from '../modules/account/auth/actions';
import { Routes } from './routes';
import { useSelector } from '@store/storeConfig/store';
import { IRoute } from './routes/type';
const NotAuthorized = lazy(() => import('@src/views/NotAuthorized'));
const Error = lazy(() => import('@src/views/Error'));
interface IFinalRoute extends RouteComponentProps {
route: IRoute;
}
const Router = () => {
const [layout, setLayout] = useLayout();
const [transition, setTransition] = useRouterTransition();
const { isLogin } = useSelector(state => state.authState);
// const isLogin = true;
const dispatch = useDispatch();
useEffect(() => {
if (!isLogin) {
dispatch(Actions.check.request());
}
}, [isLogin]);
const DefaultLayout =
layout === 'horizontal' ? 'HorizontalLayout' : 'VerticalLayout';
const Layouts = {
BlankLayout,
VerticalLayout,
HorizontalLayout,
HeaderLayout
};
const currentActiveItem = null;
const LayoutRoutesAndPaths = (layout: string) => {
const LayoutRoutes: IRoute[] = [];
const LayoutPaths: string[] = [];
if (Routes) {
Routes.filter(route => {
if (
route.layout === layout ||
(route.layout === undefined && DefaultLayout === layout)
) {
LayoutRoutes.push(route);
LayoutPaths.push(route.path);
}
});
}
return { LayoutRoutes, LayoutPaths };
};
const FinalRoute = (props: IFinalRoute) => {
const route = props.route;
// let action, resource;
// if (route.meta) {
// action = route.meta.action ? route.meta.action : null;
// resource = route.meta.resource ? route.meta.resource : null;
// }
if (isLogin === false && !route.meta?.authRoute) {
return <Redirect to='/account/login' />;
} else {
const Component: (props: IFinalRoute) => JSX.Element =
route.component as (props: IFinalRoute) => JSX.Element;
// switch (props.route.path) {
// case '/account/register':
// case '/account/find':
// return <Redirect to='/main/dashboard' />;
// default:
// return <route.component {...props} />;
// }
return <Component {...props} />;
}
};
const ResolveRoutes = useCallback(() => {
return Object.keys(Layouts).map((layout, index) => {
const LayoutTag = Layouts[layout];
const { LayoutRoutes, LayoutPaths } = LayoutRoutesAndPaths(layout);
const routerProps = {};
return (
<Route path={LayoutPaths} key={index}>
<LayoutTag
routerProps={routerProps}
layout={layout}
setLayout={setLayout}
transition={transition}
setTransition={setTransition}
currentActiveItem={currentActiveItem}
>
<Switch>
{LayoutRoutes.map(route => {
return (
<Route
key={route.path}
path={route.path}
exact={route.exact === true}
render={props => {
Object.assign(routerProps, {
...props,
meta: route.meta
});
return (
<Suspense fallback={null}>
<LayoutWrapper
layout={DefaultLayout}
transition={transition}
setTransition={setTransition}
{...(route.appLayout
? {
appLayout: route.appLayout
}
: {})}
{...(route.meta
? {
routeMeta: route.meta
}
: {})}
{...(route.className
? {
wrapperClass: route.className
}
: {})}
>
<FinalRoute route={route} {...props} />
</LayoutWrapper>
</Suspense>
);
}}
/>
);
})}
</Switch>
</LayoutTag>
</Route>
);
});
}, [Layouts]);
return (
<AppRouter basename={process.env.REACT_APP_BASENAME}>
<Switch>
<Route
exact
path='/'
render={() => {
return <Redirect to='/main/dashboard' />;
}}
/>
<Route
exact
path='/not-authorized'
render={props => (
<Layouts.BlankLayout>
<NotAuthorized />
</Layouts.BlankLayout>
)}
/>
{ResolveRoutes()}
<Route path='*' component={Error} />
</Switch>
</AppRouter>
);
};
export default Router;

15
src/router/routes/type.ts

@ -0,0 +1,15 @@
import { FC, ReactElement, ReactNode } from 'react';
interface IRoute {
component: ReactNode;
layout?: string;
meta?: {
authRoute: boolean;
};
path: string | undefined;
exact?: boolean;
appLayout?: string;
className?: string;
}
export type { IRoute };
Loading…
Cancel
Save