Add routing
This commit is contained in:
parent
18d32055ba
commit
0670d29457
|
|
@ -3,12 +3,16 @@
|
|||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@types/qs": "^6.9.7",
|
||||
"@types/react": "^17.0.15",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"@types/sprintf-js": "^1.1.2",
|
||||
"axios": "^0.21.1",
|
||||
"loglevel": "^1.7.1",
|
||||
"modern-css-reset": "^1.4.0",
|
||||
"qs": "^6.10.1",
|
||||
"ramda": "^0.27.1",
|
||||
"react": "^17.0.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"sass-rem": "^3.0.0",
|
||||
"sprintf-js": "^1.1.2"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
import React from 'react'
|
||||
|
||||
interface Route {
|
||||
path: string
|
||||
name?: string
|
||||
redirect?: string
|
||||
exact?: boolean
|
||||
navbar?: boolean
|
||||
isIndex?: boolean
|
||||
icon?: React.ComponentType
|
||||
childRoutes?: Route[]
|
||||
component?: React.ComponentType
|
||||
}
|
||||
|
||||
export default Route
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
import React from 'react'
|
||||
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom'
|
||||
import { prepareRoutes } from './config'
|
||||
import RouteDefinition from './Route'
|
||||
|
||||
const getComponentRoute = (contextPath: string, component: React.ComponentType) => (
|
||||
<Route
|
||||
exact
|
||||
key={contextPath}
|
||||
component={component}
|
||||
path={contextPath}
|
||||
/>
|
||||
)
|
||||
|
||||
const renderRouteConfig = (
|
||||
Container: React.ComponentType,
|
||||
routes: RouteDefinition[],
|
||||
contextPath: string,
|
||||
): JSX.Element => {
|
||||
// Resolve route config object in React Router v3.
|
||||
const children: React.ReactNode[] = []
|
||||
|
||||
const renderRoute = (item: RouteDefinition, routeContextPath: string) => {
|
||||
let newContextPath: string
|
||||
|
||||
if (/(^\/)|(^\*)/.test(item.path)) {
|
||||
newContextPath = item.path
|
||||
} else {
|
||||
newContextPath = `${routeContextPath}/${item.path}`
|
||||
}
|
||||
|
||||
newContextPath = newContextPath.replace(/\/+/g, '/')
|
||||
|
||||
if (item.redirect) {
|
||||
const route = (
|
||||
<Route
|
||||
exact
|
||||
key={newContextPath}
|
||||
render={() => <Redirect to={item.redirect as string} />}
|
||||
path={newContextPath}
|
||||
/>
|
||||
)
|
||||
|
||||
children.push(route)
|
||||
} else if (item.component && item.childRoutes) {
|
||||
const routeConfig = renderRouteConfig(item.component, item.childRoutes, newContextPath)
|
||||
|
||||
children.push(routeConfig)
|
||||
} else if (item.component) {
|
||||
const route = getComponentRoute(newContextPath, item.component)
|
||||
|
||||
children.push(route)
|
||||
} else if (item.childRoutes) {
|
||||
item.childRoutes.forEach(r => renderRoute(r, newContextPath))
|
||||
}
|
||||
}
|
||||
|
||||
routes.forEach(item => renderRoute(item, contextPath))
|
||||
|
||||
// Use Switch as the default container by default
|
||||
if (!Container) {
|
||||
return (
|
||||
<Switch>
|
||||
{children as JSX.TChildren[]}
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Container key={contextPath}>
|
||||
<Switch>
|
||||
{children as JSX.TChildren[]}
|
||||
</Switch>
|
||||
</Container>
|
||||
</BrowserRouter>
|
||||
)
|
||||
}
|
||||
|
||||
interface Props {
|
||||
routeConfig: RouteDefinition[]
|
||||
component: React.ComponentType
|
||||
baseUrlPath: string
|
||||
}
|
||||
|
||||
const Router: React.FC<Props> = (props: Props) => {
|
||||
const { routeConfig, component, baseUrlPath } = props
|
||||
|
||||
const preparedRoutes = prepareRoutes(routeConfig)
|
||||
|
||||
return renderRouteConfig(component, preparedRoutes, baseUrlPath)
|
||||
}
|
||||
|
||||
export default Router
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import * as R from 'ramda'
|
||||
import Route from './Route'
|
||||
|
||||
// Handle isIndex property of route config:
|
||||
// Duplicate it and put it as the first route rule.
|
||||
const handleIndexRoute = (route: Route) => {
|
||||
if (!route.childRoutes || !route.childRoutes.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const indexRoute = route.childRoutes.find(R.prop('isIndex'))
|
||||
|
||||
if (indexRoute) {
|
||||
const first = {
|
||||
...indexRoute,
|
||||
path: route.path,
|
||||
exact: true,
|
||||
}
|
||||
|
||||
route.childRoutes.unshift(first)
|
||||
}
|
||||
|
||||
route.childRoutes.forEach(handleIndexRoute)
|
||||
}
|
||||
|
||||
export const prepareRoutes: (route: Route[]) => Route[] = R.pipe(
|
||||
R.filter((r: Route): boolean => Boolean(
|
||||
r.redirect
|
||||
|| r.component
|
||||
|| (r.childRoutes && r.childRoutes.length > 0),
|
||||
)),
|
||||
R.forEach(handleIndexRoute),
|
||||
)
|
||||
Loading…
Reference in New Issue