Fix routes typing with any

Signed-off-by: Émile Ré <nemile.re@gmail.com>
This commit is contained in:
Émile Ré
2025-12-03 18:29:22 +04:00
parent 9265ad69eb
commit 638bef05a2

View File

@@ -4,11 +4,12 @@ import {
redirect, redirect,
useLoaderData, useLoaderData,
useRouteError, useRouteError,
type LoaderFunction,
type RouteObject, type RouteObject,
} from "react-router"; } from "react-router";
import { MainLayout } from "./layouts/MainLayout"; import { MainLayout } from "./layouts/MainLayout";
import { AuthLayout, CenteredLayout, CenteredLayoutSkeleton } from "@probo/ui"; import { AuthLayout, CenteredLayout, CenteredLayoutSkeleton } from "@probo/ui";
import { Fragment, Suspense } from "react"; import { Fragment, Suspense, type ComponentType, type LazyExoticComponent } from "react";
import { import {
relayEnvironment, relayEnvironment,
UnAuthenticatedError, UnAuthenticatedError,
@@ -16,7 +17,7 @@ import {
ForbiddenError, ForbiddenError,
} from "./providers/RelayProviders"; } from "./providers/RelayProviders";
import { PageSkeleton } from "./components/skeletons/PageSkeleton.tsx"; import { PageSkeleton } from "./components/skeletons/PageSkeleton.tsx";
import { loadQuery, type PreloadedQuery } from "react-relay"; import { loadQuery, type EnvironmentProviderOptions, type PreloadedQuery } from "react-relay";
import { useCleanup } from "./hooks/useDelayedEffect.ts"; import { useCleanup } from "./hooks/useDelayedEffect.ts";
import { riskRoutes } from "./routes/riskRoutes.ts"; import { riskRoutes } from "./routes/riskRoutes.ts";
import { measureRoutes } from "./routes/measureRoutes.ts"; import { measureRoutes } from "./routes/measureRoutes.ts";
@@ -38,13 +39,25 @@ import { snapshotsRoutes } from "./routes/snapshotsRoutes.ts";
import { continualImprovementRoutes } from "./routes/continualImprovementRoutes.ts"; import { continualImprovementRoutes } from "./routes/continualImprovementRoutes.ts";
import { processingActivityRoutes } from "./routes/processingActivityRoutes.ts"; import { processingActivityRoutes } from "./routes/processingActivityRoutes.ts";
import { lazy } from "@probo/react-lazy"; import { lazy } from "@probo/react-lazy";
import type { OperationType, VariablesOf } from "relay-runtime";
import type { OrganizationGraph_ViewQuery } from "./hooks/graph/__generated__/OrganizationGraph_ViewQuery.graphql.ts";
export type AppRoute = Omit<RouteObject, "Component" | "children"> & { type AppRouteWithoutQuery<TQuery extends OperationType> = Omit<RouteObject, "Component" | "children"> & {
Component?: React.ComponentType<any>; Component?: React.ComponentType;
children?: AppRoute[]; children?: AppRoute<TQuery>[];
fallback?: React.ComponentType; fallback?: React.ComponentType;
queryLoader?: (params: any) => PreloadedQuery<any>; queryLoader?: undefined;
}; }
type AppRouteWithQuery<TQuery extends OperationType> = Omit<RouteObject, "Component" | "children"> & {
Component?:
LazyExoticComponent<ComponentType<{ queryRef: PreloadedQuery<TQuery, EnvironmentProviderOptions> }>>;
children?: AppRoute<TQuery>[];
fallback?: React.ComponentType;
queryLoader?: (params: VariablesOf<TQuery>) => PreloadedQuery<TQuery, EnvironmentProviderOptions>;
}
export type AppRoute<TQuery extends OperationType> = AppRouteWithoutQuery<TQuery> | AppRouteWithQuery<TQuery>;
/** /**
* Top level error boundary * Top level error boundary
@@ -141,7 +154,7 @@ const routes = [
{ {
path: "settings", path: "settings",
fallback: PageSkeleton, fallback: PageSkeleton,
queryLoader: ({ organizationId }) => queryLoader: ({ organizationId }: VariablesOf<OrganizationGraph_ViewQuery>) =>
loadQuery(relayEnvironment, organizationViewQuery, { loadQuery(relayEnvironment, organizationViewQuery, {
organizationId, organizationId,
}), }),
@@ -199,40 +212,40 @@ const routes = [
path: "*", path: "*",
Component: PageError, Component: PageError,
}, },
] satisfies AppRoute[]; ] as AppRoute<OperationType>[];
/** /**
* Wrap components with suspense to handle lazy loading & relay loading states * Wrap components with suspense to handle lazy loading & relay loading states
*/ */
function routeTransformer({ function routeTransformer<TQuery extends OperationType>({
Component,
fallback: FallbackComponent, fallback: FallbackComponent,
queryLoader, queryLoader,
...route children,
}: AppRoute): RouteObject { ...rest
let result = { ...route }; }: AppRoute<TQuery>): RouteObject {
if (FallbackComponent && route.Component) { let route: RouteObject = { ...rest };
const OriginalComponent = route.Component;
result = { if (Component) {
...result, let RouteComponent = Component;
Component: (props) => (
if (FallbackComponent && typeof queryLoader === "undefined") {
const OriginalComponent = Component as ComponentType;
RouteComponent = () => (
<Suspense fallback={<FallbackComponent />}> <Suspense fallback={<FallbackComponent />}>
<OriginalComponent {...props} /> <OriginalComponent />
</Suspense> </Suspense>
), );
};
} route = {
if (queryLoader && route.Component) { ...route,
const OriginalComponent = route.Component; Component: RouteComponent,
result = { };
...result, } else if (queryLoader) {
loader: ({ params }) => { const OriginalComponent = Component as LazyExoticComponent<ComponentType<{ queryRef: PreloadedQuery<TQuery, EnvironmentProviderOptions> }>>;
const query = queryLoader(params as Record<string, string>);
return { RouteComponent = () => {
queryRef: query,
dispose: query.dispose,
};
},
Component: () => {
const { queryRef, dispose } = useLoaderData(); const { queryRef, dispose } = useLoaderData();
useCleanup(dispose, 1000); useCleanup(dispose, 1000);
@@ -242,12 +255,27 @@ function routeTransformer({
<OriginalComponent queryRef={queryRef} /> <OriginalComponent queryRef={queryRef} />
</Suspense> </Suspense>
); );
}, };
};
const loader: LoaderFunction = ({ params }) => {
const query = queryLoader(params as VariablesOf<TQuery>);
return {
queryRef: query,
dispose: query.dispose,
};
};
route = {
...route,
loader: loader,
Component: RouteComponent,
};
}
} }
return { return {
...result, ...route,
children: route.children?.map(routeTransformer), children: children?.map(routeTransformer<TQuery>),
} as RouteObject; } as RouteObject;
} }