dbl-components
Version:
Framework based on bootstrap 5
199 lines (170 loc) • 5.29 kB
JSX
import React, { useEffect } from "react";
import PropTypes from "prop-types";
import {
BrowserRouter,
HashRouter,
Routes,
Route,
Outlet,
useLocation
} from "react-router-dom";
import { hash, eventHandler } from "dbl-utils";
import controllers from "../controllers";
import withRouteWrapper from "./with-route-wrapper";
const routePropTypes = {
path: PropTypes.oneOfType([
PropTypes.string,
PropTypes.arrayOf(PropTypes.string)
]).isRequired,
content: PropTypes.any.isRequired,
name: PropTypes.string,
component: PropTypes.string,
exact: PropTypes.bool,
strict: PropTypes.bool,
location: PropTypes.object,
sensitive: PropTypes.bool,
routes: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.shape(this)),
PropTypes.shape(this)
])
};
const schemaPropTypes = {
test: PropTypes.bool,
theme: PropTypes.string,
routes: routePropTypes.routes,
defaultController: PropTypes.func,
forceRebuild: PropTypes.bool,
}
const schemaDefaultProps = {
routes: [],
defaultController: controllers.Controller
}
export default class SchemaController extends React.Component {
static jsClass = 'SchemaController';
static propTypes = schemaPropTypes;
static defaultProps = schemaDefaultProps;
routeNodes = [];
state = {
}
constructor(props) {
super(props);
this.routesHash = '';
this.buildRoutes();
}
buildRoutes() {
// Crear un clone de lo que se recibe
const schemaStr = JSON.stringify(this.props.routes);
const routesSchema = JSON.parse(schemaStr);
let routes;
if (Array.isArray(routesSchema))
routes = routesSchema.map(this.views);
else if (typeof routesSchema === 'object' && routesSchema.name)
routes = this.views(routesSchema);
else if (typeof routesSchema === 'object')
routes = Object.keys(routesSchema)
.map((name, i) => this.views({ name, ...routesSchema[name] }, i))
//asignación directa
this.routeNodes = routes;
}
componentDidMount() {
}
componentDidUpdate(prevProps, prevState) {
// comprobar si ha cambiado el schema
let newHash = hash(JSON.stringify(this.props.routes));
if (this.routesHash !== newHash) {
this.buildRoutes();
this.routesHash = newHash;
}
}
/** views
* Método recursivo que procesa el schema de rutas
* usar en el mapeo de un arreglo ej. routes.map(this.views)
* permite que el schema tenga un arreglo de paths
**/
views = (route, i) => {
const Controller = controllers[route.component] || this.props.defaultController || controllers.Controller;
route.test = route.test || this.props.test;
const WrappedController = withRouteWrapper(Controller, route);
let subroutes = false;
if (Array.isArray(route.routes)) subroutes = [];
else if (typeof route.routes === 'object') {
subroutes = [];
route.routes = Object.keys(route.routes)
.map(name => ({ name, ...route.routes[name] }));
}
if (subroutes) {
const mapRoutes = (subRoute, i) => {
subRoute = JSON.parse(JSON.stringify(subRoute));
return this.views(subRoute, i);
};
subroutes = route.routes.map(mapRoutes);
}
const routeProps = {
path: route.path,
index: route.index,
action: route.action,
caseSensitive: route.caseSensitive,
Component: route.Component,
ErrorBoundary: route.ErrorBoundary,
errorElement: route.errorElement,
handle: route.handle,
hasErrorBoundary: route.hasErrorBoundary,
HydrateFallback: route.HydrateFallback,
hydrateFallbackElement: route.hydrateFallbackElement,
id: route.id,
lazy: route.lazy,
loader: route.loader,
shouldRevalidate: route.shouldRevalidate,
element: (
<WrappedController {...route}>
{subroutes.length > 0 ? <Outlet /> : null}
</WrappedController>
)
};
const key = i || typeof i === 'number' ? (i + '-' + route.name) : route.name;
return (
<Route key={key} {...routeProps}>
{subroutes.length > 0 && subroutes}
</Route>
);
}
render() {
const { theme } = this.props;
if (this.props.forceRebuild) {
this.buildRoutes();
}
return (
<>
{!!theme && <link rel="stylesheet" type="text/css" href={theme} />}
<Routes>
{this.routeNodes}
</Routes>
</>
);
}
}
const RouterSchema = (props) => {
const location = useLocation();
useEffect(() => {
eventHandler.dispatch('location', location);
}, [location.pathname]);
return <SchemaController {...props} />
}
export const BrowserRouterSchema = (props) => {
return (
<BrowserRouter>
<RouterSchema {...props} />
</BrowserRouter>
);
}
BrowserRouterSchema.propTypes = schemaPropTypes;
BrowserRouterSchema.defaultProps = schemaDefaultProps;
export const HashRouterSchema = (props) => {
return (
<HashRouter>
<RouterSchema {...props} />
</HashRouter>
);
}
HashRouterSchema.propTypes = schemaPropTypes;
HashRouterSchema.defaultProps = schemaDefaultProps;