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" "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": { "@types/redux-debounced": {
"version": "0.2.19", "version": "0.2.19",
"resolved": "https://registry.npmjs.org/@types/redux-debounced/-/redux-debounced-0.2.19.tgz", "resolved": "https://registry.npmjs.org/@types/redux-debounced/-/redux-debounced-0.2.19.tgz",

3
package.json

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

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

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